Advanced ASP.NET Programming for Windows Identity Foundation

  • 9/15/2010
This chapter from Programming Windows Identity Foundation takes a concrete approach to WIF programming, tackling many important problems and scenarios you might encounter when securing ASP.NET applications.

Now that most technicalities are out of the way, we can focus on intended usage of the product for addressing a wider range of scenarios.

This chapter resumes the architectural considerations that drove Part I of the book, “Windows Identity Foundation for Everybody,” by tackling more complex situations. I’ll assume you are now familiar with the flow described in Chapter 3, “WIF Processing Pipeline in ASP.NET.” I’ll give you concrete indications about how to customize the default behavior of Windows Identity Foundation (WIF) to obtain the desired effect for every given scenario.

Using claims-based identity in your application is, for the most part, the art of choosing who to outsource authentication to and providing just the right amount of information for influencing the process. This chapter will not exhaust all the possible ways you can customize WIF—far from it. However, it will equip you with the principles you need to confidently explore new scenarios on your own.

The first section, “More About Externalizing Authentication,” takes a deeper look at the entities to which you can outsource authentication for your application. I’ll go beyond the simplifications offered so far, introducing the idea of multiple provider types. A lot of the discussion will be at the architectural level, helping you with the design choices in your solutions. However, hardcore coders should not fear! The section also dives deep into the Security Token Service (STS) project template that comes with the WIF SDK. Although in real scenarios you’ll rarely need to create a custom STS, given that more often than not you’ll rely on off-the-shelf products such as Active Directory Federation Services 2.0 (ADFS 2.0), you’ll find it useful to see a concrete example of how the architectural considerations mentioned are reflected in code.

The “Single Sign-on, Single Sign-out, and Sessions” section explores techniques that reduce the need for users to explicitly enter their credentials when visiting affiliated Web sites and shows how to clean up multiple sessions at once. One specific case, sessions with sliding validity, is the occasion for a deeper look at how WIF handles sessions.

The “Federation” section dissects the pattern that is most widely used for handling access across multiple organizations. I’ll cover more in depth the use of STSes for processing claims, and we’ll tackle the problem of deciding who should authenticate the user when there are many identity providers (IPs) to choose from (something known as the home realm discovery problem). The solutions to those problems can be easily generalized to any situation in which the relying party (RP)—which was discussed in Chapter 3—needs to communicate options to the IP. I’ll demonstrate that with another example: the explicit request for a certain authentication level.

The “Claims Processing at the RP” section closes the chapter by describing how to use Windows Identity Foundation for preprocessing the claims received from the identity provider. I’ll briefly revisit the claims-based authorization flow—introduced in minimal terms in Chapter 2, “Core ASP.NET programming.” Then I’ll show you how to filter and enrich the IClaimsPrincipal before the application code gains access to it.

After you read this chapter, you’ll be able to make informed decisions about the identity management architecture of your solutions. You’ll know what it takes to implement such decisions in ASP.NET. You’ll have concrete experience using the WIF extensibility model for solving a range of classic identity management scenarios. That experience will help you to devise your own WIF-based solutions. Once again, I’ll give you practical code indications about the ASP.NET case, but the general principles introduced here can be applied more broadly, often to the WCF services case and even on non-Microsoft platforms.

More About Externalizing Authentication

Until now, I have described situations in which the application relies on only one external entity—what I defined as the identity provider, or IP. Although this is an accurate representation of a particular common scenario, the general case can be a bit more complicated. Not only might you have to accept identities from multiple identity providers, identity providers are not the only entities you can outsource authentication to!

So far, the role played by the entity within a transaction (the identity provider) has been conflated with the instrument used to perform the function (the STS). The purpose of this section is to help you better understand the separation between the two by providing more details about the nature of the identity provider, introducing a new role known as the federation provider, and studying how those high-level functions reflect on the implementation of the associated STS.

Identity Providers

Being an identity provider is a role, a job if you will. You know from Chapter 1, “Claims-Based Identity,” that an IP “knows about subjects.” In fact, all the thinking behind the idea of IP is just good service orientation applied to identity.

The standard example of a concrete identity provider is one built on top of a directory, just as ADFS 2.0 is built on top of Active Directory. In this scenario, there’s an entity that is capable of authenticating users and making assertions about them, and all you are doing is making that capability reusable to a wider audience by slapping a standard façade (the STS) in front of it. The use of standards when exposing the STS is simply a way of maximizing the audience and increasing reusability. Here’s an example: Although a SharePoint instance on an intranet can take advantage of Active Directory authentication capabilities directly via Kerberos, that is not the case for a SharePoint instance living outside the corporate boundaries and hosted by a different company. Exposing the authentication capabilities of Active Directory via ADFS 2.0 makes it possible to reuse identities with the SharePoint instance in the second scenario, removing the platform and location constraints. WIF is just machinery that enables your application to take advantage of the same mechanism. It is worthwhile to point out that SharePoint 2010 is, in fact, based on WIF.

Another advantage of wrapping the actual authentication behind a standard interface is that you are now isolated from its implementation details. The IP could be a façade for a directory, a membership provider–based site, or an entirely custom solution on an arbitrary platform; as long as its STS exposes the authentication functionality through standards, applications can use it without ties or dependencies outside of the established contract. Who cares if the connection string to the membership database changes, or even if there is a membership database in the first place? All you need to know is the address of the STS metadata.

Those characteristics of the IP role tell you quite a lot about what to expect regarding the structure of the STS exposed by one IP.

In the WS-Federation Sign-in flow, described in Chapter 3, you saw that the details of how the STS authenticates the request for security tokens is a private matter between the STS and the user. Now you know that such a system has to be something that allows the STS to look up user information from some store—so that it can be extracted and packaged in the form of claims. Notable examples are the ones in which the STS leverages the same authentication methods of the resource it is wrapping. If the IP is a façade for Active Directory and the user is on the intranet, the STS might very well be hosted on one ASPX page that is configured in Internet Information Services (IIS) to leverage Windows native authentication. If the source is a membership database, the STS site will be protected via a membership provider, and so on. The claim value’s retrieval logic in the STS will use whatever moniker the authentication scheme offers for looking up claim values, but the authentication will often be performed by the infrastructure hosting the STS rather than the STS code itself.

Nothing prevents one IP from exposing more than one STS endpoint to accommodate multiple consumption models. For example, the same IP might be listening for Kerberos authenticated requests from the intranet and X.509 secured calls on an endpoint available on the Internet; the IP might expose further endpoints, both for browser-based requestors via WS-Federation and SAMLP or for active requestors via WS-Trust; and so on. This process offers another insight into how one IP is structured: authentication and claims issuance logic should communicate but remain separate so that multiple STS endpoints scenarios are handled with little or no duplication. As you’ll see later in the section, the WIF STS programming model is consistent with that consideration.

An IP will actively manage the list of the RPs it is willing to issue a token for. This is not only a matter of ensuring that claims are transmitted exclusively to intended recipients, but also a practical necessity. Especially in the passive case, in which token requests are usually simple, the IP decides what list of claims will be included in a token according to the RP the token is being issued for. (“Passive case” is mainly another way to say that you use a browser. You’ll know everything about it after reading Chapter 5, “WIF and WCF.”) Such a list is established when the RP is provisioned in the IP’s allow list. Just like WIF enables one application to establish a trust relationship with an IP by consuming its metadata via the Federation Utility Wizard, IP software such as ADFS 2.0 includes wizards that can consume the application metadata and automatically provision the RP entry in its allow list.

The IP also keeps track of the certificate associated with the RP, both for ensuring that the RP has a strong endpoint identity (exposed via HTTPS) and for encrypting the token with the correct key if confidentiality is required.

The scenario described so far—one application outsourcing authentication to one identity provider—is common, and none of the further details about IPs I gave here invalidate it. However, sometimes the planets do not align the way you’d like, and for some reason simple direct outsourcing to one IP does not solve the problem.

Federation Providers

Let’s consider for a moment the matter of handling multiple identity providers. Imagine being a developer for a financial institution. Let’s say you are writing a corporate banking application, which allows companies to handle the salary payment process for their workforce. This is clearly one case in which you need to trust multiple identity providers—namely, all the companies who access your financial institution for managing payments.

From what you have seen so far, you know only one way of handling the situation: adding multiple FederatedPassiveSignIn controls to your application entry page, each of them pointing to a different identity provider. Although the approach works, it can hardly be called a full externalization of identity management because provisioning and deprovisioning identity providers forces you to change the application code. Things get worse when you have one entire portfolio of applications to make available to a list of multiple identity providers—having to reapply the trick mentioned previously for every application rapidly becomes unsustainable as the number of apps and IPs goes up. This clearly indicates the need to factor out IP relationship management from the application responsibilities.

