Recipe4.2.2:(Intranet Security) TransportWithMessageCredential Security with UserName authen.

I: using basicHttpBinding.


About Me
·         TransportWithMessageCredential uses means message protection(Integrity, confidentiality) is provided at Transport level but client authentication is done at Message-level.
·         TransportWithMssageCredential allows Message-level authentication:
a)        UserName authentication with all validators (Windows, Membership and custom).
b)        Windows authentication both NTLM/Kerberos.
c)        Mutual Certificate authentication.
·         This Recipe4.2.1, uses UserName authentication with Windows Validator  and  UseWindowsGroups (or UseAspNetRoles ) Validator for authorization.

Security Criteria
Client 
Authentication
Windows Validator against AD/WG clients.
Service Authentication
By SSL certificate Validating at client-side.
Service Authorization / Impersonation
WindowsGroups Validator / AspNetRoles Validator with respective Ado.net providers
Message Protection
SSL /TLS (Transport Layer Security)
Transport / Binding
HTTP/ basicHttpBinding
Hosting / Interoperability
Self-Hosting  / WCF interoperable.
IIS authentication
None
ASP.NET configuration
None

Step 1: Enable SSL and configure IIS / Virtual directory.
·          SSL requires certificate to be location=localMachine and store=My (i.e, Personal).
·          SSL certificate can be created with(ChainTrust) or without RootCA(PeerTrust). Typically, SSL validated as ChainTrust. Hence, use certificate with RootCA
·         RootCA is nothing but a Certificate Authority that identifies all its issued certificates.

Step1.1: Create & install SSL certificate at respective location.

1: Create self-signed Root CA with private key.
sdkCmd> makecert -n "CN=RootCATest" -r -sv RootCATest.pvk RootCATest.cer

2: Install Root CA in Trusted Root CA folder at both (service/client) machines
OPEN MMC:  StartèRunèEnter MMCèFileèAdd/Remove Snap-in èAddè
                    Add Standalone Snap-inè CertificatesèAdd èComputer Account (available to all users).
IMPORT RootCA:  Right click on Trusted Root CA folderèAll TasksèImportèBrowse (path of .cer file)

3:  Create and install self-signed certificate for SSL as issued certificate.        
sqlCmd> makecert -sk yousufKey -iv RootCATest.pvk -n "CN=homepc-9c7a749d" -ic RootCATest.cer -sr localmachine -ss my -sky exchange -pe
Note: Don’t copy above command instead type with same switch order. Because characters replace “-“ è “–“   & " è
                  Machine name = homepc-9c7a749d (See MyComputerèPropertiesèComputerName tab)
Step1.2: Enable SSL over IIS.
ASSIGN SSL CERTIFICATE TO WEB-SITE(typically default Web-site):
StartèRunèInetMgr.msc; è Right click on default web-siteèProperties èDirectory Services
èSecure Communication è   Server Certificateè Next èAssign Exiting Certificate è www.MyDomain.Com

ENABLE SSL OVER Virtual.
Right click on Login file/site èpropertiesè Directory servicesèSecure Communication
èEdit è Require Secure Channel(SSL)
Step1.3: Enable anonymous Authentication over IIS
Right click on default web-site è properties èDirectory Services èAuthentication & Access Control è
Edit è Check in Enable Anonymous Access.
Step1.4: Reset IIS to update changes; Start èRun èReset iis

Step 2: Create WCF service with IIS hosting (Not in ASP.NET Development Server)
·         Create new Web-site in location=HTTP location with scheme= https;

Step 2.1. Create WCF Service:
VS è File è New Website è WCF Service è Location=HTTP; name= https://localhost/TransporCredentialOnlySecurity/
Step 2.2. Implement your Service:
[ServiceContract]
public interface IService
{
   [OperationContract]  string GetData1(int value);
   [OperationContract]  string GetData2(int value);
}

public class Service : IService
{
    public string GetData1(int value)  { return "GetData1:" + value.ToString(); }
    public string GetData2(int value)  { return "GetData2:" + value.ToString();}
}





Step 3: Configure WCF for SSL (and then Test)




