be.agiv.security.client.IPSTSClient.java Source code

Java tutorial

Introduction

Here is the source code for be.agiv.security.client.IPSTSClient.java

Source

/*
 * AGIV Java Security Project.
 * Copyright (C) 2011-2012 AGIV.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.agiv.security.client;

import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.spi.Provider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.conversation.ConversationException;
import org.apache.ws.security.conversation.dkalgo.P_SHA1;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import be.agiv.security.SecurityToken;
import be.agiv.security.handler.LoggingHandler;
import be.agiv.security.handler.WSAddressingHandler;
import be.agiv.security.handler.WSSecurityHandler;
import be.agiv.security.handler.WSTrustHandler;
import be.agiv.security.jaxb.wsaddr.AttributedURIType;
import be.agiv.security.jaxb.wsaddr.EndpointReferenceType;
import be.agiv.security.jaxb.wspolicy.AppliesTo;
import be.agiv.security.jaxb.wsse.KeyIdentifierType;
import be.agiv.security.jaxb.wsse.SecurityTokenReferenceType;
import be.agiv.security.jaxb.wstrust.BinarySecretType;
import be.agiv.security.jaxb.wstrust.CancelTargetType;
import be.agiv.security.jaxb.wstrust.EntropyType;
import be.agiv.security.jaxb.wstrust.LifetimeType;
import be.agiv.security.jaxb.wstrust.ObjectFactory;
import be.agiv.security.jaxb.wstrust.RequestSecurityTokenResponseCollectionType;
import be.agiv.security.jaxb.wstrust.RequestSecurityTokenResponseType;
import be.agiv.security.jaxb.wstrust.RequestSecurityTokenType;
import be.agiv.security.jaxb.wstrust.RequestedReferenceType;
import be.agiv.security.jaxws.wstrust.SecurityTokenService;
import be.agiv.security.jaxws.wstrust.SecurityTokenService_Service;

/**
 * JAX-WS based AGIV IP-STS WS-Trust client. Via this client one can retrieve
 * security tokens from the IP-STS WS-Trust web service using username/password
 * or X509 certificate credentials.
 * <p/>
 * Keep in mind that this IP-STS client is specifically designed to work with
 * the AGIV IP-STS and thus will most likely not work for other IP-STS
 * configurations.
 * 
 * @author Frank Cornelis
 * 
 */
public class IPSTSClient {

    private static final Log LOG = LogFactory.getLog(IPSTSClient.class);

    private final SecurityTokenService port;

    private final ObjectFactory objectFactory;

    private final be.agiv.security.jaxb.wspolicy.ObjectFactory policyObjectFactory;

    private final be.agiv.security.jaxb.wsaddr.ObjectFactory addrObjectFactory;

    private final SecureRandom secureRandom;

    private final String location;

    private final be.agiv.security.jaxb.wsse.ObjectFactory wssObjectFactory;

    private final WSAddressingHandler wsAddressingHandler;

    private final WSTrustHandler wsTrustHandler;

    private final WSSecurityHandler wsSecurityHandler;

    private final String realm;

    /**
     * Convenience constructor.
     * 
     * @param location
     *            the location of the IP-STS WS-Trust web service.
     * @param realm
     *            the AGIV R-STS realm.
     */
    public IPSTSClient(String location, String realm) {
        this(location, realm, null);
    }

    /**
     * Main constructor.
     * 
     * @param location
     *            the location of the IP-STS WS-Trust web service.
     * @param realm
     *            the AGIV R-STS realm.
     * @param secondaryParametersNodeList
     *            the DOM node list that will be used as SecondaryParameters for
     *            RST requests.
     */
    public IPSTSClient(String location, String realm, NodeList secondaryParametersNodeList) {
        this.location = location;
        this.realm = realm;

        Provider jaxwsProvider = Provider.provider();
        LOG.debug("JAX-WS provider: " + jaxwsProvider.getClass().getName());

        SecurityTokenService_Service service = SecurityTokenServiceFactory.getInstance();
        this.port = service.getSecurityTokenServicePort();
        BindingProvider bindingProvider = (BindingProvider) this.port;
        bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, location);

        Binding binding = bindingProvider.getBinding();
        List<Handler> handlerChain = binding.getHandlerChain();
        this.wsTrustHandler = new WSTrustHandler();
        this.wsTrustHandler.setSecondaryParameters(secondaryParametersNodeList);
        handlerChain.add(this.wsTrustHandler);
        this.wsAddressingHandler = new WSAddressingHandler();
        handlerChain.add(this.wsAddressingHandler);
        this.wsSecurityHandler = new WSSecurityHandler();
        handlerChain.add(this.wsSecurityHandler);
        handlerChain.add(new LoggingHandler());
        binding.setHandlerChain(handlerChain);

