How can I use the Role Manager in a WCF Service?
c#, wcf
Solution
I wrote a blog post about how to using ASP.NET authentication with WCF; the gist of it is that you want to use the following binding:
<basicHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
You must also apply the following `serviceBehavior`
<behavior>
<!-- no need for http get;
but https get exposes endpoint over SSL/TLS-->
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<!-- the authorization and credentials elements tie
this behavior (defined as the default behavior) to
the ASP.NET membership framework-->
<serviceAuthorization
principalPermissionMode="UseAspNetRoles"
roleProviderName="AspNetRoleProvider" />
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="AspNetMembershipProvider" />
</serviceCredentials>
</behavior>
An important point to note is that you must use SSL if you're going to secure WCF with a name and password, that's why transport security is specified.
Once you've done this, you should be able to use the `PrincipalPermission` attribute to secure your service methods.
Problem
How can I use the Role Manager in a WCF Service? In my .NET Application, I can restrict a class or a method with the `[Authorize(Roles=)]` tag. How can I enable this for my WCF Service? I currently have the following binding set for each endpoint: ``` <webHttpBinding> <binding name="TransportSecurity" maxReceivedMessageSize="5242880"> <security mode="Transport"> <transport clientCredentialType="None"/> </security> </binding> </webHttpBinding> ``` Since I want to have the user log in and receive a cookie with the principal, do I need to change this to another sort of `clientCredentialType`? Edit 1: This is using REST, not SOAP. It is also to note, that it is important that it works with mobile devices (android, iPhone) and can use cookies to maintain a session. So far, I have been unable to get this working, using the following code/config: Config File: ``` <roleManager enabled="true" defaultProvider="ActiveDirectoryRoleProvider" cacheRolesInCookie="true" cookieName="RoleCookie" cookiePath="/" cookieTimeout="30" cookieRequireSSL="false" cookieSlidingExpiration="true" createPersistentCookie="false" cookieProtection="All"> <providers> <clear /> <add name="ActiveDirectoryRoleProvider" connectionStringName="ADServices" connectionUsername="" connectionPassword="" attributeMapUsername="sAMAccountName" type="" /> </providers> </roleManager> <membership defaultProvider="MembershipADProvider"> <providers> <add name="MembershipADProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" applicationName="" connectionStringName="ADServices" connectionUsername="" connectionPassword="" attributeMapUsername="sAMAccountName" /> </providers> </membership> <bindings> <webHttpBinding> <!-- webHttpBinding is for REST --> <binding name="TransportSecurity" maxReceivedMessageSize="5242880"> <security mode="Transport"> </security> </binding> </webHttpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="web"> <webHttp /> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="ServiceBehaviour"> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" /> <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" /> <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="ActiveDirectoryRoleProvider" /> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="MembershipADProvider" /> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> ``` Code ``` public void SignIn2(string userName, bool createPersistentCookie) { if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName"); // put the attributes in a string for userdata string userData = ""; // create the ticket FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(240), createPersistentCookie, userData); // Now encrypt the ticket. string encryptedTicket = FormsAuthentication.Encrypt(authTicket); // Create a cookie and add the encrypted ticket to the cookie as data. HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); // add the cookie HttpContext.Current.Response.Cookies.Add(authCookie); } ``` Now using the Principal Permission, I get a `SecurityException` (I know the role is valid on the server) ``` [PrincipalPermission(SecurityAction.Demand, Role = Constants.RoleUser)] public Message TestRoles() { var context = NetworkHelper.GetWebOperationContext(); return context.CreateTextResponse("You have successfully activated the endpoint."); } ``` Am I missing a crucial step here?