Step4: Work with Validators & Providers for Windows Clients (Authentication/Authorization)
Step4.1: UserNameAuthenticationValidator
·         For username authentication against Windows clients, WCF provides predefined validator called Windows UserNamePasswordValidator.
·         Simply use it by configuring userNamePasswordValidationMode="Windows" (see Step5)

Step4.2: AuthorizationValidator
·         For username authorization use UseWindowsGroups or UseAspNetRoles" validator along with
ADO.NET Role provider either of:
a)       System.Web.Security.WindowsTokenRoleProvider / AuthorizationStoreRoleProvider for WorkGroup / ActiveDirectory Data Source respectively for role management.
        //OR //
b)       System.Web.Security.SqlRoleProvider if you want to work with SQL data source by explicitly assign roles in db.

(a) : Working with WindowsTokenRoleProvider / AuthorizationStoreRoleProvider (for WG/AD)
Enable Role Provider as follows:
<system.web>
<roleManager enabled="true" defaultProvider="MyWindowsTokenRoleProvider">
   <providers>
       <clear />
         <add name="MyWindowsTokenRoleProvider" applicationName="MyAppName"
type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
      </providers>
    </roleManager>
Note: Copy these settings form Machine.config.comments then paste and edit it.
//OR//
  (b): Working with SqlRoleProvider 
  Step-(b1): Create and Assign Roles to Windows Accounts.
//Create Role-provider database(default name=aspnetdb otherwise use –d switch)
     Sdkcmd> aspnet_regsql –S .\SQLExpress –E –A r       // - A r: Add only role-provider features; -E: Integrated Security.
// Open the database in Visual studio THEN
// Add new Role:
     Execute sp aspnet_CreateRole ‘MyApplicationName’, ‘Managers’ // name should be as in Providers.
// Assign user to role:
     Execute sp aspnet-UsersInRoles_AddUsersToRoles ‘MyAppName’, “HOMEPC-9C7A749D\nayeem’



Step5: Configure the Service behavior to use Validators for authentication and authorization.
<behaviors/serviceBehaviors>
        <behavior name="ServiceBehavior">
              <serviceCredentials>
                                                      <userNameAuthentication userNamePasswordValidationMode="Windows"
                                                                       cacheLogonTokens="true"
                                                                       cachedLogonTokenLifetime="00:01:00"
                                                                       maxCachedLogonTokens="10"/>
               </serviceCredentials>
               <serviceAuthorization principalPermissionMode="UseWindowsGroups"
                                                    roleProviderName="MyWindowsTokenRoleProvider" />
            
                       <serviceMetadata httpGetEnabled="false" httpsGetEnabled="True"/>
</behavior>

Step6: Implement the Client Application and Test Service with valid/invalid credentials
·         Solution explorer èRight Click è Add new Website è”WCFTestClient”.
·         Add service reference; https:// homepc-9c7a749d/TransportWithMessageSecurity/; instead localhost use server name.

protected void Page_Load(object sender, EventArgs e)
{
        var proxy = new ServiceReference1.ServiceClient();
        //Provide windows credentials
        proxy.ClientCredentials.UserName.UserName = "nayeem";
        proxy.ClientCredentials.UserName.Password = "pass123";
        Response.Output.Write("{0}",proxy.GetData1(123));
        Response.Output.Write("{0}",proxy.GetData2(123));
        proxy.Close();
}
          Note(1)    While adding service reference; no need to enter client credentials. But while consuming service over proxy
                         credentials needed.
(2)      No need of configuring as it is required only for Message level security not for Transport security.
(3)      No need of certificate validation neither programmatically nor declaratively  e.g., / . or handing System.Net.ServicePointManager.ServerCertificateValidationCallback event

Step7: Grant permissions on service operations with respective privileges to clients/roles.(See Recipe4.2.1)
Use [PrincipalPermission(SecurityAction.Demand, Role="Admin")] over Operation contract interface  //OR //
if(!System.Threading.Thread.currentPrincipal.IsUnerInRole("Admin"))
        throw new SecurityTokenValidationException("not Authorized" );

