Personal tools

Saml:AuthenticateService

From Adapt

Revision as of 23:41, 11 September 2008 by Scsong (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Configure service for SAML Authentication

There are two parts to consuming SAML assertions in a web service. First is checking the low level embedding of the SAML assertion in the soap headers, and second is check any authorization statements in the assertion that you wish to act on.

The previous client call hid a few details of what really happens when you make a saml call. From the introduction, you'll remember that we use holder-of-key to ensure that a client is allowed to use a given assertion. To use holder-of-key, a client must prove that is owns the private key corresponding to the public key in the assertion. According to the OASIS spec,

The attesting entity includes an XML Signature that can be verified with the key information in the <saml:ConfirmationMethod> of the subject statements of the SAML assertion referenced for keyInfo by the Signature

This translates to sign the soap message w/ clients private key and check the signature against the assertion.

Wss4j doesn't know how to natively process SAML assertions, so it breaks it up into two parts, first is the signature verification, and second is the assertion processing. The signature verification checks to make sure the signature on the soap message was signed by a certificate issued by a trusted certificate authority. The trusted authorities are extraced from a supplied keystore (later). The saml assertion processing is limited to packing the assertion into the message context and letting you retrieve it from your call. This means it's up to your call to check that the certificate from the xml signature is the same as the certificate in the assertion.

Create standard webservice and use <nop>CachedDoAllReceiver handlers

Create a standard, unauthenticated web service and make sure you can generate stubs and call it from a client. Now, in the deployment descriptor for your web service, you will need to set a requestflow.

    <service name="Receiver" provider="java:RPC" attachments="DIME">

        <requestFlow>

            <handler type="java:edu.umiacs.wssec.CachedDoAllReceiver">
                <parameter name="action" value="Timestamp Signature SAMLTokenUnsigned"/>
            </handler>

        </requestFlow>
        <parameter name="className" value="edu.umiacs.pawn.receiving.Receiver"/>
        <parameter name="allowedMethods" value="*"/>
        <namespace>urn:receiving.pawn.umiacs.edu</namespace>
        
    </service>

You can see how on the receiving side, the signature and saml token are seperated.

Prime <nop>CachedDoAllReceiver with keystore

Now that you will use cacheddoallreceiver to handle your signature checking, you need to tell it which keystore to use. In your context startup, you should load a keystore (see previous client example) and call

CachedDoAllReceiver.setSignatureKeyStore(ks);

The keystore that you load into the receiver should have all certificate authorities that are used to sign client certificates. Unlike a client, no callback configuration is needed since you're not accessing locked (private key) information.

Initialize SAMLValidator

Now that wss4j is ready to receive signed messages w/ assetions in the headers, the next step is to setup validation of assertions. This is done through the SAMLValidator class in the pawn-ws-sec class. This class will take care of checking that the assertion was issued by a trusted authority and checks that the XML message signature matched the client certificate in the assertion.


public class SampleContext extends edu.umiacs.servlet.StandardContextListener {
...

    private static SAMLValidator    samlValidator;

    public void onContextStart(ServletContext ctx, Parameters paramInit)
            throws ServletException, ParameterException {

        X509Certificate cert = ... ;// some authorities certificate

        validator = new SAMLValidator();
        validator.putCertificate(cert);
    ...
    }
    public static SAMLValidator getSAMLValidator() {
        
        return samlValidator;
        
    }
}

SAMLValidator from webservice

Now, you need to piece it all together in your web service. wss4j will handle the incoming message, and put the cert of the xml message signature as well as the assertion into the ws-security message results. You can pass that entire message context into the saml validator.


    /**
     * web service call
     */
    public void testAuthorization() throws WebServiceFault {
        
        checkAuthorization(SAMLRoles.USER, SAMLRoles.SCHEDULER);
        
    }

    /**
     * authorization check that takes a list of allowed roles
     */
    private void checkAuthorization(String ... roles) throws WebServiceFault {
        MessageContext  msgContext;
        SAMLAssertion   assertion;

        // get the message context first
        msgContext = MessageContext.getCurrentContext();
        
        // challenge token
        if (!SampleContext.getSAMLValidator().validateMessageContext(msgContext) ) {
            
            throw new ClientFault(FaultCode.SAML_TOKEN_ERROR,"SAML Token can not be validated");
            
        }
        // validateMessage loads the assertion it validated into a more convenient place in the message context
        assertion = (SAMLAssertion) msgContext.getProperty(Wss4jConstants.WSS4J_SAMLTOKEN_PROPERTY);
        
        LOG.debug("token passes");

This just certifies that a token has a trusted authority. What you'll probably want to do is to check the authorization information in the token. The SAMLUtilities class has some methods to help you out.

boolean hasRoles(SAMLAssertion assertion, String ... roles);

  • assertion - assertion to check roles in.
  • roles - list of roles from SAMLRoles that are allowed

extractRoles, extractFilePlans, and extractNameIdentifiers are also available to extract roles, file plan ID's and usernames from saml assertions.

        if (SAMLUtilities.hasRoles(assertion, roles)) {
            return;
        }

        for (String role : SAMLUtilities.extractRoles(assertion)) {
            LOG.debug("Assertion has role: " + role);
        }
        
        // throw fault since we aren't authorized
        throw new ClientFault(FaultCode.UNPRIVILEDGED_USER,"Client token fails, or not priviledged");
    }