Decrypt SAML2.0 token returned from Thinktecture IdentityServer - thinktecture-ident-server

i'm currently trying to use the Thinktecture IdentityServer as my STS (token issuer). When i get back an encrypted token from the IdentityServer, how does one decrypt the token so that I could extrapolate the claims information from it?
thank you for your help.

If configured correctly WIF should handle the decryption for you, and then you should be able to access the claims from the current claims principal.
The Relying Party WIF configuration part to define which certificate should be used for decryption:
<federationConfiguration>
<serviceCertificate>
<certificateReference findValue="the-encryption-certificate-thumbprint" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
</serviceCertificate>
</federationConfiguration>
The code to access the claims from the context:
HttpContext.Current.User.Identity.Name
Or
Claim myClaim = (HttpContext.Current.User as ClaimsPrincipal).FindFirst("http://identityserver.thinktecture.com/claims/profileclaims/myclaim");

Related

How do I implement Client Certificate authentication the right way?

WCF is extremely extensible and has a lot of ready-to-use features, however I continue struggling with some topics and the more documentation I read, the more I get confused.
I hope to get some answers from the community. Feedback on any assumption or question is extremely welcome.
For the record: to really accept a single answer I should divide this post in multiple questions but it would lead to even more confusion.
I am pretty sure there are some real WCF experts online who can answer the few questions in this document all at once so I can accept a single answer as the real deal to setup clientcertificate authentication using IIS the right way.
Let me sketch the situation and partner request:
1: The partner requirement and the question to use a client certificate.
Partner X needs to call an API on my backend and they have the clear requirement to use Clientcertificate authentication.
They created the clientcertificate and provided us the certificate with only the public key since it seems only logic they keep the private key actually private and in their own system(s).
The certificate was imported on the local computer account and looking at the certification path this is valid. All intermediate certification authorities and in the end the root certification authority are trusted.
2: Our WCF serverside configuration
I have a serviceBehavior configured as such:
<behavior name="ClientCertificateBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="<serialnumber here>" x509FindType="FindBySerialNumber" />
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
</serviceCredentials>
</behavior>
I guess I made a first mistake here and should use ChainTrust to actually validate the certificate using its certification path. What do you think?
The service is configured as such:
<service behaviorConfiguration="ClientCertificateBehavior" name="<Full service namespace and servicename>">
<endpoint binding="basicHttpBinding" bindingConfiguration="Soap11CertificateBasicHttpBinding"
contract="<The interface>"></endpoint>
</service>
The binding looks like this:
It is a basicHttpBinding to force SOAP1.1 (according to the partner's specifications).
<binding name="Soap11CertificateBasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
3: Hosting the WCF service in IIS and the IIS configuration
We host our WCF services in IIS7.
We configured the folder in which the services reside to require SSL and to accept Client certificates.
Authentication-wise anonymous authentication is enabled.
The thing is that communication from the partner works and we were confident that everything was OK, however toggling the IIS-setting to 'require' client certificate shows us that all of a sudden it is no longer possible to successfully call our service.
Am I correct to assume that following things are not done correctly:
The serviceCerticate in the serviceBehavior is not really necessary. This is a setting used by the client. Or is it necessary to provide this certificate information for the service endpoint to match the certificate that's being send by the client?
For clientcertificate authentication to really work in IIS the certificate needs to be mapped to a user. This user should be granted permissions on the folder containing the services and all authentication mechanisms (anonymous, windows,...) should be disabled.
This way IIS will handle the actual handshake and validate the servicecommunication.
Or is it more a matter of extra security mapping the certificate to a user?
By setting 'Accept' on IIS we bypass the actual certificate validation between client and server.
All authentication mechanisms like 'anonymous' and 'windows' have to be disabled on IIS for the folder which holds the services.
In your scenario, you don't need to configure certificates in WCF, IIS handles those for you. You can clear the entire <serviceCredentials> block, because:
The <serviceCertificate> of <serviceCredentials> specifies an X.509 certificate that will be used to authenticate the service to clients using Message security mode, which you do not use, and the <clientCertificate> of <serviceCredentials> defines an X.509 certificate used to sign and encrypt messages to a client form a service in a duplex communication pattern.
See here how to map client certificates to user accounts.

How to sign X509 token using WCF

I am working on a WCF client which must talk to an Oracle WebLogic service. The service enforces mutual certificate authentication.
We are not, however, able to satisfy the policy and the server logs an error stating:
"WSM-00081: The X.509 certificate is not signed."
I have been wondering what the exact meaning of this is. The Oracle documentation states:
WSM-00081: The X.509 certificate is not signed.
Cause: The X509 token used was not signed according to requirements of certificate authentication scenario.
Action: Sign the X509 token (depending upon the reference mechanism used) for certificate authentication.
Level: 1
Type: ERROR
Impact: Security
(http://docs.oracle.com/cd/E25054_01/core.1111/e10113/chapter_wsm_messages.htm)
After some research, we found out that we can disable the check in the service policy configuration file by setting is-signed="false:
<orasp:x509-token orasp:enc-key-ref-mech="direct" orasp:is-encrypted="false"
orasp:is-signed="false"
orasp:rcpt-enc-key-ref-mech="direct"
orasp:rcpt-sign-key-ref-mech="direct"
orasp:sign-key-ref-mech="direct"/>
My two theories:
The certificate needs to be signed by a CA
We checked using an a certificate signed by a CA, but this made no difference
However, we might have made som errors when configurating this. Should we try it over?
We somehow need to sign the included BinarySecurityToken's, which are included in the request.
However, I have no idea how I can do this
Have I completely misunderstood the subject or can any of you give some pointers to what the problem might be and how it can be solved?
You need to sign the security token as part of the request.
In the binding element of your config set the security element mode to SecurityMode.Message and the message element clientCredentialType to MessageCredentialType.Certificate:
<security mode="Message">
<message clientCredentialType="Certificate"
algorithmSuite="Default"
establishSecurityContext="true" />
</security>
Next, create an endpoint behavior to resolve the location of your client certificate:
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="Contoso.com"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>

The client WCF cannot connect to the server WCF without having the server certificate on local machine

The scenario is this: there are 2 WCF Web Services, one a client (WCFClient), one a server (WCFServer), deployed on different machines. I needed certificate communication between the two of them.
On the server WCF I have set the binding to use certificates as client credential type.
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
Also, in the behaviour section, among other settings, I have
<serviceBehaviors>
<behavior name="Server.ServiceBehavior">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
<serviceCertificate findValue="Server"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
On the client WCF Service I added this endpoint behaviour
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="Client"
x509FindType="FindBySubjectName"
storeLocation="LocalMachine"
storeName="TrustedPeople" />
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
When I wanted to test my services, I had an error message:
The service certificate is not provided for target 'http://blablabla...'. Specify a service certificate in ClientCredentials.
So I started checking things out on the Internet. After trying many things, the only thing that actually worked is adding this on my client:
<serviceCertificate>
<defaultCertificate findValue="Server"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectName" />
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
As you might think, yes, this means I need the Server certificate on my client machine. Which is clearly a very bad thing.
It works for my testing purposes, but it is an unacceptable for deployment.
I would want to understand what really could cause that error message and what the solution may be.
Later edit: In this project the client must not have the server certificate (even without having the private key). This is the specification of the system and it's quite difficult (in bureaucracy terms) to go beyond this.
There will be multiple clients, each with the client WCF service running, and each should know nothing more that their own certificate. The server will know the server certificate and all the clients certificate.
Looking here it reads,
When considering authentication, you may be used to thinking primarily
of the client identity. However, in the context of WCF, authentication
typically refers to mutual authentication. Mutual authentication not
only allows positive identification of the clients, but also allows
clients to positively identify the WCF services to which they are
connected. Mutual authentication is especially important for
Internet-facing WCF services, because an attacker may be able to spoof
the WCF service and hijack the client’s calls in order to reveal
sensitive data.
The service credentials to be used depend largely on the client
authentication scheme you choose. Typically, if you are using
non-Windows client authentication such as username or certificate
authentication, a service certificate is used for both service
authentication and message protection. If you are using Windows client
authentication, the Windows credentials of the process identity can be
used for both service authentication and message protection.
It looks to me that you do need the server certificate on the client machine, and that this is a good thing, not a bad thing. Note that you do not need (and should not put) the server's private key on the client machine. The private key is not contained in a certificate -- only the public key is.
Having the server certificate on the client machine means only having the server's public key on the client machine. The benefit is that the client now knows that it is talking to the real server.
I'm not familiar with WCF services, but this seems fine as far as the use of certificates.
why is it bad to have the service certificate on the client machine? it is only the public portion of it, not the private key.
if you use wshttpbinding you can set negotiateServiceCredential=true in which case the client will get the server cert dynamically. The price is a little bit of performance hit, and this endpoint will not be interoperable to non .net clients.
I actually forgot about this question, but at that time I have found the solution.
My actual problem was that I was using a basicHttpBinding for the communication I wanted to secure. basicHttpBinding implies ussing that serviceCredential part.
http://msdn.microsoft.com/en-us/library/ms731338(v=vs.85).aspx
Because of the system requirements I had, I changed the binding to wsHttpBinding. Now I don't need to put the server certificate on the client machine.

WCF service with SSL

I know that SSL certificate is used for security purpose of application so that data transfer should be in encrypted form.As per my knowledge we have to install SSL certificate in host server for our application.
These days i am working in WCF service. Client want us to make WCF service with SSL certificate.
What i want to know that is there any need to do in code level for SSL certificate. I am going to host my service in IIS.
What are the steps for configuring WCF service with SSL certificate?
I know little knowledge is always dangerous :(
Please elaborate.
Thanks in advance.
In order to configure your service for 2 way SSL below are the steps:
Create a website which has the https binding mapped on it.
When the https binding is mapped to the website it asks for a server SSL certificate that it would use to secure your transport channel.
Create a virtual directory where you want your services to be deployed.
Now the WCF services being built need to have the configuration that specifies that the service uses https and clients are authenticated using certificates.
Set the option to "Accept" on your SSL Settings of your virtual directory which states that the client might pass a certificate. IF you set it to require then the client needs to pass a certificate.
NOTE: When using certificate you need to be sure on which certificate needs to be installed in which certificate store. You might have some exceptions with self signed certificates but they can be bypassed on client by using the code below:
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, error) => true;
Some code on how to implement your custom certificate validator and use it:
public class CustomX509CertificateValidator : System.IdentityModel.Selectors.X509CertificateValidator
{
// This Validation function accepts any X.509 Certificate that is self-issued. As anyone can construct such
// a certificate this custom validator is less secure than the default behavior provided by the
// ChainTrust X509CertificateValidationMode. The security implications of this should be carefully
// considered before using this validation logic in production code.
public override void Validate(X509Certificate2 certificate)
{
// Check that we have been passed a certificate
if (certificate == null)
throw new ArgumentNullException("certificate");
// Only accept self-issued certificates
if (certificate.Subject != certificate.Issuer)
throw new SecurityTokenException("Certificate is not self-issued");
}
}
Now in your WCF service config file to use the custom certificate validator is shown below:
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<!--
The serviceCredentials behavior allows one to specify authentication constraints on client certificates.
-->
<clientCertificate>
<!--
Setting the certificateValidationMode to Custom means that if the custom X509CertificateValidator
does NOT throw an exception, then the provided certificate will be trusted without performing any
validation beyond that performed by the custom validator. The security implications of this
setting should be carefully considered before using Custom in production code.
-->
<authentication certificateValidationMode="Custom" customCertificateValidatorType="X509CertificateValidator.CustomX509CertificateValidator, service"/>
</clientCertificate>
<!--
The serviceCredentials behavior allows one to define a service certificate.
A service certificate is used by a client to authenticate the service and provide message protection.
This configuration references the "localhost" certificate installed during the setup instructions.
-->
<serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>

Custom client certificate and username validation in WCF service

My particular problem is something like this:
We are currently running a set of services which requires the clients to provide a username and password as authentication when calling the services.
We would like to implement a PKI-infrastructure on these services, but some of our partners will use longer time to accommodate to this new infrastructure than the others.
As a first step we want to require client certificates from some of our partners. A client certificate will be required (in addition to username and password) to access their data on our servers, while for the other users only username and password will be required.
To solve this problem I am trying to implement a custom validator for both the username/password authentication (using UserNamePasswordValidator) and for the client certificates (using X509CertificateValidator) in WCF. The username/password validator will verify these credentials towards our database, while the client certificate validator will inspect whether the request is from a client from which we require a certificate, and if so verify that a valid client certificate is provided. I have not been able to configure WCF so that it uses both of these validators.
My WCF configuration on the server is currently set up like this:
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpsGetEnabled="true" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<authentication customCertificateValidatorType="MyWS.Security.MyServicesCertificateValidator, MyWS"
certificateValidationMode="Custom" revocationMode="NoCheck" />
</clientCertificate>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyWS.Security.MyServicesUsernameValidator, MyWS" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<bindings>
<basicHttpBinding>
<binding name="MySoapBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Certificate" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyWS.Services.TheService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="MySoapBinding" name="TheService" bindingNamespace="https://services.my/TheService" contract="MyWS.Interfaces.Service.ITheService" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:4434/MyWS/TheService"/>
</baseAddresses>
</host>
</service>
</services>
As far as I understand this configuration is invalid because I can't use the customCertificateValidatorType at the transport layer (because IIS inspects the certificate before WCF is involved here), but I can not see how I am able to combine both the customCertificateValidatorType and customUserNamePasswordValidatorType as credential types at the message layer either.
I have implemented a message inspector and might be able to solve the problem using the OperationContext in some way (as suggested in the link below), but I have not been able to see a way for me to do it this way yet.
http://social.msdn.microsoft.com/Forums/en/wcf/thread/b6ab8b58-516b-41d4-bb0e-75b4baf92716
I suppose I might be trying to implement something that is incompatible with the way WCF works, but if someone have an idea about how this could be fixed I would be delighted to have your feedback on this.
I think I have found a solution to my problem now thanks to valuable input from #ladislav-mrnka in his answer. I realized it is necessary to provide two endpoints to configure the different requirements, and I also learned about the supporting token possibilities when configuring the services.
I found a link about supporting tokens at MSDN, and by following this recipe I have implemented the endpoint on the server with the following custom binding (I switched to configuration through code. Not sure if this can be set up in web.config as well.)
private static Binding CreateMultiFactorAuthenticationBinding()
{
var httpsTransport = new HttpsTransportBindingElement();
// The message security binding element will be configured to require 2 tokens:
// 1) A username-password encrypted with the service token
// 2) A client certificate used to sign the message
// Create symmetric security binding element with encrypted username-password token.
// Symmetric key is encrypted with server certificate.
var messageSecurity = SecurityBindingElement.CreateUserNameForCertificateBindingElement();
messageSecurity.AllowInsecureTransport = false;
// Require client certificate as endorsing supporting token for all requests from client to server
var clientX509SupportingTokenParameters = new X509SecurityTokenParameters
{
InclusionMode =
SecurityTokenInclusionMode.AlwaysToRecipient
};
messageSecurity.EndpointSupportingTokenParameters.Endorsing.Add(clientX509SupportingTokenParameters);
return new CustomBinding(messageSecurity, httpsTransport);
}
This binding creates a SymmetricSecurityBindingElement where a symmetric key (encrypted with the server certificate) is used to encrypt a username/password security token in the message header, and the message body itself.
In addition a X509 security token is added as an endorsing, supporting token to the binding. This token is configured to always be included in the client requests to the server.
This custom binding was subsequently used to configure a new WCF-service with an endpoint requiring this binding. I am using the WcfFacility in Castle Windsor to configure the service.
This code does the following:
Sets the service certificate
Sets the validation mode for the client certificates to chain trust, so that incoming client certificates must be issued by a trusted root certificate authority in the server store
Adds custom validators for username/password credentials and client certificate
//// Registering WCF-services
var returnFaults = new ServiceDebugBehavior {IncludeExceptionDetailInFaults = true};
var metaData = new ServiceMetadataBehavior {HttpsGetEnabled = true};
var serviceCredentials = new ServiceCredentials();
// Configure service sertificate
serviceCredentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"ServerCertificate");
// Configure client certificate authentication mode
serviceCredentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.ChainTrust;
// Add custom username-password validator
serviceCredentials.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
serviceCredentials.UserNameAuthentication.CustomUserNamePasswordValidator =
_container.Resolve<MyServicesUsernameValidator>();
// Add custom certificate validator
serviceCredentials.ClientCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.Custom;
serviceCredentials.ClientCertificate.Authentication.CustomCertificateValidator =
_container.Resolve<MyServicesCertificateValidator>();
var serviceModel = new DefaultServiceModel();
serviceModel.AddEndpoints(
WcfEndpoint.ForContract<IMyContract>().BoundTo(CreateMultiFactorAuthenticationBinding()));
serviceModel.BaseAddresses.Add(new Uri("https://server.com/MyServiceImplementation.svc"));
serviceModel.AddExtensions(serviceCredentials);
serviceModel.AddExtensions(metaData);
_container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero)
.Register(Component.For<IMyContract>()
.ImplementedBy<MyServiceImplementation>()
.AsWcfService(serviceModel),
Component.For<IServiceBehavior>().Instance(returnFaults));
MyServicesUsernameValidator inherits UserNamePasswordValidator and MyServicesCertificateValidator inherits X509CertificateValidator. Both overrides their corresponding Validate methods.
This seems to solve my particular problem... Hope it solves yours! :)
That is not possible to define in configuration with out of the box bindings. Even custom binding doesn't support enough infrastructure to define such binding in configuration.
First you will definitely need two endpoints for this. One will be used for clients with user name / password only. This endpoint can be configured with some common binding expecting either Message security with UserName client credentials or transport security with message credentials. The second endpoint will be for your more complex validation. This endpoint needs new binding defined in code. This binding must use:
Asymetric security binding element (mutual certificate authentication)
X.509 security token as primary security token
User name security token as supporting security token
This is example of the binding I had to use when communicating with similar service:
Custom binding = new CustomBinding();
var userNameToken = new UserNameSecurityTokenParameters();
userNameToken.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
var securityElement = new AsymmetricSecurityBindingElement();
securityElement.IncludeTimestamp = true;
securityElement.RecipientTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.Never);
securityElement.InitiatorTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.AlwaysToRecipient);
securityElement.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
securityElement.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
securityElement.SetKeyDerivation(false);
securityElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(userNameToken);
securityElement.MessageProtectionOrder = MessageProtectionOrder.EncryptBeforeSign;
securityElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
binding.Elements.Add(securityElement);
var encodingElement = new TextMessageEncodingBindingElement();
encodingElement.MessageVersion = MessageVersion.Soap12WSAddressingAugust2004;
binding.Elements.Add(encodingElement);
var httpElement = new HttpTransportBindingElement();
httpElement.UseDefaultWebProxy = true;
binding.Elements.Add(httpElement);
This example uses CustomBinding defined in code. If you want to use this in configuration you must create whole new binding and binding extension and register that extension in configuration file.
Even then I'm not sure that both validators will be used - I used this as the client of the service. The main point is that request can have only single main token and it is possible that default WCF infrastructure will choose only one to validate but such logic can be also replaced.