Table of Contents
First things First
If you are looking for an article that shows a lot of code and dissects the new WIF 4.5 APIs, then you won’t find what you need here.
My aim in this article is to explain the “why” and the “what” rather than the “how”. Once you understand that, the “how” becomes really simple. This article does not assume pre-knowledge of the topics of federation, claims, and WIF so it’s suited for beginners. However, I think that mid-level knowledge audience will also benefit from it. If you’re like super-expert, well please contact me to help me in my current project.
What Exactly
is the Problem?
Authentication (and authorization) is an ever present challenge for most applications. The challenge that these applications face is the same: authentication logic creeps into the application code and becomes coupled with it; any change to the authentication requirements will result in a change in the application itself.
Say for example that your user store is SQL Server and new business mandates adding an existing Oracle-based user store to your list of users, or maybe you want to mix your authentication to support both custom user stores (SQL Server or Oracle) with Active Directory user store. And what about social media? It’s increasingly popular nowadays for applications to allow authentication via services such as Google and Facebook.
Here is another tough case: assume you used to ask you users for username/password combination to log in. Now based on certain needs, you want them also to supply additional information such as a one-time code. This will certainly lead to UI change for your login page as well as code change.
In all these cases, something has to change in your code. Of course, having a good architecture with a proper separation of concerns will ease up the change. However, the idea is that you still have to manage this authentication logic instead of focusing on the business side of your application.
Claims-based authentication is the architecture that solves this problem.
Claims-based Authentication
Claims-Based architecture allows you to delegate authentication logic into another entity. This entity is a “some” layer which abstracts all authentication related coding and gives your application what it needs: is the user authenticated or not, and some information about the user (called claims or assertions) that lets your application take authorization decisions.
The claims-based architecture defines the following actors:
- Subject: the entity that needs to be authentication. This can be a user that wants to log in to your application, or a piece of code in your application that wants to access a web service.
- Relying Party (RP): the application (in case the Subject is a user) or the web service (in case the Subject is application code) that needs to delegate the authentication logic
- Identity Provider (IP): the entity (that “some” layer mentioned before) that actually holds the authentication logic. The IP talks to the user stores as appropriate and performs actual authentication.
- Claim: When an IP performs successful authentication, it returns to the RP a set of claims. Claims are statements about the authenticated entity – for example birth date, department, role, etc… – that gives the RP information to take authorization decisions.
- Token: Claims travel inside a token. Although a token can be a username/password combination or even a simple string such as bearer token in OAuth 2.0; in this context tokens can be either XML-based such as SAML tokens or binary-based such as X.509 certificates.
In addition to the above definitions, WS-Federation and WS-Trust protocols define another term called Secure Token Service (STS). STS is the web service exposed by the IP that provides the authentication service.
Before the claims-based flow can start, the RP and IP need to publish their policies. In abstract terms, a policy is a contract published by an entity that specifies the terms and conditions that other entities must obey before establishing communication.
In this context, the policy published by the IP specifies the supported protocol(s) and security requirements as well as supported claim types. Similarly, the policy published by the RP specifies its own protocol, security, and claims requirements as well as the list of IPs it trusts to delegate authentication to.
The rest of the article discusses WS-Federation (and related WS-standards) and its implementation in WIF, while I will also briefly discuss SAML 2.0.
The WS-* Mania
For some, the WS-* standards are something to avoid. They tend to strike developers as being overly complex. Indeed complex they are. However, with the advent and continuous enhancement of developer libraries, most of the times working with WS-* standards is nothing more than configuration tweaking. Granted however, you always need to understand what is going behind the scenes if you really want to understand the architecture.
This section discusses – briefly – some core WS-* standards that are related to WS-Federation.
WS-Security
WS-Security is a SOAP extension that adds authentication/authorization, message protection, and message integrity to SOAP messages.
- Authentication/authorization: authentication is implemented using security tokens while claims carried inside a security token aid in authorization. Although can be extended, the three types of tokens you’d usually see are Username, Binary, and XML-based tokens.
- Username tokens: these are the plain-old username/password combinations sent in the SOAP header. Verification of identity can be achieved by hashing the password or applying a digital signature.
- Binary tokens: these usually come in two flavors: X.509 certificates and Kerberos tickets.
- X.509 certificates: an X.509 certificate is the public key container of a public/private key pair. Obviously since it contains a public key it cannot be relied upon for authentication by itself. The certificate is signed with the private key portion of the sender. The receiver uses the public key to verify the signature. Since the private key is unique for the sender, signature verification proves identity
- Kerberos tickets: if a Kerberos infrastructure is already in place, WS-Security recognizes Kerberos tickets as a valid security token type
- XML-based tokens: XML tokens were published as an ad-on specification to WS-Security. XML tokens contain a set of claims about the sender. Similar to X.509 certificate tokens, XML tokens must be accompanied by a signature generated by the sender so that the receiver can verify its identity. Probably the most dominant form of XML tokens is SAML token.
- Message protection: Whereas at transport level message protection is established using SSL, at message level this is done via XML Signatures. Depending on the configuration, WS-Security uses either a symmetric shared key or an asymmetric public/private key pair to encrypt the required message content. In the symmetric approach the shared key must be exchanged securely prior to communication. In the asymmetric approach the sender encrypts the (required) message content using the receiver’s public key and the receiver decrypts it using its private key. Most of the time though, the approach used is a combination of both due to the fact of asymmetric approach being compute-expensive. In this hybrid approach, asymmetric encryption is used to exchange a shared key and then this shared key is used for encryption for the rest of the session communication.
- Message Integrity: as discussed in the authentication section, XML signatures are used to establish user identity. It is also used to establish message integrity; i.e. that the message has not been tampered with. By attaching a signature with a message, the receiver recalculates the signature and verifies integrity if both signatures match. Similar to encryption, a hybrid approach is usually used to reduce the cost of asymmetric-based signatures.
WS-Policy
WSDL does a good job describing basic web service requirements such as message schemas and authentication headers. However, WSDL cannot describe contractual requirements such as security. For example, recall form the previous section of Claims-based architecture, that an RP-IP interaction is governed by a set of security policies. These policies cannot be described using WSDL; instead they are described by WS-Policy and its related specification WS-SecurityPolicy.
In general, there are WS-Policy assertions for security, reliable messaging, sessions, transactions, reliable messaging, among others. In WCF, these policies are specified either as code attributes or configuration sections.
- WS-Policy: a specification that defines a framework for describing policy assertions. An assertion is a requirement or preference of the service. This specification defines a common language regardless of the assertion domain (security, transactions, reliable messaging, etc…).
- WS-PolicyAssertion: a specification that defines general messaging-related assertions for use with WS-Policy. Separate assertions exist for different domains; for example, WS-SecurityPolicy, WS-AtomicTransactions, and WS-ReliableMessaging.
- WS-PolicyAttachment: a specification that describes how policies are attached to WSDL (and UDDI).
WS-Addressing
WS-Addressing specification provides elements that enable end-to-end transport-independent message transmission. For example this allows you to implement message routing (previously WS-Routing) where – based on some message criteria – you can explicitly specify the next hop in the message route. Also some of the other things that you can do is specify a different response or fault return URLs to a message and thus sending the response to a different endpoint than the originator.
WS-Trust
As discussed in the claims-based architecture, you can delegate your application authentication logic to another entity which issues claims that your application. The part I skipped is how to make your application “trust” these claims? What prevents a fake IP from generating a claim and sending it to your application which then will grant him access?
Let’s take this one step further: assume two companies A and B want to conduct business. Company A want company B users to access its application. How can this be done? One way is for A to provision B users; however, this clearly is a troublesome solution as A will have to manage and control B users. Wouldn’t it be a much better solution if we make A “trust” B users without actually managing them?
WS-Trust is a specification that tackles the above two scenarios. WS-Trust introduces the concept of a Secure Token Service (STS), which is a web service that is responsible of generating claims that are trusted by consumers. In the first scenario (authentication delegation), you have your application establishing a WS-Trust relationship with an STS service for an IP. In this second scenario (companies A & B), both parties establish a WS-Trust where A trusts an STS for B IP; this way B users can carry tokens issued by their IP-STS and present these tokens to A, which trusts the STS and thus grants access.
WS-Trust defines a message request called RequestSecurityToken (RST) issued to the STS. STS in turn replies via a response called RequestSecurityTokenResponse (RSTR) that holds the security token to be used to grant access. WS-Trust describes the protocol for requesting tokens via RST and issuing tokens via RSTR.
WS-SecureConversation
WS-SecureConversation specification provide a mechanism to improve a service response time when the client engages with a lengthy communication with that service.
When a client sends a message to a secure service, part of the request will be dedicated to credential negotiation and authentication. At transport level, this is accomplished in SSL handshake process so any consequent requests use the secure session already established. WS-SecureConversation achieves the same on the message level.
WS-SecureConversation specification states that the client first sends an RST (from the WS-Trust specification) to the service. The service validates the credentials within the RST and issues back a token called Secure Context Token (SCT) with a symmetric key to perform the cryptographic operations for the remaining communication.
These tokens are used by WS-Security for authentication and integrity and are described at both ends (IP & RP) using the WS-SecurityPolicy assertion.
WS-Federation
So we’re finally at the WS-Federation section! All the previous specifications discussed lead to this place.
Let’s start by defining federation: Federation refers to multiple security domains (also called realms) – typically multiple organizations in B2B scenarios – establishing trust for granting access to resources. Carrying on with the terminology we have been using, an RP in domain A can trust an STS IP in domain B so that B users can access resources of A.
WS-Federation build on WS-Trust and simplifies the creation of such federated scenarios by defining a common infrastructure for achieving federated identity for both web services (called active clients) and web browsers (called passive clients).
WS-Federation says that organizations participating in federation should publish communication and security requirements in Federation Metadata. This metadata adds federation specific communication requirements on top of the WS-Policy (and WS-SecurityPolicy) metadata described before. For example, token types and single sign out requirements are examples of what is defined in the Federation Metadata.
WS-Federation does not mandate a specific token format, although as we will see later, SAML tokens are used heavily.
Identity and Access Control in .NET 4.5
Identity and Principal pre-.NET 4.5
If you have been creating applications in .NET framework since v 1.0, chances are you have already came across interfaces
IIdentity
and IPrincipal
. IIdentity
would represent the identity of the authenticated user while
IPrincipal
contains that specific identity in addition to a method to check if the user is a member of a certain role.
Different implementations existed for IIdentity
and IPrincipal
:
-
WindowsIdentity
and WindowsPrincipal
are used for windows, active directory, or Kerberos authentication -
GenericIdentity
and GenericPrincipal
are used for custom authentication such as forms authentication
As you can see, role-based access (or authorization) up until .NET 4.0 was really restricted to the
IsInRole
method of the IPrincipal
and its implementations. There are multiple ways to call this method; you can call it directly via the API, or you can use attribute-based authorization (PrincipalPermission
), or you can use the authorization element in the
web.config. Regardless of the method, your role-based access power was limited to checking if the logged in user belong to a certain group or not.
Now if you have reached so far in this post, you will for sure have noticed that claims-based authorization gives you much bigger power. Using claims you can make access decisions based on things like a user birth date, national id, and of course roles, among others. The idea is that the system that performed authentication (the IP in our literature) attaches any attributes agreed with the RP as a set of claims (assertions); the RP then uses these claims to make suitable authorization decisions.
So are claims not supported pre-.NET 4.5? Yes they are, and here’s how:
WCF 3.0 Claim Transformation
Before Windows Identity Foundation (WIF) 1.0 was shipped, Microsoft’s first attempt to incorporate claims into their security model came under the umbrella of WCF. In WCF 3.0 Microsoft included the System.IdentityModel assembly which basically generated a set of claims for every security token authenticated by WCF. WCF 3.0 shipped with the following classes:
System.IdentityModel.Claims.DefaultClaimSet
, which represents any additional generic claims sent to the service-
System.IdentityModel.Claims.X509CertificateClaimSet
for converting X509 tokens to claims -
System.IdentityModel.Claims.WindowsClaimSet
for converting Windows tokens to claims
WCF 3.0 included authorization policies to perform the actual claim transformation.
The problem in this approach was that now .NET developers have two completely different security infrastructures for web applications (IIdentity
and IPrincipal
) and for WCF services (System.IdentityModel
). So if you have an application which consists of both web app and web service, then you’ll have to write nearly the same code twice against two different libraries.
WIF 1.0
Microsoft enhanced their claim infrastructure in In WIF 1.0. Instead of the System.IdentityModel used in WCF 3.0, they shipped a new assembly of name Microsoft.IdentityModel.
The need to support claims was achieved by adding another implementation of
IPrincipal
, called IClaimsPrincipal
which will be populated once claims-based authentication is used. As you can see, this way WIF combined both worlds: that of base classes
IIdentity
and IPrincipal
and that of WCF 3.0 claims infrastructure.
Here is how you would retrieve claims for a claims-authentication enabled application:
IClaimsIdentity identity = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
string email = (from c in identity.Claims where
c.ClaimType == System.IdentityModel.Claims.ClaimTypes.Email
select
c.Value).Single();
As you can see, we’re casting the current principal’s identity to get the
IClaimsIdentity
.
Now even with this improved approach, can you already spot the drawback? Well the issue here is that with this approach if you use
WindowsPrincipal
or
GenericPrincipal
you won’t get claims as
IClaimsPrincipal
is just another implementation of
IPrincipal
much like the other two. It’s either this or that. This makes claims support in .NET 4.0 not a first class citizen.
Identity and Principal in .NET 4.5
In .NET 4.5 claims are made available regardless of the authentication type. What Microsoft did was creating a new implementation of the base
IPrincipal
, called ClaimsPrincipal
. Then they made every other principal (WindowsPirincipal
and GenericPrincipal
) derive from ClaimsPrincipal
, and they removed the
IClaimsPrincipal
of .NET 4.0. This way, you will get claims all the way; for example even if you use forms authentication, all the attributes you pull from a membership provider will be carried in claims.
This way, role based access is unified for all authentication types and more important, it’s much richer than the simple
IsInRole
approach because you now depend on claims to take decisions.
Let’s see how you can retrieve claims for a claims-authentication enabled application and compare this to the same code you had to write pre-.NET 4.5:
string email = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
ClaimsPrincipal.Current
basically plays the same role that Thread.CurrentPrincipal
used to play.
Let’s see the new claims-based model in .NET 4.5. Below you can see the debugger of a VS 2012 web application using
WindowsIdentity
:
You will notice that the base class is of type
System.Security.Claims.ClaimIdentity
which as explained is the new base class
for the identity classes as of .NET 4.5. Also notice how although we used
windows identity, claims are populated with windows login specific information.
In .NET 4.5, you will get claims no matter what.
The below figure shows a similar result when we define a
GenericIdentity
(simulating a forms authentication for example). Again the base
class is common and a claim of type name is generated by default:
When using forms authentication, you will get the Name claim
by default. You can get additional claims by using the ASP.NET Role Manager.
Let’s briefly discuss some more concepts and capabilities of
.NET 4.5 claims model.
Supported Credential Types
As discussed before, the biggest advantage of the claim
model is that regardless of the authentication mechanism used, your application
will always rely on claims to achieve authorization. So your application logic
does not really care about the actual type of the security token that was used
for authentication; authentication logic is a separate concern with its
separate module, your application gets claims and you use these claims to take
authorization decisions.
Now this authentication layer I am talking about, can be
part of your application itself living in a separate module, or – as discussed
in the very beginning – can be a separate STS that your application trusts in
the IP/RP model. In this discussion our focus is on .NET 4.5 so authentication
will be part of the application, the next section dives into WIF 4.5 where you
will see STS in action.
So, you .NET 4.5 application can use any of the following
security tokens:
- Windows/AD/Kerberos
- Forms authentication
- Client certificates
- SAML tokens
- Other extended token types
Once the authentication layer is passed, your application
will get claims in the ClaimsPrincipal
shown before.
Claims Transformation
Before the claims actually hit your application, it can
be subjected to a transformation/validation layer. Once example of
transformation need is that you know claims will come is a certain format and
you would like to change this format to suit your application coding. An
example of validation is – say your application accepts claims from an STS –
and you want to make sure before handing the claim to your code that the
minimum set of required claims are actually present.
To implement this transformation/validation, you will
have to override a class called ClaimsAuthenticationManager
.
Authentication Sessions
The logic you wrote in the ClaimsAuthenticationManager
derived class can be run at each and every request, or you have the option to cache
its outcome if you believe its logic is expensive. The cached value can be
saved in cookies for ASP.NET applications and using WS-SecureCoversation for
WCF services.
Claims-based Authorization
Finally we are the stage of actually performing
authorization decisions based on the claims. The class ClaimsAuthorizationManager
is what you’d want to derive from to implement your authorization logic. This
class contains the method CheckAccess
which can be called whenever you want to
make an authorization decision.
This way you won’t mingle authorization logic directly
into your business logic (which typically was the approach used in the days of
the IsInRole
checking).
Once again, I want to remind you that this approach of
using claims inside your application is the same regardless if whether the
claims are generated by authentication logic as part of your application or if
the claims are given to your application by an STS that it trusts. In both
cases, you have the ability of using the ClaimsAuthorizationManager
to minimize
the coupling between your business logic and the authorization decision.
One final note: the claims-based model is the same for web
applications and WCF services. So the .NET 4.5 code to retrieve, transform, and
authorize claims works the same regardless of whether the consumer is a .NET
4.5 web app or WCF service.
Windows Identity Foundation (WIF) in .NET 4.5
In the previous section I discussed the claims model in .NET
4.0 vs. .NET 4.5 and showed you how claims are now first class citizens in .NET
4.5. However, the previous section still used the “traditional” authentication
mechanism where authentication is still your application’s responsibility. Be
cautious though, I do not want the previous section to deviate your attention
from the main focus of this article: delegating authentication responsibility
to an external entity.
WIF is Microsoft’s technology for encapsulating the inner
workings of WS-Federation (and WS-Trust) behind a .NET library which makes it
easy for developers to create claims-based apps without the need to know the
details of the specs we discussed previously.
As was discussed in the previous section, we have seen how
identity and access support in .NET passed through multiple stages, from the
simple IsInRole
checking, to claims support in WCF 3.0, to WIF 1.0 and then to
.NET 4.5.
WIF 4.5 is where this ends (and the new work begins!). In
.WIF 4.5, Microsoft did yet another naming change to the assemblies:
WIF in Action
VS 2012 provides you with the tools to quickly set up your
RP and use a local STS. Creating an STS should be really the last thing that
you would try to do. However, you will only use this STS for
development/testing purposes. Running an STS is not a simple task as its
business critical and relies on complicated protocols and cryptographic
operations.
STS commercial products are available and you are likely
to use them. Some of these products are:
- Active Directory Federation
Services (ADFS) v2
- IBM Tivoli Federation
Manager
- Oracle Identity Manager
ADFS v2 is the topic
of the next article.
So why does Visual Studio give you this local STS? Simply to
aid you during the development (and possibly testing) phase where the STS
product might not be accessible to you. Since your RP does not hold the
authentication logic anymore, all what you have to do before going to live is
to edit the policy for your RP to trust the new STS instead of the one created
using visual studio.
Let’s roll.
Create a new VS 2012 ASP.NET 4.5 web forms application.
Right click the project and select “Identity and Access”. This will display a
wizard giving you three options: ADFS2 and ACS will be discussed in future
posts, I will just quickly note that ADFS2 is the STS of AD and ACS is the STS
on Azure.
Select the option to create a local STS. In the Local
Development STS tab, you can select the SAML token version to use, the local
port of the STS, but most important you can select the claims that the STS will
give your RP. In WIF 1.0, you had to manually edit the local STS code to change
the set of claims; this way is much cleaner and true to the promise of
isolating you (the RP owner) from the authentication logic. Notice that you can
use from the many pre-defined claim namespaces and you can define your own.
Accept the defaults to close the wizard.
VS 2012 has now equipped your RP to trust a local STS and
set up the policy between them. To see this, let’s examine the web.config of
the RP:
- Forms Authentication
removed: your RP now is neither windows nor forms authentication-base. It is a
claims-based application, so forms is disabled because forms is the default
when creating a VS web forms app.
- Two HTTP modules that makes WIF magic possible:
-
WSFederationAuthenticationModule
: this module intercepts
incoming requests and redirect unauthenticated ones to the trusted IP(s). For
authenticated requests it processes claims within the security token and
presents them to your application in a consumable format. SessionAuthenticationModule
: this module takes care of session
management after an authentication is established. The WSFederationAuthenticationModule
module is bypassed and SessionAuthenticationModule
handles requests until the
session is expired or a sign-out flow is invoked.
audienceUris
: lists the
URIs that your RP will consider valid for the received tokenstrustedIssuers
: the list of
trusted IP certificates that the RP will accept signatures from to verify the
tokenwsFederation
: configures
the WS-Federation protocol, such as using the passive protocol flow, the IP
that the protocol will talk to, and the realm which is basically the ultimate
return-URL that the protocol flow will end up in – the RP itself in this case.
In addition, VS 2012 has created a
FederationMetadata.xml
file in the RP solution. Recall from the discussion of WS-Federation that
organizations participating in federation should publish communication and
security requirements in Federation Metadata. This XML file holds these
requirements for this RP.
Now run the application, quickly notice the browser
navigation and you will see that your application gets redirected to the local
STS which performed the (hardcoded) authentication and returned back to your
application as an authentication user (assume you’re Terry for a moment!). You
can now access the claims inside your application just like we have seen
before.
Now let’s see what happened in the background to examine
WS-Federation and the supporting protocols discussed before in action. To do
so, I will use Fiddler:
Step 1: A user browses the RP
You asked for the application via the browser. The WIF HTTP
module WSFederationAuthenticationModule
detects that you are not authenticated,
so it redirects the browser back with a 302 response and with a Location header
that contains the address of the IP-STS at which you must authenticate. In
addition, a set of WS-Federation protocol query strings are also supplied to
govern how the flow will behave:
- wa: with a value of
wsignin1.0 which means that this is a sign in request (note that WS-Federation
also supports sign out flow, so this parameter is mandatory)
- wtrealm: this is the RP
itself, and it represents the intended consumer of the token
- wct: this is an optional
parameter that specified the time of the response of the RP. This might be used
as indication to possible attacks if the IP sees that there is a time lag
between this parameter value and the actual time it received the sign in
request
Step 2: The browser sends a GET request to the STS
The browser then uses the STS address in the Location
header and the query strings discussed before to assemble a sign in request to
the STS. Here is the request made to the local STS:
Step 3: The IP-STS performs authentication
In “real” scenario, the STS will normally present you
with an authentication form that you would supply your credentials to. This
procedure of STS authenticating users – as mentioned before – is outside the
scope of WS-Federation and thus WIF. The STS can authenticate you against an
AD, a custom user store, or even using an X.509 certificate. This depends on
the type of the RP application and where the users are coming from. Regardless
of the mechanism to authenticate, the STS will – assuming successful
authentication – generate a security token containing the claims agreed between
the IP and RP via policy.
Step 4: The STS sends the response back to the browser
The STS sends back to the browser a hidden form with will
POST back to the RP. The form contains the following information:
- wa: same as before
indicating a sign-in flow
- wresult: contains the SAML security
token issued by the STS.
If you carefully examine the response, you will see many
of the protocols discussed before coming into play:
- The
RequestSecurityTokenResponse
(RSTR) of WS-Trust carries the token collection - XML Signature of
WS-Security is used to provide message integrity and trust between the IP and
RP
- WS-Policy – driven by the
Federation Metadata – indicates rules such as token lifetime
- WS-Addressing is used to
identify the endpoint reference for the passive request (i.e. the RP)
I reformatted the content for ease of display, here you
can see these protocols in action:
Note: There is a difference between SAML-P (the
protocol) and SAML token. SAML-P is a full blown protocol much like
WS-Federation. SAML token is a token type that can be used independent of
SAML-P, and it’s one of the token types frequently used in WS-Federation.
I will briefly touch on SAML-P 2.0 at the end of
this article.
Step 5: The browser posts back to the RP
The browser uses the hidden post form from the previous step
to post the result shown in the previous step back to the RP
Step 6: The RP verifies the token
Verifying a token involves multiple checks that could
take place based on each situation and policy. Some of these checks are:
- Integrity: in case digital
signature is used, the RP uses the IP public certificate included in the
request to verify that the digital signature is valid
- Expiration: in case an
expiration for the token is present, the RP verifies that the token is not
expired
- Decryption: in case
encryption is used, the RP uses its private key to decrypt the contents. In the
above example, encryption was not used as we were in the passive (web browser)
case, later I will discuss the active case and illustrate the difference.
- Source: using the policy,
the RP makes sure the token is issued by a trusted IP
- Claims: also using the
policy, the RP checks that the set of claims issued are the ones agreed on
Step 7: A session cookie is issued
Once the token is verified, the RP issues a session
cookie back to the browser so that next requests do not pass through the same
WS-Federation process.
WIF for Active Clients
The browser-based scenario we have just seen is called a
passive scenario. Passive clients are those that do not possess the WS-*
capabilities. Browsers are passive because they just perform redirects they are
told to, but by themselves browsers have no notion of WS-Federation.
Another type of clients are active ones. Active clients are
those that can perform WS-* operations; an obvious example are WCF services. A
WCF service can also act as a claims-based enabled RP. In this scenario, the
client (the Subject as per the defined terminology) is an application calling
the WCF service which requires claims-based authentication from a trusted STS.
The full cycle goes as follows:
- An application reaches a
line where it is invoking a WCF service. The WCF service itself is an RP
configured for claims-based authentication.
- The WCF client library at
the application finds out that the WCF service needs a security token to grant
access. The library then issues an RST to the STS.
- The STS replies back with a
security token via RSTR
- The client application then
uses this token to access the WCF service. Now here you can spot a major
difference between the passive and active scenarios. Recall in the passive case
that the client (browser) had only Https as option for encrypting its request
to the RP – called transport level. In the active case, the client
(application) can actually use the token to perform custom message level
encryption on the message. Message level security has the benefits of better
performance as we can be selective for which parts of the message are deemed
sensitive and thus to be encrypted and it also supports end-to-end messaging.
The good news is that when it comes to WIF, you do not have
to learn anything new than what you saw in the passive case. The same
programming model applies. Again you can right click a WCF project in VS 2012
and configure it as an RP using the “Identity and Access” wizard. The defining
difference between active and passive clients becomes clear when you inspect
the
web.config of the WCF service; you will see the ws2007FederationHttpBinding
in use, which again shows you that active clients are WS-* aware.
Federation Providers
So far the discussion has been centered on one role that STS
can play, and that is issuing claims on behalf of an IP; and thus it has been
called an IP-STS. However, an STS can play another roles; the role of a
Federation Provider.
Let’s recall the scenario I discussed before of the two
companies A and B wishing to enter a federated business agreement. In that
scenario I gave an example of B users needing to access a (single) application
in A and how that application is configured as an RP for an STS in B.
Now let’s extend the scenario a bit: instead of B users
wanting to access a single application in A, both companies want to extend
their partnership and now B users must be able to access multiple A
applications. Under the role of IP-STS we have discussed so far, every A
application must establish trust with B IP which in turn must provision every A
application.
A far better solution is for A to expose a Federation
Provider. A Federation Provider is a Resource STS (R-STS) that sits on the
resource side (on the relying party side – A domain in this case). Company A
applications then establish trust with the R-STS and B then provisions this STS
only.
A typical flow will then goes as follows:
- An employee on B domain
tries to access an A application
- A detects (via WIF for
example) that the user is not authenticated and redirects the request to the
STS it trusts; in this case it’s the R-STS on A’s domain
- In its turn, the R-STS is
configured to accept tokens from B IP, so the request is redirected back to B
IP
- The user authenticated
herself again B IP using any mechanism defined by B
- A request is submitted to
the R-STS on A containing the token
- R-STS processes the request
and typically does one of 3 things:
- Issue claims exactly as they were sent from B IP. Here the R-STS
decides that the included claims satisfy A application needs
- Modify claims based on some rules, for example to satisfy special
formatting needs for A applications
- Add new claims that the R-STS knows are important for A
applications yet B IP had no information about. For example R-STS might
maintain some information from previous transactions for a specific user.
- The resulted token is then
sent to the originally request A application which grants access
Once again, using WIF you can create your own local
R-STS; although as explained before, in real scenarios you would go with
commercial products. ADFS v2 is also suited to play the role of R-STS; for
example its claims-transformation language is ideal for claims modification.
Another great example is Azure Access Control Service (ACS) which also plays
the role of a Federation Provider on the cloud.
Both ADFS v2 and ACS will be discussed in future articles.
SAML 2.0
I will close this article by briefly addressing SAML 2.0.
Please note that I have never implemented this protocol myself, rather what I present
here is a summary answer for the common question of WS-Federation vs. SAML just
to get you going; but you’ll have a lot of reading to do if you want a
definitive answer.
SAML 2.0 consists of two parts; a protocol (much like
WS-Federation) that defines interactions and supported communication protocols,
and a token format – conveniently called SAML token. The token specification is
separate from that of the protocol, so you can use the token in another
protocols. Actually that is what we have been doing in this article all along
by using SAML tokens to carry claims in the WS-Federation protocol.
From a very high level point of view, SAML 2.0 protocol
(SAML-P) achieves the same objectives of WS-Federation: it allows business
partners to enter a federation agreement and allows delegation of
authentication logic from an application (Service Provider) to an external
entity (Identity Provider). The Identity Provider creates a SAML assertion that
the Service Provider then validates to grant authentication. The SAML assertion
is a SAML token containing claims.
SAML specification is actually divided into multiple
parts:
- SAML core: this
specification defines the structure of the SAML assertions and the supported
protocols. You can think of this as the base of every other specification
- SAML bindings: each of the
protocols described in the core specification is detailed in the binding
specification where each binding has certain communication and formatting
requirements
- SAML profiles: the profiles
specification puts together the different specification into a usage profile,
such as the login and logout profile.
- SAML metadata: this specification
is basically what makes SAML-P tick. It defines the agreement requirements
between the Service Provider and the Identity Provider to establish SAML-P
(supported bindings, certificates, cryptography, etc…). Basically this is to
SAML-P what WS-Trust is to WS-Federation.
WIF does not support SAML-P, although some time ago an
extension to WIF that adds SAML 2.0 support was CTP’ed but has not took off
since then. Here you can see the announcement:
http://blogs.msdn.com/b/card/archive/2011/05/16/announcing-the-wif-extension-for-saml-2-0-protocol-community-technology-preview.aspx
It’s not all bad however, ADFS 2.0 however fully supports
SAML 2.0 protocol. Why is this great news? Well simply because of the range of
interoperability scenarios that is now possible between two environments one
adopting WS-Federation and the other SAML-P. So organizations that have already
a SAML-P-based protocol infrastructure in place, does not need to change in
order to be interoperable with an ADFS-based one.
What about the Web Space?
Claims-based architecture is also well used in the web space
(REST-based). You can check my blog posts about OpenID and OpenAuth:
[Update]
My ADFS 2.0 and ACS articles have been posted on my blog: