ASP.NET Membership Provider authentication not working authenticating WCF Service

I have a SqlMembershipProvider store with Roles enabled. This is configured and has the user "devtest" in the roles "xxUser" and "xxAdmin".

I also have a WCF service, which I want to authenticate and authorize against. My problem is that:

  1. the authorisation is not happening, code just executes despite the policy attribute
  2. I don't get any identity or security context so do not know who is calling the service

I need:

  1. to know which user is calling the method
  2. some degree of rejecting users if permissions don't match up (ideally this should be performed within the RoleProvider/MembershipProvider/WCF but can do it myself if I have to)
  3. SSL in transport

I have my service contract set up thus:

    [ServiceContract]
    public interface ISupportService
    {
        [OperationContract]
        [PrincipalPermission(SecurityAction.Demand, Role = "ThisRoleDoesNotExist")]
        List<BaseInterestRate> GetAllBaseInterestRates();
    }

the code is simple enough:

public class SupportService : ISupportService
{
    public List<BaseInterestRate> GetAllBaseInterestRates()
    {
        OperationContext operationContext = OperationContext.Current;
        ServiceSecurityContext serviceSecurityContext = ServiceSecurityContext.Current; // is always null

        using (xxxEntities entities = new xxxEntities())
        {
            return new List<BaseInterestRate>(entities.BaseInterestRates);
        }
    }}

My service configuration is thus:

-->

<behaviors>
  <serviceBehaviors>
      <behavior name="SupportServiceBehavior">
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="AspNetSqlRoleProvider" />
          <serviceCredentials>
              <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" 
 membershipProviderName="SqlMembershipProvider" />
          </serviceCredentials>
      </behavior>
    <behavior>     
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

Having already configured the MembershipProvider:

  <membership defaultProvider="SqlMembershipProvider" >
      <providers>
          <clear/>
          <add name="SqlMembershipProvider"
   connectionStringName="SqlMembershipProvider"
   applicationName="xxx"
   type="System.Web.Security.SqlMembershipProvider" />
      </providers>
  </membership>
  <roleManager enabled="true">
      <providers>
          <clear />
          <add connectionStringName="SqlMembershipProvider" applicationName="xxx"
           name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
          <add applicationName="xxx" name="AspNetWindowsTokenRoleProvider"
           type="System.Web.Security.WindowsTokenRoleProvider" />
      </providers>
  </roleManager>

I have followed the instructions at these pages to the letter:

I would at lest expect an issue with certificates/transport/etc. to fail with exceptions, but I can debug right in and over the WCF call. I have no security context/ user context available to me and when I use a user not in the two mentioned roles (which I do in the code example above), I don't get "kicked out".

My client app is currently a Web App, but will ultimately also serve a Windows Forms app and Test suite. I'm currently using the ASP.NET WebDev server and am running .NET 4.0.

Am I missing something?

Answers


I'm a little new to WCF Rest services, but during my own testing I ran into a similar problem to this. I came across this video, which helped a bit (even if it wasn't quite what I was trying to do):

http://channel9.msdn.com/blogs/rojacobs/endpointtv-securing-restful-services-with-aspnet-membership

Essentially the problem was that under the asp.net configuration I had to disable anonymous access in order for it to use the MembershipProvider authentication:

system.web>
    <authorization>
      <deny users="?" />
    </authorization>
...

I don't think you can set the principal permission on the interface. I bet if you move it onto the service implementation method it will work

or at least start breaking for a different reason (I am currently stuck at that point - I get access denied exceptions - hopefully you dont!)

(I first tried to put them on the contract interface also)


this is the correct configuration for wcf service self-hosted with SSL:

<?xml version="1.0"?>
<configuration>
   <startup>
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
   </startup>
   <connectionStrings>
      <add name="mySqlConnection" connectionString="Data Source=.\SQLEXPRESS2012;Integrated Security=SSPI;Initial Catalog=aspnetdb;"/>
   </connectionStrings>
   <system.web>
      <compilation debug="true"/>
      <!-- Configure the Sql Membership Provider -->
      <membership defaultProvider="MySqlMembershipProvider" userIsOnlineTimeWindow="15">
         <providers>
            <clear/>
            <add name="MySqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="mySqlConnection" applicationName="UsersManagementNavigationApplication" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed"/>
         </providers>
      </membership>

      <!-- Configure the Sql Role Provider -->
      <roleManager enabled="true" defaultProvider="MySqlRoleProvider">
         <providers>
            <clear/>
            <add name="MySqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="mySqlConnection" applicationName="UsersManagementNavigationApplication"/>
         </providers>
      </roleManager>
   </system.web>
   <system.serviceModel>
      <bindings>
         <webHttpBinding>
            <binding name="webBinding">
               <security mode="Transport">
                  <transport clientCredentialType="Basic"/>
               </security>
            </binding>
         </webHttpBinding>
         <basicHttpBinding>
            <binding name="basicBindingConfiguration">
               <security mode="Transport">
                  <transport clientCredentialType="Basic"/>
               </security>
            </binding>
         </basicHttpBinding>
      </bindings>
      <behaviors>
         <endpointBehaviors>
            <behavior name="webEndpointBehavior">
               <webHttp/>
            </behavior>
         </endpointBehaviors>
         <serviceBehaviors>
            <behavior name="webServiceBehavior">
               <serviceMetadata httpsGetEnabled="true"/>
               <serviceThrottling/>
               <serviceDebug/>
            </behavior>
            <behavior name="myServiceBehavior">
               <!-- Configure role based authorization to use the Role Provider -->
               <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="MySqlRoleProvider">
               </serviceAuthorization>
               <serviceCredentials>
                  <!-- Configure user name authentication to use the Membership Provider -->
                  <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfServiceHTTPSSelfHosted.MyCustomValidator, WcfServiceHTTPSSelfHosted"   />
               </serviceCredentials>
               <!-- To avoid disclosing metadata information, set the value below to false before deployment -->
               <serviceMetadata httpsGetEnabled="true"/>
               <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
               <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
         </serviceBehaviors>
      </behaviors>
      <services>
         <service behaviorConfiguration="myServiceBehavior" name="WcfServiceHTTPSSelfHosted.WcfServiceHTTPSSelfHosted">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicBindingConfiguration" contract="WcfServiceHTTPSSelfHosted.IWcfServiceHTTPSSelfHosted"/>
            <endpoint address="web" behaviorConfiguration="webEndpointBehavior" binding="webHttpBinding" bindingConfiguration="webBinding" contract="WcfServiceHTTPSSelfHosted.IWcfServiceHTTPSSelfHosted"/>
            <endpoint address="mex" binding="mexHttpsBinding" bindingConfiguration="" contract="IMetadataExchange"/>
            <host>
               <baseAddresses>
                  <add baseAddress="https://localhost:50001/WcfServiceHTTPSSelfHosted/"/>
               </baseAddresses>
            </host>
         </service>
      </services>
   </system.serviceModel>
</configuration>

if you want more info take a look this:

http://www.albertoschiassi.it/Home/tabid/55/EntryId/94/Use-ASP-NET-SqlMemberShipProvider-in-WCF-self-hosted-service.aspx

and

http://www.albertoschiassi.it/Home/tabid/55/EntryId/95/Use-ASP-NET-SqlMemberShipProvider-in-WCF-self-hosted-service-with-SSL.aspx


Need Your Help

Anchor tags and target behaviour? - HTML

html anchor target

I must say that despite this being a newb question, I don't think I have totally mastered HTML a tags.