Вы находитесь на странице: 1из 60

Building Claims-Based WPF Applications

Michele Leroux Bustamante, June 2009

Contents
Claims-Based Security ................................................................................................................................... 2
Roles, Permissions and Claims .................................................................................................................. 3
How Are Claims Different?........................................................................................................................ 3
Federated Security Scenarios........................................................................................................................ 7
Federation Basics ...................................................................................................................................... 8
(Sort Of) Federation in a Single Domain ................................................................................................. 10
Federation with a Trusted Domain ......................................................................................................... 11
Claims Transformation ............................................................................................................................ 13
More Federation Scenarios..................................................................................................................... 15
Setting up a Simple Federation Scenario .................................................................................................... 17
Claims Model .......................................................................................................................................... 18
Exposing Federated Security Endpoints.................................................................................................. 19
Generating a Federated Proxy ................................................................................................................ 21
Deferring Proxy Initialization .................................................................................................................. 25
Issuing Claims at the STS ......................................................................................................................... 28
Authorization at the RP Service .............................................................................................................. 32
WPF Clients and Claims............................................................................................................................... 35
Claims-Based UI Models ......................................................................................................................... 36
Client Authorization Service ................................................................................................................... 38
Claims-Based Access Control .................................................................................................................. 40
Caching Security Tokens ............................................................................................................................. 47
ClientCredentials and Issued Tokens ...................................................................................................... 49
Caching Issued Tokens for Multiple Proxies ........................................................................................... 51
SecurityTokenCache................................................................................................................................ 52
CachedClientCredentials ......................................................................................................................... 53
CachedClientCredentialsSecurityTokenManager ................................................................................... 55
CachedIssuedSecurityTokenProvider...................................................................................................... 56
Sharing CachedClientCredentials and Updating Client Claims ............................................................... 58
Session and Token Lifetime .................................................................................................................... 59

claimsbasedwpf.codeplex.com Page 1
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Summary ..................................................................................................................................................... 60

Claims-based and federated security scenarios are becoming more and more popular in recent years,
and as the tools continue to simplify the developers experience for these scenarios this trend will only
continue. But, it is not merely a trend for there is real value in building claims-based applications and in
supporting various federated security scenarios. These are topics that have been discussed in various
fabulous blogs, whitepapers and webcasts – delivered by very smart people – but sometimes it is hard
to find a single document that tells a concise story to bootstrap knowledge from a particular
perspective. This whitepaper will focus on the impact of these claims-based and federated security
scenarios on WPF clients. You’ll learn about claims, and several common scenarios for claims-based and
federated security that involves WPF applications, and while the server side of this story will be briefly
discussed the focus will be how to develop the client side of that experience.

In terms of technologies used this paper will leverage Windows Presentation Foundation (WPF),
Windows Communication Foundation (WCF), “Geneva” Framework, and also touch on Windows
CardSpace and CardSpace “Geneva”. While the server-side leverages WCF with Geneva Framework,
examples discussed in this whitepaper will include WPF clients that use WCF and others that leverage
WCF with Geneva Framework to illustrate a particular scenario. Note that it is entirely possible to
implement claims-based and federated WPF clients without the help of Geneva Framework since WCF
supports the appropriate protocols – and the server-side can be implemented with any technology so
long as the appropriate protocols are used.

Some of the highlights include:

 Understanding federated WCF bindings from the client developer’s perspective


 Using claims to restricting access to features at the client
 Caching and sharing tokens between proxies at the client
 Recovering from session and token expiry in a graceful manner (with a nice proxy wrapper that
handles it all!)

If you are WPF developer new to claims-based and federated security concepts, I hope that reading this
paper in its entirety will provide you with a digestible overview of these things along with some key
scenarios relevant to your plight building rich clients. If you are not new to these concepts, skip the
intro and jump to the meat of each implementation scenario.

Claims-Based Security
Claims-based and federated security are related subjects that have been described in other whitepapers
and resources so I will not reinvent the wheel here by producing a long-winded section on these

claimsbasedwpf.codeplex.com Page 2
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

subjects. In this section I will at least provide you with a short and high-level description of these
concepts to provide you with context if you are completely new to the subject – enough information so
that you can read this whitepaper without your eyes glossing over.

I’ll start with claims-based security – which one of the underpinnings of federated security.

Roles, Permissions and Claims


When you build a security model for your applications you typically think role-based. Users supply
credentials, are authenticated, and are granted one or more roles that indicate their rights in the
system. Applications and services use those roles to determine which features the user can view in the
user interface, and services typically also restrict access to operations based on the same roles. There
are a few potential challenges with role-based security:

 Roles might be renamed (think localization or co-branding) which means code relying on the
name of each role is invalidated.
 Roles can carry different meanings to different sets of application users (again, think co-
branding or departmental use). For example a different department using the same application
may want to reduce the rights of the Administrators group, and create a SuperUser account that
has all privileges.
 Applications often have to authenticate users from behind the firewall (intranet users using
domain accounts) and from outside the firewall (Internet users with accounts in a custom
credential store). To avoid writing authorization code against both sets of roles a single set of
roles must be used for both users – usually by converting Windows roles to custom roles. If
additional credentials are supported for authentication (such as certificates) the same rule
applies.

In the past these problems were often solved by creating a permission-based security model whereby all
roles are mapped to a set of permissions and authorization code never looked at roles, only the resulting
permissions granted by the user’s roles. Claims-based security offers the same benefit as permission-
based security in the sense that it is a more granular artifact for authorization – but a claims-based
security model also has many other valuable characteristics.

How Are Claims Different?


Discussing claims without discussing federation can be a bit of a chicken and egg problem, since the
value proposition for claims increases significantly when you implement federated scenarios – as does
the value of different types of claims. Put another way your applications can derive value in a claims-
based solution without federating with other partners and applications, but if you federate your
applications almost always rely on claims to authorize access to features and functionality. This is why I
like to first talk about claims in the context of how they benefit simpler application scenarios and then
expand the discussion to full-blown federation.

claimsbasedwpf.codeplex.com Page 3
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

With that in mind, in this section I will talk about claims from a simple point of view – what can they
contain and how are they different from roles and permissions in the classic sense. Later, I will talk
about claims again within the context of different federated scenarios which will hopefully add clarity.

First of all, a claim contains the following key bits of information:

Property Description
Claim Type Can be any string, often a Uri, indicating the type of claim. The type of claim could
be representative of the user’s identity, roles, permissions, or other details such as
name, email, age, birth date and so on. There are a number of predefined claim
types defined as Uri in System.IdentityModel and Microsoft.IdentityModel (Geneva
Framework) in their respective definitions for ClaimTypes.

Example:
Microsoft.IdentityModel.Claims.ClaimTypes.Role or
“http://schemas.microsoft.com/ws/2008/06/identity/claims/role”

Example:
“Permission” or
“http://claimsbasedwpf.codeplex.com/samples/2009/06/claims/permission”
Claim Value The value for the claim, relevant to the claim type of course. This can be a string,
Uri, or any other CLR type relevant to the claim type.

Example:
Claim Type =
“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress”

Claim Value = “mlb@idesign.net”

Example:
Claim Type =
“http://claimsbasedwpf.codeplex.com/samples/2009/06/claims/permission”

Claim Value =
“http://claimsbasedwpf.codeplex.com/samples/2009/06/claims/permission/create”
Claim Issuer Claims differ from permissions in that they are issued by a trusted authority. If you
issue the claims as part of your application, then your application is the authority.
Once claims start traversing boundaries we need a more reliable way to “trust” the
source of those claims and this is handled with digital signatures. To summarize,
claims are typically received by a service in a signed security token where the
signature is used to guarantee a) who issued the claims, and b) that the token has
not been tampered with en route.

The issuer is also represented a string value once the claims have been extracted
from a security token.

claimsbasedwpf.codeplex.com Page 4
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Example:
Claim Type = Microsoft.IdentityModel.Claims.ClaimTypes.Role
Claim Value = “BUILTIN\\Administrators”
Claim Issuer = “System”

Example:
Claim Type = “Permission”
Claim Value = “CreateCustomers”
Claim Issuer = “CN=MySecurityTokenService”

The issuer usually grants a set of claims to an authenticated caller, sometimes referred to as a “claim
set” or more simply a “collection of claims”. Think about authenticating a user based on their username
and password and granting them one or more roles or permissions, for example. The party handling
authentication in a federated scenario is also considered the identity provider (IdP) and is responsible
for issuing identity claims (along with other claims if relevant) for the authenticated user. Ultimately
these claims travel across service boundaries in a security token – more on this later.

I mentioned that claims can sometimes represent roles or more granular artifacts such as permissions.
One example could be that a user is authenticated (don’t worry about where they are authenticated just
yet, we’ll get there) and their name and email are supplied as claims as shown in Figure 1.

Figure 1: Authenticating a user and granting a name and email claim

Another example could be that the same user is granted a set of roles a shown in Figure 2.

Figure 2: Authenticating a user and granting role claims

claimsbasedwpf.codeplex.com Page 5
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

How about granting permissions instead of roles, for a more granular artifact useful for authorizing
access to features? Figure 3 illustrates an example of this.

Figure 3: Authenticating a user and granting permission claims

Or, how about granting all of these claims at once, so that the application can know information about
the user, the original roles they were granted, and the ultimate permissions that they have in the
application? Figure 4 illustrates this scenario.

Figure 4: Authenticating a user and granting informational, role and permission claims

claimsbasedwpf.codeplex.com Page 6
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Which scenario is best? Which is the most appropriate? Well, that depends how the application is wired,
and the way that claims are granted. For example, you may always want access to the name and email
claim for information, but only care about the permissions relevant to the current task. It may not be
practical to grant claims relevant to an entire application at once – there could be hundreds of possible
claims, some only relevant for particular services and operations. The point is that claims are a very
flexible artifact, they can be:

 Informational: name, email, address, phone number, age


 The answer to a question: Are you over 13? Do you belong to the sales department? Do you
have a driver’s license?
 Describe application rights: roles, permissions, operations you can call

As I mentioned before, claims are issued by a trusted authority. For an application to rely on a set of
claims for authorization, it must first have a trust relationship with the issuer of the claims. This is where
claims-based security adds value beyond a simple permission-based model. A set of claims can be issued
and passed in a security token signed by their issuer to guarantee the claims are not tampered on the
wire. If the signature matches one of the application’s trusted issuer certificates, the claims are
considered valid. This level of guarantee makes federation possible where the issuer may not be part of
the same domain as the application. And this is where we segue into a discussion of federated scenarios.

Federated Security Scenarios


At this point you should be comfortable with the concept that a claim can carry information about the
user and his roles or permissions as deemed necessary by the application. So, hopefully the first

claimsbasedwpf.codeplex.com Page 7
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

