Customizing the AD FS 2.0 Sign-in Web Pages

What do the following three questions in the AD FS 2.0 forums have in common?

· Reducing default steps in Sign-In process and changing default look & feel in Sign-In process in Geneva server

· How to authenticate a non-Active Directory user in "Geneva" Server

· Posting a WSTrustClient token to Geneva Server

They’re three customer scenarios that are made easier with the release candidate!

During the lead up to the release candidate, we did some housekeeping in the sign-in webpages. For example, a developer looking at customizing the home realm discovery page in Beta 2 would have seen the following 450 lines of code:

Beta 2:

Yikes! In the release candidate, that same file contains less logic and is easier for a new developer to dive into and start changing.

RC:

The first forum question was about look and feel. In the release candidate, the look and feel of the pages is controlled by ASP.NET Master Pages and options in the web.config file. This should be standard fare for most ASP.NET developers, so I’ll let MSDN do the explaining:

· Customizing the Sign-In Pages Using Web.config

· ASP.NET Master Pages Overview

The second and third forum question each describe variations on a common scenario: account stores that are either not Active Directory, or that are in domains that do not trust each other. Your users shouldn’t need to know the difference. In the example below, I’ve created an installation of AD FS that authenticates users in both its domain as well as Microsoft’s https://www.federatedidentity.net/ sandbox STS, but you can imagine substituting in the right values for your own STSes where needed.

Step 1: Add a claims provider trust for the STS in the other domain. In this case, the relevant values were:

· Claims provider identifier: https://ipsts.federatedidentity.net

· Token-signing certificate: the SSL certificate from https://ipsts.federatedidentity.net/

Step 2: Customize the logic in the FormsSignInPage.aspx.cs file. I added the following function:

const string OtherSTSAddress = "https://ipsts.federatedidentity.net/SecurityTokenService/InteropSts.svc/Sts";

const string YourSTSAddress = "https://your-sts/adfs/ls/";

private void SignInWithTokenFromOtherSTS( string username, string password )

{

    //

    // This function will use WIF's WSTrustChannel class to

    // request a token from the other STS.

    //

    // If successful, it will attempt to sign the user in to

    // the local STS using that token.

    //

    EndpointAddress endpointAddress = new EndpointAddress( OtherSTSAddress );

    UserNameWSTrustBinding binding = new UserNameWSTrustBinding( SecurityMode.TransportWithMessageCredential );

    //

    // Configure the request with the appropriate credentials.

    //

    WSTrustChannelFactory factory = new WSTrustChannelFactory( binding, endpointAddress );

    factory.Credentials.UserName.UserName = username;

    factory.Credentials.UserName.Password = password;

    factory.TrustVersion = System.ServiceModel.Security.TrustVersion.WSTrustFeb2005;

    WSTrustChannel channel = (WSTrustChannel)factory.CreateChannel();

    RequestSecurityToken rst = new RequestSecurityToken(

        WSTrustFeb2005Constants.RequestTypes.Issue,

        WSTrustFeb2005Constants.KeyTypes.Bearer );

    rst.AppliesTo = new EndpointAddress( YourSTSAddress );

    //

    // Make the request and sign in.

    //

    SecurityToken token = channel.Issue( rst );

    SignIn( token );

}

 

And I changed the button click handler to look like the following:

protected void SubmitButton_Click( object sender, EventArgs e )

{

    try

    {

        SignInWithTokenFromOtherSTS( UsernameTextBox.Text, PasswordTextBox.Text );

    }

    catch ( Exception ex )

    {

        //

        // Fall back to signing in locally with the given username and password.

        //

        SignIn( UsernameTextBox.Text, PasswordTextBox.Text );

    }

}

 

And voilà! Of course, this code isn’t quite ready for production – you might want to only contact the other STS if you see that the username is in a certain domain, you may want additional logging and auditing, and so on – but hopefully it gives you a feel of how you can easily customize the sign-in pages.

 

For all the details and the API reference, be sure to check out the MSDN documentation for AD FS 2.0.

 

Colin

SDE on the AD FS Protocols team

Comments

  • Anonymous
    March 16, 2010
    For authenticating users against a non-AD credential store, calling a custom STS is an "ok" workaround. However, if I have to create a custom STS to authenticate users against a non-AD credential store, then in many cases I may not both with ADFS V2 at all. Why pay the price for another STS bounce? By the time I create the custom STS I can authenticate the user and issue the SAML token carrying appropriate claims in a single call. Insetad I might create a custom RP-STS, federate with ADFS V2 for my windows domain users, and then use the RP-STS as the domain for non-AD users.What I really wish for is a way to have a sign-in or RST to ADFS V2 look at a different credential store behind the scenes without bouncing to another STS. Is there a roadmap for this?
  • Anonymous
    September 13, 2010
    This sample doesn't work, for some reason I've tried with multiple custom STS'es and with "ipsts.federatedidentity.net/.../Sts" and the result is the same: "http 500 Internal Server Error".Any ideeas what's happening?
  • Anonymous
    November 17, 2011
    With this solution, the SSO doesn't work.