Internet – WCF and ASMX Client to Remote WCF Using Transport Security (HTTP)

- J.D. Meier, Jason Taylor, Prashant Bansode, Carlos Farre, Madhu Sundararajan, Steve Gregersen

Applies To

  • Microsoft® Windows Communication Foundation (WCF) 3.5

Scenario

In this scenario, your users do not have Windows accounts and use a Windows Forms client to make calls to the WCF Service through either a WCF or ASMX client proxy. User accounts are in SQL and users are authenticated with user name authentication.
The business logic called by the WCF Service is backed by a Microsoft SQL Server® data store. The following figure illustrates the basic model for this application scenario.

Scenario8.jpg

Key Characteristics

This scenario applies to you if:
  • Your users are WCF and ASMX clients.
  • Your user accounts are in SQL. IIS authenticates users against SQL Member Ship Provider, via custom HTTP module
  • Your user roles are in SQL. WCF authorizes users with ASP.NET roles
  • Your application transmits user credentials and other sensitive data over the network and needs to be protected.
  • The service is compatible with legacy ASMX clients with prior versions of .NET framework

Solution

Solution8.jpg

Solution Summary Table

In this solution you will:
  • Use SQL to authenticate clients using SQL Member Ship Provider.
  • The authentication is done by IIS via custom HTTP module using SQL Member Ship Provider.
  • The authorization is done by WCF with roles in SQL using ASP.NET role provider.
  • Use a service account to call the SQL Server from WCF.
  • Use transport security to protect user credentials and sensitive data between the clients and the WCF Service.
  • Service uses basicHttpBinding with transport security to provide compatibility with legacy ASMX clients.
  • The authentication is done with custom HTTP module to be able to transmit user credentials over transport, so the service is compatible with legacy ASMX clients.

Clients

What Checks Example More Info
WCF Proxy
Client needs to manually configure the authentication as Basic type. In a generated proxy, you will need to change the value from None to Basic. <security mode="Transport"> <transport clientCredentialType="Basic"/> </security> If the proxy is generated, this value will be generated as None as the WCF service sets the authentication as None. The basic authentication type is needed for authentication negotiation to occur so authentication header is sent to service.
Client has a WCF proxy reference to the WCF service. The application has access to the WCF metadata to create a service reference. The client will be prompted with credentials to get the metadata
Root CA certificate for the service is installed in “Trusted Root Certification Authorities” This is required for SSL. All certificates that are signed with this certificate will be trusted by the client machine.
Proxy invokes service passing user credentials to the WCF proxy WCFTestService.ServiceClient myService = new WCFTestService.ServiceClient(); myService.ClientCredentials.UserName.UserName = "username"; myService.ClientCredentials.UserName.Password = "p@ssw0rd"; myService.GetData(123); myService.Close(); The UserName and Password properties must be set before the proxy invokes a WCF method
ASMX Proxy
Client has a ASMX Web service proxy reference to the WCF service. The application has access to the WCF metadata to create a service reference. The client will be prompted with credentials to get the metadata
Root CA certificate for the service is installed in “Trusted Root Certification Authorities” All certificates that are signed with this certificate will be trusted by the client machine.
Proxy invokes service passing user credentials to the ASMX Web service proxy NetworkCredential netCred = new NetworkCredential("username", " p@ssw0rd"); asmxwebservice.Service proxy = new asmxwebservice.Service(); proxy.Credentials = netCred; proxy.GetData(21, true); The proxy’s credentials need to be set with the user name and password before invoking a WCF method

Application Server