connection has been made that as long as you have a set of claims from a trusted issuer, your
application can authorize access to features and functionality. On to the next set of questions:

 Where does the user authenticate?


 Who issues the claims?
 How are trust relationships established between the application and issuer?

Federation Basics
The first, simple way to look at federation is to use a scenario that involves the common participants in a
federated security scenario: the Relying Party, the Identity Provider, the client application and the user
(or, subject) to be authenticated. The Relying Party (RP) can be any web site or service that relies on a
set of claims from a trusted issuer to authorize access. For the purposes of this whitepaper we will focus
on services that back WPF client applications. The Identity Provider (IdP) is the party responsible for
authenticating the user and can grant claims for the user on request. More specifically, if the IdP has a
Security Token Service (STS) it can issue a security token carrying claims for the authenticated user. The
IdP is responsible for using appropriate measures to authenticate the user before granting said claims
and the RP must be able to trust the those measure are adequate. The client application is responsible
for presenting credentials from the user (this can be done in a variety of ways depending on the
credentials used to authenticate to the STS) and calls the STS at the IdP to get a security token carrying
claims for the RP. The client then includes that security token in calls to the RP so that access can be
authorized according to the claims it carries.

This dance involving the user, the client, the STS and the RP, where the RP is a service, is known as active
federation based on WS-Trust protocol. Passive Federation is similar but all communications are handled
through the browser as the RP is a web site and the STS invoked over HTTP, and this is based on WS-
Federation protocol. Figure 5 illustrates the moving parts of active federation.

Figure 5: A simple federation scenario involving a single RP and STS

claimsbasedwpf.codeplex.com Page 8
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

From a high level what is happening is this:

1. The client gathers the user’s credentials according to the requirements of the STS
2. The client sends a WS-Trust message called a Request for Security Token (RST) along with those
user credentials. The RST indicates the RP for whom the token will be issued, the type of token,
and the claims the RP is requesting the token to contain (although, the STS often knows this
based on the RP).
3. The STS determines if it has a trust relationship with the RP before doing anything. Assuming
there is trust, the STS authenticates the user against its credential store and determines which
claims to grant.
4. The STS issues a security token carrying the claims granted the user and returns it in a Request
for Security Token Response (RSTR).
5. The client sends a request message to the RP passing along the security token for authorization.
6. The RP validates the token, verifies that it trusts the issuer, and authorizes the request based on
the security token’s claims.
7. If all goes well, the RP executes the request, possibly returning data.

Typically SAML tokens are issued in a federated security scenario. SAML is an interoperable, XML-based
security token format that contains one or more SAML assertions (equivalent to a claim) and is digitally
signed by the STS. Although this type of security token is not a requirement in federated security
scenarios – it is the most commonly used since most platforms support it.

claimsbasedwpf.codeplex.com Page 9
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

(Sort Of) Federation in a Single Domain


In the last section I discussed the flow of communications between participants in a federated security
scenario, but I didn’t mention domains and this is a very important part of the discussion. The whole
point of federation is to support scenarios where users authenticate to their own domain (or, realm) and
present proof of that authentication in the form of claims. In the scenario shown in Figure 5 the user
authenticates to the IdP and presents the RP with a security token signed by the STS at the IdP which
proves he was authenticated. The RP doesn’t care how authenticate took place – it could be a Windows
credential, a username and password, a certificate or any other valid credential that the IdP can use to
validate the users identity. The RP must only trust the issuer to authenticate users in an acceptable
fashion – hence the trust relationship.

Do the IdP and RP belong to the same domain? Possibly yes, in a simple scenario. Let’s say you are
building an application with a bunch of services (this would be the RP) and you want to decouple the
process of authentication from the service so that you can support multiple different credential types
without affecting how the service handles authorization. By delegating authentication to an STS within
the domain of the RP (let’s call it the RP-STS) you can achieve this. This way, service developers can
focus on authorization of the claims issued by the RP-STS, and the RP-STS has the job of authenticating
users based on any number of supported credential types, and issuing a normalized set of claims
relevant to the RP for each authenticated user. This scenario is illustrated in Figure 6.

Figure 6: Delegating authentication to an RP-STS to support a streamlined support claims-based


authorization model

claimsbasedwpf.codeplex.com Page 10
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

In this scenario, the RP-STS is also the IdP since it is responsible for authenticating users and granting
claims to those users.

In fact, this is not federation in the true sense of the word even though federation protocols are in play.
If the IdP were located outside the RP’s domain, we would have federation.

Federation with a Trusted Domain


The RP can trust users from another domain removing the need to manage credentials for those users in
its domain. This yields several benefits including:

 No need to duplicate user credentials at the RP


 Prevention of errors keeping credentials in sync across domains
 Prevention of errors introduced with provisioning and de-provisioning users in multiple locations

The flow of communication between user, client, RP and IdP are still the same (see Figure 7) however
the IdP is not owned by the RP. An explicit trust relationship is established between the RP STS (RP-STS)
and the IdP STS (IP-STS) before users can gain access to the RP.

Figure 7: Federation between the RP domain and IP domain

claimsbasedwpf.codeplex.com Page 11
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Why would an RP want to trust users from another domain? There are so many possible scenarios, all
leading to a common result – users from another trusted domain are granted access to features of the
RP. A few reasons for this could include:

 Granting access to users of another application access to the RP within a corporate environment
to enable Single Sign-On (SSO).
 Granting access to users of another domain behind the firewall access to applications in the RP
domain, again within a corporate environment.
 Granting access to users within a particular department or role of another company access to
certain features of applications in the RP domain.
 Granting access to any user with a Windows Live account, preventing the need to provision user
accounts at the RP.

Security tokens from a trusted issuer may vary in terms of the claims they carry. Sometimes the RP and
IdP can establish an agreed upon set of claims that is meaningful to the RP. For example the IdP might
supply a name claim plus information about the roles of the user in that domain. Perhaps the IdP

claimsbasedwpf.codeplex.com Page 12
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

transforms some of its claims into claims that the RP can use to authorize access. For example the IdP
might convert a role from its system into a new claim indicating that role in a way the RP can
understand. It is also possible that the IdP may only supply proof of authentication with some
information about the user, such as in the case of Windows Live – where no roles or granular
permissions exist. A social networking application may not need to differentiate users by their role, they
either have an account or they don’t. In this case a set of claims that identifies the user without specific
roles and permissions is perfectly acceptable.

Claims Transformation
In the scenario illustrated in Figure 6, the RP-STS is also the IdP authenticating users. It can therefore
generate claims appropriate for the RP to use to authorize users (roles, permissions, or other) after the
authentication step – no claims transformation required. In a true federation scenario that involves
other trusted issuers the IdP is not owned by the RP and so the claims issued by the IdP may not be
enough for authorization at the RP.

The RP can supply an STS (RP-STS) to transform claims issued by the IdP (from the IP-STS) into claims the
RP can use for authorization. Sometimes the IdP can be wired in advance to send claims that help the RP
perform this transformation, sometimes the RP can make use of whatever claims the IdP issues.

Figure 8 illustrates a scenario where the RP supplies an STS (RP-STS) to handle transformation of trusted
issuer claims. The RP-STS forms a trust relationship with the STS authenticating users from the IP domain
(IP-STS). Security tokens from the IP-STS flow to the RP-STS for transformation and the RP only deals
with tokens from the RP-STS. This makes it possible for the RP to authorize access based only on RP
claims relevant to the application, without having to handle claims from potentially different trusted
issuers.

Figure 8: Transforming claims at the RP-STS

claimsbasedwpf.codeplex.com Page 13
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

The RP-STS can also act as IdP to clients in the same domain as shown in Figure 9. Once again, this
ensures that the RP need only worry about claims issued by its RP-STS – trusting that users have been
authenticated by their respective domains.

Figure 9: Authenticating internal users and transforming claims for users from a trusted domain

claimsbasedwpf.codeplex.com Page 14
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

If you are familiar with .NET Services, part of Azure Services – Microsoft’s cloud computing platform –
the Access Control Service is an STS in the cloud that an RP can use to do nothing but transform claims
from trusted issuers. It removes the need for an RP to supply an RP-STS to perform this step, pretty cool
stuff.

More Federation Scenarios


From a high level, federated security scenarios are not difficult to understand. An application (the RP)
needs some claims to authorize access, and needs to know that they come from a trusted issuer. The
user is authenticated by its domain (the IdP, which could be the RP or some other domain that the RP
trusts). The IdP grants claims and issues a security token with those claims. Ultimately the IdP claims are
transformed into claims that the RP can use for authorization (this can be handled by the RP, or by some
intermediate STS in a more advanced scenario).

Fortunately, the process of passing user credentials for authentication, gathering claims from the IdP,
and traversing whatever chain of STS live between the IdP and the RP is handled automatically by WCF.
The developer is shielded from the complexity most of the time (very little to code, but you do have to
understand a few things).

claimsbasedwpf.codeplex.com Page 15
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

So far I discussed only a few simple federation scenarios:

 Using an STS at the RP to facilitate delegation of authentication and to support a claims-based


security model.
 The RP trusting another domain for authentication, and transforming those claims to support a
normalized set for authorization – which involves two STS hops.
 A combination of both of these.

This model scales well. The RP can have trust relationships with several domains – each an IdP for their
respective users – and merely add additional transformation rules for each based on the claims they
issue.

Another area where this can expand is that there can be a chain of trust that traverses multiple STS (see
Figure 10).

Figure 10: The RP trusting a particular domain, which leads to an STS trust chain

Figure 10 introduces a new type of participant, a Federation Provider (FP), which also hosts an STS (FP-
STS). TO help explain its role, consider the following points:

claimsbasedwpf.codeplex.com Page 16
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

 An STS issues security tokens based on internal rules, perhaps as the result of authentication, or
in order to transform claims received by one issuer into a format expected for a particular
request.
 An IdP usually has an STS (IP-STS) which authenticates users and issues claims for that user.
 An RP can have an STS (RP-STS) that will transform claims into a format that the RP can use for
authorization. Sometimes the RP-STS also authenticates users within the RP domain, thus is also
an IdP.
 An FP is not an IdP or an RP – its role in a federated security scenario is often to transform
claims from one issuer to a new set of claims issued by the FP. It is invited to the federation
dance because one of the key players invited it. For example, the RP may rely on a particular FP
to manage its federation partners. The RP still decides which IdP it trusts, but configures that in
a central place at the FP. The .NET Services Access Control Service is an example of an FP playing
this type of role.

Back to Figure 10, if the RP expects a token from the RP-STS, and the RP-STS trusts FP-STS, and the FP-
STS trusts IP-STS, we now have a chain of trust that must be resolved to navigate from user credentials
to RP claims. As I already mentioned, fortunately WCF knows how to resolve this chain of trust (the
service policy chain, really) so that developers are shielded and need only generate a proxy and make
calls to the RP’s services. That doesn’t mean there aren’t a few things to understand along the way
which is why I’ll walk through these scenarios in one form or another from the perspective of the client
developer.

