• The holy grail of Enterprise SOA security

    Published by Matias Woloski on March 11th, 2007 1:34 am under Architecture, Indigo, SaaS, ServiceFactory

    1 Comment

    A couple of years ago, the platform was not rich enough to create complex security solutions for service oriented applications based on standards. WSE was a half way path. With the advent of WCF we finally have a foundation to build a security subsystem flexible and robust for the enterprise.

    The following illustration shows the different components involved and how they interact between each other.

    soa

    Most of enterprise line of business apps have used a login to authenticate their users and roles to authorize them. When webservices were not there, the business logic was hosted in the application itself and advanced users hosted in COM+. The authentication and access checks were mixed in the same code that performed the business logic. Sometime later enterprises started to realize that integration between applications was getting harder: SOA implemented with webservices came to the rescue.

    Now, the business logic lived in the application server and was accessed through webservices. The problem became to "how can I secure my services?". I’ve seen many different implementations: using kerberos, using custom tickets, certificates, etc. However they were coupled to the platform or they were custom solutions. Single sign on and access check across applications of different platform is hard to accomplish: WS-Trust, STS and SAML comes to the rescue.

    Let’s describe the scenario:

    1. A user browses to Login.aspx, enters his username and password and click "Login". As this is the only time when we have username and password available from the user, we can fill the UserName token on the proxy. We call a Ping service which is just a dummy service that we use to obtain a SamlToken.

    using (SystemServiceChannel channel = new SystemServiceChannel())
    {
        channel.ClientCredentials.UserName.UserName = LoginControl.UserName;
        channel.ClientCredentials.UserName.Password = LoginControl.Password;
        channel.Ping();
    }

    2. The client endpoint is configured to use wsFederationHttpBinding and the issuer of the token is the Authorization STS. Since the client does not have a SamlToken yet, it will send the UserName token to the Authorization STS so he can issue one. Below is the binding.

    <binding name="SecureConversationBinding">
      <security mode="Message">
        <message issuedKeyType="SymmetricKey" 
                 issuedTokenType="http://....saml-token-profile-1.1#SAMLV1.1">
          <issuer address="http://services.litwarehr.com/Authz/STS.svc"
            binding="wsFederationHttpBinding" bindingConfiguration="AuthorizationSTS">
            <identity>
              <dns value="SaasyLongTailCert" />
            </identity>
          </issuer>
        </message>
      </security>

    3.  The Authorization STS trust on the Authentication STS and request him a SamlToken. The Authentication STS message security is configured to use wsHttpBinding with UserName token.

    <binding name="AuthorizationSTS">
      <security mode="Message">
        <message issuedKeyType="SymmetricKey"
                         issuedTokenType="http://...-saml-token-profile-1.1#SAMLV1.1">
          <issuer address="http://services.litwarehr.com/Auth/Sts.svc"
            binding="wsHttpBinding" bindingConfiguration="AuthenticationSTS">
            <identity>
              <dns value="SaasyLongTailCert" />
            </identity>
          </issuer>
        </message>
      </security>
    </binding>
    <binding name="AuthenticationSTS">
      <security mode="Message">
        <message clientCredentialType="UserName"
                         negotiateServiceCredential="true"
                         establishSecurityContext="false" />
      </security>
    </binding>

    4. The Authentication STS service has a custom UserName Password validator behavior configured. Before the request actually gets to the STS it will go through the username/password validation. LitwareHr default implementation uses ADAM.

    <serviceBehaviors>
       <behavior name="AuthenticationSTS">
          <serviceCredentials>
            <userNameAuthentication
    userNamePasswordValidationMode="Custom"
    customUserNamePasswordValidatorType="CustomValidator, Sts"/>
           </serviceCredentials>
       </behavior>
    </serviceBehaviors>

    5. If the authentication was succesful , the Authentication STS will issue a basic SamlToken containing the identity name of the caller.

    Collection GetIssuedClaims(RequestSecurityToken rst)
    {
        string caller = ServiceSecurityContext.Current.PrimaryIdentity.Name;
        Collection samlAttributes =
                        new Collection();
        samlAttributes.Add(
            new SamlAttribute(
            new Claim(ClaimTypes.Authentication,
                      caller,
                      Rights.PossessProperty)));
    
        return samlAttributes;
    }

    6. Since the Authorization STS trusts on the SamlTokens issued by the Authentication STS, it will grab the token, extract the username claim and retrieve the actions available for the user. This happens in the IAuthorizationPolcy configured on the STS.

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        // check if this context was updated for this user
        if (state == null)
        {
            // Create an empty list of Claims
            IList claims = new List();
            // Add list of actions the user can perform
            string user = GetUserFromClaimSets(evaluationContext.ClaimSets);
            foreach (string action in GetActionsForUser(user))
            {
                claims.Add(new Claim(
                        ClaimTypes.AuthorizationDecision,
                        action,
                        Rights.PossessProperty));
            }
            ...
         }
    }

    7. The SamlToken enriched now is ready to go through the service pipeline.

    8. This is where the access check happens. The ServiceAuthorizationManager class has access to the AuthorizationContext which exposes the SamlToken with the claims.

    public override bool CheckAccess(OperationContext operationContext)
    {
        // Extract the AuthorizationContext from the ServiceSecurityContext
        AuthorizationContext authContext =
            operationContext.ServiceSecurityContext.AuthorizationContext;
    
        // Guard denies exectuion if the action is not in the token as a claim
        string action = operationContext.IncomingMessageHeaders.Action;
        IEnumerable authorizationDecisionClaims =
            claimSet.FindClaims(ClaimTypes.AuthorizationDecision, Rights.PossessProperty);
    
        foreach (Claim claim in authorizationDecisionClaims)
        {
            string authzAction = claim.Resource as string;
            if (!string.IsNullOrEmpty(authzAction) &&
                authzAction.Equals(action,
                                  StringComparison.InvariantCultureIgnoreCase))
            {
                return true;
            }
        }
    
        // If no AuthorizationDecision claim had a resource value that matched the 
        // current action name, return false (Access Denied)
        return false;
    }

    9. Finally, the SOAP message gets to the service implementation and the response is sent back to the client with the SamlToken attached.

    10. The SamlToken is cached on the client using an HTTP cookie. This is achieved by using a custom IssuedSecurityTokenProvider.

    Conclusion and a bit of SaaS

    WCF provides an extensible foundation that allow taking the service oriented on the enterprise to the next level using standards like WS-Trust and SAML.

    Since SOA is part of the deal for Software as a Service apps we implemented this architecture on LitwareHR to get ready for future scenarios like Federated Security. In this scenario the tenant wants to manage authentication and authorization using its own infrastructure. He owns an STS that issues SamlTokens for every app in the enterprise and the IT guys don’t want to manage yet another user/password. The SaaS provider (LitwareHR) will allow the tenant to configure the claims mapping and the tenant STS to rely on. By doing this, the IT administrator for Contoso (the tenant) will manage a single authorization store and will configure the claim mappings on the "cloud" apps: the "Administrator" role in my enterprise is the "ConfigureAndCustomize" role in the SaaS application.

    If you want to see a working implementation of the scenario described in the figure above download LitwareHr Software as a Service sample application and look for Shp.Security.BrokeredReceiver and Shp.Security.BrokeredSender projects. If you are taking SOA seriously, then it might worths looking at it.

  • 1 Comment:

    1. Menard Soliven said on December 11, 2008:

      Hi Matias,

      Does it make sense to use HTTPS on top of WCF Message Security, which I understand is already encrypted?

      Would the LITWARE HR app work if I enabled SSL on the different STS and other service endpoints?

      I tried changing the security mode to “TransportWithMessageCredential” thinking that this would let me use HTTPS.

      Thanks in advance!

      Menard
      MSoliven@fssnet.com

    Leave a comment

    Your email address will not be published.

Tags