Rebuild Service and execute host application. Execute client application.


II: using wsHttpBinding.


About Me
·         TransportWithMessageCredential uses  means message protection(Integrity, confidentiality) is provided at Transport level but client authentication is done at Message-level.
·         TransportWithMssageCredential allows Message-level authentication:
Ø       UserName authentication with all validators (Windows, Membership and custom).
Ø       Windows authentication both NTLM/Kerberos.
Ø       Mutual Certificate authentication.
·         This variation Recipe is same as Recipe 4.3.1, but uses wsHttpBinding instead of basicHttpBinding.

·         wsHttpbinding needs some additional requirements when working with TransportWithMessageCredential / Transport security.
1)       You must have to configure http port with ssl certificate.
2)       You must validate the ssl certificate at client by handling
        System.Net.ServicePointManager.ServerCertificateValidationCallback event.
Note: These are 2 additional configurations are not required when binding is either basicHttpBinding / netTcpBinding.

Step 1: Configure http port with ssl certificate.
  • SSL configuration are required for WsHttpBinding + transport security+[Username authentication | certificate authentication]
1.1: Get SSL certificate hash
§         StartèRunèenter MMCèFileèAdd/Remove snap-inèAddèCertificateèComputerAccountèFinish
§         Open Personal certificate folder è Open installed ssl certificate.
§         Copy thumbprint i.e, (certificate Hash) to a Text file è Remove spaces è again copy it.(use it in next step)
1.2:  Configure HTTP for HTTPS
§         Use utility httpcfg.exe (for Win2k3/Xp) / netsh.exe (vista/Win2k8).
§         These utilities are available as ServicePack support tools; and needs to be download explicitly.
For Win 2003 Server / XP
(a)      To bind SSL certificate to a HTTP port number.
httpcfg set ssl -i 0.0.0.0:8005 -h 0000000000003ed9cd0c315bbb6dc1c08da5e6
(b)      To view/determine bind certificate when HTTP port.
httpcfg query ssl  //or//
httpcfg query ssl>myMachinePorts.txt
(c)      To delete SSL certificate form a port number
httpcfg delete ssl -i 0.0.0.0:8005 -h 0000000000003ed9cd0c315bbb6dc1c08da5e6

For Win 2008 Server / Vista
(a)      To bind SSL certificate to a HTTP port number.
netsh http add sslcert ipport=0.0.0.0:8005 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 

appid={00112233-4455-6677-8899-AABBCCDDEEFF} 
Note: To generate appid ( VS èTools ècreate GUID èSelect registry format è Copy èExit.
(b)      To view/determine bind certificate when HTTP port.
netsh http show sslcert
(c)      To delete SSL certificate form a port number
netsh http delete sslcert ipport=0.0.0.0:8005
 

Step 2: Change binding(basicHttpBindingèWsHttpBinding) at and elements.
2.1: <endpoint address="https://localhost:8005/service" binding="wsHttpBinding" contract="IService" bindingConfiguration="wsEndpointBinding">

2.2:   <bindings>/HttpBinding><binding name="basicEndpointBinding">
          <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None"/>
                        <message clientCredentialType="UserName"/>
          </security>     
Step 3: Validate the ssl certificate at client side while consuming service:
using System.Security.Cryptography.X509Certificates;  using System.Net;  using System.Net.Security;
public partial class _Default : System.Web.UI.Page
{
        protected void Page_Load(object sender, EventArgs e)
        {
        ServicePointManager.ServerCertificateValidationCallback +=
                                    new System.Net.Security.RemoteCertificateValidationCallback(CertificateNoCheckHandler);
        var proxy = new ServiceReference1.ServiceClient();
        proxy.ClientCredentials.UserName.UserName = "user1";
        proxy.ClientCredentials.UserName.Password = "password#1";
        Response.Output.Write("{0}",proxy.GetData1(123));
        Response.Output.Write("{0}",proxy.GetData2(123));
        proxy.Close();
        }
     public static bool CertificateNoCheckHandler(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {  return true;  }
}

4 comments: