Mixed credentials: Username & Certificate

Greetings,

Our services will be exposed on the Internet. Only specific partners applications should be able to have access to them. At the same time, the partners applications users will need to be authenticated & authorized by our services. We will use role-based security to authorize them. The reason why we need a double validation using a certificate for each application is because we don't want anybody on the internet to be able to query those services directly (that includes our users having usr/pwd credentials who could try to pull the services content from their own app). We want to make sure only "known" applications can call these services.

Is that possible to do and if so, is there any sample in the SDK or somewhere else that demonstrates such configuration

Thanks

-Jonathan



Answer this question

Mixed credentials: Username & Certificate

  • gorden

    Jonathan,

    Your service certificate is now being propogated over SSL and so has probably been configured as part of your IIS install, if you are hosted inside IIS, or if you are self-hosted, has been configured via httpcfg.

    We essentially ignore the client cert on the service side and just use the message level credentials to authenticate the client.

    Gudge


  • Ramcat

    I just tried the TransportWithMessageCredential mode with this config on both sides

    <security mode="TransportWithMessageCredential">
    <transport clientCredentialType="Certificate"/>
    <message clientCredentialType="UserName" negotiateServiceCredential="false" />
    </security>

    What i don't understand is that now, with this config, i don't have to put a certificate anywhere and its still working... I was expecting since i am using negotiateServiceCredential = false to still have to put the service certificate on the client side but i didn't and it works. I don't specify the client certificate to use either and it still works...

    Am i missing something

    Thx

    -Jonathan


  • drgonjo

    Jonathan,

    Here is some code that creates a binding that requires both Username and Certificate credentials;

    static Binding CreateCertAndUsernameBinding()
    {
    WSHttpBinding b = new WSHttpBinding();
    b.Security.Mode = SecurityMode.Message;
    b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
    b.Security.Message.NegotiateServiceCredential = false;

    BindingElementCollection bec = b.CreateBindingElements();

    SecurityBindingElement sbe = bec.Find<SecurityBindingElement>();

    if (sbe != null)
    {
    UserNameSecurityTokenParameters p = new UserNameSecurityTokenParameters();
    sbe.EndpointSupportingTokenParameters.SignedEncrypted.Add(p);
    }

    return new CustomBinding(bec);
    }

    And here is the code to set up the client credentials on the client side before making the call to the service.

    cf.Credentials.UserName.UserName = "Alice";
    cf.Credentials.UserName.Password = "ecilA";

    cf.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "Alice");

    Hope this helps,

    Gudge


  • Aibo

    I believe it's possible with a custom binding ( although not via config ). I'll try to work up a sample but it won't be today ( and probably not tomorrow either, I'm afraid )

    Gudge


  • Jovo Filips

    It turns out we don't allow you to specify client credentials at the transport layer in this mode. Sorry to send you down a blind alley. Will the message level stuff I sent earlier work for you Or do you need an HTTPS based solution

    Gudge


  • Gregory P

    Jonathan,

    I now have this working with a custom binding over HTTPS. The binding creation code is as follows;

     

    static Binding CreateCertAndUsernameBinding()
    {
     WSHttpBinding b = new WSHttpBinding();
     b.Security.Mode = SecurityMode.Transport;
     b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

     BindingElementCollection bec = b.CreateBindingElements();

     TransportSecurityBindingElement sbe = bec.Find<TransportSecurityBindingElement>();

     if (sbe == null)
     {
      sbe = new TransportSecurityBindingElement();
      BindingElementCollection bec2 = new BindingElementCollection();
      bec2.Add(sbe);

      foreach (BindingElement be in bec)
       bec2.Add(be);
     
      bec = bec2;
     }

     UserNameSecurityTokenParameters p = new UserNameSecurityTokenParameters();
     sbe.EndpointSupportingTokenParameters.SignedEncrypted.Add(p);

     return new CustomBinding(bec);
    }

     

    The client side credential specification looks like this;

     

    proxy.Credentials.UserName.UserName = "username";
    proxy.Credentials.UserName.Password = "password";
    proxy.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByThumbprint, "...");

     

    This has the client cert at the HTTPS layer and UsernameToken at the SOAP layer. Both sets of credentials show up in the resulting AuthorizationContext on the service side.

    The above code should work with FebCTP.

    Hope this helps,

    Gudge


  • Zaph0d

    Oh really That means i was on a good track before i got your sample. I was just trying to do that with TransportWithMessageCredential and using Certificate at the transport level. I never finished making it work though. Yes i was planning to use Https in the solution so if you have a ready to use config sample for me it would be great.

    Once that work, it will be time for me to dive into making this work with an internal STS using wsFederationBinding .

    Client --> Intermediary Router --> STS
    --> BizService

    Thx

    -Jonathan


  • JDanon

  • Jams1999

    Humm... not sure these samples are doing what i need...

    I mean, there is a bunch of samples about how to use one mechanism or the other but my question was about how to use both at the same time for authenticating the client.

    In the Membership Provider Sample for example, it is mentionned "server authentication using the server's X509v3 certificate". By "server", does that mean the client-side server or the services server If it is the client-side (app) server, then yes i guess this is exactly what i was talking about.

    Thx

    -Jonathan


  • elpepe

    Jonathan,

    Here is another code that does the same thing but I think is more transparent about what needs to be done to set client transport authentication using certificate and to add username on the message-level:

    public static Binding CreateBinding()
    {
    HttpsTransportBindingElement transportBindingElement = new HttpsTransportBindingElement();
    transportBindingElement.RequireClientCertificate = true;
    SecurityBindingElement securityBindingElement = new TransportSecurityBindingElement();
    securityBindingElement.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
    CustomBinding binding = new CustomBinding(securityBindingElement, transportBindingElement);
    return binding;
    }
    --Jan


  • MalcolmB

    Jonathan,

    My code is RC0 based, so there may be some minor diffs between what I have and existing samples. You can probably do what you want with a standard binding if you use the TransportWithMessageCredential security mode and use Certificate at the transport level and Username at the message level but I wasn't sure what your constraints were so didn't want to limit you to https. If you can use https, let me know and I'll post some code/config that shows how to do that.

    Gudge



  • Tika

    I wanted it to be https at least between my clients and my Intermediary Router so i can get the best performance. These services will serve the content of many Web sites, so my guess (according to the documentation) is that using Https will put lesser stress on the servers. Also, P2P security of the messages is more than enough for us. Once the messages are received by the services, they don't need to be secured anymore.

    Do you have any suggestion Is it something that would be possible with a custom binding or is it just impossible

    Your input & help is very appreciated.

    Thx

    -Jonathan


  • Gordon Pollokoff

    Thanks Gudge, it really helped. I was hitting my head trying to do that by configuring predefined bindings only without relying on code. I would have try for a long time if it would not be of your post.

    I am eager to try it. Btw, while i was looking for references about some of the classes and methods you are using in your example, i found a very interesting sample in the "Extensibility samples" of the SDK named "Supporting Tokens". It looks like it is exactly doing what i need to do. The implementation is slightly different than yours though...

    Here is the link for those who are interested:

    http://windowssdk.msdn.microsoft.com/library/default.asp url=/library/en-us/WCF_samples/html/27dfb023-0066-494c-be4e-b4d0c3b04d22.asp

    I feel bad since i never thought about looking into these extensibility samples because i thought that this scenario would have been possible with predefined bindings only...

    Thx again

    -Jonathan


  • willko

    hi Gudge,

    I m having an issue, so far could not found the solution. Please could you help me with this

    ok the main struggle I m using the secure transport. So I dont want any extra message oriented security. here I m building binding with my STS giving my custom token parameters.

    TransportSecurityBindingElement transportSecurity = SecurityBindingElement.CreateIssuedTokenOverTransportBindingElement(new CustomerSecurityTokenParameters());

    CustomBinding stsBinding = new CustomBinding(transportSecurity, new HttpsTransportBindingElement());

    However this equivalent to

    transportSecurity.EndpointSupportingTokenParameters.Endorsing.Add(CustomerSecurityTokenParameters);

    As I know I will using endorsing token to sign my signature and creating another signature. I dont really need this.

    so I would like to have something like

    transportSecurity.EndpointSupportingTokenParameters.Endorsing.Signed.Add(CustomerSecurityTokenParameters);

    but I do having an error in this case. the error that my message cannot verified.

    My question why I should use endorsing token. Or am I building some kind a securetokencontext which tends to substitute transport layer in message level security scenario. I m really lost here. I want to send as just supporting token not endorsing i.e no any keys been creating.

    Another question would be, can I use internal RST/RSTR classes of WCF. I was using your implementation so far as many others. but I have been asked why I can tuse the RST/RSTR classes those are within the WCF.

    thank you.


  • Mixed credentials: Username & Certificate