at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet.java Source code

Java tutorial

Introduction

Here is the source code for at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet.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.auth.servlet;

import iaik.x509.X509Certificate;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.activation.DataSource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.opensaml.saml2.core.StatusCode;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import at.gv.egovernment.moa.id.auth.AuthenticationServer;
import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.data.IdentityLink;
import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
import at.gv.egovernment.moa.id.auth.stork.STORKException;
import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor;
import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.HTTPUtils;
import at.gv.egovernment.moa.id.util.IdentityLinkReSigner;
import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.DOMUtils;
import at.gv.egovernment.moa.util.StringUtils;
import at.gv.egovernment.moa.util.XPathUtils;
import at.gv.util.xsd.xmldsig.SignatureType;
import at.gv.util.xsd.xmldsig.X509DataType;
import eu.stork.oasisdss.api.ApiUtils;
import eu.stork.oasisdss.api.LightweightSourceResolver;
import eu.stork.oasisdss.api.exceptions.ApiUtilsException;
import eu.stork.oasisdss.api.utils.ByteArrayDataSource;
import eu.stork.oasisdss.profile.DocumentType;
import eu.stork.oasisdss.profile.DocumentWithSignature;
import eu.stork.oasisdss.profile.SignRequest;
import eu.stork.oasisdss.profile.SignResponse;
import eu.stork.peps.auth.commons.IPersonalAttributeList;
import eu.stork.peps.auth.commons.PEPSUtil;
import eu.stork.peps.auth.commons.PersonalAttribute;
import eu.stork.peps.auth.commons.PersonalAttributeList;
import eu.stork.peps.auth.commons.STORKAttrQueryRequest;
import eu.stork.peps.auth.commons.STORKAuthnRequest;
import eu.stork.peps.auth.commons.STORKAuthnResponse;
import eu.stork.peps.auth.engine.STORKSAMLEngine;
import eu.stork.peps.exceptions.STORKSAMLEngineException;

import eu.stork.documentservice.DocumentService;
import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.BindingProvider;

/**
 * Endpoint for receiving STORK response messages
 * @deprecated Use {@link at.gv.egovernment.moa.id.auth.modules.stork.tasks.PepsConnectorTask} instead.
 */
public class PEPSConnectorServlet extends AuthServlet {

    private static final long serialVersionUID = 1L;

    public static final String PEPSCONNECTOR_SERVLET_URL_PATTERN = "/PEPSConnector";

    private String dtlUrl = null;

    public PEPSConnectorServlet() {
        super();

        try {
            AuthConfigurationProvider authConfigurationProvider = AuthConfigurationProvider.getInstance();
            dtlUrl = authConfigurationProvider.getDocumentServiceUrl();
            Logger.info("PEPSConnectorServlet, using dtlUrl:" + dtlUrl);
        } catch (Exception e) {
            dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService";
            e.printStackTrace();
            Logger.error("Loading documentservice url failed, using default value:" + dtlUrl);
        }

        //      Properties props = new Properties();
        //      try {
        //         props.load(DatabaseConnectorMySQLImpl.class.getResourceAsStream("docservice.properties"));
        //         dtlUrl = props.getProperty("docservice.url");
        //      } catch (IOException e) {
        //         dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService";
        //         Logger.error("Loading DTL config failed, using default value:"+dtlUrl);
        //         e.printStackTrace();
        //      }   
    }

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

