AD FS 2.0 in Identity Solutions
Using Active Directory Federation Services 2.0 in Identity Solutions
As a developer, you probably know something about Windows Identity Foundation (WIF), formerly called “Geneva Framework,” which provides a powerful API to claims-enable your applications and to create custom security token services. Perhaps less familiar to you is Active Directory Federation Services version 2.0 (AD FS 2.0), originally code named “Geneva server,” which is an enterprise-ready federation and single-sign-on (SSO) solution. AD FS 2.0 is an evolution of AD FS 1.0, and it supports both active (WS-Trust) and passive (WS-Federation and SAML 2.0) scenarios.
In this article, I start with an overview of AD FS 2.0 and then provide insight into how developers can use AD FS 2.0 in their identity solutions. The focus is on the token issuance functionality of AD FS 2.0, based on the Beta 2 release. As you can see from Figure 1, this token issuance is only one small piece of AD FS 2.0, but it is one of particular interest to .NET developers moving toward federated identity. Architecturally, AD FS 2.0 is built on top of WIF and Windows Communication Foundation (WCF), so if you’re familiar with these technologies, you should feel right at home with AD FS 2.0.
Figure 1 Architecture of AD FS 2.0
Overview of AD FS 2.0
At a high level, AD FS 2.0 is a collection of the services shown in Figure 2.
At the core of AD FS 2.0 is a security token service (STS) that uses Active Directory as its identity store and Lightweight Directory Access Protocol (LDAP), SQL or a custom store as an attribute store. The STS in AD FS 2.0 can issue security tokens to the caller using various protocols, including WS-Trust, WS-Federation and Security Assertion Markup Language (SAML) 2.0. The AD FS 2.0 STS also supports both SAML 1.1 and SAML 2.0 token formats.
AD FS 2.0 is designed with a clean separation between wire protocols and the internal token issuance mechanism. Different wire protocols are transformed into a standardized object model at the entrance of the system while internally AD FS 2.0 uses the same object model for every protocol. This separation enables AD FS 2.0 to offer a clean extensibility model, independent of the intricacies of different wire protocols. Further details of AD FS 2.0 extensibility will be provided in the AD FS 2.0 SDK prior to RTM.
Figure 2 Components of AD FS 2.0
AD FS 2.0 as an Identity Provider
You can use AD FS 2.0 in several common scenarios. The simplest and most common scenario is to use AD FS 2.0 as an identity provider so that it can issue SAML tokens for the identities it manages. For that, a new relying party needs to be created. A relying party in AD FS 2.0 is a representation of an application (a Web site or a Web service) and contains all the security-related information, such as encryption certificate, claims transformation rules and so on.
Setting Up a Relying Party
Setting up a new relying party via AD FS 2.0 is easy. You can access the Add Relying Party Wizard through the Policy node of the AD FS 2.0 Management console. Once there, you or your system administrator needs to specify the appropriate data sources in the Select Data Source page of the wizard, which is shown in Figure 3.
Figure 3 Select Data Source Page of Add Relying Part Wizard
The first two options enable you to automatically configure the relying party using federation metadata. If you have access to the relying party’s federation metadata on a network or in a local file, select one of these two options because they are less prone to error, they automate the entire process and they auto-update if any details of the relying party change in the future. These options are a major improvement over AD FS 1.0, which doesn’t offer such automated processes.
The third option requires you to enter all the configuration details manually. Use this option only when you don’t have access to federation metadata or you want to control the details of the relying party configuration.
It’s instructive to run through the “Enter relying party configuration manually” option just so you can see all the steps that are required to set up a new relying party. In the next few pages of the wizard, you’ll be asked to choose a profile—choose AD FS 2.0 Profile if you want to support both browser-based and WCF-based clients or AD FS 1.x Profile if you only need AD FS 1.x interoperability and don’t support active (WCF, CardSpace) clients; configure the certificate that is used to encrypt the token so that only the relying party with the corresponding private key can decrypt and use the issued token; and configure the identifier that will be used to identify this relying party in all token issuance requests.
Once you finish the Add Relying Party Wizard, a Rules Editor tool opens. In this tool, you configure claims issuance and transformation rules. Figure 4 shows the Rules Editor tool configured to issue a token with a single claim whose value will be retrieved from the main attribute store. Notice that the displayName attribute is mapped to the Given Name claim. AD FS 2.0 introduces a new, textual domain-specific language that enables you to define simple rules for deriving the claims issuance and transformation process. Each rule consists of a condition and an action and ends—as in [c] => a;—with a semicolon. The transformation logic is a series of rules that execute sequentially during the token issuance process. In Figure 4, the Simple View tab provides a user interface to define these rules. The Advanced View tab lets you author rules directly using the domain-specific language.
Figure 4 Rules Editor Tool
This example has illustrated how easy it is to configure a trusted relying party in AD FS 2.0. At this point, when AD FS 2.0 receives a token issuance request, it extracts an identifier from the wire protocol (for example, the appliesTo element in the case of WS-Trust) and uses it to look up a target relying party. Once a relying party is found, the settings specified in the wizard are used to derive the token issuance logic.
Now let’s look at how you can use WCF to request a token for this relying party from AD FS 2.0.
Requesting a Token Using WCF
There are two options for interacting with AD FS 2.0 STS using WCF:
- Explicitly acquire a token acting as a WS-Trust client
- Configure a WCF client so that the infrastructure implicitly acquires a token as part of the call
In the explicit option, the WSTrustClient class provides a simple and direct API to request tokens from an STS using the WS-Trust protocol, as shown here.
string baseUri = "https://bccoss.com/"; WindowsWSTrustBinding binding = new WindowsWSTrustBinding(SecurityMode.Transport); WSTrustClient tokenClient = new WSTrustClient(binding, new EndpointAddress(baseUri + "Trust/2005/WindowsTransport/"), TrustVersion.WSTrustFeb2005, new ClientCredentials()); //create a token issuance issuance RequestSecurityToken rst = new RequestSecurityToken(WSTrustFeb2005Constants.RequestTypes.Issue); //Relying Party’s identifier rst.AppliesTo = new EndpointAddress("http://local.zamd.net/"); //call ADFS STS SecurityToken token = tokenClient.Issue(rst);
This code requests a token using Windows Authentication with transport security. As you can see, in explicit mode, you get access to the raw token, which you can use to call services later on. For example, in a smart client application, you might acquire tokens for different services at application startup or login time, save them in a token cache and then use them throughout the lifetime of the application to call different back-end services. Also, in a scenario where many services live in the same logical security boundary, sharing the same certificate, you can use the explicit mode to acquire a single token and then use it when calling all those services.
In a test environment, in which you usually have access to the relying party’s private key, you can use the following code to extract a SAML assertion from the returned token.
//Private Key certificate of RP (local.zamd.net) X509Certificate2 rpCertificate = new X509Certificate2("zamd.net.pfx", "pwd"); string assertion = Util.ExtractSAMLAssertion(token, rpCertificate); <saml:Attribute AttributeName="givenname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"> <saml:AttributeValue>Zulfiqar Ahmed</saml:AttributeValue> </saml:Attribute>
The SAML token contains only the claims configured for this particular relying party. Refer back to Figure 4, which shows how this relying party’s output token was configured to return a single attribute. You can edit the relying party’s configuration to include more claims in the output, and you should see all of them reflected here. You can also use claims policy language directly to define rich transformation and filtering logic.
Both the WSTrustClient API and the new WSTrust bindings are part of WIF, so for the preceding code to work, WIF must be installed on the client. You can also use the WCF API directly to explicitly acquire a token, but the simplicity and ease of use WIF offers can take one task off your to-do list.
In the code in Figure 5, IssuedSecurityTokenProvider is the WCF equivalent of WSTrustClient and is normally used by wsFederationBinding when requesting tokens on your behalf. Because it’s a public API, you are free to use it in your code should you need access to a raw token. The CustomBinding is equivalent to WindowsWSTrustBinding.
Figure 5 Using IssuedSecurityTokenProvider to Access a Raw Token
sstring baseUri = "https://bccoss.com/"; //Limited edition of WSTrustClient:) IssuedSecurityTokenProvider provider = new IssuedSecurityTokenProvider(); provider.SecurityTokenSerializer = new WSSecurityTokenSerializer(); //Relying Party's identifier provider.TargetAddress = new EndpointAddress(new Uri("http://local.zamd.net")); provider.IssuerAddress = new EndpointAddress(new Uri(baseUri + "Trust/2005/WindowsTransport/")); provider.SecurityAlgorithmSuite = SecurityAlgorithmSuite.Basic256; provider.MessageSecurityVersion = MessageSecurityVersion. WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10; HttpsTransportBindingElement tbe = new HttpsTransportBindingElement(); tbe.AuthenticationScheme = AuthenticationSchemes.Negotiate; CustomBinding stsBinding = new CustomBinding(tbe); provider.IssuerBinding = stsBinding; provider.Open(); //Request a token from ADFS STS SecurityToken issuedToken = provider.GetToken(TimeSpan.FromSeconds(30));
In the implicit option, you can use the standard wsFederationHttpBinding, in which case the WCF infrastructure transparently acquires the token and sends it to the service as part of the call. Whenever you create a new WCF proxy and use it to call a service, the infrastructure fetches a new token for you. Obviously, this would be overkill in some scenarios. The code in Figure 6 configures a fictional EmployeeService to require tokens from AD FS 2.0.
Figure 6 Using wsFederationHttpBinding to Acquire a Token Implicitly
<system.serviceModel> <services> <service name="EmployeeService.EmployeeService"> <endpoint address="http://localhost:9990/ES" binding="ws2007FederationHttpBinding" contract="EmployeeServiceContract.IEmployeeService" bindingConfiguration="adfsFed"/> </service> </services> <bindings> <ws2007FederationHttpBinding> <binding name="adfsFed"> <security mode="Message"> <message negotiateServiceCredential="false" > <issuer address="https://bccoss.com/Trust13/KerberosMixed" binding="customBinding" bindingConfiguration="MixedKerberos"/> </message> </security> </binding> </ws2007FederationHttpBinding> <customBinding> <binding name="MixedKerberos"> <security authenticationMode="KerberosOverTransport"/> <httpsTransport/> </binding> </customBinding> </bindings> </system.serviceModel>
Mapping AD FS 2.0 Concepts to WCF
The core responsibility of AD FS 2.0 is to issue tokens to authenticated users. Users can be authenticated using different authentication mechanisms (such as Windows Authentication). You can see all the supported authentication mechanisms by selecting the Endpoints node in the management console.
You’ll notice two familiar WCF security concepts as column headings within the Endpoints node:
- Authentication Type is the AD FS 2.0 equivalent of the WCF clientCredentialType terminology.
- Security Mode choices are Transport, Message or Mixed. Mixed is the AD FS 2.0 equivalent of WCF’s TransportWithMessageCredentials.
Different combinations of these two values are exposed using different endpoints, and you choose a specific endpoint based on your authentication needs. For example, if you need to authenticate using Username/Password, you would choose the Clear Password authentication endpoint.
For AD FS 2.0 STS, mapping these concepts back to Address, Binding and Contract (ABC) in WCF, you get the following equivalents:
- Address = AD FS 2.0 base address + the endpoint’s URL Path
- Binding = Endpoint’s Security Mode + Authentication Type
- Contract = Standard WS-Trust protocol
Federating AD FS 2.0 with Another STS
In addition to creating relying parties, you can establish a trust relationship between AD FS 2.0 and your custom STS or another AD FS 2.0. For example, if you already have an STS that authenticates users and issues tokens, you can simply add it as a trusted identity provider inside AD FS 2.0, which will accept tokens issued from the STS.
Setting Up an Identity Provider
Setting up a new, trusted identity provider in AD FS 2.0 is similar to setting up a new relying party. The Add Identity Provider wizard you use looks and acts a lot like the Add Relying Party Wizard (refer back to Figure 3).
To get to the Configure Identifier page, select the manual configuration option again (as you did in Figure 3) and select AD FS 2.0 Profile on the Choose Profile page. Leave the default settings on the Configure URL page. You then choose an identifier and a public key certificate for your identity provider and finish the wizard to register the new identity provider.
Requesting a Token Using WCF
Once you register an additional identity provider with AD FS 2.0, the logical architecture looks like the configuration shown in Figure 7.
Figure 7 Architecture of AD FS 2.0 with an Additional Identity Provider
The code in Figure 8 lets you acquire a token explicitly, giving you the flexibility to cache the token locally and send it to the service as needed.
Figure 8 Using IssuedTokenWSTrustBinding to Acquire a Token Explicitly
string adfsStsUri = "http://bccoss.com/Trust/2005/IssuedTokenAsymmetricBasic256"; //binding for local STS(IP-STS) WSHttpBinding localStsBinding = new WSHttpBinding(SecurityMode.Message); localStsBinding.Security.Message.ClientCredentialType = MessageCredentialType.None; localStsBinding.Security.Message.EstablishSecurityContext = false; localStsBinding.Security.Message.NegotiateServiceCredential = false; EndpointAddress localStsEpr = new EndpointAddress( new Uri("http://localhost:9000/STS/"), new X509CertificateEndpointIdentity(new X509Certificate2(@"MyCustomSTSPublicKey.cer"))); //This binding will transparently acquire all the intermediate tokens as part of the call. (R-STS) IssuedTokenWSTrustBinding fedBinding = new IssuedTokenWSTrustBinding(localStsBinding, localStsEpr); fedBinding.TrustVersion = TrustVersion.WSTrustFeb2005; EndpointAddress adfsStsEpr = new EndpointAddress( new Uri(adfsStsUri), new X509CertificateEndpointIdentity(new X509Certificate2("AdfsStsPubicKeyOnly.cer"))); WSTrustClient trustClient = new WSTrustClient(fedBinding, adfsStsEpr, TrustVersion.WSTrustFeb2005, null); //Create a security token request RequestSecurityToken rst = new RequestSecurityToken(RequestTypeConstants.Issue); //Set Relying Party's identifier accordingly rst.AppliesTo = new EndpointAddress("http://local.zamd.net"); SecurityToken finalToken = trustClient.Issue(rst);
IssuedTokenWSTrustBinding is very similar to wsFederationHttpBinding in that it hides all the complexity of intermediate tokens by transparently talking to the IP-STS to acquire an intermediate token that is then sent to R-STS as an authentication token.
The code in Figure 9 uses wsFederationHttpBinding to enable a WCF client to implicitly acquire a token as part of a service call.
Notice that I’m using a customBinding when talking to the /IssuedTokenMixedSymmetricBasic256 endpoint. The standard wsFederationHttpBinding doesn’t work here because it tries to establish a secure session, which is incompatible with this AD FS 2.0 endpoint. To federate WCF clients with AD FS 2.0, you have to use either a customBinding or one of the new WS-Trust-based bindings that ships with WIF.
Figure 9 Using wsFederationHttpBinding to Acquire a Token Implicitly
<system.serivceModel> <bindings> <wsFederationHttpBinding> <binding name="R-STS"> <security mode="Message"> <message> <issuer address="https://bccoss.com/Trust/2005/IssuedTokenMixedSymmetricBasic256" binding="customBinding" bindingConfiguration="IP-STS"/> </message> </security> </binding> </wsFederationHttpBinding> <customBinding> <binding name="IP-STS"> <security authenticationMode="IssuedTokenOverTransport"> <issuedTokenParameters> <issuer address="http://localhost:9000/CustomSTS" binding="wsHttpBinding"/> </issuedTokenParameters> </security> <httpsTransport/> </binding> </customBinding> </bindings> <client> <endpoint address="http://localhost:9990/ES" binding="wsFederationHttpBinding" bindingConfiguration="R-STS" contract="ServiceReference1.IEmployeeService" name="WSFederationHttpBinding_IEmployeeService"/> </client> </system.serviceModel>
AD FS 2.0 and Browser Clients
AD FS 2.0 has first-class support for Web single sign-on (WebSSO) and federation using both WS-Federation and SAML 2.0 protocols.
Conceptually, WS-Federation and the SAML protocol are similar even though they have different wire representations. The WS-Federation wire format is closely related to WS-Trust protocol, so it is the logical choice when you’re serving both active and passive (browser-based) clients. The SAML protocol has better interoperability across different vendors. AD FS 2.0 natively supports both of these protocols. It’s a good idea to stick to a single protocol (for example, WS-Federation) inside your security boundary and use AD FS 2.0 as a protocol broker hub for incoming or outgoing SSOs.
Let’s consider an example. Say that you have a simple ASP.NET application that provides functionality only to authenticated users. As a stand-alone application, authentication logic is implemented as part of the application, and an interaction with this application would follow the steps shown in Figure 10.
Figure 10 Direct Authentication in a Simple ASP.NET Application
Here the usual ASP.NET authentication mechanisms, such as Forms Authentication, are being implemented. Our goal is to extract the authentication functionality from this application and use AD FS 2.0 instead.
In the AD FS 2.0 setup, which is shown in Figure 11, the application becomes a trusted relying party inside AD FS 2.0 and therefore trusts tokens issued by AD FS 2.0. The application uses WIF to do all the heavy lifting of token parsing, extracting claims and so on. Identity information is provided to the application using the standard IIdentity/IPrincipal abstractions.
The distributed authentication in AD FS 2.0 is much more flexible than direct authentication, and it provides some major benefits:
- Authentication is externalized from the application, so the authentication mechanism can be changed (for example, from username to Kerberos) without affecting the application.
- The flexibility of a claims-based model can provide all the required information to the application (as part of the token) directly rather than the application itself retrieving that information from different sources.
The Beta 2 release of WIF introduced new project templates that make it easy to externalize an application’s authentication logic to an STS. As of this writing, these templates are available only in C#.
Figure 11 Distributed Authentication in AD FS 2.0
Externalizing Authentication Logic
To externalize an application’s authentication logic, you use the Microsoft Visual Studio dialog box New Web Site. Select the Claims-aware Web Site template to create a standard ASP.NET Web site that is preconfigured with WIF.
To launch the Federation Utility wizard, shown in Figure 12, right-click the Web Site node in Solution Explorer and select Modify STS Reference from the menu.
Figure 12 Federation Utility
For this example, let's choose the “Use an existing STS” option and specify AD FS 2.0 as the STS. The wizard requires the URL of the metadata document to automate all the required configurations. The metadata document URL is available as an endpoint inside AD FS 2.0.
Federation metadata contains essential information such as the STS signing certificate, the claims offered and the token issuance URL. Having a standardized format for this information enables tools to automate the establishment of trusts between an STS and relying parties.
The Summary page of the wizard summarizes the changes that are going to be made in the web.config file.
The Federation Utility wizard configures WIF on your Web site to provide the following functionality:
- All unauthenticated requests will be redirected to AD FS 2.0.
- Any request containing a valid token will be processed, and identity information will be presented to the application in the form of ClaimsIdentity/ClaimsPrincipal. The Application will continue to access identity information using the standard IPrincipal/IIdentity abstractions regardless of the source of that information.
Before testing the application, you need to make one last configuration change on AD FS 2.0. You must add an additional endpoint to the relying party for browser clients. This endpoint is required because once AD FS 2.0 has processed a token issuance request, two pieces of information are required before it can send the token back to the browser:
- The address where the token should be sent
- The protocol (SAML or WS-Federation) over which the token should be sent
You can add a passive endpoint to the relying party in the Endpoints tab of the Test RP Properties dialog box. For example, if you select WS-Federation as the Endpoint Type, AD FS 2.0 will send tokens back to the relying party using the WS-Federation protocol. Inside the relying party, the WIF, which natively understands WS-Federation protocol, processes these tokens.
Now when you try to browse to the application, you are automatically redirected to AD FS 2.0 for authentication, where you can choose the authentication method you want to use: Windows Integrated Authentication, Certificate Authentication or Username/Password Form.
Once authentication is successful, you—along with a token issued by AD FS 2.0—are redirected back to the application. WIF processes this token and makes the final identity (in the form of claims) available to the application using the standard ASP.NET mechanisms (for example, Page.User).
You can extend a basic external authentication scenario into a federation scenario by adding an additional trusted identity provider. The identity provider options are shown during the authentication process.
You can authenticate with AD FS 2.0 or another trusted identity provider. If you select a different identity provider, you are redirected to that identity provider and, upon successful authentication, redirected back to AD FS 2.0, which would then authenticate you based on the token issued by the trusted identity provider.
As you’ve seen in this article, AD FS 2.0 STS provides a simply and ready-made solution to claims-enable your WCF services and browser-based applications. STS itself is only one small piece of AD FS 2.0, which also includes a CardSpace provisioning system, a rule-based claims transformation engine, automatic trust management infrastructure, management and configuration services and their respective tools. Along with WIF, AD FS 2.0 creates a powerful combination to program identity solutions on the Windows platform.
Zulfiqar Ahmed is a Senior Consultant on the UK Application Development Consulting (ADC) team and can be reached at http://zamd.net.