We have a ASP.Net 2.0 web site secured by Forms authentication with custom membership provider & role manager, within this web site, we have a web service exposed as an API. We want this web service also be secured with same mechanism.
I thought of adding Credentials to web service proxy class, but this fails since Credentials should only work with Windows authentication.
Then I thought of maybe <location/> element helps since this element enables you have different configuration settings with different urls. and this also failed, because you can't write a web.config like this:
<location path="." allowOverride="true" inheritInChildApplications="true">
<system.web>
<authentication mode="Forms">
<forms loginUrl="login.aspx" name=".ASPXFORMSAUTH">
</forms>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
<location path="svc.asmx">
<system.web>
<forms loginUrl="svc.asmx?op=Logon" name=".ASPXFORMSAUTH">
</forms>
</system.web>
</location>
And this fails still because <authentication/> is not a overridable element in web.config, so that you can not specify 2 different login pages in same web site.
Finally, Andrew Arnott's Blog saves me, he has the same issue I have, follow his instruction, we are now able to use same Membership provider/Role manager to authenticate both web site & web service.
Bellow is a summary:
- Install WSE 3.0
- On your web project, open up WSE 3.0 property page
- Check both [Enable this project for web services Enhancements] and [Enable Microsoft web services Enhacement Soap protocol Factory]
- Under [Security] tab, add a custom token manager
- Enable policy, name your new policy, this policy name will be used both server side and client side, so don't miss it.
- Click OK to complete server setting.
- a wse3policyCache.config file will be generated
- Enable your web site's Membership/RoleManager if they are not enabled yet.
- Modify wse3policyCache.config, allow specificed roles to access this web service(for me,"User" role are allowed), your wse3policyCache.config should look like this
<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">
<extensions>
<extension name="usernameOverTransportSecurity" type="Microsoft.Web.Services3.Design.UsernameOverTransportAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</extensions>
<policy name="usernameTokenSecurity">
<authorization>
<allow role="User"/>
<deny role="*"/>
</authorization>
<usernameOverTransportSecurity />
<requireActionHeader />
</policy>
</policies>
- Add a custom token manager in APP_CODE folder, code listed bellow:
using System.Xml;
using System.Web.Security;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class CustomUsernameTokenManager : UsernameTokenManager
{
//codes omitted.
protected override string AuthenticateToken(UsernameToken token)
{
bool validCredentials = Membership.ValidateUser(token.Username, token.Password);
if (!validCredentials) throw new UnauthorizedAccessException();
GenericIdentity identity = new GenericIdentity(token.Username);
GenericPrincipal principal = new GenericPrincipal(identity, Roles.GetRolesForUser(token.Username));
token.Principal = principal;
return token.Password;
}
}
- Modify <microsoft.web.services3> section in your web site's web.config, should look like this:
<microsoft.web.services3>
<security>
<securityTokenManager>
<add
type="CustomUsernameTokenManager, __code"
namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" localName="UsernameToken" />
</securityTokenManager>
</security>
<policy fileName="wse3policyCache.config" />
</microsoft.web.services3>
Modify web.config to allow client to call your web service
<location path="svc.asmx">
<system.web>
<authorization>
<allow users="*"></allow>
</authorization>
</system.web>
</location>
Now it's time to configure your client application.
- open WSE property page on client project
- Check [Enable this project for Web Service Enhancements]
- Enable Policy, add a new policy with exactly same name you named your server policy, in our case, should be "usernameTokenSecurity"
- A wse3policyCache.config file will be generated
- Update your web reference
- Modify your client code as follow:
private GetService CreateWebService()
{
if (ws == null)
ws = new svcWse();
ws = new svcWse();
UsernameToken userName = new UsernameToken(user, password,PasswordOption.SendPlainText);
ws.SetClientCredential(userName);
ws.SetPolicy("usernameTokenSecurity");
return ws;
}
public String[] GetItemList()
{
return CreateWebService().GetItemList();
}
N
沒有留言:
張貼留言