        this.objectFactory = new ObjectFactory();
        this.policyObjectFactory = new be.agiv.security.jaxb.wspolicy.ObjectFactory();
        this.addrObjectFactory = new be.agiv.security.jaxb.wsaddr.ObjectFactory();
        this.wssObjectFactory = new be.agiv.security.jaxb.wsse.ObjectFactory();

        this.secureRandom = new SecureRandom();
        this.secureRandom.setSeed(System.currentTimeMillis());
    }

    /**
     * Retrieve a new security token from the IP-STS WS-Trust web service using
     * the given X509 certificate credentials.
     * 
     * @param certificate
     * @param privateKey
     * @return
     * @see IPSTSClient#getSecurityToken(String, String)
     */
    public SecurityToken getSecuritytoken(X509Certificate certificate, PrivateKey privateKey) {
        SecurityToken securityToken = getSecurityToken(null, null, certificate, privateKey);
        return securityToken;
    }

    /**
     * Retrieve a new security token from the IP-STS WS-Trust web service using
     * the given username/password credentials.
     * 
     * @param username
     * @param password
     * @return the IP-STS security token to be used by the R-STS.
     * @see IPSTSClient#getSecuritytoken(X509Certificate, PrivateKey)
     */
    public SecurityToken getSecurityToken(String username, String password) {
        SecurityToken securityToken = getSecurityToken(username, password, null, null);
        return securityToken;
    }

    private SecurityToken getSecurityToken(String username, String password, X509Certificate certificate,
            PrivateKey privateKey) {
        RequestSecurityTokenType requestSecurityToken = this.objectFactory.createRequestSecurityTokenType();
        List<Object> requestSecurityTokenContent = requestSecurityToken.getAny();
        requestSecurityTokenContent.add(this.objectFactory.createRequestType(WSConstants.ISSUE_REQUEST_TYPE));

        EntropyType entropy = this.objectFactory.createEntropyType();
        requestSecurityTokenContent.add(this.objectFactory.createEntropy(entropy));
        BinarySecretType binarySecret = this.objectFactory.createBinarySecretType();
        entropy.getAny().add(this.objectFactory.createBinarySecret(binarySecret));
        binarySecret.setType(WSConstants.SECRET_TYPE_NONCE);

        requestSecurityTokenContent.add(this.objectFactory.createKeyType(WSConstants.KEY_TYPE_SYMMETRIC));

        requestSecurityTokenContent.add(this.objectFactory.createKeySize(256L));

        if (null == this.wsTrustHandler.getSecondaryParameters()) {
            requestSecurityTokenContent
                    .add(this.objectFactory.createKeyWrapAlgorithm(WSConstants.KEY_WRAP_ALGO_RSA_OAEP_MGF1P));

            requestSecurityTokenContent.add(this.objectFactory.createEncryptWith(WSConstants.ENC_ALGO_AES256_CBC));

            requestSecurityTokenContent.add(this.objectFactory.createSignWith(WSConstants.SIGN_ALGO_HMAC_SHA1));

            requestSecurityTokenContent
                    .add(this.objectFactory.createCanonicalizationAlgorithm(WSConstants.C14N_ALGO_EXC));

            requestSecurityTokenContent
                    .add(this.objectFactory.createEncryptionAlgorithm(WSConstants.ENC_ALGO_AES256_CBC));
        }

        AppliesTo appliesTo = this.policyObjectFactory.createAppliesTo();
        EndpointReferenceType endpointReference = this.addrObjectFactory.createEndpointReferenceType();
        AttributedURIType address = this.addrObjectFactory.createAttributedURIType();
        address.setValue(this.realm);
        endpointReference.setAddress(address);
        appliesTo.getAny().add(this.addrObjectFactory.createEndpointReference(endpointReference));
        requestSecurityTokenContent.add(appliesTo);

        requestSecurityTokenContent
                .add(this.objectFactory.createComputedKeyAlgorithm(WSConstants.COMP_KEY_ALGO_PSHA1));

        byte[] entropyData = new byte[256 / 8];
        // entropy = keysize / 8
        this.secureRandom.setSeed(System.currentTimeMillis());
        this.secureRandom.nextBytes(entropyData);
        binarySecret.setValue(entropyData);

        BindingProvider bindingProvider = (BindingProvider) this.port;
        if (null != username) {
            this.wsSecurityHandler.setCredentials(username, password);
        } else if (null != certificate) {
            this.wsSecurityHandler.setCredentials(privateKey, certificate);
        }
        this.wsAddressingHandler.setAddressing(WSConstants.WS_TRUST_ISSUE_ACTION, this.location);

        RequestSecurityTokenResponseCollectionType requestSecurityTokenResponseCollection = this.port
                .requestSecurityToken(requestSecurityToken);

        SecurityToken securityToken = new SecurityToken();

        List<RequestSecurityTokenResponseType> requestSecurityTokenResponseList = requestSecurityTokenResponseCollection
                .getRequestSecurityTokenResponse();
        RequestSecurityTokenResponseType requestSecurityTokenResponse = requestSecurityTokenResponseList.get(0);
        List<Object> requestSecurityTokenResponseContent = requestSecurityTokenResponse.getAny();
        for (Object contentObject : requestSecurityTokenResponseContent) {
            LOG.debug("content object: " + contentObject.getClass().getName());
            if (contentObject instanceof Element) {
                Element contentElement = (Element) contentObject;
                LOG.debug("element name: " + contentElement.getLocalName());
            }
            if (contentObject instanceof JAXBElement) {
                JAXBElement jaxbElement = (JAXBElement) contentObject;
                QName qname = jaxbElement.getName();
                LOG.debug("qname: " + qname);
                if (WSConstants.ENTROPY_QNAME.equals(qname)) {
                    LOG.debug("trust:Entropy");
                    EntropyType serverEntropy = (EntropyType) jaxbElement.getValue();
                    List<Object> entropyContent = serverEntropy.getAny();
                    for (Object entropyObject : entropyContent) {
                        if (entropyObject instanceof JAXBElement) {
                            JAXBElement entropyElement = (JAXBElement) entropyObject;
                            if (WSConstants.BINARY_SECRET_QNAME.equals(entropyElement.getName())) {
                                BinarySecretType serverBinarySecret = (BinarySecretType) entropyElement.getValue();
                                byte[] serverSecret = serverBinarySecret.getValue();
                                P_SHA1 p_SHA1 = new P_SHA1();
                                byte[] key;
                                try {
                                    key = p_SHA1.createKey(entropyData, serverSecret, 0, 256 / 8);
                                } catch (ConversationException e) {
                                    LOG.error(e);
                                    return null;
                                }
                                LOG.debug("client secret size: " + entropyData.length);
                                LOG.debug("server secret size: " + serverSecret.length);
                                LOG.debug("key size: " + key.length);
                                securityToken.setKey(key);
                            }
                        }
                    }
                } else if (WSConstants.LIFETIME_QNAME.equals(qname)) {
                    LOG.debug("trust:Lifetime");
                    LifetimeType lifetime = (LifetimeType) jaxbElement.getValue();
                    String createdValue = lifetime.getCreated().getValue();
                    DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeParser();
                    DateTime created = dateTimeFormatter.parseDateTime(createdValue);
                    securityToken.setCreated(created.toDate());
                    String expiresString = lifetime.getExpires().getValue();
                    DateTime expires = dateTimeFormatter.parseDateTime(expiresString);
                    securityToken.setExpires(expires.toDate());
                } else if (WSConstants.REQUESTED_ATTACHED_REFERENCE_QNAME.equals(qname)) {
                    RequestedReferenceType requestedReference = (RequestedReferenceType) jaxbElement.getValue();
                    SecurityTokenReferenceType securityTokenReference = requestedReference
                            .getSecurityTokenReference();
                    List<Object> securityTokenReferenceContent = securityTokenReference.getAny();
                    for (Object securityTokenReferenceObject : securityTokenReferenceContent) {
                        LOG.debug("SecurityTokenReference object: "
                                + securityTokenReferenceObject.getClass().getName());
                        if (securityTokenReferenceObject instanceof JAXBElement) {
                            JAXBElement securityTokenReferenceElement = (JAXBElement) securityTokenReferenceObject;
                            LOG.debug("SecurityTokenReference element: " + securityTokenReferenceElement.getName());
                            if (securityTokenReferenceElement.getName().equals(WSConstants.KEY_IDENTIFIER_QNAME)) {
                                KeyIdentifierType keyIdentifier = (KeyIdentifierType) securityTokenReferenceElement
                                        .getValue();
                                String attachedReference = keyIdentifier.getValue();
                                securityToken.setAttachedReference(attachedReference);
                            }

                        }
                    }
                } else if (WSConstants.REQUESTED_UNATTACHED_REFERENCE_QNAME.equals(qname)) {
                    RequestedReferenceType requestedReference = (RequestedReferenceType) jaxbElement.getValue();
                    SecurityTokenReferenceType securityTokenReference = requestedReference
                            .getSecurityTokenReference();
                    List<Object> securityTokenReferenceContent = securityTokenReference.getAny();
                    for (Object securityTokenReferenceObject : securityTokenReferenceContent) {
                        LOG.debug("SecurityTokenReference object: "
                                + securityTokenReferenceObject.getClass().getName());
                        if (securityTokenReferenceObject instanceof JAXBElement) {
                            JAXBElement securityTokenReferenceElement = (JAXBElement) securityTokenReferenceObject;
                            LOG.debug("SecurityTokenReference element: " + securityTokenReferenceElement.getName());
                            if (securityTokenReferenceElement.getName().equals(WSConstants.KEY_IDENTIFIER_QNAME)) {
                                KeyIdentifierType keyIdentifier = (KeyIdentifierType) securityTokenReferenceElement
                                        .getValue();
                                String unattachedReference = keyIdentifier.getValue();
                                securityToken.setUnattachedReference(unattachedReference);
                            }

                        }
                    }
                }
            }
        }

        Element requestedSecurityToken = this.wsTrustHandler.getRequestedSecurityToken();
        securityToken.setToken(requestedSecurityToken);
        securityToken.setRealm(this.realm);
        securityToken.setStsLocation(this.location);

        return securityToken;
    }

    /**
     * NOT FUNCTIONAL.
     * 
     * @param securityToken
     */
    public void cancelSecurityToken(SecurityToken securityToken) {
        RequestSecurityTokenType requestSecurityToken = this.objectFactory.createRequestSecurityTokenType();
        List<Object> requestSecurityTokenContent = requestSecurityToken.getAny();

        requestSecurityTokenContent.add(this.objectFactory.createRequestType(WSConstants.CANCEL_REQUEST_TYPE));

        CancelTargetType cancelTarget = this.objectFactory.createCancelTargetType();
        requestSecurityTokenContent.add(this.objectFactory.createCancelTarget(cancelTarget));
        SecurityTokenReferenceType securityTokenReference = this.wssObjectFactory
                .createSecurityTokenReferenceType();
        cancelTarget.setAny(this.wssObjectFactory.createSecurityTokenReference(securityTokenReference));
        KeyIdentifierType keyIdentifier = this.wssObjectFactory.createKeyIdentifierType();
        securityTokenReference.getAny().add(this.wssObjectFactory.createKeyIdentifier(keyIdentifier));
        keyIdentifier.setValue(securityToken.getUnattachedReference());
        keyIdentifier.setValueType(WSConstants.SAML_KEY_IDENTIFIER_TYPE);

        BindingProvider bindingProvider = (BindingProvider) this.port;
        this.wsAddressingHandler.setAddressing(WSConstants.WS_TRUST_CANCEL_ACTION, this.location);
        this.wsSecurityHandler.setCredentials((String) null, (String) null);
        this.wsSecurityHandler.setKey(securityToken.getKey(), securityToken.getAttachedReference(),
                securityToken.getToken());

        RequestSecurityTokenResponseCollectionType requestSecurityTokenResponseCollection = this.port
                .requestSecurityToken(requestSecurityToken);

        List<RequestSecurityTokenResponseType> requestSecurityTokenResponseList = requestSecurityTokenResponseCollection
                .getRequestSecurityTokenResponse();
        RequestSecurityTokenResponseType requestSecurityTokenResponse = requestSecurityTokenResponseList.get(0);
        List<Object> requestSecurityTokenResponseContent = requestSecurityTokenResponse.getAny();
        boolean tokenCancelled = false;
        for (Object contentObject : requestSecurityTokenResponseContent) {
            LOG.debug("content object: " + contentObject.getClass().getName());
            if (contentObject instanceof JAXBElement) {
                JAXBElement jaxbElement = (JAXBElement) contentObject;
                QName qname = jaxbElement.getName();
                LOG.debug("qname: " + qname);
                if (WSConstants.REQUESTED_TOKEN_CANCELLED_QNAME.equals(qname)) {
                    tokenCancelled = true;
                }
            }
        }
        if (false == tokenCancelled) {
            throw new RuntimeException("token not cancelled");
        }
    }
}