umu.eadmin.servicios.umu2stork.ReturnPage.java Source code

Java tutorial

Introduction

Here is the source code for umu.eadmin.servicios.umu2stork.ReturnPage.java

Source

package umu.eadmin.servicios.umu2stork;

/*
 * Copyright (C) 2015 Elena Torroglosa (emtg@um.es)
 * Copyright (C) 2015 Jordi Ortiz      (jordi.ortiz@um.es)
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.joda.time.DateTime;
import org.opensaml.Configuration;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.common.SAMLVersion;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Attribute;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Status;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.impl.ResponseMarshaller;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.parse.XMLParserException;
import org.opensaml.xml.security.SecurityConfiguration;
import org.opensaml.xml.security.SecurityHelper;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureException;
import org.opensaml.xml.signature.Signer;
import org.opensaml.xml.util.XMLHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import eu.stork.peps.auth.commons.AttributeUtil;
import eu.stork.peps.auth.commons.IPersonalAttributeList;
import eu.stork.peps.auth.commons.PEPSUtil;
import eu.stork.peps.auth.commons.PEPSValues;
import eu.stork.peps.auth.commons.PersonalAttribute;
import eu.stork.peps.auth.commons.PersonalAttributeList;
import eu.stork.peps.auth.commons.STORKAuthnResponse;
import eu.stork.peps.auth.engine.STORKSAMLEngine;
import eu.stork.peps.exceptions.STORKSAMLEngineException;
import eu.storkWebedu.translator.EGAttribute;
import eu.storkWebedu.translator.Translator;

/**
 * Servlet implementation class ReturnPage
 */
