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

Java tutorial

Introduction

Here is the source code for umu.eadmin.servicios.umu2stork.EduGAIN2StorkProxy.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.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.Properties;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

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.bouncycastle.util.encoders.Base64;

import eu.stork.peps.auth.commons.PersonalAttribute;
import eu.stork.peps.auth.commons.PersonalAttributeList;
import eu.stork.peps.auth.commons.STORKAuthnRequest;
import eu.stork.peps.auth.engine.STORKSAMLEngine;
import eu.stork.peps.exceptions.STORKSAMLEngineException;

import org.opensaml.DefaultBootstrap;
import org.opensaml.Configuration;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.parse.XMLParserException;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.opensaml.saml2.core.AuthnRequest;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.NamedNodeMap;

import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;

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

    public static final String PRIVATE_KEY_FILE_PARAM = "proxy.privatekey";

    public static final String DATAHEADERSTR = "DATA";
    public static final String URLHEADERSTR = "URL";
    public static final String APPHEADERSTR = "APP";
    public static final String SERVICEHEADERSTR = "service";
    public static final String LANGHEADERSTR = "lang";
    public static final String SAMLIntREQSTR = "SAMLRequest";

    private static final String PROPERTIES_APP_PARAM_PREFIX = "proxy.apps";
    private static final String PROPERTIES_MANDPROP_PARAM_POSTFIX = ".mandatoryattributes";
    private static final String PROPERTIES_OPTPROP_PARAM_POSTFIX = ".optionalattributes";
    private static final String PROPERTIES_APP_URL_POSTFIX = ".url";

    private static final String PROPERTIES_PROXY_URL_PARAM = "proxy.url";
    private static final String PROPERTIES_PEPS_URL_PARAM = "proxy.peps";
    private static final String PROPERTIES_RETURNPAGE_URL_PARAM = "proxy.return";
    private static final String PROPERTIES_SPNAME_PARAM = "proxy.spName";
    private static final String PROPERTIES_SPSECTOR_PARAM = "proxy.spSector";
    private static final String PROPERTIES_SPINSTITUTION_PARAM = "proxy.spInstitution";
    private static final String PROPERTIES_SPAPP_PARAM = "proxy.spApplication";
    private static final String PROPERTIES_SPCOUNTRY_PARAM = "proxy.spCountry";
    private static final String PROPERTIES_SPID_PARAM = "proxy.spId";

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

    //Attributes
    private static Properties properties;
    private static Properties i18n;
    private static Map<String, String[]> mandattributesxapp;
    private static Map<String, String[]> optattributesxapp;
    private static String returnPageUrl;
    private static String PEPSPageUrl;
    private static String spname;
    private static String spsector;
    private static String spinstitution;
    private static String spapp;
    private static String spcountry;
    private static String spid;

    private Stork2ProxyH2DB proxyH2db;

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

    private BasicParserPool ppMgr;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public EduGAIN2StorkProxy() throws Exception {
        super();
        // TODO Auto-generated constructor stub
        mandattributesxapp = new HashMap<String, String[]>();
        optattributesxapp = new HashMap<String, String[]>();

        try {
            properties = new Properties();
            properties.load(ReturnPage.class.getClassLoader().getResourceAsStream("proxyconfig.properties"));
            // Load app configuration
            logger.info(PROPERTIES_APP_PARAM_PREFIX);
            String appsproperty = properties.getProperty(PROPERTIES_APP_PARAM_PREFIX);
            logger.info("ATTR:" + appsproperty);
            String[] appsarray = appsproperty.split(";");
            for (String app : appsarray) {
                logger.info(PROPERTIES_APP_PARAM_PREFIX + "." + app + PROPERTIES_MANDPROP_PARAM_POSTFIX);
                String mandappattributesproperty = properties
                        .getProperty(PROPERTIES_APP_PARAM_PREFIX + "." + app + PROPERTIES_MANDPROP_PARAM_POSTFIX);
                if (mandappattributesproperty != null) {
                    logger.info("MANDATTRPROP:" + mandappattributesproperty);
                    String[] mandpropertiesarray = mandappattributesproperty.split(";");
                    mandattributesxapp.put(app, mandpropertiesarray);
                }
                logger.info(PROPERTIES_APP_PARAM_PREFIX + "." + app + PROPERTIES_OPTPROP_PARAM_POSTFIX);

                String appattributesproperty = properties
                        .getProperty(PROPERTIES_APP_PARAM_PREFIX + "." + app + PROPERTIES_OPTPROP_PARAM_POSTFIX);
                if (appattributesproperty != null) {
                    logger.info("MANDATTRPROP:" + appattributesproperty);
                    String[] propertiesarray = appattributesproperty.split(";");
                    optattributesxapp.put(app, propertiesarray);
                }
            }

            EduGAIN2StorkProxy.PEPSPageUrl = properties.getProperty(PROPERTIES_PEPS_URL_PARAM);
            EduGAIN2StorkProxy.returnPageUrl = properties.getProperty(PROPERTIES_RETURNPAGE_URL_PARAM);
            EduGAIN2StorkProxy.spname = properties.getProperty(PROPERTIES_SPNAME_PARAM);
            EduGAIN2StorkProxy.spsector = properties.getProperty(PROPERTIES_SPSECTOR_PARAM);
            EduGAIN2StorkProxy.spinstitution = properties.getProperty(PROPERTIES_SPINSTITUTION_PARAM);
            EduGAIN2StorkProxy.spapp = properties.getProperty(PROPERTIES_SPAPP_PARAM);
            EduGAIN2StorkProxy.spcountry = properties.getProperty(PROPERTIES_SPCOUNTRY_PARAM);
            EduGAIN2StorkProxy.spid = properties.getProperty(PROPERTIES_SPID_PARAM);

        } catch (IOException e) {
            throw new Exception("Could not load configuration file " + e.getMessage());
        }

        // Initialise OpenSAML
        DefaultBootstrap.bootstrap();
        this.ppMgr = new BasicParserPool();
    }

    /**
     * @see HttpServlet#init()
     */
    public void init() throws ServletException {
        try {
            proxyH2db = Stork2ProxyH2DB.getInstance();
        } catch (Exception e) {
            throw new ServletException("Unable to start in memory DB");
        }

    }

    /**
     * @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 + BODY_START + "<h2>Hello world! (GET) </h2><br/><h3>Date=" + date + "</h3>"
                + BODY_END + HTML_END);

        logger.info("---- edupeps::EduGAIN2StorkProxy::doGet() ----");

        response.setContentType("text/html");
        out.close();
    }

    private static byte[] inflate(byte[] bytes, boolean nowrap) throws Exception {
        Inflater decompressor = null;
        InflaterInputStream decompressorStream = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            decompressor = new Inflater(nowrap);
            decompressorStream = new InflaterInputStream(new ByteArrayInputStream(bytes), decompressor);
            byte[] buf = new byte[1024];
            int count;
            while ((count = decompressorStream.read(buf)) != -1) {
                out.write(buf, 0, count);
            }
            return out.toByteArray();
        } finally {
            if (decompressor != null) {
                decompressor.end();
            }
            try {
                if (decompressorStream != null) {
                    decompressorStream.close();
                }
            } catch (IOException ioe) {
                /*ignore*/
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ioe) {
                /*ignore*/
            }
            logger.info("SAMLRequest inflated.");
        }
    }

    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);
    }

    private String printXMLNode(Node n, int depth) {
        String result = "";
        for (int i = 0; i < depth; i++)
            result += "&emsp;";
        result += n.getNodeName() + ": " + n.getNodeValue();
        if (n.hasChildNodes()) {
            for (int i = 0; i < n.getChildNodes().getLength(); i++) {
                result += "</BR>" + printXMLNode(n.getChildNodes().item(i), depth + 1);
            }
        }
        return result;
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        logger.info("---- edupeps::EduGAIN2StorkProxy::doPost() ----");

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        i18n = new Properties();
        i18n.load(ReturnPage.class.getClassLoader().getResourceAsStream("en.properties")); //default

        UtilesRsa encoder = new UtilesRsa();

        out.println(HTML_START);
        out.println(HTML_HEAD);
        // AUTO-LOAD FORM
        //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\">");

        // Enumeration <String> params = request.getParameterNames();

        Map<String, String> headerparammap = new HashMap<String, String>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            headerparammap.put(key, value);
        }
        for (String aux : headerparammap.values()) {
            logger.info("\tparam: " + aux);
        }

        String jsessionid = "";
        try {
            String cookie = headerparammap.get("cookie");
            if (cookie != null) {
                logger.info("Cookie: " + cookie);
                String[] cookiesplt = cookie.split("=");
                if (cookiesplt.length < 1)
                    throw new ServletException("Unable to recover jsessionid, regex problem over: " + cookie);
                jsessionid = cookiesplt[1];
            } else {
                logger.warning("No cookie found!!");
            }
        } catch (ClassCastException cce) {
            logger.severe("Unable to recover jsessionid\n" + cce);
            throw new ServletException(
                    "eduGAIN2StorkProxy::DoPost() - Unable to recover jsessionid (InvalidCast)\n" + cce);
        } catch (NullPointerException npe) {
            logger.severe("Unable to recover jsessionid\n" + npe);
            throw new ServletException(
                    "eduGAIN2StorkProxy::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(
                    "eduGAIN2StorkProxy::DoPost() - Unable to recover jsessionid (IndexOutOfBoundsException)\n"
                            + iobe);
        }

        // Load Multi-language i18n
        String langparam = request.getParameter(LANGHEADERSTR);
        if (langparam != null)
            if (langparam.equals("es")) {
                i18n = new Properties();
                i18n.load(ReturnPage.class.getClassLoader().getResourceAsStream("es.properties"));
            } else
                langparam = "en";

        /*** SAMLInt ***/
        // Recover SAML_int request and parse
        // https://wiki.shibboleth.net/confluence/display/OpenSAML/OSTwoUsrManJavaCreateFromXML
        String samlreq = request.getParameter(SAMLIntREQSTR);
        if (samlreq == null) {
            logger.severe("FATAL ERROR: Missing SAML Int Request!");
            this.log("FATAL ERROR: Missing SAML Int Request!");
            closeWithError(out, i18n, "error.proxy.saml.missing");
            return;
        }

        logger.info("We have a SAMLRequest");
        logger.info("samlreq=" + samlreq);
        byte[] samlreqbase64decoded = Base64.decode(samlreq.getBytes("UTF-8"));
        logger.info("samlreqbase64decoded=" + new String(samlreqbase64decoded));

        byte[] samlreqinflated = null;
        try {
            //try DEFLATE (rfc 1951) -- according to SAML spec
            samlreqinflated = inflate(samlreqbase64decoded, true);
            logger.info("samlreqinflated=" + new String(samlreqinflated));
        } catch (Exception e) {
            logger.severe("FATAL ERROR: SAMLRequest could not be inflated");
            this.log("FATAL ERROR: SAMLRequest could not be inflated");
            closeWithError(out, i18n, "error.proxy.saml.inflate");
        }

        //InputStream samlreqstream = new ByteArrayInputStream(samlreqbase64decoded);
        InputStream samlreqstream = new ByteArrayInputStream(samlreqinflated);

        String returnPageUrlSP = null;
        String SPIssuer = null;
        try {
            Document samlreqdoc = ppMgr.parse(samlreqstream);
            Element samlelement = samlreqdoc.getDocumentElement();
            UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
            Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(samlelement);
            AuthnRequest authnRequestSAML = null;
            try {
                authnRequestSAML = (AuthnRequest) unmarshaller.unmarshall(samlelement);
                SPIssuer = authnRequestSAML.getIssuer().getValue();
                logger.info("issuer: " + SPIssuer);
                returnPageUrlSP = authnRequestSAML.getAssertionConsumerServiceURL();
                logger.info("consumerService-returnpage: " + returnPageUrlSP);
                //Signature sig = authnRequestSAML.getSignature();
            } catch (UnmarshallingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (XMLParserException xmlparsee) {
            logger.severe("Unable to xml parse SAMLint Request)" + xmlparsee);
            throw new ServletException("ERROR: Unable to xml parse SAMLint Request");
        }
        out.println("</BR></BR>");

        // Country code attribute recovery
        String countryCodeParam = request.getParameter("CountryCode");
        if (countryCodeParam == null) {
            logger.severe("FATAL ERROR: Missing Country Code Parameter, abort!");
            this.log("FATAL ERROR: Missing Country Code Parameter, abort!");
            closeWithError(out, i18n, "error.proxy.contrycode");
            return;
        }
        logger.info("CountryCode: " + countryCodeParam);

        logger.info("Creando Personal Attribute List para consulta");
        PersonalAttributeList pal = new PersonalAttributeList();
        PersonalAttribute pa = null;

        // Serviceparam indicates configuration var to select the attributes to request. To be removed when SAMLint request is fine
        String serviceparam = properties.getProperty(PROPERTIES_PROXY_URL_PARAM);
        boolean appfound = false;
        for (String app : optattributesxapp.keySet()) {
            logger.info("Checking: "
                    + properties.getProperty(PROPERTIES_APP_PARAM_PREFIX + "." + app + PROPERTIES_APP_URL_POSTFIX)
                    + " vs " + serviceparam + "</BR>");
            if (properties.getProperty(PROPERTIES_APP_PARAM_PREFIX + "." + app + PROPERTIES_APP_URL_POSTFIX)
                    .equals(serviceparam)) {
                if (optattributesxapp.containsKey(app)) {
                    String[] mandattrs = mandattributesxapp.get(app);
                    for (String attr : mandattrs) {
                        logger.info("Mandatory " + app + " : " + attr);
                        pa = new PersonalAttribute();
                        pa.setName(attr);
                        pa.setIsRequired(true);
                        pal.add(pa);
                    }

                    String[] attrs = optattributesxapp.get(app);
                    for (String attr : attrs) {
                        logger.info("Optional " + app + " : " + attr);
                        pa = new PersonalAttribute();
                        pa.setName(attr);
                        pa.setIsRequired(false);
                        pal.add(pa);
                    }
                    appfound = true;
                }
            }
        }
        if (!appfound) {
            logger.info("Servicio Desconocido " + serviceparam);
            closeWithError(out, i18n, "error.proxy.appunk");
            return;

        }

        int QAA = 1;

        final String destinationURL = EduGAIN2StorkProxy.PEPSPageUrl;
        final String assertConsumerUrl = EduGAIN2StorkProxy.returnPageUrl;

        final String spName = EduGAIN2StorkProxy.spname;
        final String spSector = EduGAIN2StorkProxy.spsector;
        final String spInstitution = EduGAIN2StorkProxy.spinstitution;
        final String spApplication = EduGAIN2StorkProxy.spapp;
        final String spCountry = EduGAIN2StorkProxy.spcountry;
        final String spId = EduGAIN2StorkProxy.spid;

        final STORKAuthnRequest authRequest = new STORKAuthnRequest();

        logger.info("Generating STORK Auth Request");

        authRequest.setDestination(destinationURL);
        authRequest.setProviderName(spName);
        authRequest.setQaa(QAA);
        authRequest.setPersonalAttributeList(pal);
        authRequest.setAssertionConsumerServiceURL(assertConsumerUrl);

        // new parameters
        authRequest.setSpSector(spSector);
        authRequest.setSpInstitution(spInstitution);
        authRequest.setSpApplication(spApplication);
        authRequest.setSpCountry(spCountry);
        authRequest.setSPID(spId);
        authRequest.setCitizenCountryCode(countryCodeParam);
        authRequest.setPersonalAttributeList(pal);

        logger.info("Recuperando STORK Engine");

        STORKSAMLEngine engine = STORKSAMLEngine.getInstance("SP"); // SP -
        // Magic
        // Number?

        String authReqSTORKString = "";
        final STORKAuthnRequest saml;
        try {
            logger.info("Generate STORK SAML Auth Request from auth Request");
            saml = engine.generateSTORKAuthnRequest(authRequest);
            byte[] authReqSTORKbytes = Base64.encode(saml.getTokenSaml());
            authReqSTORKString = new String(authReqSTORKbytes);
            logger.info("STORKAuthnRequest Size: " + authReqSTORKbytes);
            logger.info("STORKAuthnRequest String: " + authReqSTORKString);
            logger.info("STORKAuthnRequest Id: " + saml.getSamlId());

            out.println("<form id='myForm' name='myForm' action='" + destinationURL + "' method='post'>");
            out.println("<input type='hidden' name='country' value='" + countryCodeParam + "'>");
            out.println("<input type='hidden' name='SAMLRequest' value='" + authReqSTORKString + "'>");
            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>");

        } catch (STORKSAMLEngineException e) {
            out.println(i18n.getProperty("error.proxy.saml") + " " + e);
            logger.severe("Engine error generating the Stork Authn Request");
            e.printStackTrace();
        }

        // SAVE SESSION
        // saveSession(String jsessionid, String uuid, String appname, String url, String service, String lang)
        try {
            this.proxyH2db.saveSession(jsessionid, "", "", returnPageUrlSP, SPIssuer, langparam);
        } catch (Exception e) {
            throw new ServletException("DB Problem: " + e);
        }

        Date date = new Date();

        out.println("<h2>" + i18n.getProperty("info.proxy.wait") + "</h2><br/><h3>Date=" + date + "</h3><br>");

        out.println("</body>");
        out.println(HTML_END);
        out.close();

    }

}