Showing posts with label WCF SSL HTTPS Authentication. Show all posts
Showing posts with label WCF SSL HTTPS Authentication. Show all posts

Wednesday, 18 April 2012

Federated custom tcp binding (and http binding)

This is a work in progress, but so far it allows me to take a token from ACS (Azure Access Control Services) - I followed the basic SDK/MSDN advice to set up a relying party, provider and rules - and send it to a service (acting as Relying Party) by way of authentication.

I was particularly interested to try this with TCP binding and it looks like custom binding is the only way.

For the http I started with the Federated HTTP binding, but since the custom binding took shape, you get more control this way, so I formulated an https equivalent here too.

Note this is for illustration purposes it's certainly not production ready.

1. Get token from ACS
  

        private static SecurityToken GetIdentityProviderToken(string acsEndpoint, string serviceEndpoint)
        {
            var factory =
                new WSTrustChannelFactory(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), acsEndpoint)
                {
                    TrustVersion = TrustVersion.WSTrust13
                };

            factory.Credentials.ClientCertificate.SetCertificate(
                StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindBySubjectName,
                "[cert dns/hostname]");

            var rst = new RequestSecurityToken
            {
                RequestType = RequestTypes.Issue,
                AppliesTo = new EndpointAddress(serviceEndpoint),
                //specify URI realm that ACS token will apply to
                //AppliesTo = new EndpointAddress( new Uri( "urn:federation:customer:222:agent:11" ) ),
                KeyType = KeyTypes.Symmetric
            };

            factory.Credentials.UserName.UserName = ClientUsername;
            factory.Credentials.UserName.Password = ClientPassword;
            var channel = factory.CreateChannel();

            return channel.Issue(rst);
        } 


2. Http Client config (code)
 

        private static ChannelFactory GetCustomHttpBoundService(SecurityToken token, string address)
        {


            var securityBootStrap = SecurityBindingElement.CreateIssuedTokenForCertificateBindingElement(new IssuedSecurityTokenParameters());
            var security = SecurityBindingElement.CreateSecureConversationBindingElement(securityBootStrap, requireCancellation: true);
            
            Console.WriteLine("Include timestamp " + security.IncludeTimestamp);
            Console.WriteLine("Allow insecure transport " + security.AllowInsecureTransport);
            Console.WriteLine("Client: Detect replays " + security.LocalClientSettings.DetectReplays);
            Console.WriteLine("Client: Max clock skew " + security.LocalClientSettings.MaxClockSkew);
            Console.WriteLine("Server: Detect replays " + security.LocalServiceSettings.DetectReplays);
            Console.WriteLine("Server: Max clock skew " + security.LocalServiceSettings.MaxClockSkew);


            var customBinding = new CustomBinding(new List
            {  
                security,
                new BinaryMessageEncodingBindingElement(),
                new HttpsTransportBindingElement()
            });

            var factory = new ChannelFactory(customBinding,
                new EndpointAddress(new Uri(address), EndpointIdentity.CreateDnsIdentity("[cert dns/hostname]")));
            factory.ConfigureChannelFactory();

            Debug.Assert(factory.Credentials != null);
            factory.Credentials.SupportInteractive = false;
            factory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindBySubjectName,
                "[cert dns/hostname]");

            return factory;
        }