@WebServlet("/ReturnPage")
public class ReturnPage extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public static final String HTML_START = "<html>";
    public static final String HTML_END = "</body></html>";
    public static final String HTML_HEAD = "<head><title>edupeps SAML Adapter</title></head>";

    private static Properties properties;
    private static Properties i18n;

    private final static Logger logger = Logger
            .getLogger(umu.eadmin.servicios.umu2stork.ReturnPage.class.getName());

    private final long MAX_SESSION_TIME = 10 * 60000 * 2; // 60000 ms in a minute x2

    private Stork2ProxyH2DB proxyH2db;

    /**
     * @throws Exception 
     * @see HttpServlet#HttpServlet()
     */
    public ReturnPage() throws Exception {
        super();
        // TODO Auto-generated constructor stub
        try {
            properties = new Properties();
            properties.load(ReturnPage.class.getClassLoader().getResourceAsStream("proxyconfig.properties"));
        } catch (IOException e) {
            throw new Exception("Could not load configuration file " + e.getMessage());
        }
    }

    /**
     * @see HttpServlet#init()
     */
    public void init() throws ServletException {
        try {
            proxyH2db = Stork2ProxyH2DB.getInstance();
        } catch (Exception e) {
            throw new ServletException("ReturnPage::init() - Unable to open Proxy H2 DB" + e);
        }

    }

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

        PrintWriter out = response.getWriter();
        out.println(HTML_START + "<h2>Byebye world! (GET) </h2><br/><h3>Date=" + date + "</h3>" + HTML_END);
        // TODO Auto-generated method stub
    }

    private void closeWithError(PrintWriter out, Properties i18n, String key) {
        out.println(i18n.getProperty(key));
        out.println("<b>" + i18n.getProperty("error.proxy.abort") + "</b>");
        out.println("</body>");
        out.println(HTML_END);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        i18n = new Properties();
        i18n.load(ReturnPage.class.getClassLoader().getResourceAsStream("en.properties")); //default

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(HTML_START);
        out.println(HTML_HEAD);
        // AUTO-LOAD Form header
        //out.println("<body style=\"background-image:url(webapp/img/background.png); background-size:scale; background-repeat: no-repeat;background-position: center top\" onload=\"document.createElement('form').submit.call(document.getElementById('myForm'))\">");
        // NO AUTO-LOAD
        out.println(
                "<body style=\"background-image:url(webapp/img/background.png); background-size:scale; background-repeat: no-repeat;background-position: center top\">");

        logger.info("---- edupeps::ReturnPage::doPost() ----");
        Map<String, String> map = new HashMap<String, String>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        String jsessionid = "";
        try {
            String cookie = map.get("cookie");
            String[] cookiesplt = cookie.split("=");
            if (cookiesplt.length < 1)
                throw new ServletException("Unable to recover jsessionid, regex problem over: " + cookie);
            jsessionid = cookiesplt[1];
        } catch (ClassCastException cce) {
            logger.severe("Unable to recover jsessionid\n" + cce);
            throw new ServletException("ReturnPage::DoPost() - Unable to recover jsessionid (InvalidCast)\n" + cce);
        } catch (NullPointerException npe) {
            logger.severe("Unable to recover jsessionid\n" + npe);
            throw new ServletException("ReturnPage::DoPost() - Unable to recover jsessionid (null)\n" + npe);
        } catch (java.lang.IndexOutOfBoundsException iobe) {
            logger.severe("Unable to recover jsessionid - Malformed cookie\n" + iobe);
            throw new ServletException(
                    "ReturnPage::DoPost() - Unable to recover jsessionid (IndexOutOfBoundsException)\n" + iobe);
        }

        String paramSAMLResponse = null;

        logger.info("Parameters Received:");
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String paramName = parameterNames.nextElement();
            logger.info(paramName + ":");
            String[] paramValues = request.getParameterValues(paramName);
            for (int i = 0; i < paramValues.length; i++) {
                String paramValue = paramValues[i];
                logger.info("    " + paramValue);
            }
            if (paramName.compareTo("SAMLResponse") == 0)
                paramSAMLResponse = paramValues[0];
        }

        String appparam = "";
        String dataparam = "";
        String returnURLparam = "";
        String serviceparam = "";

        // Recover session or abort if timeout
        Stork2ProxyH2DB.Stork2ProxyH2DBSession session = null;
        try {
            session = proxyH2db.getSession(jsessionid);
        } catch (Exception e) {
            closeWithError(out, i18n, "error.return.jsession");
            throw new ServletException("Unable to recover session: " + jsessionid);
        }
        // Multi Language i18n
        String langparam = session.getLang();
        if (langparam.equals("es")) {
            i18n = new Properties();
            i18n.load(ReturnPage.class.getClassLoader().getResourceAsStream("es.properties"));
        }

        Date maxallowedtime = new Date(session.getSessiontime().getTime() + MAX_SESSION_TIME);
        Date actualtime = new Date();
        out.println("ActualTime: " + actualtime + "\nsessiontime: " + session.getSessiontime() + "/"
                + session.getSessiontimestr() + "\n maxallowedtime: " + maxallowedtime);
        if (actualtime.after(maxallowedtime)) {
            // closeWithError(out, i18n, "error.return.timeout");
            logger.severe("Session TimedOut " + jsessionid);
            if (!proxyH2db.deleteSession(jsessionid))
                logger.severe("Unable to remove session: " + jsessionid);
            out.println("WARNING: Ignoring session timeout!");
            // return;
        }
        logger.info("Session OK, deleting session from database");
        if (!proxyH2db.deleteSession(jsessionid)) {
            logger.severe("Unable to remove session after successfully found: " + jsessionid);
            closeWithError(out, i18n, "error.return.jsession");
            return;
        }

        appparam = session.getAppname();
        dataparam = session.getUuid();
        returnURLparam = session.getUrl();
        serviceparam = session.getService();

        //STORKAttrQueryResponse response = new STORKAttrQueryResponse();
        STORKAuthnResponse authnResponse = null;
        IPersonalAttributeList personalAttributeList = null;

        String proxyID = properties.getProperty("proxy.entityID");
        logger.info("proxy.entityID: " + proxyID);
        //Decodes SAML Response
        byte[] decSamlToken = PEPSUtil.decodeSAMLToken(paramSAMLResponse);

        //Get SAMLEngine instance
        STORKSAMLEngine engine = STORKSAMLEngine.getInstance("SP");
        if (engine != null) {
            try {
                //validate SAML Token
                authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost());
                logger.info("STORKAuthnResponse Id: " + authnResponse.getSamlId());
                logger.info("Base64 SAML Response: " + new String(authnResponse.getTokenSaml()));

                //response = engine.validateSTORKAttrQueryResponse(decSamlToken, (String) request.getRemoteHost());
            } catch (STORKSAMLEngineException e) {
                logger.severe("Could not validate token for Saml Response: \n" + e.getErrorMessage());
            }

            if (authnResponse.isFail()) {
                logger.severe("Saml Response is fail:\n" + authnResponse.getMessage());
                closeWithError(out, i18n, "error.return.saml");
                return;
            } else {
                // Generate output form
                out.println("<center><h1>" + i18n.getProperty("info.return.form") + "</h1></br><h2>"
                        + new Date().toString() + "</h2></center>");
                out.println("<form id='myForm' name='myForm' action='" + returnURLparam + "' method='post'>");

                // Get PersonalAttributeList form StorkResponse
                personalAttributeList = authnResponse.getPersonalAttributeList();

                // Initialise OpenSAML
                BasicParserPool ppMgr = null;

                try {
                    DefaultBootstrap.bootstrap();
                    ppMgr = new BasicParserPool();
                } catch (Exception e) {
                    // TODO
                }
                byte[] samlreqbase64decoded = Base64.decodeBase64(paramSAMLResponse);
                InputStream samlrespstream = new ByteArrayInputStream(samlreqbase64decoded);

                try {
                    Document samlrespdoc = ppMgr.parse(samlrespstream);
                    Element samlelement = samlrespdoc.getDocumentElement();
                    NamedNodeMap attrmap = samlelement.getAttributes();
                    for (int i = 0; i < attrmap.getLength(); i++) {
                        Node n = attrmap.item(i);
                        if (n.getNodeName().equals("AssertionConsumerServiceURL")) {
                            logger.info("Esta es la assertion url:" + n.getNodeValue());
                        }
                        logger.info(" " + attrmap.item(i));
                    }
                    logger.info(attrmap.toString());

                    UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
                    Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(samlelement);

                    Response responseSAML = null;
                    Response responseSAMLfromPEPS = null;
                    try {
                        responseSAMLfromPEPS = (Response) unmarshaller.unmarshall(samlelement);
                    } catch (UnmarshallingException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    Assertion assertionPEPS = responseSAMLfromPEPS.getAssertions().get(0);
                    XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();

                    String statusCode = responseSAMLfromPEPS.getStatus().getStatusCode().getValue();
                    logger.info("responseSAMLfromPEPS status: " + statusCode);
                    SAMLObjectBuilder<Issuer> issuerbuilder = (SAMLObjectBuilder<Issuer>) builderFactory
                            .getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
                    Issuer issuerobj = issuerbuilder.buildObject();
                    issuerobj.setValue(proxyID);
                    responseSAMLfromPEPS.setIssuer(issuerobj);
                    logger.info("responseSAMLfromPEPS Issuer: " + issuerobj.getValue());
                    responseSAMLfromPEPS.setDestination(returnURLparam);

                    String subject = assertionPEPS.getSubject().getNameID().getValue();
                    logger.info("assertionPEPS old subject: " + subject);
                    SAMLObjectBuilder<NameID> nameidbuilder = (SAMLObjectBuilder<NameID>) builderFactory
                            .getBuilder(NameID.DEFAULT_ELEMENT_NAME);
                    NameID nameid = nameidbuilder.buildObject();
                    nameid.setFormat(NameID.TRANSIENT);
                    nameid.setValue(UUID.randomUUID().toString());
                    assertionPEPS.getSubject().setNameID(nameid);
                    logger.info("assertionPEPS new nameID: " + assertionPEPS.getSubject().getNameID());

                    assertionPEPS.getSubject().getSubjectConfirmations().get(0).getSubjectConfirmationData()
                            .setRecipient(returnURLparam);
                    logger.info("assertionPEPS subject recipient: " + assertionPEPS.getSubject()
                            .getSubjectConfirmations().get(0).getSubjectConfirmationData().getRecipient());
                    Issuer assertionIssuer = ((SAMLObjectBuilder<Issuer>) builderFactory
                            .getBuilder(Issuer.DEFAULT_ELEMENT_NAME)).buildObject();
                    assertionIssuer.setValue(proxyID);
                    assertionPEPS.setIssuer(assertionIssuer);
                    logger.info("assertionPEPS issuer: " + assertionPEPS.getIssuer().getValue());
                    assertionPEPS.getConditions().getAudienceRestrictions().get(0).getAudiences().get(0)
                            .setAudienceURI(serviceparam);
                    logger.info("assertionPEPS audience: " + assertionPEPS.getConditions().getAudienceRestrictions()
                            .get(0).getAudiences().get(0).getAudienceURI());
                    assertionPEPS.getConditions().getConditions()
                            .remove(assertionPEPS.getConditions().getOneTimeUse());

                    // Attribute translation from stork format to edugain format
                    logger.info(" personalAttributeList: \n" + personalAttributeList.size());
                    logger.info(
                            " personalAttributeList get(0): " + personalAttributeList.iterator().next().getName());
                    ArrayList<Attribute>[] aledugain = eu.storkWebedu.translator.Translator
                            .translateToOpenSAML(personalAttributeList);
                    if (aledugain != null)
                        logger.info("aledugain not null");
                    else
                        logger.info("aledugain is null");

                    logger.info(" aledugain: \ntranslated: " + aledugain[0].size() + "\tpassthrough: "
                            + aledugain[1].size());
                    logger.info(" aledugain get(0): \n" + aledugain[0].get(0).getName());

                    assertionPEPS.getAttributeStatements().get(0).getAttributes().clear();
                    assertionPEPS.getAttributeStatements().get(0).getAttributes().addAll(aledugain[0]);
                    assertionPEPS.getAttributeStatements().get(0).getAttributes().addAll(aledugain[1]);

                    Assertion assertionSign = assertionPEPS;
                    Response responseSign = responseSAMLfromPEPS;

                    SigningCredential sign = new SigningCredential();
                    sign.intializeCredentials("edupeps", "edupeps-cert", "edupeps", "/opt/keystores/edupeps.jks");

                    Signature signatureAssertion = (Signature) Configuration.getBuilderFactory()
                            .getBuilder(Signature.DEFAULT_ELEMENT_NAME).buildObject(Signature.DEFAULT_ELEMENT_NAME);

                    Signature signatureResponse = (Signature) Configuration.getBuilderFactory()
                            .getBuilder(Signature.DEFAULT_ELEMENT_NAME).buildObject(Signature.DEFAULT_ELEMENT_NAME);

                    signatureAssertion.setSigningCredential(sign.getSigningCredential());
                    signatureResponse.setSigningCredential(sign.getSigningCredential());

                    // This is also the default if a null SecurityConfiguration is specified
                    SecurityConfiguration secConfig = Configuration.getGlobalSecurityConfiguration();
                    // If null this would result in the default KeyInfoGenerator being used
                    String keyInfoGeneratorProfile = "XMLSignature";

                    try {
                        SecurityHelper.prepareSignatureParams(signatureAssertion, sign.getSigningCredential(),
                                secConfig, null);
                        SecurityHelper.prepareSignatureParams(signatureResponse, sign.getSigningCredential(),
                                secConfig, null);
                    } catch (SecurityException e) {
                        e.printStackTrace();
                    } catch (org.opensaml.xml.security.SecurityException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    assertionSign.setSignature(signatureAssertion);
                    responseSign.setSignature(signatureResponse);

                    try {
                        Configuration.getMarshallerFactory().getMarshaller(assertionSign).marshall(assertionSign);
                    } catch (MarshallingException e) {
                        e.printStackTrace();
                    }

                    try {
                        Signer.signObject(signatureAssertion);
                    } catch (SignatureException e) {
                        e.printStackTrace();
                    }

                    try {
                        Configuration.getMarshallerFactory().getMarshaller(assertionSign).marshall(assertionSign);
                        Configuration.getMarshallerFactory().getMarshaller(responseSign).marshall(responseSign);
                    } catch (MarshallingException e) {
                        e.printStackTrace();
                    }

                    try {
                        Signer.signObject(signatureResponse);
                    } catch (SignatureException e) {
                        e.printStackTrace();
                    }

                    ResponseMarshaller marshaller = new ResponseMarshaller();
                    Element plain = null;
                    try {
                        plain = marshaller.marshall(responseSign);
                    } catch (MarshallingException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    String samlResponse = XMLHelper.nodeToString(plain);
                    String xml = samlResponse;
                    logger.info("response-xml:\n" + xml);
                    String eduresponseEncoded = org.opensaml.xml.util.Base64.encodeBytes(xml.getBytes(),
                            org.opensaml.xml.util.Base64.DONT_BREAK_LINES);
                    // Parameter saml response to form
                    out.println("<input type='hidden' name='SAMLRequest' value='" + eduresponseEncoded + "'>");

                } catch (XMLParserException xmlparsee) {
                    System.err.println("Unable to xml parse SAMLint Request)" + xmlparsee);
                }

                out.println("<input type='hidden' name='" + EduGAIN2StorkProxy.SERVICEHEADERSTR + "' value='"
                        + serviceparam + "'>");
                out.println(
                        "<center><button type='submit' value='Send' method='post'><img src='webapp/img/send.png' width=25 border=3></button></center>");
                out.println("</form>");
            }
        }
        out.println(HTML_END);
    }

    /**
     * Copied from branches/dev_branch/Commons/src/main/java/eu/stork/peps/auth/commons/PersonalAttribute.java
     * 
     * Prints the PersonalAttribute in the following format.
     * name:required:[v,a,l,u,e,s]|[v=a,l=u,e=s]:status;
     * 
     * @return The PersonalAttribute as a string.
     */
    public String printPersonalAttribute(PersonalAttribute pa) {
        final StringBuilder strBuild = new StringBuilder();

        AttributeUtil.appendIfNotNull(strBuild, "Stork." + pa.getName());
        strBuild.append(PEPSValues.ATTRIBUTE_TUPLE_SEP.toString());
        AttributeUtil.appendIfNotNull(strBuild, String.valueOf(pa.isRequired()));
        strBuild.append(PEPSValues.ATTRIBUTE_TUPLE_SEP.toString());
        strBuild.append('[');

        if (pa.isEmptyValue()) {
            if (!pa.isEmptyComplexValue()) {
                AttributeUtil.appendIfNotNull(strBuild,
                        AttributeUtil.mapToString(pa.getComplexValue(), PEPSValues.ATTRIBUTE_VALUE_SEP.toString()));
            }
        } else {
            AttributeUtil.appendIfNotNull(strBuild,
                    AttributeUtil.listToString(pa.getValue(), PEPSValues.ATTRIBUTE_VALUE_SEP.toString()));
        }

        strBuild.append(']');
        strBuild.append(PEPSValues.ATTRIBUTE_TUPLE_SEP.toString());
        AttributeUtil.appendIfNotNull(strBuild, pa.getStatus());
        strBuild.append(PEPSValues.ATTRIBUTE_SEP.toString());

        return strBuild.toString();
    }
}