at.gv.egovernment.moa.id.demoOA.servlet.pvp2.Index.java Source code

Java tutorial

Introduction

Here is the source code for at.gv.egovernment.moa.id.demoOA.servlet.pvp2.Index.java

Source

/*******************************************************************************
 * Copyright 2014 Federal Chancellery Austria
 * MOA-ID has been developed in a cooperation between BRZ, the Federal
 * Chancellery Austria - ICT staff unit, and Graz University of Technology.
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * http://www.osor.eu/eupl/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 *
 * This product combines work with different licenses. See the "NOTICE" text
 * file for details on the various modules and licenses.
 * The "NOTICE" text file is part of the distribution. Any derivative works
 * that you distribute must include a readable copy of the "NOTICE" text file.
 *******************************************************************************/
package at.gv.egovernment.moa.id.demoOA.servlet.pvp2;

import java.io.IOException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.joda.time.DateTime;
import org.opensaml.common.SAMLObject;
import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.binding.decoding.HTTPPostDecoder;
import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder;
import org.opensaml.saml2.binding.encoding.HTTPPostEncoder;
import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule;
import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.LogoutRequest;
import org.opensaml.saml2.core.LogoutResponse;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.NameIDType;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.StatusResponseType;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
import org.opensaml.security.MetadataCredentialResolver;
import org.opensaml.security.MetadataCredentialResolverFactory;
import org.opensaml.security.MetadataCriteria;
import org.opensaml.security.SAMLSignatureProfileValidator;
import org.opensaml.ws.security.SecurityPolicyResolver;
import org.opensaml.ws.security.provider.BasicSecurityPolicy;
import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver;
import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.security.CriteriaSet;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.xml.security.criteria.EntityIDCriteria;
import org.opensaml.xml.security.criteria.UsageCriteria;
import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver;
import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
import org.opensaml.xml.security.keyinfo.KeyInfoProvider;
import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider;
import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider;
import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider;
import org.opensaml.xml.security.x509.KeyStoreX509CredentialAdapter;
import org.opensaml.xml.security.x509.X509Credential;
import org.opensaml.xml.signature.SignableXMLObject;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureConstants;
import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.gv.egovernment.moa.id.demoOA.Configuration;
import at.gv.egovernment.moa.id.demoOA.exception.ConfigurationException;
import at.gv.egovernment.moa.id.demoOA.utils.ApplicationBean;
import at.gv.egovernment.moa.id.demoOA.utils.SAML2Utils;
import at.gv.egovernment.moa.util.DOMUtils;
import at.iaik.commons.util.MiscUtil;

public class Index extends HttpServlet {

    private static final long serialVersionUID = -2129228304760706063L;
    private static final Logger log = LoggerFactory.getLogger(Index.class);

    private void process(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ApplicationBean bean = new ApplicationBean();

        String method = request.getMethod();
        HttpSession session = request.getSession();
        if (session == null) {
            log.info("NO HTTP Session");
            bean.setErrorMessage("NO HTTP session");
            setAnser(request, response, bean);
            return;
        }

        if (method.equals("GET")) {
            try {
                Configuration config = Configuration.getInstance();

                //Decode with HttpPost Binding
                HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(new BasicParserPool());
                BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
                messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(request));

                decode.decode(messageContext);

                messageContext.setMetadataProvider(config.getMetaDataProvier());
                CriteriaSet criteriaSet = new CriteriaSet();
                criteriaSet
                        .add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS));
                criteriaSet.add(new EntityIDCriteria(config.getPVP2IDPMetadataEntityName()));
                criteriaSet.add(new UsageCriteria(UsageType.SIGNING));

                MetadataCredentialResolverFactory credentialResolverFactory = MetadataCredentialResolverFactory
                        .getFactory();
                MetadataCredentialResolver credentialResolver = credentialResolverFactory
                        .getInstance(config.getMetaDataProvier());

                //Verify Signature
                List<KeyInfoProvider> keyInfoProvider = new ArrayList<KeyInfoProvider>();
                keyInfoProvider.add(new DSAKeyValueProvider());
                keyInfoProvider.add(new RSAKeyValueProvider());
                keyInfoProvider.add(new InlineX509DataProvider());

                KeyInfoCredentialResolver keyInfoResolver = new BasicProviderKeyInfoCredentialResolver(
                        keyInfoProvider);

                ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(
                        credentialResolver, keyInfoResolver);

                SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule(
                        trustEngine);
                SAML2AuthnRequestsSignedRule signedRole = new SAML2AuthnRequestsSignedRule();
                BasicSecurityPolicy policy = new BasicSecurityPolicy();
                policy.getPolicyRules().add(signatureRule);
                policy.getPolicyRules().add(signedRole);
                SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(policy);
                messageContext.setSecurityPolicyResolver(resolver);

                messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);

                signatureRule.evaluate(messageContext);

                SignableXMLObject samlResponse = (SignableXMLObject) messageContext.getInboundMessage();

                log.info("PVP2 statusrequest or statusresponse is valid");

                if (samlResponse instanceof LogoutResponse) {

                    LogoutResponse sloResp = (LogoutResponse) samlResponse;

                    //set assertion
                    org.w3c.dom.Document doc = SAML2Utils.asDOMDocument(samlResponse);
                    String assertion = DOMUtils.serializeNode(doc);
                    bean.setAssertion(assertion);

                    if (sloResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {

                        bean.setSuccessMessage(
                                "Der Single Log-Out Vorgang konnte erfolgreich durchgefhrt werden.");

                        setAnser(request, response, bean);
                        return;

                    } else {
                        bean.setErrorMessage(
                                "Der Single Log-Out Vorgang war nicht erfolgreich.<br>Bitte schlieen Sie aus sicherheitsgrnden den Browser!");
                        setAnser(request, response, bean);
                        return;

                    }

                } else if (samlResponse instanceof LogoutRequest) {
                    //invalidate user session
                    request.getSession().invalidate();

                    //build LogOutResponse
                    LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class);
                    SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator();
                    sloResp.setID(gen.generateIdentifier());
                    sloResp.setIssueInstant(new DateTime());
                    NameID name = SAML2Utils.createSAMLObject(NameID.class);
                    Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class);

                    String serviceURL = config.getPublicUrlPreFix(request);
                    if (!serviceURL.endsWith("/"))
                        serviceURL = serviceURL + "/";
                    name.setValue(serviceURL);
                    issuer.setValue(serviceURL);
                    issuer.setFormat(NameIDType.ENTITY);
                    sloResp.setIssuer(issuer);

                    Status status = SAML2Utils.createSAMLObject(Status.class);
                    sloResp.setStatus(status);
                    StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class);
                    statusCode.setValue(StatusCode.SUCCESS_URI);
                    status.setStatusCode(statusCode);

                    String entityname = config.getPVP2IDPMetadataEntityName();
                    if (MiscUtil.isEmpty(entityname)) {
                        log.info("No IDP EntityName configurated");
                        throw new ConfigurationException("No IDP EntityName configurated");
                    }

                    //get IDP metadata from metadataprovider
                    HTTPMetadataProvider idpmetadata = config.getMetaDataProvier();
                    EntityDescriptor idpEntity = idpmetadata.getEntityDescriptor(entityname);
                    if (idpEntity == null) {
                        log.info("IDP EntityName is not found in IDP Metadata");
                        throw new ConfigurationException("IDP EntityName is not found in IDP Metadata");
                    }

                    //select authentication-service url from metadata
                    SingleLogoutService redirectEndpoint = null;
                    for (SingleLogoutService sss : idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS)
                            .getSingleLogoutServices()) {

                        //Get the service address for the binding you wish to use
                        if (sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
                            redirectEndpoint = sss;
                        }
                    }
                    sloResp.setDestination(redirectEndpoint.getLocation());

                    //sign authentication request
                    KeyStore keyStore = config.getPVP2KeyStore();
                    X509Credential authcredential = new KeyStoreX509CredentialAdapter(keyStore,
                            config.getPVP2KeystoreAuthRequestKeyAlias(),
                            config.getPVP2KeystoreAuthRequestKeyPassword().toCharArray());

                    Signature signer = SAML2Utils.createSAMLObject(Signature.class);
                    signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
                    signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
                    signer.setSigningCredential(authcredential);
                    sloResp.setSignature(signer);

                    HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
                    HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(response, true);
                    BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
                    SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject();
                    service.setBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
                    service.setLocation(redirectEndpoint.getLocation());
                    ;

                    context.setOutboundSAMLMessageSigningCredential(authcredential);
                    context.setPeerEntityEndpoint(service);
                    context.setOutboundSAMLMessage(sloResp);
                    context.setOutboundMessageTransport(responseAdapter);
                    context.setRelayState(messageContext.getRelayState());

                    encoder.encode(context);

                } else {
                    bean.setErrorMessage("Kein gltiger LogOut Request oder LogOut Response");
                    setAnser(request, response, bean);
                    return;

                }

            } catch (Exception e) {
                log.warn("Internal error", e);
                bean.setErrorMessage("Internal Error: " + e.getMessage());
                setAnser(request, response, bean);
                return;
            }

        } else {
            bean.setErrorMessage("Die Demoapplikation untersttzt nur SAML2 POST-Binding.");
            setAnser(request, response, bean);
            return;

        }
    }

    private void setAnser(HttpServletRequest request, HttpServletResponse response, ApplicationBean answersBean)
            throws ServletException, IOException {
        // store bean in session
        request.setAttribute("answers", answersBean);

        // you now can forward to some view, for example some results.jsp
        request.getRequestDispatcher("demoapp.jsp").forward(request, response);

    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        process(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        process(request, response);
    }
}