Without turning this into a whitepaper about all the possible business scenarios for federation, my goal
up to now has been to provide some background on the reasoning behind claims-based security, despite
federation, and on some of the possible scenarios for federation to help you understand the flow of
communication. In the remainder of this whitepaper I will explain how some of these scenarios are
achieved focusing on the WPF client developer’s perspective – while also discussing relevant aspects of
the relying party and security token services along the way.

Setting up a Simple Federation Scenario


In this section I will walk through the process of configuring a WPF client application to communicate
with a WCF service in a federated scenario – that is, the WCF service requires an issued token from an
STS. To provide a complete picture of the moving parts in this scenario I’ll also provide a brief summary
of the relevant configurations at the service and STS. The scenario I’ll use for this example is a Todo List
application (see Figure 11). The Todo List client application uses a WCF proxy to call the TodoListService.
Since the service requires an issued token from RP-STS the proxy first passes credentials to authenticate
to RP-STS, requesting a token for the TodoListService. The proxy then proceeds to make the call to the
TodoListService – which in turn authorizes access according to the claims granted.

Figure 11: Federation between the Todo List client, TodoListService and RP-STS

claimsbasedwpf.codeplex.com Page 17
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Claims Model
Before discussing the implementation details it will be helpful to understand what the claims-based
authorization model looks like for this scenario. The TodoListService exposes four operations:
GetItems(), AddItem(), UpdateItem() and DeleteItem(). These items each require a single claim be
granted the caller: Read, Create, Update and Delete, respectively. Figure 12 illustrates this.

Figure 12: Demanding claims for each service operation

claimsbasedwpf.codeplex.com Page 18
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

The RP-STS grants some combination of these four claims according to the authenticated user.

Exposing Federated Security Endpoints


This section will briefly summarize how the TodoListService exposes an endpoint that requires an issued
token from the RP-STS. Services can use one of two bindings to expose federated security endpoints:

 WSFederationHttpBinding: supports WS-Trust February 2005 and WS-SecureConversation


February 2005
 WS2007FederationHttpBinding: supports the latest versions of the same standards, WS-Trust
1.3 and WS-SecureConversation 1.3.

claimsbasedwpf.codeplex.com Page 19
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

The service should choose the binding that best suits protocols supported by the STS. In this example,
WS-Trust 1.3 is used by all parties, and so the service model configuration for the TodoListService
endpoint looks as shown in Figure 13.

Figure 13: Exposing a federated security endpoint at the service

<system.serviceModel>
<services>
<service name="TodoList.TodoListService" behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="ws2007FederationHttpBinding"
bindingConfiguration="wsFed" contract="Contracts.ITodoListService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/TodoListService"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<ws2007FederationHttpBinding>
<binding name="wsFed">
<security mode="Message">
<message negotiateServiceCredential="false">
<claimTypeRequirements>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
isOptional="false"/>
<add
claimType="http://claimsbasedwpf.codeplex.com/samples/2009/06/claims/permission"
isOptional="false"/>
</claimTypeRequirements>
<issuerMetadata address="http://localhost:8010/rpsts/mex" />
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>

claimsbasedwpf.codeplex.com Page 20
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

</behaviors>
</system.serviceModel>

Figure 14 lists the key configurable elements common to both of the federation bindings.

Figure 14: Key elements in a federated binding configuration

Element Description
Token Type In theory federation can involve any number of token types, but the most
common is SAML. Currently SAML 1.0 and SAML 1.1 are supported by WCF,
each represented by the following Uri respectively:
urn:oasis:names:tc:SAML:1.0:assertion, http://docs.oasis-open.org/wss/oasis-
wss-saml-token-profile-1.1#SAMLV1.1. If the value is omitted, SAML 1.1 is
assumed.
Claim Types The service can supply a list of expected optional or required claim types. This
information is included in the service metadata and therefore available to the
client after proxy generation. The client includes this information in its RST to
the STS, and the STS can optionally use it to determine the claims to issue the
caller once authenticated. In reality, most STS have a predefined set of rules
for granting claims for a particular RP.
Issuer Metadata The service must indicate where the metadata exchange endpoint is for the
STS so that clients will know where to send their token request. SvcUtil uses
this endpoint during proxy generation to gather endpoints available to the
client for authentication to the STS.
Issuer Address The service can optionally specify a particular STS endpoint where the client
should authenticate to retrieve an issued token. Even if there are multiple
endpoints available at the STS, SvcUtil will generate configuration for the
specified endpoint.

As indicated in the listing in Figure 13, the TodoListService expects a SAML 1.1 security token (the
default), to be issued from a WS-Trust 1.3 endpoint at the RP-STS whose metadata can be found at the
Url: http://localhost:8010/rpsts/mex. The service expects a Name claim and (optionally) one or more
permission claims. The service enables metadata exchange at its endpoint so that clients can access this
metadata and generate proxies.

As you can see there isn’t much to implementing a federated endpoint using one of the standard
federated bindings supplied by WCF. All of the heavy lifting for the messaging protocols is handled by
the underlying channel stack.

Generating a Federated Proxy


To communicate with a federated service endpoint the client developer will typically generate a proxy to
kick start the process. To generate a proxy, the service must either expose a metadata exchange
endpoint, or it must supply a Web Service Description Language (WSDL) document that contains all of

claimsbasedwpf.codeplex.com Page 21
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

the metadata for the service and its endpoints. Ultimately, the client needs a copy of the service
contract associated with the federated endpoint, and any associated data contracts or other serializable
types. In addition, the appropriate configuration for the proxy – which is usually close to what the
service configuration looks like – but for federated scenarios things are a little different at the client.

The client requires additional aspects of the federation binding to be supplied before it can
communicate with the STS. This information is not supplied by the service – it is gathered directly from
the STS. When you generate a proxy using Add Service Reference, SvcUtil calls the metadata exchange
endpoint exposed by the STS and gathers information about its WS-Trust endpoints to produce the
appropriate client configuration. The client can then use this configuration to initialize an instance of the
ClientBase<T> proxy or create the channel directly with ChannelFactory<T>.

Figure 15 shows the binding configuration generated for the Todo List client application based on the
service configuration shown in Figure 13. I have cleaned up the generated configuration to remove
default values that are not relevant to this discussion.

Figure 15: Configuration generated for the TodoListService federated endpoint

<system.serviceModel>
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_ITodoListService">
<security mode="Message">
<message algorithmSuite="Default" issuedKeyType="SymmetricKey"
negotiateServiceCredential="false">
<issuer address="http://localhost:8010/rpsts" binding="ws2007HttpBinding"
bindingConfiguration="http://localhost:8010/rpsts">
<identity>
<certificate
encodedValue="AwAAAAEAAAAUAAAAw5XNSnQJp3fU495G1whJhnYamVAgAAAAAQAAAO4BA
AAwggHqMIIBU6ADAgECAhAfYtbn6q4Ytkg7+CbBMULBMA0GCSqGSIb3DQEBBAUAMBAxDjAMB
gNVBAMTBVJQU1RTMB4XDTA5MDYyOTA1NDQ1NloXDTM5MTIzMTIzNTk1OVowEDEOMAwGA
1UEAxMFUlBTVFMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK+ocZ51zrBpIGC1SjFu4io0
qWLhSi53S1Uas0jfInaNvHjyJzEZJhtiRIaXVxfcQiMX1yToPvWzoNDZ8M24x/AM0PCm5JR1TYqUNS
VDpLbYjCE23w30IsYqqOpWVFo0Vs3GZ8B4XZYUB/QOv4zNz5/R69eeSAiU2QgWiJ2RrfTPAgMBA
AGjRTBDMEEGA1UdAQQ6MDiAEK2EFXxZKjypLl5TT/Q34M6hEjAQMQ4wDAYDVQQDEwVSUFNU
U4IQH2LW5+quGLZIO/gmwTFCwTANBgkqhkiG9w0BAQQFAAOBgQBvxxg3XM03jT3UHgnLic4zTP
ceP/uPz4XP/WrM0ey1tN4s9t15mtAEjYcHEEtTRba8xAic5gZKYsDAgmonFeAbsd286rvtIcGO6R/jql
Z2+2eVAPiY18F5U62uLooboXh3H7+GVuXZRPgouHM5gz1rRWgIBEzRIQjlXvTPLFHdWg==" />
</identity>
</issuer>
<issuerMetadata address="http://localhost:8010/rpsts/mex" />
<tokenRequestParameters>

claimsbasedwpf.codeplex.com Page 22
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

<trust:SecondaryParameters
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:KeyType
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
<trust:KeySize
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">256</trust:KeySize>
<trust:Claims Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity"
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wsid:ClaimType
Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
xmlns:wsid="http://schemas.xmlsoap.org/ws/2005/05/identity" />
<wsid:ClaimType
Uri="http://claimsbasedwpf.codeplex.com/samples/2009/06/claims/permission"
xmlns:wsid="http://schemas.xmlsoap.org/ws/2005/05/identity" />
</trust:Claims>
<trust:KeyWrapAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-
sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#rsa-oaep-
mgf1p</trust:KeyWrapAlgorithm>
<trust:EncryptWith xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-
trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
<trust:SignWith xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-
trust/200512">http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
<trust:CanonicalizationAlgorithm xmlns:trust="http://docs.oasis-
open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/10/xml-exc-
c14n#</trust:CanonicalizationAlgorithm>
<trust:EncryptionAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-
sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-
cbc</trust:EncryptionAlgorithm>
</trust:SecondaryParameters>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<binding name="http://localhost:8010/rpsts" >
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="false"
algorithmSuite="Default" establishSecurityContext="false" />
</security>
</binding>
</ws2007HttpBinding>

claimsbasedwpf.codeplex.com Page 23
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

</bindings>
<client>
<endpoint address="http://localhost:8000/TodoListService"
binding="ws2007FederationHttpBinding"
bindingConfiguration="WS2007FederationHttpBinding_ITodoListService"
contract="TodoList.ITodoListService" name="default">
<identity>
<certificate
encodedValue="AwAAAAEAAAAUAAAAMTNxA8ZXL5/j4SM7kjejoa6aZscgAAAAAQAAAOUBAAA
wggHhMIIBSqADAgECAhDtugE1LpBwuUuwJHt6AjsKMA0GCSqGSIb3DQEBBAUAMA0xCzAJBgNV
BAMTAlJQMB4XDTA5MDcwMTE0NTMxM1oXDTM5MTIzMTIzNTk1OVowDTELMAkGA1UEAxMC
UlAwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO3BQX7ZOxcKCSzj2SF/Ibldy47RSCRrsSVe
7hR2sDeqy5T7RCOgBi6s5oVn44O8twUYHJF5eZH84+gJfQOeaQW08mlrv96s8FaPZr9QZd9/RwbJ
oaMBlErdSBiKZciqQZUw5JLJDI1VrWzpIGa1FwyoP6eNd8VwxUCPaRwmM9TnAgMBAAGjQjBAM
D4GA1UdAQQ3MDWAELmxuUZ/CRnp4cwF6XoiJOShDzANMQswCQYDVQQDEwJSUIIQ7boBNS6
QcLlLsCR7egI7CjANBgkqhkiG9w0BAQQFAAOBgQBb0ZfGov5xc/X4f/HqTWxAvbJoALvXeG263h8F
A3Ogie1GE4KJozbONEWQVILsT1EUnSEtVZgH0sHt2bBxYViC9BBFGfmISiq8iAWmLMDcBRyj1r13q
TcRiq19+6mi+MZ0ycUI/sMATEG+3DDCQEO8GblyY3VGu/cJGgpk1ajFaw==" />
</identity>
</endpoint>
</client>
</system.serviceModel>

Beyond the information the TodoListService provided, the client-side federation binding adds the
following necessary pieces of information:

 The issuer address is provided, indicating the endpoint the proxy will call to request tokens for
the TodoListService.
 A binding configuration is provided for this issuer endpoint, in this case indicating that the client
will use WS2007HttpBinding to call the STS.
 The WS2007HttpBinding configuration for the STS endpoint indicates that the client must pass a
UserName credential to authenticate to the STS.
 A base64-encoded copy of the STS certificate is provided as the identity of the STS, removing the
need to acquire the STS public key out-of-band in order to encrypt messages to the STS.
 Token request parameters include information about the WS-Trust dialect to use, the claim
types requested by the service, along with other key signing and encryption details.

This is all very straight-forward so far since proxy generation makes things super easy. But, it is still
important to understand the moving parts so that you can make adjustments to the generated
configuration as needed. Also, keep in mind that the results of proxy generation can vary under some
circumstances. Here is a summary of some extended situations to be aware of:

claimsbasedwpf.codeplex.com Page 24
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

 Proxy generation will fail if the service or STS are not online. Of course, one would hope they are
online 
 For interoperability with other platforms, you may need to adjust some of the token request
parameters such as the key type, key size, or algorithms used for signing and encryption. Proxy
generation should produce the correct result, but this is an area to keep in mind if you are
having problems.
 The setting to negotiate service credentials should be set to false on the federated and http
bindings since negotiation is not interoperable. It is a convenient way to dynamically acquire the
service certificate at the STS or RP when both sides are WCF.
 As with any WCF scenario, you may need to adjust binding elements related to message size,
byte array size, and other reader quotas.
 If the STS exposes multiple endpoints that satisfy the WS-Trust protocol supported by the
service endpoint, the client-side configuration will include some options. SvcUtil currently will
default the client configuration to the first compatible STS endpoint it finds and provide
alternatives in the commented out in the <alternativeIssuedTokenParameters> element. The
client developer should look at this section and determine which endpoint best suits its
authentication or protocol requirements. The configuration requirements for each of the
commented STS endpoints are generated and ready to use if any of the other alternatives are
uncommented.
 If the service specifies a particular issuer address in its federation configuration, the client will
include configuration for that specific STS endpoint.

As the client developer, your job can be as easy as generating a proxy for a federated endpoint and
supplying the appropriate credentials to authenticate to the STS. This experience is identical to any
other scenario – you simply need to look at the issuer binding to find out what credentials it expects. For
example, the TodoListService scenario calls an STS endpoint that requires a username and password,
and so the proxy initialization code looks like this:

TodoListServiceProxy _Proxy = new TodoListServiceProxy("default");

this._Proxy.ClientCredentials.UserName.UserName = this.Username;
this._Proxy.ClientCredentials.UserName.Password = this.Password;
this._TodoItems = this._Proxy.GetItems();

The call to GetItems() handles acquiring the issued security token from the STS first, authenticating with
the username and password collected from the user, and then calling the TodoListService passing the
issued token for authorization.

Deferring Proxy Initialization


This tip applies to more than WCF proxies, but it rears its head quickly if you initialize your proxies when
you declare them, or in the Windows constructor. Imagine you declare a proxy as a member of the main
window, and initialize it inline like this:

claimsbasedwpf.codeplex.com Page 25
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

public partial class MainWindow : Window


{
private ExceptionHandlingProxy _Proxy = new ExceptionHandlingProxy("default");

public MainWindow()
{
InitializeComponent();
}
}

Let’s say you have a configuration error such as a certificate reference that can’t be found. When the
window is loaded, you’ll get a parsing error like that shown in Figure 16 during construction:

Figure 16: Generic XamlParseException resulting from problems that occur during Window
construction

In fact, you’ll see this type of XamlParseException if any exception occurs as the Window is being
constructed. The exception makes sense the error is limited to loading the XAML document, however it
doesn’t apply to other code such as proxy construction. You can drill down to reach the error by
selecting View Detail…and this will get you to the real exception. Figure 17 illustrates the example where
the certificate reference could not be loaded.

Figure 17: InnerException for the XamlParseException

claimsbasedwpf.codeplex.com Page 26
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

The problem is, this extra drilldown step is really annoying when you are trying to debug your
application. The same problem, by the way, occurs for any exceptions that happen during window
construction, not just proxy initialization. As for proxy construction, the same problem exists if you
initialize the proxy in the Window constructor, and if you initialize a ChannelFactory<T> instance instead
of a generated proxy based on ClientBase<T>:

private ChannelFactory<TodoList.ITodoListService> _ChannelFactory = new


ChannelFactory<TodoList.ITodoListService>("default");

To work around this, you should defer proxy initialization to the Window.Loaded event (or later) such as
in this example:

public partial class MainWindow : Window


{

private ExceptionHandlingProxy _Proxy;

public MainWindow()
{
InitializeComponent();
}

private void window_Loaded(object sender, RoutedEventArgs e)


{
_Proxy = new ExceptionHandlingProxy("default");

claimsbasedwpf.codeplex.com Page 27
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

this._Proxy.ClientCredentials.UserName.UserName = this.Username;
this._Proxy.ClientCredentials.UserName.Password = this.Password;

this._Proxy.Open();

private void window_Closing(object sender, CancelEventArgs e)


{
_Proxy.Dispose();
}
}

After making this change you’ll see the correct exception immediately. For the example
discussed previously Figure 18 illustrates the certificate reference exception, no extra drilling
down required.

Figure 18: An example of a proxy initialization exception thrown during the Window.Loaded
event

Hopefully this little tip helps you to avoid some potentially painful debugging sessions. 

Issuing Claims at the STS


The STS in this example is a custom STS created with Geneva Framework – however in reality the STS
will usually be a platform STS such as that provided by “Geneva” Server. At its core, an active STS is
merely a service exposing one or more WS-Trust endpoints according to one of the following versions of
the protocol: the pre-released version WS-Trust February 2005, or the latest release WS-Trust 1.3. The

claimsbasedwpf.codeplex.com Page 28
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

RP service determines the protocols it supports by exposing endpoints using either


WSFederationHttpBinding or WS2007FederationHttpBinding. When implemented with Geneva
Framework the STS determines protocol support by exposing endpoints with the correct version of the
WS-Trust contract.

From the client developer’s perspective the RP endpoint indicates the correct STS endpoint, proxy
generation provides the necessary configuration to communicate with the STS, and the client developer
(usually) need only collect user credentials to authenticate to the STS when the proxy requests a token.
In this section I will explain some of the semantics of token issuance, and assuming a SAML 1.1 token is
issued – describing some of the important underlying details that are handled by WCF and Geneva
Framework.

Figure 19 captures the communication flow between the Todo List client, the RP-STS and the
TodoListService. An RST is sent to RP-STS to request a token, which returns an RSTR (if all goes well) with
a SAML 1.1 token. The client sends this SAML 1.1 token to the service to be used for authorization.

Figure 19: Core elements in the RST, RSTR, and SAML 1.1 token

claimsbasedwpf.codeplex.com Page 29
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Although you need not write the core plumbing to achieve this scenario, there are a few underlying
details that I want to touch on so that you are familiar.

The RST includes an AppliesTo element which indicates for whom (which RP) the token should be issued.
The STS uses this information to determine if it has a trust relationship with the RP, and if it does, will
typically encrypt the token with matching RP public key. Encryption is not a requirement, but is
recommended. As I have mentioned, the claim types passed in the RST are a hint to the claims the RP
would like issued, however the STS will typically figure out the right claims to issue based on the context
of the call.

The SAML 1.1 token returned in the RSTR includes the following information:

 Issued claims are stored as SAML attributes


 Token lifetime information indicates the date and time range for which the token can be used
 The subject confirmation is usually “holder-of-key” for active federation scenarios, indicating
that a proof key will be used to ensure that the requestor of the token (the client application in
this case) is indeed the sender of the token to the RP service. What this means from a high level
is that a symmetric key will be supplied by the STS, embedded in the SAML token, and returned
separately to the client so that it can sign the message to the RP service with this token. The RP
service can verify that the signature of the message matches the proof key inside the token to
“prove” that the sender was also the requestor of the token.
 The token signature is a hash of the token using the STS private key, to be used to verify that the
token contents have not been tampered with

Since the platform handles this protocol exchange, what you really care about is that the STS has a trust
relationship with the RP service so that they will indeed issue the requested token. Figure 20 shows the
listing for the RP-STS implemented with Geneva Framework. The two key overrides are:

 GetScope() – which checks that the RP indicated by the AppliesTo element is trusted
 GetOutputClaimsIdentity() – which returns a ClaimsIdentity instance with the claims to be issued
for the authenticated user

Figure 20: The RP-STS SecurityTokenService implementation

public class RPSTS : SecurityTokenService


{
public RPSTS(SecurityTokenServiceConfiguration config)
: base( config )
{
}

protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal,


RequestSecurityToken request, Scope scope)

claimsbasedwpf.codeplex.com Page 30
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

{
IClaimsIdentity claimsIdentity = new ClaimsIdentity();

claimsIdentity.Claims.AddRange(CredentialStore.GetClaimsForUser(principal.Identity.Name));

return claimsIdentity;
}

protected override Scope GetScope(Microsoft.IdentityModel.Claims.IClaimsPrincipal


principal, RequestSecurityToken request)
{

Scope scope = new Scope(request.AppliesTo.Uri.AbsoluteUri);


scope.EncryptingCredentials = this.GetCredentialsForAppliesTo(request.AppliesTo);
scope.SigningCredentials = new
X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My,
StoreLocation.LocalMachine, "CN=RPSTS"));

return scope;
}

private X509EncryptingCredentials GetCredentialsForAppliesTo(EndpointAddress appliesTo)


{
if (appliesTo == null || appliesTo.Uri ==null ||
string.IsNullOrEmpty(appliesTo.Uri.AbsolutePath))
{
throw new InvalidRequestException("AppliesTo must be supplied in the RST.");
}

X509EncryptingCredentials creds = null;


if (appliesTo.Uri.AbsoluteUri.StartsWith("http://localhost:8000/TodoListService"))
{
creds = new
X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.TrustedPeople,
StoreLocation.LocalMachine, "CN=RP"));
}
else
throw new InvalidRequestException(String.Format("Invalid relying party address: {0}",
appliesTo.Uri.AbsoluteUri));

return creds;
}

claimsbasedwpf.codeplex.com Page 31
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Authorization at the RP Service


At this point I have discussed how to think about the claims-based security model up front, how the RP
service exposes federation endpoints, how the client generates a proxy to communicate with that
service and the indicated STS, and how the STS issues tokens for trusted RPs. At this point, when the
client application attempts to call the RP service, calls will succeed or fail based on the issued claims –
assuming of course that the service enforces these claims.

Geneva Framework supplies features to WCF services for claims-based authorization. Here is a summary
of what can happen at the service:

 Enable the federation behavior for the ServiceHost instance


 This results in a ClaimsPrincipal created for each request, containing the authenticate user’s
claims
 Classic .NET role-based security will work to authorize access based on the current principal’s
claims

Let’s consider how the TodoListService handles the process. The federation behavior is enabled
declaratively by adding this service behavior:

<federatedServiceHostConfiguration name="TodoList.TodoListService"/>

This requires an extension be registered within the <system.serviceModel> section:

<extensions>
<behaviorExtensions>
<add name="federatedServiceHostConfiguration"
type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement,
Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</behaviorExtensions>
</extensions>

The behavior will look to the <microsoft.identityModel> section for configuration details, and so this
configuration section must be registered:

<configSections>

claimsbasedwpf.codeplex.com Page 32
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

<section name="microsoft.identityModel"
type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection,
Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</configSections>

The actual configuration for the behavior requires only two things for an RP scenario: a list of trusted
issuers and a certificate to be used for decrypting tokens. For the TodoListService the following
configuration is used:

<microsoft.identityModel>
<service name="TodoList.TodoListService">
<issuerNameRegistry type="TodoListHost.TrustedIssuerNameRegistry, TodoListHost"/>
<serviceCertificate>
<certificateReference findValue="CN=RP" storeLocation="LocalMachine"
storeName="My" x509FindType="FindBySubjectDistinguishedName"/>
</serviceCertificate>
</service>
</microsoft.identityModel>

The TrustedIssuerNameRegistry type checks that the RP-STS is the issuer:

public class TrustedIssuerNameRegistry : IssuerNameRegistry


{
public override string GetIssuerName(SecurityToken securityToken)
{
X509SecurityToken x509Token = securityToken as X509SecurityToken;
if (x509Token != null)
{
if (String.Equals(x509Token.Certificate.SubjectName.Name, "CN=RPSTS"))
{
return x509Token.Certificate.SubjectName.Name;
}
}

throw new SecurityTokenException("Untrusted issuer.");


}
}

Lastly, since the service relies on the permission claim type for authorization, this must be
indicated as the role claim type so that classic .NET role-based security checks that use
IPrincipal.IsInRole() functionality will work. You do this by removing and re-adding the SAML 1.1

claimsbasedwpf.codeplex.com Page 33
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

security token handler with the appropriate parameters to replace the default role claim type
as follows:

<securityTokenHandlers>
<remove type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler,
Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
<add type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler,
Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35">
<samlSecurityTokenRequirement >
<roleClaimType
value="http://claimsbasedwpf.codeplex.com/samples/2009/06/claims/permission"/>
</samlSecurityTokenRequirement>
</add>
</securityTokenHandlers>

This is not a requirement, you can always programmatically check the claims – but it is very
convenient to integrate with role-based security techniques such as permission demands and
IsInRole() checks. The TodoListService implements a permission demand at each operation like
this:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,
ConcurrencyMode=ConcurrencyMode.Multiple, UseSynchronizationContext=false)]
public class TodoListService: ITodoListService
{

[PrincipalPermission(SecurityAction.Demand, Role = Constants.Permissions.Read)]


public List<TodoItem> GetItems()
{…}

[PrincipalPermission(SecurityAction.Demand, Role = Constants.Permissions.Create)]


public string CreateItem(TodoItem item)
{…}

[PrincipalPermission(SecurityAction.Demand, Role = Constants.Permissions.Update)]


public void UpdateItem(TodoItem item)
{…}

[PrincipalPermission(SecurityAction.Demand, Role = Constants.Permissions.Delete)]


public void DeleteItem(string id)
{…}

claimsbasedwpf.codeplex.com Page 34
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

This will prevent users from calling operations they haven’t been granted the rights to –
however it would also be nice if the UI prevented the user from accessing those features
proactively. This is the subject of the next section.

WPF Clients and Claims


The stability of the protocols for federated security makes it possible for platforms like WCF and Geneva
Framework to hide the details of the implementation from the developer – and that is the way it should
be. There isn’t, however, a well-defined protocol for supplying the client application with access to the
claims issued to the authenticated user – to be used for authorization. This leaves the client developer
to come up with custom ways to restrict access to features and functionality.

Some of the possible ways a developer might think to gain access to claims at the client are summarized
in Figure 21 – but only the last in the list is acceptable in my books.

Figure 21: Possible ways to access issued claims at the client

Approach Discussion Points


Use the issued token When the STS issues a security token for an RP, the client proxy has access
to this token. In theory that might make it tempting to use this token for
client-side authorization, however there are some flaws in this approach:
 The token might be encrypted for the RP. Sure, the client and RP
may be part of the same domain, but it is not generally acceptable
to distribute private keys to the client machine.
 The token format may not be understood by the client. What if the
token is not a SAML 1.1 token? Should the client care? Not really,
they merely supply the credentials for authentication to the STS and
let the STS decide what token is best for the RP.
 Even if the token format is known, and the token is not encrypted,
the claims issued for the request may not be representative of the
rights the user has across all features and functionality. The claim
issued may only target a particular set of features for a particular
service (among multiple RP services).
Request a display token There is the concept of a DisplayToken that the STS can return with the
issued token. Unlike the issued token whose format may not be known to
the client, the DisplayToken has a well-defined format. CardSpace uses this
to present claims to the user, for example. The problem with the
DisplayToken is that it should really be used to present information to the
user about a set of claims, but not in a format that could be
programmatically reliable. By definition display claims should include a
friendly representation of the issued token’s claims without violating any

claimsbasedwpf.codeplex.com Page 35
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

privacy.
Return a serialized Ok, now we are getting somewhere. The service could, in theory, return the
ClaimsPrincipal ClaimsPrincipal for the request thread or the claims collection held by the
ClaimsPrincipal. There are a few flaws in this approach as well:
 The ClaimsPrincipal and claims collection are not directly
serializable without some extra effort. Ok, we can work around this
one…but…
 The result of serialization will includes a lot more information than
the client really needs, so the wire is bloated unnecessarily.
 The claims issued may differ depending on which RP service is
called. Once again, this may not be representative of the entire
application (all RP services) and what the user can or cannot do.
Different claims may be issued for each service, or even for a
particular operation!
Return a customized Provide a special authorization endpoint that triggers the STS to issue a set
collection of claims of claims representative of the user’s rights across the entire set of RP
services. The call to this service can then return a simple collection of claims
that can be tailored for the application’s requirements. Perhaps some
applications only care about a collection of claim type and claim value pairs.
Others might want to know the issuer. Others might want additional
information.

The advantage of the latter is that you can gather a broader representation of overall application claims
and still return only what the client needs to work with – based on some context. The fact of the matter
is that you need to come up with a model for claims-based authorization that also includes how you
want the client to manage authorization. Then, you can decide how to go about achieving the result. In
the sections to follow I’ll discuss this approach in more detail.

Claims-Based UI Models
As I mentioned earlier, there are many different types of claims that could be valuable to an application:
details about the user, roles and permissions, and any number of other details specific to an application
scenario. Obviously knowledge of the claims you are dealing with must play a role in how you control
access to an application. Ultimately, the RP is responsible for transforming claims into a format that is
useful both to the service, and to the client, to restrict access to features and functionality.

Before I discuss the Todo List application scenario, I’ll describe a richer scenario that involves an
application with multiple RP services. Figure 22 illustrates such a scenario where the RP exposes services
to control access to Customers, Orders and Reports. The RP-STS is responsible for issuing tokens for
users that interact with these services, but may issue different claims depending on the service being
called based on the value of AppliesTo in the RST.

Figure 22: A scenario where the RP exposes multiple services and the RP-STS issues tokens for each of
them accordingly

claimsbasedwpf.codeplex.com Page 36
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

What would the claims-based security model look like for this service? Here are some options:

 All users may be globally assigned Create, Read, Update and Delete claims that apply to all
application resources
 The application may grant CRUD rights differently per resource, and so perhaps permission
claims expand to CreateCustomers, CreateOrders, CreateReports, and similar for Read, Update
and Delete rights.

Assuming the latter case, as Figure 22 illustrates, the claims issued by the RP-STS will depend which
service is being called, which means it will be challenging for the UI to filter access to the entire set of
application features.

One way to decouple the idea of claims issued for a particular RP service, and claims issued for the UI, is
to create a client authorization service of some sort that is a specific RP service that returns client-
friendly claims for authorization according to the application’s needs. This service would be known to
the RP-STS as an AppliesTo that triggers returning some sort of global set of claims for the authenticated
user. Figure 23 illustrates this model.

Figure 23: Using an authorization service to return claims for the authenticated user

claimsbasedwpf.codeplex.com Page 37
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

The sections to follow will explain how this model is implemented for the Todo List application discussed
throughout this whitepaper.

Client Authorization Service


Implementing a client authorization service to facilitate supplying claims to the client application is a
completely custom implementation for reasons I already discussed. That means it is up to you to decide
what kinds of requests this service should support so that the appropriate claims can be returned. For
the Todo List application there is only a single RP service – the TodoListService. That means a simple
GetClaims() function will probably suffice since there isn’t the need to differentiate sets of functionality
so that the RP-STS can issue different claims according to context.

For this example I created a service contract called IClientAuthorization as follows:

claimsbasedwpf.codeplex.com Page 38
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

[ServiceContract(Namespace=Constants.Namespaces.ServiceContractNS)]
public interface IClientAuthorization
{
[OperationContract]
List<ClientClaim> GetClaims();
}

GetClaims() will return a collection of ClientClaim instances – another custom type I created for this
scenario as shown here:

[DataContract(Namespace = Constants.Namespaces.DataContractNS)]
public class ClientClaim
{
[DataMember(Order=1, IsRequired=true)]
public string ClaimType { get; set; }
[DataMember(Order = 2, IsRequired = true)]
public string ClaimValue { get; set; }
}

You can easily add the issuer or some form of lifetime information to each claims as appropriate to your
application scenario, and I discussed some of these options earlier.

The implementation of ClientAuthorizationService is shown in Figure 24. When the client calls
GetClaims() the proxy will first call the RP-STS passing a username and password for authentication as it
does for the TodoListService. This will result in a set of claims for the application as a whole, not
specifically targeting the TodoListService. GetClaims() accesses these issued claims through the
ClaimsPrincipal attached to the request thread – and builds a collection of ClientClaim instances to
return.

Figure 24: Implementation of IClientAuthorization

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,
ConcurrencyMode=ConcurrencyMode.Multiple, UseSynchronizationContext=false)]
public class ClientAuthorizationService: IClientAuthorization
{

#region IClientAuthorization Members

public List<ClientClaim> GetClaims()


{

claimsbasedwpf.codeplex.com Page 39
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

List<ClientClaim> clientClaims = new List<ClientClaim>();

ClaimsPrincipal p = Thread.CurrentPrincipal as ClaimsPrincipal;


foreach (IClaimsIdentity identity in p.Identities)
{
if (identity.Claims != null)
{
foreach (Claim c in identity.Claims)
{
if (c.ClaimType.Contains(Constants.ClaimTypes.Permission))
{
clientClaims.Add(new ClientClaim { ClaimType = Constants.ClaimTypes.Permission,
ClaimValue = c.Value });
}
}
}
}

return clientClaims;
}
}

