Personal tools

Saml:SamlAuthority

From Adapt

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

Creating a SAML Authority

Overview

Generally, you will want to create as few Authorities as possible, it will make administration and tieing projects together easier. The current realms where are will have them are at the producer manager, and at the archive(run off of scheduler).

To create an authority, you need two components, a call that a client can use to request an assertion. The standard way to do this is to have a client connect, ask to assume a role, and present a certificate, or create special purpose calls for each role an authority provides

ie: authenticateClient(byte[] certificate)

An Authority should validate the certificate against a CA, and check authentication and allowed authorization of a client. In the PAWN scheduler this authentication is done by making the saml call authenticated using WS-security <nop>UsernameToken provided by wss4j. The saml authority then grabs username information from the ws-security headers.

Initialize Issuer

The SAMLIssuer class makes it a little easier to create SAML assertions for use in PAWN. You should initialize it when your webservice starts. It takes a set of parameters describing a keystore to use. The keystore contains certificate authorities for certificates that clients will present and a keypair used to sign saml assertions. It's part of the pawn-ws-sec project.

The Issuer takes a set of parameters in it's constructor that is used to load the keystore. These parameters are described below:

  • edu.umiacs.wssec.keystore.file (required) : absolute path to keystore file
  • edu.umiacs.wssec.keystore.passwd (required) : password to open keystore file
  • edu.umiacs.wssec.keystore.privkeyalias (optional) : alias that contains the private/public keypair used to sign assertions, defaults to 'server' if not supplied
  • edu.umiacs.wssec.keystore.aliaspasswd : (optional) password for the private key alias, defaults to keystore.passwd if not supplied
  • edu.umiacs.wssec.authorityuri (required) : domain that this authority has control of.
  • edu.umiacs.wssec.keystore.type (optional) : type of keystore, defaults to 'PKCS12'
  • edu.umiacs.wssec.provider (optional) : security provider to use to open keystore, defaults to 'BC'
  • edu.umiacs.wssec.keystore.caalias (optional) : certificate to return on getCACertificate, defaults to null

Example configuration from the scheduler service

  <Parameter name="edu.umiacs.wssec.keystore.file" value="/tmp/scheduler/server.p12"/>
  <Parameter name="edu.umiacs.wssec.keystore.passwd" value="xxx"/>
  <Parameter name="edu.umiacs.wssec.keystore.aliaspasswd" value="xxx"/>
  <Parameter name="edu.umiacs.wssec.keystore.privkeyalias" value="producer"/>
  <Parameter name="edu.umiacs.wssec.authorityuri" value="http://umiacs.umd.edu"/>
  <Parameter name="edu.umiacs.wssec.keystore.ca" value="ca" />

After you have the configuration for the SAMLIssuer set, you need to initialize it. Usually this is done in the Context of your webapp, and a static getSAMLIssuer() call will return the initialized issuer.

public class SchedulerContext extends edu.umiacs.servlet.StandardContextListener {
    ...
    ...
    private static SAMLIssuer           samlIssuer;

    ...
    ...
    public void onContextStart(ServletContext ctx, Parameters paramInit)
    throws ServletException, ParameterException {
        
        boolean         loadbc = true;
        
        // make sure bouncycastle is loaded for keystore operations
        for (Provider p: Security.getProviders()) {
            if (p.getName().equals("BC")) {
                loadbc = false;
                LOG.debug("BC provider already loaded");
            }
        }
        
        if (loadbc) {
            Security.addProvider(new BouncyCastleProvider());
        }

        // load samlIssuer, and initialize validator w/ this trusted cert
        try {
            
            samlIssuer = new SAMLIssuer(paramInit);
            
        } catch (edu.umiacs.wssec.SAMLIssuerException e) {
            LOG.error("Cannot load issuer",e);
            throw new ServletException("Cannot load saml Issuer",e);
        }
    ...
    ...
    }
    ...
    ...
    public static SAMLIssuer getSAMLIssuer() {
        return samlIssuer;
    }

Create assertion

The SAMLIssuer contains a method createAssertion that can be used to create saml assertions with user and fileplan information embedded.

createAssertion(String username, String role, X509Certificate cert, String ... filePlans)

  • username - username to embed
  • role - role of user, see SAMLRoles for available roles.
  • cert - client certificate to embed
  • fileplans - list of file plans that this assertion/client is authorized to work with.

Sample Authority service

After you can create a SAMLIssuer, you need to create a service that will use the issuer, and supply assertions to a client. The following example exposes a method called authenticateClient that accepts a client public key, validates the client's key, and returns a signed assertion with the client's username and role of USER embedded in it.


public class Authority {
    
    private static final Logger         LOG = Logger.getLogger(Authority.class);
    
    /**
     * Create a SAML token with a client role, embedding the supplied certificate
     */
    public String authenticateClient(byte[] certificate) throws WebServiceFault {
        
        try {
            
            return authorizeUser(certificate, SAMLRoles.USER);
            
        } catch (WebServiceFault wsf) {
            throw wsf;
            
        } catch (Throwable t) {
            LOG.error("authenticateclient error",t);
            throw new ServerFault(FaultCode.UNKNOWN,"Unknown server error");
        }

    }

    private String authorizeUser(byte[] certificate, String role) throws WebServiceFault {
        try {
            
            SAMLAssertion       sa = null;
            String              username;
            CertificateFactory  cf;
            X509Certificate     clientCert;
            SAMLIssuer          samlIssuer;
            
            // get token issuer
            samlIssuer  = SchedulerContext.getSAMLIsuer();
            
            // extract username
            username    = //call to your own code, see scheduler for grabbing usernames from wss4j
            
            // reconstitute certificate 
            cf = CertificateFactory.getInstance("X.509");
            clientCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certificate));
            
            // create signed SAMLAssertion, this call will also validate certificate path of client cert
            // throws CertificateException if it can't validate
            sa    = samlIssuer.createAssertion(username, role, clientCert, "testplan");
            
            return sa.toString();
            
            
        } catch (java.security.cert.CertificateException e) {
            LOG.error("Bad client certificate",e);
            throw new ClientFault(FaultCode.CERTIFICATE_ERROR, "Bad Client Certificate");
            
        } catch (WebServiceFault wsf) {
            throw wsf;
            
        } catch (Exception e) {
            LOG.error("Uncaught Exception", e);
            throw new ServerFault(FaultCode.UNKNOWN, "Unknown server error, check logs");
        }
    }
}

-- Main.MikeSmorul - 27 Aug 2005