What Checks Example More Info
IIS
Configuration A dedicated application pool is created and configured to run under a custom service account. Use a domain account if possible.
The WCF Service is configured to run under the service account. Assign the WCF Service to the custom application pool.
A custom HTTP module is configured in web configuration <httpModules> … <add name="BasicAuthentication Module" type="Module.UserNameAuthenticator,Authenticator" /> </httpModules> The custom HTTP module will authenticate the users against the SqlMemberShip Provider
ASP.NET database is created for use with SQL Membership Provider and SQL Role provider. aspnetregsql -S .\SQLExpress -E -A r m Aspnetregsql.exe creates the SQL database to store the user and role information.
Connection string is configured to point to the user and role stored in SQL Server. <add name="MyLocalSQLServer" connectionString="Initial Catalog=aspnetdb;data source=localhost;Integrated Security=SSPI;" /> The database connection string includes Integrated Security=SSPI or Trusted Connection=Yes for Windows Authentication.
SqlMembershipProvider is configured as a Membership provider. <membership defaultProvider="MySqlMembershipProvider"> <providers> <clear/> <add name= "MySqlMembershipProvider" connectionStringName= "MyLocalSQLServer" applicationName="MyAppName" type="System.Web.Security.SqlMembershipProvider"/> </providers> </membership> The membership feature helps protect credentials, can enforce strong passwords, and provides consistent APIs for user validation and secure user management.
Role Manager feature is enabled and SqlRoleProvider is configured for roles authorization. <roleManager enabled="true" defaultProvider="MySqlRoleProvider" > <providers> <clear/> <add name="MySqlRoleProvider" connectionStringName="MyLocalSQLServer" applicationName="MyAppName" type="System.Web.Security.SqlRoleProvider" /> </providers> </roleManager> Role Manager allows you to look up users' roles without writing and maintaining custom code.
WCF Service process identity is given access permissions on the ASP.NET database. spgrantlogin '<<Custom Service Account>>'; USE aspnetdb GO spgrantdbaccess '<<Custom Service Account>>', '<<Custom Service Account>>'; spaddrolemember 'aspnetMembershipFullAccess', '<<Custom Service Account>>'; spaddrolemember 'aspnetRolesFullAccess', '<<Custom Service Account >>’ Your WCF service process identity requires access to the Aspnetdb database.
WCF Service
Configuration WCF Service is configured to use basicHttpBinding binding. <services> <service behaviorConfiguration="ServiceBehavior" name="Service"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BindingConfiguration" name="basicEndpoint" contract="IService" /> </service> </services> basicHttpBinding uses the HTTP protocol and provides compatibility with ASMX clients
Service Metadata is configured in service behavior to enable httpsGetEnabled and disable httpGetEnabled. <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" /> </behavior> </serviceBehaviors> The service metadata entry is required to publish metadata to the clients
Service is configured for ASP.NET compatibility mode both in configuration and in service implementation Configuration <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> …</system.serviceModel> Service Implementation AspNetCompatibilityRequirements(RequirementsMode AspNetCompatibilityRequirementsMode.Required) public class Service : IService The ASP.NET compatibility mode is necessary because IIS is performing authentication
Authentication basicHttpBinding is configured to use transport security and no authentication. <basicHttpBinding> <binding name="BindingConfiguration"> <security mode="Transport"> <transport clientCredentialType="None" /> </security> </binding> </basicHttpBinding> The authentication will be performed by the ASP.NET HTTP module against the SqlMemberShipProvider
SqlMembershipProvider is configured to provide user authentication. <membership defaultProvider="MySqlMembershipProvider"> <providers> <clear/> <add name="MySqlMembershipProvider" connectionStringName="MyLocalSQLServer" applicationName="MyAppName" type="System.Web.Security.SqlMembershipProvider"/> </providers> </membership> The membership feature automatically authenticates and creates the authentication ticket for you.
Authorization Role Manager feature is enabled with aspnetroles and Provider is configured for roles authorization. <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="MySqlRoleProvider" /> </behavior> </serviceBehaviors> Roles authorization can be performed declaratively or imperatively in the operation contract.
Class that derives from IAuthorizationPolicy is implemented to set the principal of the current thread to do declarative authorization and to set the identity so it is available in WCF security context
Authorization policy is included in the configuration file <authorizationPolicies> <add policyType="AuthorizationPolicy.HttpContextPrincipalPolicy, AuthorizationPolicy" /> </authorizationPolicies>
Perform Role-checks declaratively using Windows Identity Token, for checking Active Directory group membership. PrincipalPermission(SecurityAction.Demand, Role "accounting") public string GetData(string message) { return "hello"; } You should prefer declarative role-check over imperative role-check for a service operation
Perform Role-checks imperatively using Windows Identity Token, for checking Active Directory group membership. public string GetData(string myValue) { if(Roles.IsUserInRole(@"Accounting")) { //Do something for Accounting role } else { //Do something for non-accounting role or throw an error } } If you need more fin-grained authorization control, you can use imperative role checks in the code itself. Use call to Roles.IsUserInRole to perform the check.
SQL The connection string for the database is configured to use Windows authentication. SqlConnection sqlcon = new SqlConnection("Server=SqlServer;Database=Northwind;IntegratedSecurity=SSPI"); The database connection string includes Integrated Security=SSPI or Trusted Connection=Yes.
Database connection is opened using the WCF process identity’s security context. This happens by default.

Database Server

What Check Example More Info
Configuration A SQL Server login is created for the WCF service account (process identity). exec sp_grantlogin 'Custom Service Account' This grants access to the SQL Server.
The login is granted access to the target database. use targetDatabase go exec sp_grantdbaccess 'Custom Service Account' go This grants access to the specified database.
A database role is created in the target database. use targetDatabase go exec sp_addrole 'DB Role Name' go This allows access control and authorization to the DB.
The login is added to the database role. use targetDatabase go exec sp_addrolemember 'DB Role Name', 'Custom Service Account' go Grant minimum permissions. For example, grant execute permissions to selected stored procedures and provide no direct table access.
Authentication SQL Server is configured to use Windows authentication.

Communication Security

What Check Example More Info
App server to Database You can use IPSec or SSL between App server and database server to protect sensitive data on the wire.

Analysis

Clients

WCF Proxy

  • The client configuration file is configured to use Basic authentication type to allow the authentication negotiation to occur.
  • The user’s credentials are required in ASP.NET HTTP module for Authentication. Username credentials are set on the WCF proxy and all calls to the WCF service are made through that proxy instance.
  • The user’s credentials are required in WCF for Authorization. Username credentials are set on the WCF proxy and all calls to the WCF service are made through that proxy instance.
  • For validating the service certificate, the Root CA certificate is installed on the client machine in the “Trusted Root Certification Authorities” location.

ASMX Web Service Proxy

  • The user’s credentials are required in ASP.NET HTTP module for Authentication. Network credentials are set on the ASMX Web Service proxy and all calls to the WCF service are made through that proxy instance.
  • The user’s credentials are required in WCF for Authorization. Username credentials are set on the ASMX Web Service and all calls to the WCF service are made through that proxy instance.
  • For validating the service certificate, the Root CA certificate is installed on the client machine in the “Trusted Root Certification Authorities” location.

Application Server

Authentication

  • As the users communicate to the WCF service over the Internet and you cannot assume they have a Windows account, the user information is stored in SQL. As WCF does not support transport security with username authentication a custom HTTP module is created that will authenticate the user against SqlMemberShip Provider. This will support both WCF and ASMX Web Services clients.
  • WCF is configured to use no authentication because the ASP.NET HTTP module will handle authentication.
  • To protect the user credentials over the wire, a Service Certificate is installed and configured to be used as Service Credentials in WCF.

Authorization

  • For coarse grained access control, authorization checks are performed in the WCF Service at the operation level, declaratively. Unless fine grained access control is needed, declarative authorization should be preferred over imperative authorization.
  • For fine grained access control or implementing business logic, authorization checks are made within the operations programmatically.
  • The Roles Manager is a good choice for this scenario because it allows you to look up users' roles without writing and maintaining custom code.

SQL

  • To reduce the risk of stolen database credentials, the database connection string is configured to use Windows authentication. This avoids storing credentials in files and passing credentials over the network to the database server.
  • The WCF Service accesses the database using the WCF process identity. As a result, all calls use the single process account and the designated database connection pooling.

Configuration

  • Since all of the clients communicate over the Internet, the best transport protocol for this scenario is HTTP. Additionally since compatibility with ASMX Web services clients is required, basicHttpBinding is an ideal choice.
  • Because basicHttpBinding is supported by IIS 6.0, the WCF service is hosted in IIS.
  • In order to reduce attack surface and minimize the impact of a compromise, the WCF Service is running under the security context of the Service account using a least privileged account.
  • In order to reduce attack surface and minimize the impact of a compromise, the Windows service is running under the security context of the Service account using a least privileged account.

Database Server

  • SQL Server database user roles are preferred to SQL Server server application roles to avoid the associated password management and connection pooling issues associated with the use of SQL application roles. Applications activate SQL application roles by calling a built-in stored procedure with a role name and a password. Therefore, the password must be stored securely. Database connection pooling must also be disabled when you use SQL application roles, which severely impacts application scalability.
  • Creating a new user-defined database role, and adding the database user to the role, lets you give specific minimum permissions to the role. Therefore, if the database account changes you don't have to change the permissions on all database objects.

Communication Security

  • Transport security protects sensitive data between Thick Client and WCF Service.
  • You can use IPSec or SSL between WCF Service and the database server to protect sensitive data on the wire.

Example

IIS

Code

  • A Class that derives from IHttpModule is implemented. This class authenticates the users against SqlMembershipProvider.
  • Initially the class checks if there is an authorization header in the request from the client. If it is not present, the status of the context is assigned as 401(not authorized) and a WWW-Authenticate header is created and sent in the response to the client. This is the handshake for authentication process. The client will know that it needs to send credentials for authentication.
  • Once the credentials are sent by the client, they are extracted from the authorization header, so they can be used to call the SqlMemberShip provider
  • The class authenticates the user calling Membership.ValidateUser(username, password) to validate the user against the SqlMemberShipProvider
  • If the user is authenticated, an identity is created and assigned to HttpApplication.Context.User property.
  • If the user is not authenticated, a 401 status is returned to the client and user is denied access.

HTTP Module Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Security.Principal;

namespace Module
{
    public class UserNameAuthenticator : IHttpModule    {


        public void Dispose()
        {
        }

        public void Init(HttpApplication application)
        {
            application.AuthenticateRequest += new 
		EventHandler(this.OnAuthenticateRequest);
            application.EndRequest += new EventHandler(this.OnEndRequest);
        }

        public void OnAuthenticateRequest(object source, EventArgs eventArgs)
        {
            
            HttpApplication app = (HttpApplication)source;
      
             //the Authorization header is checked if present
           
            string authHeader = app.Request.Headers["Authorization"];

            if (!string.IsNullOrEmpty(authHeader))
            {
                string authStr = app.Request.Headers["Authorization"];

                if (authStr == null || authStr.Length == 0)
                {
                    // No credentials; anonymous request
                    return;
                }

                authStr = authStr.Trim();
                if (authStr.IndexOf("Basic", 0) != 0)
                {
                    //header not correct we do not authenticate
                    return;
                }


                authStr = authStr.Trim();


                string encodedCredentials = authStr.Substring(6);

                byte[] decodedBytes = 
		    Convert.FromBase64String(encodedCredentials);
                string s = new ASCIIEncoding().GetString(decodedBytes);

                string[] userPass = s.Split(new char[] { ':' });
                string username = userPass[0];
                string password = userPass[1];

                //the user is validated against the SqlMemberShipProvider
                //If it is validated then the roles are retrieved from the
                //role provider and a generic principal is created
                //the generic principal is assigned to the user context
                // of the application


                if (Membership.ValidateUser(username, password))
                {
                    string[] roles = Roles.GetRolesForUser(username);
                    app.Context.User = new GenericPrincipal(new
                    GenericIdentity(username, "Membership Provider"), roles);

                }
                else
                {
                    DenyAccess(app);
                    return;

                }



            }
            else
            {
               //the authorization header is not present
               //the status of response is set to 401 and it ended
               //the end request will check if it is 401 and add
               //the authentication header so the client knows
               //it needs to send credentials to authenticate

                app.Response.StatusCode = 401;
                app.Response.End();

                //context.Response.StatusCode = 401;
                //context.Response.End();
            }
           
                      
        }

        public void OnEndRequest(object source, EventArgs eventArgs)
        {
            
            if (HttpContext.Current.Response.StatusCode == 401)
            {

            //if the status is 401 the WWW-Authenticated is added to 
            //the response so client knows it needs to send credentials 

                HttpContext context = HttpContext.Current;
                context.Response.StatusCode = 401;
                context.Response.AddHeader("WWW-Authenticate", "Basic
                Realm");
            }   
        }



        private void DenyAccess(HttpApplication app)
        {
            app.Response.StatusCode = 401;
            app.Response.StatusDescription = "Access Denied";

            // error not authenticated
            app.Response.Write("401 Access Denied");

            app.CompleteRequest();
        }

       
      
    }
}


Configuration

  • The custom module is configured in web.config file in HTTP modules section
  • The service configuration file has an entry with a connection string pointing to the SQL store for authentication and authorization.
  • The service configuration file has an entry for the SqlRoleProvider under system.web to define which role provider is being used.
  • The service configuration file has an entry for the SqlMemberShipProvider under system.web to define the SQL provider for authentication.

<configuration>
…
<connectionStrings>
*    <add name="MyLocalSQLServer"*
*         connectionString="Initial Catalog=aspnetdb;data source=10.3.19.60;Integrated Security=SSPI;"/>*
  </connectionStrings>

    <system.web>


      <membership defaultProvider="MySqlMembershipProvider" >
        <providers>
          <clear/>
*          <add name="MySqlMembershipProvider"*
*               connectionStringName="MyLocalSQLServer"*
*               applicationName="MyAppName"*
*               type="System.Web.Security.SqlMembershipProvider" />*
        </providers>
      </membership>

      <roleManager enabled="true" defaultProvider="MySqlRoleProvider" >
        <providers>
          <clear/>
*          <add name="MySqlRoleProvider"*
*               connectionStringName="MyLocalSQLServer"*
*               applicationName="MyAppName"*
*               type="System.Web.Security.SqlRoleProvider" />*
        </providers>
      </roleManager>

      
<httpModules>
…
*<add name="BasicAuthenticationModule"     type="Module.UserNameAuthenticator,Authenticator" />*
</httpModules>
      


    </system.web>

</configuration>

Application Server

Code

  • The service performs imperative authorization checks calling Roles.IsUserInRole.
  • If auditing is required the service retrieves the identity of the caller.
  • Authorization policy class is developed to set the thread current principal and the identity to do
declarative authorization and to have the identity in WCF security context
  • The service calls SQL using Windows Authentication.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.Web;
using System.Security.Principal;


namespace AuthorizationPolicy
{
    // syncs Thread.CurrentPrincipal and identity in WCF with whatever is set 
    // by the HTTP pipeline on Context.User (optional)
    public class HttpContextPrincipalPolicy : IAuthorizationPolicy
    {
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            HttpContext context = HttpContext.Current;

            if (context != null)
            {
                evaluationContext.Properties["Principal"] = context.User;
                evaluationContext.Properties["Identities"] =
                   new List<IIdentity>() { context.User.Identity };
            }

            return true;
        }

        public System.IdentityModel.Claims.ClaimSet Issuer
        {
            get { return ClaimSet.System; }
        }

        public string Id
        {
            get { return "HttpContextPrincipalPolicy"; }
        }
    }
}


The service does imperative or declarative authorization

Imperative
using System.Data.SqlClient;
using System.Web.Security;


public string GetData(string myValue)
{
           
public string GetData(int value)
	{
        *if (Roles.IsUserInRole(@"accounting"))*
        {
*            SqlConnection sqlcon = new SqlConnection("Server=sqlServer;*
*Database=testdb;Integrated Security=SSPI");*
*            sqlcon.Open();*

*            string identity =* 
*		HttpContext.Current.User.Identity.Name;*
            return “data”
        }
        else
            return "not authorized";
	}
}



Declarative
using System.Data.SqlClient;
using System.Web.Security;


[PrincipalPermission(SecurityAction.Demand, Role  "accounting")]
public string GetData(int value)
{
        
     SqlConnection sqlcon = new SqlConnection("Server=sqlServer; Database=testdb;Integrated Security=SSPI");
     sqlcon.Open();
     string identity = HttpContext.Current.User.Identity.Name;
     return “data”   
}

Configuration

  • The service has a binding endpoint that uses basicHttpbinding with binding configuration that enables transport security and no authentication.
  • The service behavior is configured with the element serviceMetadata to allow publishing metadata.
  • The service behavior is configured with element ServiceAuthorization to use aspnetroles for authorization
  • The service behavior is configured with service authorization to include authorization policy to allow the current thread principal and the identity in the security context of WCF
<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <bindings>
      <basicHttpBinding>
        <binding name="BindingConfiguration">
          <security mode="Transport">
            <transport clientCredentialType="None" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="Service">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BindingConfiguration"
          name="basicEndpoint" contract="IService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata  httpGetEnabled="false" httpsGetEnabled="true" />
          <serviceAuthorization principalPermissionMode="UseAspNetRoles"
            roleProviderName="MySqlRoleProvider" >
            <authorizationPolicies>
               <add policyType="AuthorizationPolicy.HttpContextPrincipalPolicy, AuthorizationPolicy" />
            </authorizationPolicies>
          <serviceAuthorization >
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  

Clients

WCF client

Code

  • Client passes user credentials explicitly when making calls to the service.
  • Client needs to provide credentials when creating Service reference
WCFTestService.ServiceClient myService = new
              WCFTestService.ServiceClient();
*myService.ClientCredentials.UserName.UserName = "username";*
*myService.ClientCredentials.UserName.Password = "p@ssw0rd";*
myService.GetData(123);
myService.Close();

Configuration

  • The client is configured to use basic authentication
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="None"
                            realm="" />
</security>

ASMX Web service Client

Code

  • Client passes user credentials explicitly when making calls to the service.
  • Client needs to provide credentials when creating Service reference
NetworkCredential netCred = new NetworkCredential("username", " p@ssw0rd");
asmxwebservice.Service proxy = new asmxwebservice.Service();
proxy.Credentials = netCred;               
 proxy.GetData(21, true);

Database Server

Configuration

  • A SQL Server login is created for the WCF Service account.
  • The WCF login name is given access to the application database.
  • The role is created in the application database.
  • The WCF login name is added to the role.
-- Create a SQL Server login  that matches the WCF machine name
EXEC SP_GRANTLOGIN 'npscode\perfpres02$'

-- Grant the login access to the application database
use testdb 
go 
exec sp_grantdbaccess 'npscode\perfpres02$' 

-- Create the new database role
use testdb
go
exec sp_addrole 'myrole2','db_owner' 

-- Add the new login to the role
use testdb
go
exec sp_addrolemember 'myrole2','npscode\perfpres02$' 

Additional Resources

TBD

Contributors and Reviewers

  • External Contributors and Reviewers:
  • Microsoft Consulting Services and PSS Contributors and Reviewers:
  • Test team: Rohit Sharma, Chaitanya Bijwe, Parameswaran Vaideeswaran.
  • Edit team: Dennis Rea.
  • SEO team: Rob Boucher.

Last edited Aug 15, 2008 at 6:16 AM by rboucher, version 7

Comments

kritlop Jul 23, 2012 at 5:22 AM 
When using a custom http module as described in the above example be sure to set your app pool on IIS to classic mode. See http://msdn.microsoft.com/en-us/library/ms227673.aspx for more info

SpoBo Aug 7, 2008 at 8:54 AM 
Another quick question ... could you also just hook up the UserNameAuthenticator to an ADAM store with an AuthorizationManager instead of using MembershipProvider?

SpoBo Aug 7, 2008 at 8:19 AM 
Thx for this interesting concept. A couple of issues though ... there is no mention as to when and where to set the certificates in IIS. For a certificate-newb like me that could be handy.

Also, when I try to add a reference to the service in my client I get 'The request failed with HTTP status 401: Unauthorized.' in the 'Service Reference' output. Even when I use browse and enter the credentials.

Another problem I have is that when I surf to the service, I enter my username & password; it validates but then it brings me to a non-existant login.aspx page? Odd!

Also, I'm not using Roles ... I did not declare a RoleProvider and I just modified the code to skip fetching the roles if Roles.Enabled = False under the if (Membership.ValidateUser(username, password)) condition in the UserNameAuthenticator.

Finally, the WSDL isn't generated properly when using an SSL certificate I think. It tells me that the url for the svcutil isn't an IP but the actual name of the server. That's probably not very interesting when I try to expose it to the internet. I used to have the same problem for regular IP's when I didn't enter the 'Host header value' in IIS under 'Advanced Web Site Identification'.

Thx for the guidance though :)