Even if the claims returned by the RP-STS are the same for the ClientAuthorizationService and the
TodoListService now – this could change in future if additional RP services are added to the application.
The ClientAuthorizationService could be used to gather additional claims later on. Thus, decoupling the
service used to return claims to the client from a particular RP service is a good idea. This allows the STS
to evolve the set of global claims as new RP services are brought online.

Claims-Based Access Control


Once you have designed your claims-based model, and created an authorization service that can be
used to gather the right claims for the client, the next step is to use those claims to restrict access to
features and functionality in your WPF clients. A big part of this is hiding, showing or disabling UI
elements according to the appropriate claims. This can be done programmatically by writing code to
hide, show, enable or disable – or declaratively through WPF bindings.

Consider the claims required to enable features in the Todo List Client shown in Figure 25. The following
lists each claim and the rights it grants the user in the UI:

 Read – this claim is required for the user to view the application
 Create – this claim allows the new item panel to be visible, otherwise it will be collapsed
 Update – this claim allows editing grid items, otherwise the user cannot select text or enter any
new values in any column

claimsbasedwpf.codeplex.com Page 40
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

 Delete – this claim controls if the Delete Task button is shown or hidden

Figure 25: Claims authorization in the Todo List client

To explain how bindings can be used to for claims-based security, let me dissect how the DataGrid
visibility is controlled based on the presence of the Read claim. Here is the Binding statement for the
control’s IsReadOnly property:

IsReadOnly="{Binding Path=ClientClaims, Converter={StaticResource


ClaimsToIsReadOnlyConverter}, ElementName=window, Mode=Default}"

The Path and ElementName respectively indicate that the public ClientClaims property exposed by the
window associated with this XAML file will be used in the property binding. To support this the window
exposes a ClientClaims property defined as follows:

public List<ClientClaim> ClientClaims { get; set; }

The Converter is the key to adequately converting the bound property, a List<ClientClaim> type, into a
true or false value for the IsReadOnly property. When the property is evaluated, the IValueConverter

claimsbasedwpf.codeplex.com Page 41
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

type specified in the Converter property is invoked. More specifically, the Convert() function of the
ClaimsToIsReadOnlyConverter shown in Figure 26 is called.

Figure 26: The implementation of ClaimsToIsReadOnlyConverter

class ClaimsToIsReadOnlyConverter : IValueConverter


{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return true;

List<ClientClaim> actualClaims = (List<ClientClaim>)value;


var results = from c in actualClaims
where c.ClaimType == Constants.ClaimTypes.Permission && c.ClaimValue ==
Constants.Permissions.Update
select c.ClaimValue;
if (results != null && results.Count() > 0)
return false;

return true;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo


culture)
{
throw new NotImplementedException();
}
}

The logic works as follows:

 If the ClientClaims property is null, true is returned indicating that Update rights have not been
granted yet since there are no claims to work with.
 If there is a collection of claims, the collection is queried to see if the Update claim exists and if
so Convert() returns false indicating Update rights have been granted.
 If not, Convert() returns true since Update rights were not granted.

The result is that the IsReadOnly property of the DataGrid is controlled without writing any additional
code. The next trick, however, is updating the value when claims have changed. This is done by
implementing INotifyPropertyChanged on the window (which owns the ClientClaims property).
Whenever the ClientClaims are reevaluated if the PropertyChanged event is fired then the DataGrid will
reevaluate by calling the converter again. Figure 27 shows the window listing showing only aspects

claimsbasedwpf.codeplex.com Page 42
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

relevant to this discussion. Specifically, the PropertyChanged event is triggered before the window is
loaded since claims haven’t been collected yet, and this will hide appropriate items; and again each time
the proxies are initialized. If there were additional code to handle session and token expiry this would
also be a good place to trigger the PropertyChanged event for the ClientClaims property.

Figure 27: Triggering the PropertyChanged event to bind the UI to the ClientClaims property

public partial class MainWindow : Window, INotifyPropertyChanged


{

private TodoListServiceProxy _Proxy = new TodoListServiceProxy("todolistdefault");


private ClientAuthorizationProxy _ClientAuthProxy = new
ClientAuthorizationProxy("clientauthdefault");
public List<ClientClaim> ClientClaims { get; set; }

public MainWindow()
{
InitializeComponent();
NotifyPropertyChanged("ClientClaims");
}

private void InitializeProxies()


{
try
{
this._ClientAuthProxy.ClientCredentials.UserName.UserName = this.Username;
this._ClientAuthProxy.ClientCredentials.UserName.Password = this.Password;
this._ClientAuthProxy.Open();

this._Proxy.ClientCredentials.UserName.UserName = this.Username;
this._Proxy.ClientCredentials.UserName.Password = this.Password;
this._Proxy.Open();

this.ClientClaims = this._ClientAuthProxy.GetClaims();
NotifyPropertyChanged("ClientClaims");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

#region INotifyPropertyChanged Members

claimsbasedwpf.codeplex.com Page 43
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(string property)


{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
#endregion

The ClaimsToIsReadOnly converter is defined in the <Window.Resources> section along with the
ClaimsToVisibilityConverter as shown here:

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:TodoList_WpfClient_TodoList="clr-namespace:WpfClient.TodoList"
xmlns:TodoList_WpfClient_Utilities="clr-namespace:WpfClient.Utilities"
xmlns:TodoList_WpfClient_Security="clr-namespace:WpfClient.Security"
xmlns:TodoList_WpfClient_DesignTime="clr-namespace:WpfClient.DesignTime"
x:Class="WpfClient.MainWindow"
Title="Todo List Client"
x:Name="window" d:DesignHeight="498" Background="{DynamicResource
WindowBackgroundBrush}" MinWidth="671" d:DesignWidth="672" Closing="window_Closing"
Loaded="window_Loaded">
<Window.Resources>
<TodoList_WpfClient_Security:ClaimsToIsReadOnlyConverter
x:Key="ClaimsToIsReadOnlyConverter"/>
<TodoList_WpfClient_Security:ClaimsToVisibilityConverter
x:Key="ClaimsToVisibilityConverter"/>
<TodoList_WpfClient_Utilities:StatusToTextConverter x:Key="StatusToTextConverter"/>
</Window.Resources>

</Window>

claimsbasedwpf.codeplex.com Page 44
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

The namespace for the component is defined earlier in the XAML document, as is required for all
components. The ClaimsToIsReadOnlyConverter is used by the IsReadOnly property of the DataGrid, and
by the IsReadOnly property of the description TextBox shown when an item is selected in the DataGrid.
The ClaimsToVisibilityConverter is used to set the Visibility property of the DataGrid, the Delete button,
and the new item panel which is encapsulated in a <Border> element. The following show these
snippets of the XAML document without the irrelevant properties and clutter.

DataGrid bindings:

<my:DataGrid x:Name="TodoDataGrid" IsReadOnly="{Binding Path=ClientClaims,


Converter={StaticResource ClaimsToIsReadOnlyConverter}, ElementName=window,
Mode=Default}" Visibility="{Binding Path=ClientClaims, Converter={StaticResource
ClaimsToVisibilityConverter}, ConverterParameter=Read, ElementName=window,
Mode=Default}" >

Description TextBox bindings:

<TextBox IsReadOnly="{Binding Path=ClientClaims, Converter={StaticResource


ClaimsToIsReadOnlyConverter}, ElementName=window, Mode=Default}" />

Delete Button bindings:

<Button Visibility="{Binding Path=ClientClaims, Converter={StaticResource


ClaimsToVisibilityConverter}, ConverterParameter=Delete, ElementName=window,
Mode=Default}" />

New item Border bindings:

<Border Margin="8,8,8,3.04" BorderThickness="1,1,1,1" CornerRadius="4,4,4,4"


BorderBrush="{DynamicResource NormalBorderBrush}" Padding="4,4,4,4" Visibility="{Binding
Path=ClientClaims, Converter={StaticResource ClaimsToVisibilityConverter},
ConverterParameter=Create, ElementName=window, Mode=Default}">
<Grid x:Name="NewItemPanel">…<Grid>
</Border>

The ClaimsToVisibilityConverter is also an IValueConverter that has a slightly different implementation.


In this case, the WPF binding passes a parameter indicating a comma delimited list of required claims for
visibility to be true, and the Convert() implementation uses this parameter to search the ClientClaims
collection:

claimsbasedwpf.codeplex.com Page 45
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Visibility visibilitySetting = Visibility.Visible;

if (value == null) return Visibility.Collapsed;

List<ClientClaim> actualClaims = (List<ClientClaim>)value;

string claimsParameter = (string)parameter;


List<string> requestedClaims = new List<string>(claimsParameter.Split(','));

requestedClaims.ForEach(x=>{
var results = from c in actualClaims
where c.ClaimType == Constants.ClaimTypes.Permission &&
c.ClaimValue.ToLower().Contains(x.ToLower())
select c.ClaimValue;
if (results == null || results.Count() == 0)
visibilitySetting = Visibility.Collapsed;
});

return visibilitySetting;
}

In this implementation, the parameter passed from the WPF binding is not the actual claim Uri – only
the suffix “Create”, “Read”, “Update”, or “Delete” is required. This is used to match up the suffix of the
claim value – but you can pattern this as appropriate to your application.

The parameter is passed to the converter parameter as shown here:

<Button Visibility="{Binding Path=ClientClaims, Converter={StaticResource


ClaimsToVisibilityConverter}, ConverterParameter=Delete, ElementName=window,
Mode=Default}" />