    /**
     * Handles the reception of a STORK response message
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String pendingRequestID = null;

        try {

            Logger.warn(getClass().getName() + " is deprecated and should not be used any more.");

            Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message.");
            Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request));

            super.setNoCachingHeadersInHttpRespone(request, response);
            Logger.trace("No Caching headers set for HTTP response");

            //check if https or only http
            super.checkIfHTTPisAllowed(request.getRequestURL().toString());

            Logger.debug("Beginning to extract SAMLResponse out of HTTP Request");

            //extract STORK Response from HTTP Request
            //Decodes SAML Response
            byte[] decSamlToken;
            try {
                decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse"));
                Logger.debug("SAMLResponse: " + new String(decSamlToken));

            } catch (NullPointerException e) {
                Logger.error("Unable to retrieve STORK Response", e);
                throw new MOAIDException("stork.04", null);
            }

            //Get SAMLEngine instance
            STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing");

            STORKAuthnResponse authnResponse = null;
            try {
                //validate SAML Token
                Logger.debug("Starting validation of SAML response");
                authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost());
                Logger.info("SAML response succesfully verified!");
            } catch (STORKSAMLEngineException e) {
                Logger.error("Failed to verify STORK SAML Response", e);
                throw new MOAIDException("stork.05", null);
            }

            Logger.info("STORK SAML Response message succesfully extracted");
            Logger.debug("STORK response: ");
            Logger.debug(authnResponse.toString());

            Logger.debug("Trying to find MOA Session-ID ...");
            //String moaSessionID = request.getParameter(PARAM_SESSIONID);
            //first use SAML2 relayState 
            String moaSessionID = request.getParameter("RelayState");

            // escape parameter strings
            moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID);

            //check if SAML2 relaystate includes a MOA sessionID
            if (StringUtils.isEmpty(moaSessionID)) {
                //if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier

                moaSessionID = authnResponse.getInResponseTo();
                moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID);

                if (StringUtils.isEmpty(moaSessionID)) {
                    //No authentication session has been started before
                    Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started");
                    Logger.debug("PEPSConnectorURL was: " + request.getRequestURL());
                    throw new AuthenticationException("auth.02", new Object[] { moaSessionID });

                } else
                    Logger.trace(
                            "Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute.");

            } else
                //Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter.");
                Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState.");

            /*INFO!!!!
             * SAML message IDs has an different format then MOASessionIDs
             * This is only a workaround because many PEPS does not support SAML2 relayState or
             * MOASessionID as AttributConsumerServiceURL GET parameter
            */
            //            if (!ParamValidatorUtils.isValidSessionID(moaSessionID))
            //                throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12");

            pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID);

            //load MOASession from database
            AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID);
            //change MOASessionID
            moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession);

            Logger.info("Found MOA sessionID: " + moaSessionID);

            String statusCodeValue = authnResponse.getStatusCode();

            if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) {
                Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue);
                throw new MOAIDException("stork.06", new Object[] { statusCodeValue });
            }

            Logger.info("Got SAML response with authentication success message.");

            Logger.debug("MOA session is still valid");

            STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest();

            if (storkAuthnRequest == null) {
                Logger.error(
                        "Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID);
                throw new MOAIDException("stork.07", null);
            }

            OAAuthParameter oaParam = AuthConfigurationProvider.getInstance()
                    .getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix());
            if (oaParam == null)
                throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() });
            //================== Check QAA level start ====================
            int reqQaa = -1;
            int authQaa = -1;
            String authQaaStr = null;
            try {
                reqQaa = storkAuthnRequest.getQaa();

                //TODO: found better solution, but QAA Level in response could be not supported yet
                try {

                    authQaaStr = authnResponse.getAssertions().get(0).getAuthnStatements().get(0).getAuthnContext()
                            .getAuthnContextClassRef().getAuthnContextClassRef();
                    moaSession.setQAALevel(authQaaStr);

                } catch (Throwable e) {
                    Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level");
                    moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel());
                    authQaaStr = PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel();
                }
                if (authQaaStr != null)//Check value only if set
                {
                    authQaa = Integer.valueOf(authQaaStr.substring(PVPConstants.STORK_QAA_PREFIX.length()));
                    //               authQaa = Integer.valueOf(authQaaStr);
                    if (reqQaa > authQaa) {
                        Logger.warn("Requested QAA level does not match to authenticated QAA level");
                        throw new MOAIDException("stork.21", new Object[] { reqQaa, authQaa });

                    }
                }
            } catch (MOAIDException e) {
                throw e;

            } catch (Exception e) {
                if (Logger.isDebugEnabled())
                    Logger.warn("STORK QAA Level evaluation error", e);

                else
                    Logger.warn("STORK QAA Level evaluation error (ErrorMessage=" + e.getMessage() + ")");

                throw new MOAIDException("stork.21", new Object[] { reqQaa, authQaa });

            }
            //================== Check QAA level end ====================

            Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID);

            ////////////// incorporate gender from parameters if not in stork response

            IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList();

            // but first, check if we have a representation case
            if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList)
                    || STORKResponseProcessor.hasAttribute("representative", attributeList)
                    || STORKResponseProcessor.hasAttribute("represented", attributeList)) {
                // in a representation case...
                moaSession.setUseMandate("true");

                // and check if we have the gender value
                PersonalAttribute gender = attributeList.get("gender"); // TODO Do we need to check gender value if there is no representation case?
                if (null == gender) {
                    String gendervalue = (String) request.getParameter("gender");
                    if (null != gendervalue) {
                        gender = new PersonalAttribute();
                        gender.setName("gender");
                        ArrayList<String> tmp = new ArrayList<String>();
                        tmp.add(gendervalue);
                        gender.setValue(tmp);

                        authnResponse.getPersonalAttributeList().add(gender);
                    }
                }
            }

            //////////////////////////////////////////////////////////////////////////

            Logger.debug("Starting extraction of signedDoc attribute");
            //extract signed doc element and citizen signature
            String citizenSignature = null;
            try {
                String signatureInfo = authnResponse.getPersonalAttributeList().get("signedDoc").getValue().get(0); // TODO ERROR HANDLING

                Logger.debug("signatureInfo:" + signatureInfo);

                SignResponse dssSignResponse = (SignResponse) ApiUtils
                        .unmarshal(new StreamSource(new java.io.StringReader(signatureInfo)));

                // fetch signed doc
                DataSource ds = null;
                try {
                    ds = LightweightSourceResolver.getDataSource(dssSignResponse);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (ds == null) {
                    //Normal DocumentServices return a http-page, but the SI DocumentService returns HTTP error 500 
                    //which results in an exception and ds==null

                    //try to load document from documentservice
                    citizenSignature = loadDocumentFromDocumentService(dssSignResponse);
                    //throw new ApiUtilsException("No datasource found in response");
                } else {
                    InputStream incoming = ds.getInputStream();
                    citizenSignature = IOUtils.toString(incoming);
                    incoming.close();

                    Logger.debug("citizenSignature:" + citizenSignature);
                    if (isDocumentServiceUsed(citizenSignature) == true) {
                        citizenSignature = loadDocumentFromDocumentService(dssSignResponse);
                        //               Logger.debug("Loading document from DocumentService.");
                        //               String url = getDtlUrlFromResponse(dssSignResponse);
                        //               //get Transferrequest
                        //               String transferRequest = getDocTransferRequest(dssSignResponse.getDocUI(), url);
                        //               //Load document from DocumentService
                        //               byte[] data = getDocumentFromDtl(transferRequest, url);
                        //               citizenSignature = new String(data, "UTF-8");
                        //               Logger.debug("Overridung citizenSignature with:"+citizenSignature);
                    }
                }
                JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName());
                SignatureType root = ((JAXBElement<SignatureType>) ctx.createUnmarshaller()
                        .unmarshal(IOUtils.toInputStream(citizenSignature))).getValue();

                // memorize signature into authblock
                moaSession.setAuthBlock(citizenSignature);

                // extract certificate
                for (Object current : root.getKeyInfo().getContent())
                    if (((JAXBElement<?>) current).getValue() instanceof X509DataType) {
                        for (Object currentX509Data : ((JAXBElement<X509DataType>) current).getValue()
                                .getX509IssuerSerialOrX509SKIOrX509SubjectName()) {
                            JAXBElement<?> casted = ((JAXBElement<?>) currentX509Data);
                            if (casted.getName().getLocalPart().equals("X509Certificate")) {
                                moaSession.setSignerCertificate(
                                        new X509Certificate(((String) casted.getValue()).getBytes("UTF-8")));
                                break;
                            }
                        }
                    }

            } catch (Throwable e) {
                Logger.error("Could not extract citizen signature from C-PEPS", e);
                throw new MOAIDException("stork.09", null);
            }
            Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)");
            Logger.debug("Citizen signature will be verified by SZR Gateway!");

            Logger.debug("fetching OAParameters from database");

            //         //read configuration paramters of OA
            //           AuthenticationSession moasession;
            //         try {
            //            moasession = AuthenticationSessionStoreage.getSession(moaSessionID);
            //         } catch (MOADatabaseException e2) {
            //            Logger.error("could not retrieve moa session");
            //            throw new AuthenticationException("auth.01", null);
            //         }
            //          OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix());
            //          if (oaParam == null)
            //                throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() });

            // retrieve target
            //TODO: check in case of SSO!!!
            String targetType = null;
            if (oaParam.getBusinessService()) {
                String id = oaParam.getIdentityLinkDomainIdentifier();
                if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_))
                    targetType = id;
                else
                    targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier();
            } else {
                targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget();
            }

            IdentityLink identityLink = null;
            try {
                AuthConfigurationProvider config = AuthConfigurationProvider.getInstance();
                if (config.isStorkFakeIdLActive()
                        && config.getStorkFakeIdLCountries().contains(storkAuthnRequest.getCitizenCountryCode())) {
                    // create fake IdL
                    // - fetch IdL template from resources
                    InputStream s = PEPSConnectorServlet.class
                            .getResourceAsStream("/resources/xmldata/fakeIdL_IdL_template.xml");
                    Element idlTemplate = DOMUtils.parseXmlValidating(s);

                    identityLink = new IdentityLinkAssertionParser(idlTemplate).parseIdentityLink();

                    // replace data
                    Element idlassertion = identityLink.getSamlAssertion();
                    // - set bpk/wpbk;
                    Node prIdentification = XPathUtils.selectSingleNode(idlassertion,
                            IdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH);
                    if (!STORKResponseProcessor.hasAttribute("eIdentifier", attributeList))
                        throw new STORKException("eIdentifier is missing");
                    String eIdentifier = STORKResponseProcessor.getAttributeValue("eIdentifier", attributeList,
                            false);
                    prIdentification.getFirstChild().setNodeValue(eIdentifier);

                    // - set last name
                    Node prFamilyName = XPathUtils.selectSingleNode(idlassertion,
                            IdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH);
                    if (!STORKResponseProcessor.hasAttribute("surname", attributeList))
                        throw new STORKException("surname is missing");
                    String familyName = STORKResponseProcessor.getAttributeValue("surname", attributeList, false);
                    prFamilyName.getFirstChild().setNodeValue(familyName);

                    // - set first name
                    Node prGivenName = XPathUtils.selectSingleNode(idlassertion,
                            IdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH);
                    if (!STORKResponseProcessor.hasAttribute("givenName", attributeList))
                        throw new STORKException("givenName is missing");
                    String givenName = STORKResponseProcessor.getAttributeValue("givenName", attributeList, false);
                    prGivenName.getFirstChild().setNodeValue(givenName);

                    // - set date of birth
                    Node prDateOfBirth = XPathUtils.selectSingleNode(idlassertion,
                            IdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH);
                    if (!STORKResponseProcessor.hasAttribute("dateOfBirth", attributeList))
                        throw new STORKException("dateOfBirth is missing");
                    String dateOfBirth = STORKResponseProcessor.getAttributeValue("dateOfBirth", attributeList,
                            false);
                    prDateOfBirth.getFirstChild().setNodeValue(dateOfBirth);

                    identityLink = new IdentityLinkAssertionParser(idlassertion).parseIdentityLink();

                    //resign IDL
                    IdentityLinkReSigner identitylinkresigner = IdentityLinkReSigner.getInstance();
                    Element resignedilAssertion = identitylinkresigner.resignIdentityLink(
                            identityLink.getSamlAssertion(), config.getStorkFakeIdLResigningKey());
                    identityLink = new IdentityLinkAssertionParser(resignedilAssertion).parseIdentityLink();
                } else {
                    //contact SZR Gateway
                    Logger.debug("Starting connecting SZR Gateway");
                    identityLink = STORKResponseProcessor.connectToSZRGateway(
                            authnResponse.getPersonalAttributeList(), oaParam.getFriendlyName(), targetType, null,
                            oaParam.getMandateProfiles(), citizenSignature);
                }
            } catch (STORKException e) {
                // this is really nasty but we work against the system here. We are supposed to get the gender attribute from
                // stork. If we do not, we cannot register the person in the ERnP - we have to have the
                // gender for the represented person. So here comes the dirty hack. 
                if (e.getCause() instanceof STORKException
                        && e.getCause().getMessage().equals("gender not found in response")) {
                    try {
                        Logger.trace("Initialize VelocityEngine...");

                        VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine();
                        Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html");
                        VelocityContext context = new VelocityContext();
                        context.put("SAMLResponse", request.getParameter("SAMLResponse"));
                        context.put("action", request.getRequestURL());

                        StringWriter writer = new StringWriter();
                        template.merge(context, writer);

                        response.getOutputStream().write(writer.toString().getBytes("UTF-8"));
                    } catch (Exception e1) {
                        Logger.error("Error sending gender retrival form.", e1);
                        //                  httpSession.invalidate();
                        throw new MOAIDException("stork.10", null);
                    }

                    return;
                }

                Logger.error("Error connecting SZR Gateway", e);
                throw new MOAIDException("stork.10", null);
            }
            Logger.debug("SZR communication was successfull");

            if (identityLink == null) {
                Logger.error("SZR Gateway did not return an identity link.");
                throw new MOAIDException("stork.10", null);
            }
            moaSession.setForeigner(true);

            Logger.info("Received Identity Link from SZR Gateway");
            moaSession.setIdentityLink(identityLink);

            Logger.debug("Adding addtional STORK attributes to MOA session");
            moaSession.setStorkAttributes(authnResponse.getPersonalAttributeList());

            Logger.debug("Add full STORK AuthnResponse to MOA session");
            moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));

            //We don't have BKUURL, setting from null to "Not applicable"
            moaSession.setBkuURL("Not applicable (STORK Authentication)");

            // free for single use
            moaSession.setAuthenticatedUsed(false);

            // stork did the authentication step
            moaSession.setAuthenticated(true);

            //         //TODO: found better solution, but QAA Level in response could be not supported yet
            //         try {
            //
            //            moaSession.setQAALevel(authnResponse.getAssertions().get(0).
            //                  getAuthnStatements().get(0).getAuthnContext().
            //                  getAuthnContextClassRef().getAuthnContextClassRef());
            //            
            //         } catch (Throwable e) {
            //            Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level");
            //            moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel());
            //            
            //         }

            //session is implicit stored in changeSessionID!!!!
            String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession);

            Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID);

            //redirect
            String redirectURL = null;
            redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(),
                    ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID),
                    newMOASessionID);
            redirectURL = response.encodeRedirectURL(redirectURL);

            //          response.setContentType("text/html");
            //          response.setStatus(302);
            //          response.addHeader("Location", redirectURL);
            response.sendRedirect(redirectURL);
            Logger.info("REDIRECT TO: " + redirectURL);

        } catch (AuthenticationException e) {
            handleError(null, e, request, response, pendingRequestID);

        } catch (MOAIDException e) {
            handleError(null, e, request, response, pendingRequestID);

        } catch (Exception e) {
            Logger.error("PEPSConnector has an interal Error.", e);
        }

        finally {
            ConfigurationDBUtils.closeSession();
        }

    }

    private String loadDocumentFromDocumentService(SignResponse dssSignResponse) throws Exception {
        Logger.debug("Loading document from DocumentService.");
        String url = getDtlUrlFromResponse(dssSignResponse);
        Logger.debug("Loading document from DocumentService, url:" + url);
        //get Transferrequest
        String transferRequest = getDocTransferRequest(dssSignResponse.getDocUI(), url);
        //Load document from DocumentService
        byte[] data = getDocumentFromDtl(transferRequest, url);
        String citizenSignature = new String(data, "UTF-8");
        Logger.debug("Overridung citizenSignature with:" + citizenSignature);
        return citizenSignature;
    }

    private boolean isDocumentServiceUsed(String citizenSignature) //TODo add better check
    {
        if (citizenSignature.contains(
                "<table border=\"0\"><tr><td>Service Name:</td><td>{http://stork.eu}DocumentService</td></tr><tr><td>Port Name:</td><td>{http://stork.eu}DocumentServicePort</td></tr></table>")) {
            Logger.trace("isDocumentServiceUsed => true");
            return true;
        }
        Logger.trace("isDocumentServiceUsed => false");
        return false;
    }

    /**
     * Get DTL uril from the oasis sign response
     * @param signRequest The signature response
     * @return The URL of DTL service
     * @throws SimpleException
     */
    private String getDtlUrlFromResponse(SignResponse dssSignResponse) {
        List<DocumentWithSignature> documents = ApiUtils.findNamedElement(dssSignResponse.getOptionalOutputs(),
                ApiUtils.OPTIONAL_OUTPUT_DOCUMENTWITHSIGNATURE, DocumentWithSignature.class);
        DocumentType sourceDocument = documents.get(0).getDocument();

        if (sourceDocument.getDocumentURL() != null)
            return sourceDocument.getDocumentURL();
        else
            return null;//throw new Exception("No document url found");
    }

    //From DTLPEPSUTIL

    /**
       * Get document from DTL
       * @param transferRequest The transfer request (attribute query)
       * @param eDtlUrl The DTL url of external DTL
       * @return the document data
       * @throws SimpleException
       */
    private byte[] getDocumentFromDtl(String transferRequest, String eDtlUrl) throws Exception {
        URL url = null;
        try {
            Logger.debug("getDocumentFromDtl, dtlUrl:'" + dtlUrl + "' eDtlUrl:'" + eDtlUrl + "'");
            url = new URL(dtlUrl);
            QName qname = new QName("http://stork.eu", "DocumentService");

            Service service = Service.create(url, qname);
            DocumentService docservice = service.getPort(DocumentService.class);

            BindingProvider bp = (BindingProvider) docservice;
            SOAPBinding binding = (SOAPBinding) bp.getBinding();
            binding.setMTOMEnabled(true);

            if (eDtlUrl.equalsIgnoreCase(dtlUrl))
                return docservice.getDocument(transferRequest, "");
            else
                return docservice.getDocument(transferRequest, eDtlUrl);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("Error in getDocumentFromDtl", e);
        }
    }

    /**
     * Get a document transfer request (attribute query)
     * @param docId
     * @return
    * @throws SimpleException 
     */
    private String getDocTransferRequest(String docId, String destinationUrl) throws Exception {
        String spCountry = docId.substring(0, docId.indexOf("/"));
        final STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP");
        STORKAttrQueryRequest req = new STORKAttrQueryRequest();
        req.setAssertionConsumerServiceURL(dtlUrl);
        req.setDestination(destinationUrl);
        req.setSpCountry(spCountry);
        req.setQaa(3);//TODO
        PersonalAttributeList pal = new PersonalAttributeList();
        PersonalAttribute attr = new PersonalAttribute();
        attr.setName("docRequest");
        attr.setIsRequired(true);
        attr.setValue(Arrays.asList(docId));
        pal.add(attr);
        req.setPersonalAttributeList(pal);

        STORKAttrQueryRequest req1;
        try {
            req1 = engine.generateSTORKAttrQueryRequest(req);
            return PEPSUtil.encodeSAMLTokenUrlSafe(req1.getTokenSaml());
        } catch (STORKSAMLEngineException e) {
            e.printStackTrace();
            throw new Exception("Error in doc request attribute query generation", e);
        }
    }

    /**
     * Get mime type of document from DTL
     * @param docId The document id
     * @param dtlUrl The url of dtl
     * @return The mime type
     */
    //        private String getDocumentMimeFromDtl(String docId, String eDtlUrl) throws Exception
    //        {
    //           URL url = null;
    //         try 
    //         {
    //            url = new URL(dtlUrl);
    //            QName qname = new QName("http://stork.eu",
    //                   "DocumentService");
    //
    //            Service service = Service.create(url, qname);
    //            DocumentService docservice = service.getPort(DocumentService.class);
    //                 
    //            BindingProvider bp = (BindingProvider) docservice;
    //            SOAPBinding binding = (SOAPBinding) bp.getBinding();
    //            binding.setMTOMEnabled(true);
    //                        
    //              if (eDtlUrl.equalsIgnoreCase(dtlUrl))
    //                 return docservice.getDocumentMime(docId, "");
    //              else
    //                  return docservice.getDocumentMime(docId, eDtlUrl);
    //         }
    //          catch (Exception e)
    //          {
    //               e.printStackTrace();
    //               throw new Exception("Error in getDocumentFromDtl", e);
    //          }
    //        }
}