WIF, ACS, STS and SSO Configuration Challenges

This post will be extended to cover all the issues I’ve encountered on trying to work with WIF/ACS/STS & SSO in general.

Error #1 – Occurs on the WIF enabled ASP.NET web site after successfully logging in via ACS and any identity provider

The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread’s user context, which may be the case when the thread is impersonating.

  • Configure IIS to load user profile. To configure IIS to load user profile follow these steps:
  • Open IIS Manager.
  • Find out what AppPool your application is using by selecting your App, right-click on it, and Select Manage Application -> Advanced Settings.
  • After that, on the top left hand side, select Applications Pools, and go ahead and select the App Pool used by your app.
  • Right-click on the App Pool, and select Advanced Settings, Go to the Process Model Section and Find the “Load User Profile” Option and set it to true.

Error #2 – Visual Studio STS template issue

The default template created by adding a new STS from the Federation Utility needs the line added in red below when debugging. A ThreadAbortException is thrown when the page redirects back to the calling web app. It is safe to ignore this exception.

    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 )
            {
                // Process signout request.
                SignOutRequestMessage requestMessage = (SignOutRequestMessage)WSFederationMessage.CreateFromUri( Request.Url );
                FederatedPassiveSecurityTokenServiceOperations.ProcessSignOutRequest( requestMessage, User, requestMessage.Reply, Response );
            }
            else
            {
                throw new InvalidOperationException(
                    String.Format( CultureInfo.InvariantCulture,
                                   "The action '{0}' (Request.QueryString['{1}']) is unexpected. Expected actions are: '{2}' or '{3}'.",
                                   String.IsNullOrEmpty(action) ? "<EMPTY>" : action,
                                   WSFederationConstants.Parameters.Action,
                                   WSFederationConstants.Actions.SignIn,
                                   WSFederationConstants.Actions.SignOut ) );
            }
        }
        catch (System.Threading.ThreadAbortException) { } // Thrown by redirect, safe to ignore
        catch ( Exception exception )
        {
            throw new Exception( "An unexpected error occurred when processing the request. See inner exception for details.", exception );
        }
    }
 

Error #3 – Claims aware ASP.NET site gives this error

A potentially dangerous Request.Form value was detected from the client (wresult=”<trust:RequestSecuri…”).

If you get this it’s because page validation is turned on by default. You can turn it off but I wouldn’t recommend that.

The best way around this is to write a customer validation handler and insert it into the asp.net pipeline. Here is the code for the http handler.

    public class WifRequestValidator : RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            validationFailureIndex = 0;
            if (requestValidationSource == RequestValidationSource.Form && collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))
            {
                SignInResponseMessage message = WSFederationMessage.CreateFromFormPost(context.Request) as SignInResponseMessage;
                if (message != null)
                    return true;
            }
            return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
        }
    }

Here is the line to insert in the system.web section of your web.config  

<httpRuntime requestValidationType="WifRequestValidator"/> 

Error #4 – AppPool User Profile

Although not directly related to this subject, my site was using the membership provider for authentication. I discovered that IIS doesn’t load the Windows user profile, but certain applications might take advantage of it anyway to store temporary data. SQL Express is an example of an application that does this. However, a user profile has to be created to store temporary data in either the profile directory or in the registry hive. The user profile for the NETWORKSERVICE account was created by the system and was always available. However, with the switch to unique Application Pool identities, no user profile is created by the system. Only the standard Application Pools (DefaultAppPool and Classic .NET AppPool) have user profiles on disk. No user profile is created if the Administrator creates a new Application Pool.

However, if you want, you can configure IIS Application Pools to load the user profile by setting the “LoadUserProfile” attribute to “true”.

Advertisements