Getting a token from ADFS (ex Geneva Server) using WCF
July 17th, 2009
I’ve been doing some tests to get a token from ADFS (Geneva Server) using Windows Identity Foundation WSTrustClient. In this case we are using the UserNameMixed endpoint that expects a WS-Security UsernameToken (notice the MessageCredentialType.UserName).
internal static ClaimsIdentityCollection RequestTokenWithUsernameMixed()
{
var binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
var credentials = new ClientCredentials();
credentials.UserName.UserName = "Mary";
credentials.UserName.Password = "Passw0rd!";
var endpoint = "https://mygenevaserver/Trust/13/UsernameMixed";
var client = new WSTrustClient(binding, new EndpointAddress(new Uri(endpoint)), TrustVersion.WSTrust13, credentials);
var request = new RequestSecurityToken();
request.RequestType = "http://schemas.microsoft.com/idfx/requesttype/issue";
request.AppliesTo = new EndpointAddress("http://localhost/activerp");
var token = client.Issue(request) as GenericXmlSecurityToken;
var claims = token.ToClaimsIdentityCollection(TrustVersion.WSTrust13, CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=Geneva Signing Certificate - WIN-66EYOLL2BVY"), CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=WMSvc-WIN-66EYOLL2BVY"));
return claims;
}
Here is another one using the WindowsMixed endpoint (notice the MessageCredentialType.Windows and no username and password set)
internal static ClaimsIdentityCollection RequestTokenWithWindowsMixed()
{
var binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Message.EstablishSecurityContext = false;
var credentials = new ClientCredentials();
var endpoint = "https://mygenevaser/Trust/13/WindowsMixed";
var client = new WSTrustClient(binding, new EndpointAddress(new Uri(endpoint)), TrustVersion.WSTrust13, credentials);
var request = new RequestSecurityToken();
request.RequestType = "http://schemas.microsoft.com/idfx/requesttype/issue";
request.AppliesTo = new EndpointAddress("http://localhost/activerp");
var token = client.Issue(request) as GenericXmlSecurityToken;
var claims = token.ToClaimsIdentityCollection(TrustVersion.WSTrust13, CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=Geneva Signing Certificate - WIN-66EYOLL2BVY"), CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=WMSvc-WIN-66EYOLL2BVY"));
return claims;
}
You can use this together with the CreateChannelWithIssuedToken extension method (as shown in a previous post).
IssueTracker Azure Edition - a Cloud Application
February 13th, 2009
Couple of weeks ago Ryan Dunn announced Azure Issue Tracker. From this post:
"This sample application is a simple issue tracking service and website that pulls together a couple of the Azure services: SQL Data Services and .NET Access Control Service."![]()
I’ve been working with Ryan and other guys at DPE and Southworks to put together this sample before PDC. With all the back and forth (the .NET services were not working as reliable as they work now) we were not able to pull it through at that time. Well, it’s now live and you can download the source code. Some of its features:
- [Identity] .NET Services Access Control as a relying party and claims transformation STS
- [Identity] Federation against LiveID and claim mapping between email -> tasks. I hinted the implementation in these post.
- [Identity] Claims aware application and service layer (by doing identity delegation with ActAs)
- [Data] Storage on SDS using the flexible schema to extend the data model of the issue
- [General] Multi tenancy at all levels (identity, data, programming model)
- [General] Clean separation of concerns using ASP.NET MVC, Geneva Framework, WCF and WF.
This is the standard edition. The enterprise edition is coming with features related to manageability (Management API, Powershell CmdLets, MMC, SCOM, etc.) and identity federations against third party STS. Stay tuned!
Managing the lifecycle of security tokens (Geneva, STS, WCF…)
December 14th, 2008
Calling your STS to obtain a token
private SecurityToken GetIdentityProviderToken() { var client = new WSTrustClient( this.identityProviderActiveStsBinding, this.identityProviderActiveStsUrl, System.ServiceModel.Security.TrustVersion.WSTrustFeb2005, new System.ServiceModel.Description.ClientCredentials()); client.ClientCredentials.ServiceCertificate.DefaultCertificate = this.identityProviderStsCertificate; var request = new RequestSecurityToken(RequestTypeConstants.Issue); request.AppliesTo = this.identityProviderAppliesToUrl; var identityToken = client.Issue(request); client.Close(); return identityToken; }
Overriding the ClientBase to inject the security token with Geneva
Once you have the token you want to inject that token into your client proxy. The code below shows a nice and clean way to inject the SAML token into the WCF channel. Notice the ctor takes a dependency on a custom interface ISecurityTokenProvider. This is a very simple interface I created with a single method GetSecurityToken. On channel construction we are going to pass the proxy through Geneva CreateChannelWithIssuedToken method. This will change the ClientCredentials of the channel to use the FederatedClientCredentials that will shortcircuit the IssuedSecurityTokenProvider of the binding by returning the "external" security token.
public class FederatedCatalogServiceClient : ClientBase<ICatalogService>, ICatalogService { private ISecurityTokenProvider tokenProvider; public FederatedCatalogServiceClient(ISecurityTokenProvider tokenProvider, …) { this.tokenProvider = tokenProvider; } // operations … protected override ICatalogService CreateChannel() { ICatalogService channel; lock (this.ChannelFactory) { FederatedClientCredentials.ConfigureChannelFactory(this.ChannelFactory); channel = ChannelFactoryOperations.CreateChannelWithIssuedToken( this.ChannelFactory, this.tokenProvider.GetSecurityToken()); } return channel; } }
Custom Binding to call a service that requires a token
Finally, since we don’t want to use WSFederationBinding anymore because it will grab the token for us, the code below will create a binding "similar" to the federation binding but won’t never call our STS. We still have to provide some configuration settings like the urls so the binding can be constructed, but they won’t be used on runtime.
public Binding CreateBinding() { var finalBinding = new CustomBinding(); var bindingProtection = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.Thumbprint); bindingProtection.ReferenceStyle = SecurityTokenReferenceStyle.Internal; bindingProtection.InclusionMode = SecurityTokenInclusionMode.Never; bindingProtection.X509ReferenceStyle = X509KeyIdentifierClauseType.Thumbprint; var security = new SymmetricSecurityBindingElement(bindingProtection); security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10; security.RequireSignatureConfirmation = true; var issuerBinding = new CustomBinding(); issuerBinding.Elements.Add(new TransactionFlowBindingElement()); var protection = new SecureConversationSecurityTokenParameters(); var issuerSecurity = new SymmetricSecurityBindingElement(protection); issuerSecurity.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10; issuerBinding.Elements.Add(issuerSecurity); security.EndpointSupportingTokenParameters.Endorsing.Add( new IssuedSecurityTokenParameters( "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1", new EndpointAddress("http://notused"), issuerBinding) { IssuerMetadataAddress = new EndpointAddress("http://notused/mex") }); security.ProtectionTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.Thumbprint, SecurityTokenInclusionMode.Never); var protectionSecurityProtectionParameters = new SspiSecurityTokenParameters(); protectionSecurityProtectionParameters.RequireCancellation = true; security.ProtectionTokenParameters.InclusionMode = SecurityTokenInclusionMode.Never; var protectionSecurity = new SymmetricSecurityBindingElement(protectionSecurityProtectionParameters); protectionSecurity.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10; protection.BootstrapSecurityBindingElement = protectionSecurity; finalBinding.Elements.Add(security); issuerBinding.Elements.Add(new TextMessageEncodingBindingElement()); issuerBinding.Elements.Add(new HttpTransportBindingElement()); finalBinding.Elements.Add(new TextMessageEncodingBindingElement()); finalBinding.Elements.Add(new HttpTransportBindingElement()); return finalBinding; }
Happy Federation!