4

I am trying to use custom ASP.NET MembershipProvider and RoleProvider to handle security for my service. The service is self-hosted in a console app, not in IIS. I use webHttpBinding with Basic Authentication. I configured serviceCredentials and serviceAuthorization to use providers. Providers really get initialized. But WCF seems to ignore my settings and tryes to login user to Windows. I figured that out from Events Log, and proved by sending my windows credentials to the service. Below you can see my configuration and debug screenshots. Why is it using windows for auth? Maybe it is impossible to use ASP.NET auth providers without IIS?

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.web>
    <roleManager
    enabled="true"
    defaultProvider="CustomRoleProvider">
      <providers>
        <clear/>
        <add
            name="CustomRoleProvider"
            type="CustomRoles.CustomRoleProvider, CustomRoles"/>
      </providers>
    </roleManager>
    <membership defaultProvider="CustomMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear/>
        <add name="CustomMembershipProvider"
          type="CustomRoles.CustomMembershipProvider, CustomRoles"/>
      </providers>
    </membership>
  </system.web>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="webHttp">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Basic" />
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Service">
          <serviceAuthorization principalPermissionMode="UseAspNetRoles"
            roleProviderName="CustomRoleProvider" />
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
              membershipProviderName="CustomMembershipProvider" />
          </serviceCredentials>
          <serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="SuccessOrFailure"
            messageAuthenticationAuditLevel="SuccessOrFailure" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="Service" name="CustomRoles.Service">
        <endpoint address="http://127.0.0.1:8060" binding="webHttpBinding"
          bindingConfiguration="webHttp" contract="CustomRoles.IService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

That's what I see when debug. Why is it using windows for auth?

credentials screen http://img81.imageshack.us/img81/1289/credentials.gif

link to full size screen

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Pasho
  • 488
  • 3
  • 15
  • Playing with the app found out that role provider is working, but the membership provider doesn't. Currently I am checking if it is ignored due to the difference of how service instance gets initialized between asp.net and self-hosted. But it seems really wierd. Now I'll try to summarize the problem. There are 3 options in user name validation - windows, membershipprovider and custom. Custom works, windows works, but membership option is ignored and wcf uses windows instead of it. Why? – Pasho Aug 22 '09 at 09:38

3 Answers3

0

I'm trying to do the same thing.

My service is working well, I'm able to trace the call made to the service via the Service Trace Viewer.

The only problem remaining is that I don't receive any answer to the call. My application is freezing and I have a TimoutException on the call. Here's my settings :

<system.web>
    <membership defaultProvider="ClientAuthenticationMembershipProvider">
      <providers>
        <add name="ClientAuthenticationMembershipProvider"
             type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
             serviceUri="http://localhost:21200/Authentication_JSON_AppService.axd"
             credentialsProvider="LacT.Windows.LoginWindow, LacT.Windows" />

        <add name="FooMembershipProvider"
             type="Foo.Security.Business.Provider.FooTMembershipProvider, LacT.Security.Business"
             serviceUri="http://localhost:21200/Authentication_JSON_AppService.axd"
             credentialsProvider="Foo.Windows.LoginWindow, Foo.Windows" />
      </providers>
    </membership>
    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
      <providers>
        <add name="ClientRoleProvider"
             type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
             serviceUri="http://localhost:21200/Role_JSON_AppService.axd"
             cacheTimeout="86400" />
      </providers>
    </roleManager>
  </system.web>

And the service model...`

<behaviors>
  <endpointBehaviors>
    <behavior name="WebBehavior">
      <webHttp />
      <enableWebScript />
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="WebBehavior">
      <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>


<bindings>
  <basicHttpBinding>
    <binding name="basicHttpMode">
      <security mode="None" />
    </binding>
  </basicHttpBinding>
  <webHttpBinding>
    <binding name="webHttpMode">
      <security mode="None" />
    </binding>
  </webHttpBinding>
</bindings>

<services>
  <service behaviorConfiguration="WebBehavior"
           name="Foo.Security.Business.Manager.Wcf.Host.SecurityManager">

    <endpoint address=""
              binding="webHttpBinding"
              contract="Foo.Security.Business.Contract.ISecurityContract"
              behaviorConfiguration="WebBehavior"
              bindingConfiguration="webHttpMode" />
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:21200" />
      </baseAddresses>
    </host>
  </service>
</services>

`

Maybe with this piece of code it can help you to figure out what's going on with yours. If you find let me know something.

esylvestre
  • 1,850
  • 4
  • 21
  • 30
0

I've done this during the WCF Master Class, so it is definitely possible. Unfortunately I did not use this in practice and it's a year ago now...

However, try this link, and look for the different downloads about ASP.NET membership stuff. It is basically the outcome of the training session.

Marc Wittke
  • 2,991
  • 2
  • 30
  • 45
0

Yes is possible:

<?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="TransportCredentialOnly">
                  <transport clientCredentialType="Basic"/>
               </security>
            </binding>
         </webHttpBinding>
         <basicHttpBinding>
            <binding name="basicBindingConfiguration">
               <security mode="TransportCredentialOnly">
                  <transport clientCredentialType="Basic"/>
               </security>
            </binding>
         </basicHttpBinding>
      </bindings>
      <behaviors>
         <endpointBehaviors>
            <behavior name="webEndpointBehavior">
               <webHttp/>
            </behavior>
         </endpointBehaviors>
         <serviceBehaviors>
            <behavior name="webServiceBehavior">
               <serviceMetadata httpGetEnabled="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="WcfServiceHTTPSelfHosted.MyCustomValidator, WcfServiceHTTPSelfHosted"/>
               </serviceCredentials>
               <!-- To avoid disclosing metadata information, set the value below to false before deployment -->
               <serviceMetadata httpGetEnabled="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="WcfServiceHTTPSelfHosted.WcfServiceHTTPSelfHosted">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicBindingConfiguration"
               contract="WcfServiceHTTPSelfHosted.IWcfServiceHTTPSelfHosted" />
            <endpoint address="web" behaviorConfiguration="webEndpointBehavior"
               binding="webHttpBinding" bindingConfiguration="webBinding"
               contract="WcfServiceHTTPSelfHosted.IWcfServiceHTTPSelfHosted" />
            <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
               contract="IMetadataExchange" />
            <host>
               <baseAddresses>
                  <add baseAddress="http://localhost:50002/WcfServiceHTTPSelfHosted/" />
               </baseAddresses>
            </host>
         </service>
      </services>
   </system.serviceModel>
</configuration>

And uses a custom UserNamePasswordValidator:

public class MyCustomValidator : UserNamePasswordValidator
   {

      public MyCustomValidator()
      {

      }

      public override void Validate(string userName, string password)
      {
         if (!Membership.ValidateUser(userName, password))
         {
            throw new SecurityTokenException("Users validation failed: " + userName);
         }
      }
   }

this works fine!

lupok
  • 1,025
  • 11
  • 15