Using declarative bindings to control access to features is something unique to WPF. Although quite
useful, that is not to say that imperative authorization checks aren’t also useful. There are many reasons
why an imperative check may be necessary:

 For requirements that cannot be easily represented as a single claim. Perhaps the user has
rights to create a report, but this is only allowed during business hours. The Create Report
button could be disabled or hidden if the user doesn’t have the CreateReport right. If they do
have the CreateReport right, the code still must check the time of day before proceeding.

claimsbasedwpf.codeplex.com Page 46
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

 To control access to functionality in dependent assemblies. Client code could use a library that
enforces claims-based security rules using .NET role-based security techniques discussed earlier
for the TodoListService. For example declarative permission demands, imperative permission
demands, or IsInRole() checks could be performed.

To support imperative demands you should initialize a security principal with the appropriate claims-
based “roles” at the client. At the server, ASP.NET and WCF handle initialize every request thread with a
security principal so that we can do role-based permission demands. By default, the client thread does
not have a security principal, unless you explicitly construct one and provide it with the appropriate
roles.

After gathering the claims from the service, you can easily construct a GenericPrincipal and attach it to
the client thread as follows:

this.ClientClaims = this._ClientAuthProxy.GetClaims();

var results = from item in this.ClientClaims


where item.ClaimType == Constants.ClaimTypes.Permission
select item.ClaimValue;
GenericIdentity clientIdentity = new GenericIdentity(this.Username, "CN=RPSTS");
GenericPrincipal clientPrincipal = new GenericPrincipal(clientIdentity, results.ToArray());
Thread.CurrentPrincipal = clientPrincipal;

Permission claims are assigned to the roles collection of the GenericPrincipal, which makes it possible to
check claims with IsInRole(). For example, to check if the user has a particular claim:

Thread.CurrentPrincipal.IsInRole(Constants.Permissions.Delete);

Of course Geneva Framework provides a ClaimsPrincipal type that could be used instead of a
GenericPrincipal – with first class support for claims. This requires you to add Geneva Framework
assemblies as a dependency at the client.

Caching Security Tokens


Inevitably you will encounter situations that require reusing or caching security tokens in your WPF
clients. Some possible reasons include:

 To avoid prompting the user for credentials more than once to initialize multiple proxies for
multiple RP services
 To avoid unnecessary trips to the STS to request a security token for multiple proxies for
multiple RP services
 To avoid extra prompting or STS trips when recreating proxies if the channel times out or is
faulted for some reason

claimsbasedwpf.codeplex.com Page 47
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Since tokens are issued for a particular RP, they can only be shared across RP services if the following is
true:

 Assuming tokens are encrypted for the RP, all RP services must share the same service
certificate.
 The STS must be aware of all relevant RP addresses used in the AppliesTo of the RST (discussed
earlier) and be able to issue a token with claims that will be useful across all RP services. A
workaround to this would be to always use an authentication service to issue a token relevant to
all RP services as indicated in Figure 28 for the Todo List application.
 If tokens are issued for one RP service and to be received by another, the service must allow
tokens that potentially have an AudienceUri indicating one of the other RP services.

Assuming you can get past these obstacles, read on and I will discuss how to share tokens among related
proxies. As part of the discussion I’ll cover handling session timeouts and token expiry as well.

Figure 28: Sharing tokens between the ClientAuthorizationService and the TodoListService

claimsbasedwpf.codeplex.com Page 48
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

ClientCredentials and Issued Tokens


Every proxy (channel) exposes a ClientCredentials property which is used to supply information required
to authenticate to the service. For example, you might set the Windows, UserName or ClientCertificate
properties of the ClientCredentials type before making the first call to the service. The following code
illustrates setting the UserName credential:

this._ClientAuthProxy = new ClientAuthorizationProxy("clientauthdefault");


this._ClientAuthProxy.ClientCredentials.UserName.UserName = this.Username;
this._ClientAuthProxy.ClientCredentials.UserName.Password = this.Password;

claimsbasedwpf.codeplex.com Page 49
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

In federated security scenarios, you will still set the appropriate Windows, UserName or ClientCertificate
credentials if the STS endpoint expects to authenticate users with one of those credential types (keeping
in mind that there are other authentication options such as HttpDigest or another IssuedToken from a
chained STS). In addition, the ClientCredentials type exposes an IssuedToken property which supplies
information about the STS to authenticate to such as its address and binding requirements. This
information can be initialized programmatically, however when you generate a proxy as I’ve discussed,
this information is initialized from the federated binding configuration.

Figure 29 illustrates how the issued token is acquired. The proxy has a reference to a ClientCredentials
instance and supplies the user’s credentials required to authenticate to the STS. The runtime triggers the
CreateSecurityTokenManager() method of ClientCredentials to construct a SecurityTokenManager –
specifically the ClientCredentialsSecurityTokenManager. A SecurityTokenManager type is responsible for
provisioning, authenticating and serializing tokens. In this scenario, we are interested in overriding how
tokens are provisioned. The SecurityTokenManager type supplies an implementation for
CreateSecurityTokenProvider() to construct the appropriate token provider responsible for supplying
tokens for all outgoing calls. In this case, the IssuedSecurityTokenProvider is used to request an issued
token from the STS indicated in the ClientCredentials configuration. This token is then used for the call
to the service.

Figure 29: Requesting an issued token through the IssuedSecurityTokenProvider

The IssuedToken property of ClientCredentials is an instance of the IssuedTokenClientCredential type.


This type has a property to control caching tokens: CachedIssuedTokens. By default, this property is set
to true, which means that tokens will be cached until they expire, and reused to call the service instead
of re-authenticating to the STS. This reduces overhead for an individual proxy, but does not provide the
ability to share that cached token across multiple proxies. To share an issued token across proxies, you
can create a custom IssuedSecurityTokenProvider that will draw a token from a shared cache it one
exists, rather than calling the STS for each proxy.

claimsbasedwpf.codeplex.com Page 50
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Caching Issued Tokens for Multiple Proxies


To produce a shared token cache at the client a custom IssuedSecurityTokenProvider can be created to
check the local token cache prior to calling the STS to request a token. To install a custom
IssuedSecurityTokenProvider, you must also create a custom ClientCredentialsSecurityTokenManager,
and ClientCredentials type. The custom ClientCredentials type can be shared between proxies if the
configuration requirements are identical, and this will lead both proxies to the same custom
IssuedSecurityTokenProvider – thus the same cached token if one exists in the token cache. The
architecture for this scenario is illustrated in Figure 30.

Figure 30: Sharing CachedClientCredentials between two proxies

Here is a summary of the new types created:

 SecurityTokenCache: a custom type that holds a SecurityToken reference and issued an event
when the token has changed so the client application can respond if interested
 CachedClientCredentials: a custom ClientCredentials type that holds a reference to the
SecurityTokenCache and overrides CreateSecurityTokenManager() to create a custom
CachedClientCredentialsSecurityTokenManager
 CachedClientCredentialsSecurityTokenManager: a custom
ClientCredentialsSecurityTokenManager type that holds a reference of the SecurityTokenCache

claimsbasedwpf.codeplex.com Page 51
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

and overrides CreateSecurityTokenProvider() to create a custom


CachedIssuedSecurityTokenProvider
 CachedIssuedSecurityTokenProvider: a custom IssuedSecurityTokenProvider that holds a
reference to the SecurityTokenCache and overrides GetTokenCore() to customize how the
issued token is acquired – returning the cached token if valid, otherwise calling the STS for a
new token and updating the cache

Another possible view of the architecture in Figure 30 is shown in Figure 31. In my view this is a better
way to share the token cache between two proxies using the same customized object model just
summarized. In this case each proxy gets a new instance of the CachedClientCredentials,
CachedClientCredentialsSecurityTokenManager, and CachedIssuedSecurityTokenManager – however
the same SecurityTokenCache. This is a bit more pure since the item the proxies are really sharing is the
issued token, not the other configuration settings – and though they may be the same for all proxies
calling a group of RP services, it is probably best to decouple those elements that may differ.

Figure 31: Using a new CachedClientCredentials for each proxy, still sharing the token cache

In the next sections I’ll explain the code that implements this scenario.

SecurityTokenCache
There are many possible views for how to create a custom security token cache. You might have a very
complicated client application that calls many different groups of services and requires caching issued
tokens for each group. Or, you may just have an application that calls a number of related RP services
and each can share the issued token. The latter is the more common scenario in my experience, and so I
have kept this implementation very simple. Figure 32 shows the code for a custom SecurityTokenCache.

claimsbasedwpf.codeplex.com Page 52
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Figure 32: SecurityTokenCache implementation

public class SecurityTokenCache


{
private SecurityToken _Token;
public SecurityToken Token
{
get
{
return _Token;
}
set
{
_Token = value;
if (TokenUpdated != null)
{
TokenUpdated(this, null);
}
}
}

public event EventHandler TokenUpdated;


}

I’ve made some assumptions in this implementation:

 The client application is responsible for constructing however many of these


SecurityTokenCache instances it requires for the number of issued tokens it needs to create for
related groups of proxies. This will usually be just one.
 The client application may want to know when the token is updated by the
CachedIssuedSecurityTokenProvider – and so the TokenUpdated event is fired whenever this
happens. For example, the client may want to update its client-side claims collection (discussed
earlier).

This type is supplied to the CachedClientCredentials type when constructed.

CachedClientCredentials
The CachedClientCredentials type is responsible for creating a custom SecurityTokenManager, which will
in turn create a custom IssuedSecurityTokenProvider for this scenario. The implementation of the
CachedClientCredentials type is shown in Figure 33. It holds a reference to the SecurityTokenCache and
passes so that the custom CachedClientCredentialsSecurityTokenManager has access to it once

claimsbasedwpf.codeplex.com Page 53
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

constructed. The CreateSecurityTokenManager() override is the heart of this custom implementation –


shown highlighted in Figure 33.

Figure 33: CachedClientCredentials implementation

public class CachedClientCredentials: ClientCredentials