3. TCP Client config (code)
  

        private static ChannelFactory GetCustomTcpBoundService(SecurityToken token, string address)
        {

            var securityBootStrap = SecurityBindingElement.CreateIssuedTokenForCertificateBindingElement(new IssuedSecurityTokenParameters());
            var security = SecurityBindingElement.CreateSecureConversationBindingElement(securityBootStrap, requireCancellation: true);
      
            Console.WriteLine("Include timestamp " + security.IncludeTimestamp);
            Console.WriteLine("Allow insecure transport " + security.AllowInsecureTransport);
            Console.WriteLine("Client: Detect replays " + security.LocalClientSettings.DetectReplays);
            Console.WriteLine("Client: Max clock skew " + security.LocalClientSettings.MaxClockSkew);
            Console.WriteLine("Server: Detect replays " + security.LocalServiceSettings.DetectReplays);
            Console.WriteLine("Server: Max clock skew " + security.LocalServiceSettings.MaxClockSkew);

            var customBinding = new CustomBinding(new List
            {  
                security,
                new BinaryMessageEncodingBindingElement(),
                new SslStreamSecurityBindingElement {RequireClientCertificate = false},
                new TcpTransportBindingElement()
            });

            var factory = new ChannelFactory(customBinding,
                new EndpointAddress( new Uri(address),  EndpointIdentity.CreateDnsIdentity("[cert dns/hostname]")));
            factory.ConfigureChannelFactory();
       
            Debug.Assert(factory.Credentials != null);
            factory.Credentials.SupportInteractive = false;
            factory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindBySubjectName,
                "[cert dns/hostname]");

            return factory;
        }


4. Http Server config
  


        <binding name="customfedhttps">
          <security authenticationmode="SecureConversation" requiresecuritycontextcancellation="true">
            <secureconversationbootstrap authenticationmode="IssuedTokenForCertificate">
            </secureconversationbootstrap>
          </security>
          <binarymessageencoding>
          <httpstransport requireclientcertificate="false">
        </httpstransport></binarymessageencoding>
       </binding>

5. TCP Server config
  


        <binding name="customfedtcp">
          <security authenticationmode="SecureConversation" requiresecuritycontextcancellation="true">
            <secureconversationbootstrap authenticationmode="IssuedTokenForCertificate">
            </secureconversationbootstrap>
          </security>
          <binarymessageencoding>
          <sslstreamsecurity requireclientcertificate="false">
          <tcptransport>
        </tcptransport></sslstreamsecurity></binarymessageencoding>
        </binding>

6. Server behaviour
  

    <behaviors>
      <servicebehaviors>
        <behavior name="fedbehaviour">

          <servicemetadata httpsgetenabled="true">
          <federatedservicehostconfiguration>
          
        </federatedservicehostconfiguration></servicemetadata></behavior>
      </servicebehaviors>
    </behaviors>

    <extensions>
      <behaviorextensions>
        <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      </add></behaviorextensions>
    </extensions>


7. Identity model config
  

  <microsoft.identitymodel>
    <service>
      <audienceuris>
        <add value="https://localhost/Service1.svc">
        <add value="net.tcp://localhost:997/Service2.svc">
      </add></add></audienceuris>

      <servicecertificate>
        <certificatereference findvalue="[cert dns/hostname]" storelocation="LocalMachine" storename="My" x509findtype="FindBySubjectName">
      </certificatereference></servicecertificate>

      <issuernameregistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedissuers>
          <add name="[cert dns/hostname]" thumbprint="[cert thumb print]">
        </add></trustedissuers>
      </issuernameregistry>

      <certificatevalidation certificatevalidationmode="None">

      
    </certificatevalidation></service>
  </microsoft.identitymodel>



Useful links:








Tuesday, 12 July 2011

IIS Express and SSL

There's plenty about this, but still I got caught out for a while this afternoon...

When using IIS express you can host a service expecting SSL, if you want to make calls into the local service it looks like you do have to trust the default localhost cert installed for IISExpress (see inetmgr "server certificates", this can be exported and imported into certmgr.msc)

See here for enabling SSL and a neat workaround for port numbers (iis express doesn't use 443 by default)

And
Jon Simpsons nice post for sending client credentials to a service which then uses ASP net authentication


Update: Another way (but not that safe) is to ingore the local cert trust issue in the client by adding this (in vb in this example)

System.Net.ServicePointManager.ServerCertificateValidationCallback = New System.Net.Security.RemoteCertificateValidationCallback(Function() True)