Another common issue you might encounter has to do with the ability of your application to understand claims as issued by one identity provider. Here is why:

  • Sometimes you might have simple format issues. For example, the users you are interested in might come from another country and their IP might use claim URIs containing locale-specific terms your application does not understand. (An English application might need to know the name of the current user and expect it in an http://claims/name format, while an Italian IP might send the desired information in the http://claims/nome claim format.)

  • Sometimes the information will need some processing before being fed to your application. For example, an IP might offer a birth date claim, but your application might be forbidden from receiving personally identifiable information (PII). All you require here is a simple Boolean value indicating if the user is below or above a certain threshold age. Although the information is clearly available to the IP, it might not be offered as a claim.

  • Finally, you might need to integrate the claims received from the IP with further information that the IP does not know. For example, you might be an online book shop accepting users from a partner IP. The IP can provide you with name and shipping address claims, but it cannot provide you with the last 10 books the user bought from your store. That is data that belongs to you, and you have the responsibility of making it available in the form of claims if you want to offer to your developers a consistent way of consuming identity information.

What is needed here is a means of doing some preprocessing—some kind of intermediary that can massage the claims and make them more digestible for the application.

The standard solution to these issues is the introduction of a new role in identity transactions, which goes by the name of Federation Provider (FP).

A Federation Provider is a claims transformer; it is an entity that accepts tokens in input—kind of like an RP does—and issues tokens that are (usually) the result of some kind of processing of the input claims. An FP offers its token manipulation capabilities exactly like an IP, by exposing STS endpoints. The main difference is that, whereas one IP usually expects requests for security tokens secured by user credentials that will be used for looking up claims, the FP expects requests to be secured with an issued token that will be used as input for the claims transformation process. In the IP case, the issued token contains the claims describing the authenticated user; in the FP case, the issued token is the result of the processing applied to the token received in the request. Given the fact that an FP exposes one STS, applications can use it for externalizing authentication in exactly the same way as you have seen they do with IPs. WIF’s Federation Utility Wizard does not distinguish between IPs and FPs—all it needs is an STS and its metadata.

The reason that it’s known as the Federation Provider is that enabling federation is the primary purpose that led to the emergence of this role. In a nutshell, here’s how that works. Imagine company A is a manufacturer that has a number of line-of-business (LOB) applications for its own employees, including applications for supply management, inventory, and other usual stuff. Company B is a retailer that sells the products manufactured by A. To improve the efficiency of their collaboration, A and B decide to enter into a federation agreement: certain B employees will have access to certain A applications. Instead of having every A application add the B identity provider and having the B IP provision every application as a recognized RP, A exposes a Federation Provider.

The B IP will provision the A FP just like any other RP, associating to the relationship the list of claims that B decides to share with A about its users. All of the A applications that need to be accessible will enter into a trust relationship with the A FP, outsourcing their authentication management to its STS. Figure 4-1 shows the trust relationships and the sign-in flow.

Figure 4-1

FIGURE 4-1 The authentication flow in a federation relationship between two organizations

The flow goes as follows:

  1. One employee of B navigates to one application in A.

  2. The user is not authenticated because the application will accept only users presenting tokens issued by the A FP. The application redirects the user to the A FP.

  3. Again, the user is not authenticated. The A FP will accept only users presenting tokens issued by the B IP. The application redirects the user to the B IP.

  4. The user lands on the B IP, where authentication will take place according to the modes decided by B. The user gets a token from the B IP.

  5. The user gets back to the A FP and presents the token from the B IP.

  6. The A FP processes the token according to the application’s needs—some claims might be reissued verbatim as they were received from B; others might be somehow processed; still others might be produced and added anew. The A FP packages the results of the processing in the form of claims and issues the new token to the user.

  7. The user gets back to the application and presents the token from the A FP; the application authenticates the call by examining the token from A FP.

The main advantage of using an FP in a federation scenario is obvious: you now have a single place where you can manage your relationship, defining its terms (such as which claims you should receive). The applications are decoupled from those details. Because the FP knows about both the incoming claims (because it is on point for handling the relationships) and the claims needed by the application (because it is part of the organization, it knows about which claim types are available and their semantics), applications can effectively trust it to handle authentication on their behalf even if the actual user credentials verification takes place elsewhere. The process can be iterated. For example, you can have an FP trusting another FP, which in turn trusts an IP, although that does not happen too often in practice.

The WIF STS Template

Outsourcing authentication to one external STS makes life much easier for the application developer, at the price of relinquishing control of a key system function to the STS itself. Although relinquishing control of the mechanics of authentication is sweet, as I’ve been pointing out through the entire book, the STS you choose better be good, or else. Here’s what I mean by “good” in this case:

  • An STS must be secure A compromised STS is an absolute catastrophe because it can abuse your application’s trust by misrepresenting the user privileges.

  • An STS must be available If the STS endpoint is down, as a consequence of peak traffic or any other reason, your application is unreachable: no token, no party.

  • An STS must be high-performing Every time a user begins a session with your application, the STS comes into play. Bad performance is extremely visible, can become a source of frustration for users, and even pile up to compromise the system’s availability.

  • An STS must be manageable If you own the STS, whether it used as an IP or FP, you’ll need to manage many aspects of its activities and life cycle, such as the logic used for retrieving claim values, provisioning of recognized RPs, establishment of trust relationships with the IP of federated partners, management of signing and encryption keys, auditing of the issuing activities, and management of multiple endpoints for different credential types and protocols. The list goes on and on.

In other words, running an STS is serious business: don’t let anybody convince you otherwise. An endpoint that understands WS-Federation, WS-Trust, or SAMLP requests and can issue a token accordingly technically fits the definition of “STS,” but protocol capabilities alone can’t help with any of the requirements just mentioned.

This is why in the vast majority of real-world scenarios it is wise to rely on off-the-shelf STS products, such as ADFS 2.0. Those products host STS endpoints and advanced management features that simplify both small and large maintenance operations that running an IP or an FP (or both) entails. Let’s take ADFS 2.0 as an example: ADFS 2.0 is a true Windows server role—tried, stressed, and tested just like any other Windows server feature.

The Windows Identity Foundation SDK makes the generation of an STS deceivingly simple by offering Microsoft Visual Studio templates for both ASP.NET Web sites and WCF services projects that implement a bare-bones STS endpoint (for WS-Federation and WS-Trust, respectively). The Generate New STS option in the Add STS Reference Wizard just instantiates one of those templates in the current solution. Those test STSes are an incredibly useful tool for testing applications, thanks to the near absence of infrastructure requirements (ADFS 2.0 requires a working Active Directory instance, SQL Server, Windows Server 2008 R2, and so on) and instantaneous creation. As somebody who had to write STSes from scratch with WCF in the past (a long and messy business), I am delighted by how easy it is to generate a test STS with WIF. For the same reason, such test STSes are consistently used in WIF samples and courseware. This book is no exception.

Why do I say “deceivingly simple”? Because of all the requirements I listed earlier. WIF can certainly be used to build an enterprise-class STS—it has been used for building ADFS 2.0 itself. However, between the STS template offered by the WIF SDK and ADFS 2.0, there are many, many man-years of design, enormous amounts of development and testing, tons of assumptions and default choices, brutal fuzzing, relentless stressing, and so on. The fact that the STS template gives you back a token does not mean it can be used as is in a real-life system. People regularly underestimate the effort required for building a viable STS, an error of judgment that can result in serious issues. That is why I always discourage the creation of custom STSes unless it’s absolutely necessary, and there’s not a lot of detailed guidance on that.

Now that I’ve got the disclaimer out of the way: this chapter will use a lot of custom STSes. Taking a peek inside an STS is a powerful educational tool that can help you understand scenarios end to end. Being able to put together test STSes can help you simulate complex setups before committing resources to them. Finally, you’ll likely encounter situations in which setting up a custom STS is the way to go—for example, if your user credentials are not stored in Active Directory. The guidance here is absolutely not enough for handling the task—that would involve teaching how to build secure, scalable, manageable, and performing services, which is well beyond the scope of this text—but it can be a starting point for understanding the token issuance model offered by WIF.

The rest of the section describes the STS template for ASP.NET offered by WIF SDK 4.0. As you read through this section, I suggest you go back to the simple example you created in Chapter 2 and put breakpoints on the parts of the STS project being discussed. Every time something is not too clear, try a test run in the debugger to get a better sense of what’s going on.

Structure of the STS ASP.NET Project Template

The ASP.NET Security Token Service Web Site template, as WIF SDK 4.0 names it, can be found in the C# Web sites templates list in Visual Studio. As mentioned, this is also the template that is used by the Add STS Reference Wizard for generating an STS project within an existing solution. Figure 4-2 shows the list of templates installed by the WIF SDK 4.0.

Figure 4-2

FIGURE 4-2 The templates installed by WIF SDK 4.0, with the template used for creating an ASP.NET STS highlighted

The STS Web site is typically created on the local IIS. Although it is possible to use the plain HTTP binding, in general the STS Web site will be created on an HTTPS endpoint.

Figure 4-3 shows the structure of the STS project.

Figure 4-3

FIGURE 4-3 The ASP.NET STS project structure

That is the structure of a minimal Web site protected via Forms authentication, containing the classic Login.aspx and Default.aspx pages. The web.config file is minimal, containing practically nothing specific to WIF apart from the reference to its assembly and a few values in the <appSettings>. The Web site is configured to use Forms Authentication. As you saw in the first example in Chapter 2, Login.aspx does not actually verify any credentials and represents just a pro-forma authentication page: the page will just create the authentication cookie and start a session regardless of the credentials entered in the UI.

The hands-on lab Web Sites and Identity (C:\IdentityTrainingKit2010\Labs\WebSitesAndIdentity\Source\Ex1-ClaimEnableASPNET) exercise 2, shows how to use an existing Membership store for authenticating calls to the STS, and how to source claim values from a Role provider.

All this emphasizes what I mentioned earlier about the separation between the STS functions and the authentication mechanism: here Forms authentication is the method of choice, but it is independent from what WIF does for implementing the token-issuing functionality. The authentication system could be easily substituted with Windows integrated authentication or whatever else, as long as it takes care of authenticating the user before giving access to Default.aspx.

The Default.aspx page represents the STS endpoint, and it takes care of instantiating and executing the token-issuing logic in the context of an ASP.NET request. The page itself does not contain much. What we are interested in is the Page_PreRender handler in Default.aspx.cs:

public partial class _Default : Page
{  /// <summary>
  /// Performs WS-Federation Passive Protocol processing.
  /// </summary>
  protected void Page_PreRender( object sender, EventArgs e )
  {
    string action = Request.QueryString[WSFederationConstants.Parameters.Action];

    try
    {
      if ( action == WSFederationConstants.Actions.SignIn )
      {
        // Process signin request.
        SignInRequestMessage requestMessage =
          (SignInRequestMessage)WSFederationMessage.CreateFromUri( Request.Url );
        if ( User != null && User.Identity != null && User.Identity.IsAuthenticated )
        {
          SecurityTokenService sts =
          new CustomSecurityTokenService( CustomSecurityTokenServiceConfiguration.Current );
          SignInResponseMessage responseMessage =
             FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest
              (requestMessage, User, sts );
           FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse
              (responseMessage, Response );
         }
         else
         {
           throw new UnauthorizedAccessException();
         }
       }
       else if ( action == WSFederationConstants.Actions.SignOut )
       {
         // Ignore the rest for now
         // ...
 }
}

This code is the STS counterpart of the WS-Federation processing logic that WIF provides for RPs, as studied in Chapter 3. Whereas the RP generates the request for a security token and validates it, the STS listens to those requests and issues tokens according to the WS-Federation protocol. Here’s a quick explanation of what the method does:

  • The handler inspects the request QueryString for the WS-Federation action parameter, wa. Let’s focus on the case in which wa is present and has the value wsignin1.0, which indicates a request for a token. (We’ll explore the sign-out case later in the chapter.)

  • The code creates a new SignInRequestMessage from the request—that is, a name-value collection that surfaces the various WS-Federation parameters as properties.

  • Do you have a non-empty IPrincipal? Is the current user authenticated? If it isn’t, an UnauthorizedAccessException is thrown and the user is redirected to the login page. If it is, the following must take place:

    • Get an instance of SecurityTokenService by retrieving an instance of a subclass, CustomSecurityTokenService. This class contains the core STS logic, as you’ll see in a moment.

    • The new STS instance, along with the incoming SignInRequestMessage and the user’s IPrincipal, is fed to FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest, where it will be used for issuing the token and producing a suitable SignInResponseMessage.

    • Finally, FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse writes the SignInResponseMessage in the response stream, which will be eventually forwarded to the RP and processed as you saw in Chapter 3.

There are a lot of classes with long names, but in the end the code shown earlier just feeds the authenticated user and the request to a custom SecurityTokenService class and sends back the result. The STS project features an App_Code folder, which contains all the classes the STS needs, including the CustomSecurityTokenService class; all you need to do is take a look at what happens there.

STS Classes and Methods in App_Code

The Common.cs file is not very interesting; it’s just a bunch of constants. CertificateUtil.cs is not that remarkable either; it’s a helper class for retrieving X.509 certificates from the Windows stores, although there is an interesting piece of trivia for it. WIF uses that code, instead of the classic X509Certificate2Collection.Find because the latter does not call Reset on the certificates it opened.

CustomSecurityTokenServiceConfiguration, as the name implies, takes care of storing some key configuration settings for the STS: the name, the certificate that should be used for signing tokens, serializers for the various protocols, and so on. The most important setting it stores is the type of the custom SecurityTokenService itself.

Finally, we get to the very heart of the STS: the class in CustomSecurityToken.cs. The code generated by the template has the purpose of doing the bare minimum for obtaining a working STS; hence, I won’t analyze it too closely here, except for pointing out some notable behavior. Rather, I’ll use it as a base for telling you about the more general model that you have to follow when developing a custom STS in WIF. Note that the considerations about SecurityTokenService apply both to ASP.NET and WCF STSes.

SecurityTokenService In WIF, a custom STS is always a subclass of SecurityTokenService, and the ASP.NET template is no exception. The claims-issuance process is represented by a series of SecurityTokenService methods, which are invoked following a precise syntax that leads the form request validation to emit the token bits. Complete coverage of that sequence is beyond the scope of this book; however, here I’ll list the main methods you should know about:

  • ValidateRequest This method takes in a RequestSecurityToken and verifies that it is in a request that can be handled by the current implementation. For example, it checks that the required token type is known. SecurityTokenService provides an implementation of ValidateRequest. You should override it only if you are adding or subtracting from the default STS capabilities. There are also few things taking place in GetScope that could perhaps be done in ValidateRequest. I’ll point those out as we encounter them.

  • GetScope GetScope is an abstract method in SecurityTokenService that must be overridden in any concrete implementation. It takes as input the IClaimsPrincipal of the caller and the current RequestSecurityToken.

    The purpose of GetScope is to validate and establish some key parameters that will influence the token-issuance process. Those parameters are saved in one instance of Scope, which is returned by GetScope and will cascade through all the subsequent methods in the token-issuance sequence. Here are the main questions that GetScope answers:

    • Which certificate should be used for signing the issued token? Although a signing certificate has already been identified in the configuration class, GetScope should confirm that certificate (as done by the template implementation) or override it with custom criteria—for example, if something in the request influences which certificate should be used.

    • Is the intended token destination a recognized RP? As discussed earlier, normally an STS issues tokens only to the RP URIs that have been explicitly provisioned. If the incoming wtrealm (available in RequestSecurityToken via the property AppliesTo) does not correspond to a known RP, an InvalidRequestException should be thrown.

      If the AppliesTo value is valid, it is fed into the Scope object. It will be needed for the AudienceRestriction element of the issued token, which in turn will be validated by WIF against the <audienceURI> config element on the RP.

    • Should the issued token be encrypted? If yes, with which certificate? The STS configuration should specify whether the token should be encrypted. If it should be, the same store that was used for establishing whether the RP was valid should also carry information about which encryption certificate should be used. The template uses a value from config.

    • To which address should the token be returned? The template assumes that wtrealm—that is, the AppliesTo value—is both the identifier of the RP and its network-addressable URI. As a result, GetScope assigns the value of AppliesTo to the ReplyToAddress property of the Scope object.

      When the Scope is ready, a number of lower level token-issuance preparation steps take place. You can influence those if you want to, but I won’t go into further details here. After those steps are completed, it is finally time to work with claims.

  • GetOutputClaimsIdentity This method takes as input the IClaimsPrincipal of the caller, the RequestSecurityToken, and the Scope. It returns an IClaimsIdentity, which contains the claims that should be issued in the token for the caller. Note that at this point the IClaimsPrincipal of the caller is a representation of the IPrincipal obtained from the STS caller via Forms authentication. This should not be confused with the output IClaimsPrincipal created by the STS, which will be available at the RP after successful sign-in.

    This is perhaps the least realistic of the implementations in the STS template. It returns two hard-coded claims, Name and Role, regardless of the targeted RP or the caller (the only concession being the value of the Name claim, extracted from the incoming principal):

    protected override IClaimsIdentity GetOutputClaimsIdentity
       (IClaimsPrincipal principal, RequestSecurityToken request, Scope scope )
      {
        if ( principal == null )
        {
          throw new ArgumentNullException( "principal" );
        }
        ClaimsIdentity outputIdentity = new ClaimsIdentity();
    
        // Issue custom claims.
        // TODO: Change the claims below to issue custom claims required by your
    application.
        // Update the application's configuration file too to reflect new claims
    requirement.
    
        outputIdentity.Claims.Add( new Claim( System.IdentityModel.Claims.ClaimTypes.Name,
    principal.Identity.Name ) );
        outputIdentity.Claims.Add( new Claim( ClaimTypes.Role, "Manager" ) );
    
        return outputIdentity;
      }

    In a more realistic setting, your GetOutputClaimsIdentity implementation would need to make some decisions about the outgoing IClaimsIdentity. These are the questions it will need to answer:

    • Given the current request, which claim types should be included? The list of claims that should be issued is often established per RP, at provisioning time. That is especially common for WS-Federation scenarios, and some products will go as far as implementing that tactic for the WS-Trust case as well.

      Chances are that the list of claims to use will be available in the same store you used in GetScope for retrieving the RP URI and encryption certificate.

      WS-Trust (and WS-Federation, via wreq or wreqptr parameters) supports requesting a specific list of claims for every request. Although that requires more work, which probably includes checking on an RP-bound list if the required claims are allowed for that given RP, there are many advantages to the approach. Apart from minimal disclosure and privacy considerations, possibly a bit out of scope here, one obvious advantage is that this can help keep the token size under control. A token representing a Windows identity can have many group claims. If for a given transaction the group claim is not required, being able to exclude it can dramatically shrink the resulting token.

      If you want to support requests that specify the required claims, you’ll find that list in the RequestSecurityToken.Claims collection.

    • Given the current principal, which claim values should be assigned? Together with the request authentication method, this is the question that determines whether your STS is an IP-STS or an R-STS.

      One IP-STS uses some claims of the incoming IClaimsPrincipal for looking up the caller in one or more attribute stores, from where the STS will retrieve the values to assign to the established claim types. That’s the direct descendent of using a user name for looking up attributes in a profile store; in fact, it can take place in exactly the same way if you have a user name claim. Of course, you are not limited to it—you can use any claim you like.

      One R-STS processes the claims in the incoming IClaimsPrincipal in arbitrary ways, storing the results in other claims in the outgoing IClaimsIdentity. Note that the STS can also just copy some claims from the incoming token to the outgoing one without modification, and it can even add new claims in the same way the IP-STS does. I’ll show some examples of this later, during the federation and home-realm discovery discussions.

      ADFS 2.0 offers a management UI, where administrators can specify how to source or transform claims. The mappings can be specified via a simple UI or via a SQL-like language that is especially well suited for claims issuance. In your own STS, you can embed the corresponding code directly in GetOutputClaimsIdentity, or you can develop a mechanism for driving its behavior from outside.

Metadata

You know about metadata from Chapter 3. If you need to change something in the metadata document of one RP, you can simply edit it. Perhaps that’s not the greatest fun you’ll have, but it is feasible.

Doing the same for one STS is out of the question because an STS metadata document must always be signed. The WIF SDK has one example showing how to use the WIF API for generating a metadata document programmatically. It’s not rocket science, just a lot of serialization. Generating the document has the advantage of keeping it automatically updated if you play your cards well and read things from the config. It also has another advantage of granting you better control of complicated situations, such as cases in which on the same Web site you expose both WS-Federation and WS-Trust endpoints.

Any dynamic content generation mechanism will do. My favorite is exposing a WCF service and hiding the .svc extension with some IIS URL rewriting.