{
public SecurityTokenCache TokenCache { get; private set; }

public CachedClientCredentials(SecurityTokenCache tokenCache): base()


{
this.TokenCache = tokenCache;
}

public CachedClientCredentials(SecurityTokenCache tokenCache, ClientCredentials


clientCredentials)
: base(clientCredentials)
{
this.TokenCache = tokenCache;
}

public CachedClientCredentials(CachedClientCredentials clientCredentials):


base(clientCredentials)
{
this.TokenCache = clientCredentials.TokenCache;
}

public override System.IdentityModel.Selectors.SecurityTokenManager


CreateSecurityTokenManager()
{
return new
CachedClientCredentialsSecurityTokenManager((CachedClientCredentials)this.Clone());

protected override ClientCredentials CloneCore()


{
return new CachedClientCredentials(this);
}
}

The client code will construct a new CachedClientCredentials type and pass in the original
ClientCredentials type to preserve any settings initialized from configuration. Figure 34 shows the code

claimsbasedwpf.codeplex.com Page 54
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

to create the token cache, create a proxy, remove the original ClientCredentials behavior, create a new
CachedClientCredentialsBehavior passing the token cache and original behavior, and then set up the
UserName credentials to supply credentials to call the STS.

Figure 34: Initializing the CachedClientCredentials type

this.TokenCache = new SecurityTokenCache();

this._Proxy = new TodoListServiceProxy("todolistdefault");

ClientCredentials oldCreds = this._Proxy.Endpoint.Behaviors.Remove<ClientCredentials>();


CachedClientCredentials newCreds = new CachedClientCredentials(this.TokenCache, oldCreds);
this._Proxy.Endpoint.Behaviors.Add(newCreds);
this._Proxy.ClientCredentials.UserName.UserName = this.Username;
this._Proxy.ClientCredentials.UserName.Password = this.Password;
this._Proxy.Open();

Shortly I’ll describe how to share this between proxies and respond to updated tokens.

CachedClientCredentialsSecurityTokenManager
As I mentioned, the CachedClientCredentials type creates a custom SecurityTokenManager – the
CachedClientCredentialsSecurityTokenManager. The heart of this implementation is the override to
CreateSecurityTokenProvider() – which returns a new CachedIssuedSecurityTokenProvider to the
runtime. Figure 35 shows this implementation.

Figure 35: CachedClientCredentialsSecurityTokenManager implementation

public class CachedClientCredentialsSecurityTokenManager :


ClientCredentialsSecurityTokenManager
{
public CachedClientCredentialsSecurityTokenManager(CachedClientCredentials
clientCredentials): base(clientCredentials)
{
}

public override System.IdentityModel.Selectors.SecurityTokenProvider


CreateSecurityTokenProvider(System.IdentityModel.Selectors.SecurityTokenRequirement
tokenRequirement)
{
if (!this.IsIssuedSecurityTokenRequirement(tokenRequirement))
return base.CreateSecurityTokenProvider(tokenRequirement);

IssuedSecurityTokenProvider provider =
base.CreateSecurityTokenProvider(tokenRequirement) as IssuedSecurityTokenProvider;

claimsbasedwpf.codeplex.com Page 55
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

CachedIssuedSecurityTokenProvider cachedProvider = new


CachedIssuedSecurityTokenProvider(provider, (CachedClientCredentials)this.ClientCredentials);
return cachedProvider;
}

One of the things you’ll notice in the implementation is that a custom provider is only created if the
token requirement is for an issued token. This can be verified by calling the
IsIssuedSecurityTokenRequirement() method of the SecurityTokenManager type. Note that the
CachedIssuedSecurityTokenProvider is passed a reference to the CachedClientCredentials instance so
that it has access to the cached token.

CachedIssuedSecurityTokenProvider
A partial listing of the CachedIssuedSecurityTokenProvider is shown in Figure 36. I have omitted some of
the noise related to implementing ICommunicationObject and IDisposable. The GetTokenCore() override
is where the magic happens. The code checks to see if there is a valid security token in the cache, and if
so returns it. If a valid token doesn’t exist, the base functionality to retrieve a token is called and the
token cache is updated. The token is considered valid if its ValidTo property is greater than the current
UTC time.

Figure 36: CachedIssuedSecurityTokenProvider implementation

public class CachedIssuedSecurityTokenProvider: IssuedSecurityTokenProvider,


ICommunicationObject, IDisposable
{
private CachedClientCredentials ClientCredentials { get; set; }
private IssuedSecurityTokenProvider InnerProvider {get; set;}

public CachedIssuedSecurityTokenProvider(IssuedSecurityTokenProvider provider,


CachedClientCredentials clientCredentials):base()
{
this.InnerProvider = provider;
this.ClientCredentials = clientCredentials;

this.CacheIssuedTokens = provider.CacheIssuedTokens;
this.IdentityVerifier = provider.IdentityVerifier;
this.IssuedTokenRenewalThresholdPercentage =
provider.IssuedTokenRenewalThresholdPercentage;
this.IssuerAddress = provider.IssuerAddress;
this.IssuerBinding = provider.IssuerBinding;

claimsbasedwpf.codeplex.com Page 56
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

foreach (IEndpointBehavior item in provider.IssuerChannelBehaviors)


this.IssuerChannelBehaviors.Add(item);

this.KeyEntropyMode = provider.KeyEntropyMode;
this.MaxIssuedTokenCachingTime = provider.MaxIssuedTokenCachingTime;
this.MessageSecurityVersion = provider.MessageSecurityVersion;
this.SecurityAlgorithmSuite = provider.SecurityAlgorithmSuite;
this.SecurityTokenSerializer = provider.SecurityTokenSerializer;
this.TargetAddress = provider.TargetAddress;

foreach (XmlElement item in provider.TokenRequestParameters)


this.TokenRequestParameters.Add(item);

protected override System.IdentityModel.Tokens.SecurityToken GetTokenCore(TimeSpan


timeout)
{
SecurityToken securityToken = null;

if (this.ValidTokenInCache(this.ClientCredentials.TokenCache.Token))
{
securityToken = this.ClientCredentials.TokenCache.Token;
}
else
{
securityToken = this.InnerProvider.GetToken(timeout);
this.ClientCredentials.TokenCache.Token = securityToken;
}

return securityToken;
}

private bool ValidTokenInCache(SecurityToken token)


{
if (token == null)
return false;

return (DateTime.UtcNow <= token.ValidTo.ToUniversalTime());


}

claimsbasedwpf.codeplex.com Page 57
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

Sharing CachedClientCredentials and Updating Client Claims


Figure 31 illustrated a design where each proxy has its own CachedClientCredentials reference, but
shared the SecurityTokenCache. Figure 37 illustrates the code to achieve this by initializing each instance
of the CachedClientCredentials with the same SecurityTokenCache instance. The code also illustrates
gathering client claims (as discussed earlier) and hooking the TokenUpdated event so that client claims
can be refreshed if a new token is retrieved.

Figure 37: Sharing the token cache between proxies

this.TokenCache = new SecurityTokenCache();

this._Proxy = new TodoListServiceProxy("todolistdefault");

ClientCredentials oldCreds = this._Proxy.Endpoint.Behaviors.Remove<ClientCredentials>();


CachedClientCredentials newCreds = new CachedClientCredentials(this.TokenCache, oldCreds);
this._Proxy.Endpoint.Behaviors.Add(newCreds);
this._Proxy.ClientCredentials.UserName.UserName = this.Username;
this._Proxy.ClientCredentials.UserName.Password = this.Password;
this._Proxy.Open();

_ClientAuthProxy = new ClientAuthorizationProxy("clientauthdefault");


ClientCredentials oldCreds =
this._ClientAuthProxy.Endpoint.Behaviors.Remove<ClientCredentials>();
newCreds = new CachedClientCredentials(this.TokenCache, oldCreds);
this._ClientAuthProxy.Endpoint.Behaviors.Add(newCreds);
this._ClientAuthProxy.ClientCredentials.UserName.UserName = this.Username;
this._ClientAuthProxy.ClientCredentials.UserName.Password = this.Password;
this._ClientAuthProxy.Open();

this.ClientClaims = this._ClientAuthProxy.GetClaims();
NotifyPropertyChanged("ClientClaims");
this.TokenCache.TokenUpdated += new EventHandler(TokenCache_TokenUpdated);

When the application is first loaded and each proxy is initialized, the first call to retrieve a token will
populate the cache. In this scenario, the ClientAuthorizationProxy instance calls the GetClaims()
operation to retrieve client claims based on the issued token. After retrieving the claims the first time,
the client subscribes to the TokenUpdated event exposed by the SecurityTokenCache so that future
updates to the token will also update the local claims. Here is the event handler that does the work:

void TokenCache_TokenUpdated(object sender, EventArgs e)


{

claimsbasedwpf.codeplex.com Page 58
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

try
{
this.ClientClaims = this._ClientAuthProxy.GetClaims();
NotifyPropertyChanged("ClientClaims");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

Note that after updating the ClientClaims property to keep it in sync with the current cached security
token, a UI update is triggered with NotifyPropertyChanged – so that the XAML will rebind properties
based on the latest claims.

Session and Token Lifetime


At this point I’ve discussed how to share a cached token at the client with multiple proxies and provided
one approach to synchronizing client-side claims with the latest token – but there is one more issue that
can bite you with federated security scenarios and that is secure session timeout and faulted channels.

Any time a transport session exists it is subject to timeout at the server when the channel is inactive. In
addition, any uncaught exceptions thrown at the service will fault the service channel which results in
the proxy becoming unusable. The interesting thing is that the user may not necessarily be interested in
knowing about timeouts or communication exceptions – and just prefer that the application create a
new channel so they can keep working with the application. Based on the implementation I have
discussed thus far we know that an invalid token will trigger another call to the STS to retrieve a fresh
issued token – but what happens in these other two scenarios?

As for session timeout, the client may not be aware of it until trying to make a call to the service – at
which point the call fails. Since there is no way to confirm he failed call was the result of a timeout, what
we want is for the failed call to be retried after recreating the proxy. If the retry fails we have a bigger
communication issue, but if it succeeds a new token is issued, the cache is updated, the client claims are
updated, the UI is rebound and all is well in the world.

If an exception is thrown by the service, and that exception is not a CommunicationException, the user
should be presented with the error but the next attempt to use the proxy will fail because the channel is
in a faulted state. The user doesn’t need to know about this as they were already informed of the
originating exception that caused the faulted channel. So, what we want is to recreate the proxy when
the channel is faulted and if the next call executes properly – once again things are well in the world.

I’m providing only a high-level summary of this issue because I have discussed it in greater detail in a
separate whitepaper and in a few short webcasts at http://wcfguidanceforwpf.codeplex.com. In
addition, I have created an ExceptionHandlingWCFProxyGenerator at

claimsbasedwpf.codeplex.com Page 59
Building Claims-Based WPF Applications
Michele Leroux Bustamante, June 2009

http://wcfproxygenerator.codeplex.com that automates creating a special proxy base class that handles
these specific issues and allows you to shield the user from unnecessary exceptions. The side-benefit is
that the same proxy also helps us to recreate gather a new issued token when the channel is faulted.

Summary
In this whitepaper I attempted to summarize a very big topic from the perspective of the WPF developer
that could be new to federated security scenarios – so that you could have a single place to get up to
speed before discussing specific implementations that would be useful to your federated WPF clients. I
talked about the process of building your first federated client, how to build a claims-based
authorization model at the client with some ideas for a possible implementation, and talked about some
other common issues around sharing issued tokens and dealing with all of these features together in a
single application. The reference samples for this discussion are located on the web site at
http://claimsbasedwpf.codeplex.com so that you can take a closer look. Enjoy!

claimsbasedwpf.codeplex.com Page 60

Вам также может понравиться