org.aselect.server.request.handler.IDPFHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.aselect.server.request.handler.IDPFHandler.java

Source

/*
 * * Copyright (c) Anoigo. All rights reserved.
 *
 * A-Select is a trademark registered by SURFnet bv.
 *
 * This program is distributed under the EUPL 1.0 (http://osor.eu/eupl)
 * See the included LICENSE file for details.
 *
 * If you did not receive a copy of the LICENSE
 * please contact Anoigo. (http://www.anoigo.nl) 
 */
package org.aselect.server.request.handler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.regex.Pattern;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aselect.server.config.Version;
import org.aselect.server.crypto.CryptoEngine;
import org.aselect.server.request.RequestState;
import org.aselect.system.error.Errors;
import org.aselect.system.exception.ASelectCommunicationException;
import org.aselect.system.exception.ASelectConfigException;
import org.aselect.system.exception.ASelectException;
import org.aselect.system.utils.Utils;

/**
 * IDPF RequestHandler. <br>
 * <br>
 * <b>Description:</b><br>
 * This class serves as a an IDP first generic request handler 
 *  It handles generic authentication requests
 *  Requests a rid from the aselectserver and sends of the user to authenticate 
 * <br>
 * <b>Concurrency issues:</b> <br>
 * Use one <code>IDPFHandler</code> implementation for a single request. <br>
 * 
 * @author Remy Hanswijk
 */
public class IDPFHandler extends ProtoRequestHandler {
    private final static String MODULE = "IDPFHandler";
    private String idpfEndpointUrl = null;

    private String _sMyServerID = null;
    private String appID = null;
    private String sharedSecret = null;
    private String defaultUID = null;
    private String elected_uid_attributename = null;
    private String passed_credentials_attributename = null;
    private String aselectServerURL = null;
    private String endpointurl = null;

    private String _sPostTemplate = null;
    private String secretKey = null;
    // if we want to use other signing key than de default privatekey
    private String authsp4Signing = null;

    /* @param oServletConfig
     *            the o servlet config
     * @param oConfig
     *            the o config
     * @throws ASelectException
     *             the a select exception
     * @see org.aselect.server.request.handler.AbstractRequestHandler#init(javax.servlet.ServletConfig, java.lang.Object)
     */
    @Override
    public void init(ServletConfig oServletConfig, Object oConfig) throws ASelectException {
        String sMethod = "init";

        try {
            super.init(oServletConfig, oConfig);
            Object oASelect = null;
            try {
                oASelect = _configManager.getSection(null, "aselect");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "Could not find 'aselect' config section in config file", e);
                throw e;
            }

            try {
                _sMyServerID = _configManager.getParam(oASelect, "server_id");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "Could not retrieve 'server_id' config parameter in 'aselect' config section", e);
                throw e;
            }
            try {
                aselectServerURL = _configManager.getParam(oASelect, "redirect_url");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "Could not retrieve 'server_id' config parameter in 'redirect_url' config section", e);
                throw e;
            }

            try {
                idpfEndpointUrl = _configManager.getParam(oConfig, "idpfendpointurl");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'ists' found", e);
                throw new ASelectException(Errors.ERROR_ASELECT_INIT_ERROR, e);
            }

            try {
                appID = _configManager.getParam(oConfig, "application");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'application' found", e);
                throw new ASelectException(Errors.ERROR_ASELECT_INIT_ERROR, e);
            }

            try {
                sharedSecret = _configManager.getParam(oConfig, "shared_secret");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'shared_secret' found", e);
                throw new ASelectException(Errors.ERROR_ASELECT_INIT_ERROR, e);
            }

            //         try {
            //            verifySignature = _configManager.getParam(oConfig, "verify_signature");
            //         }
            //         catch (ASelectConfigException e) {
            //            _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'verify_signature' found", e);
            //            throw new ASelectException(Errors.ERROR_ASELECT_INIT_ERROR, e);
            //         }

            try {
                defaultUID = _configManager.getParam(oConfig, "uid");
            } catch (ASelectConfigException e) {
                defaultUID = "siam_user";
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "No config item 'uid' found, using default: " + defaultUID);
            }

            try {
                elected_uid_attributename = _configManager.getParam(oConfig, "elected_uid_attributename");
            } catch (ASelectConfigException e) {
                elected_uid_attributename = "uid";
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "No config item 'elected_uid_attributename' found, using default: "
                                + elected_uid_attributename);
            }

            try {
                passed_credentials_attributename = _configManager.getParam(oConfig,
                        "passed_credentials_attributename");
            } catch (ASelectConfigException e) {
                passed_credentials_attributename = "ssoCredentials";
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "No config item 'passed_credentials_attributename' found, using default: "
                                + passed_credentials_attributename);
            }

            try {
                endpointurl = _configManager.getParam(oConfig, "applicationendpointurl");
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'applicationendpointurl' found");
                throw new ASelectException(Errors.ERROR_ASELECT_INIT_ERROR, e);
            }

            //         try {
            //            endpointsigning = _configManager.getParam(oConfig, "applicationendpointsigning");
            //         }
            //         catch (ASelectConfigException e) {
            //            endpointsigning = "sha1";   // set default to sha1
            //            _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'applicationendpointsigning' found, using default: " + endpointsigning , e);
            //         }

            try {
                setPostTemplate(_configManager.getParam(oConfig, "post_template"));
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'post_template' found", e);
            }
            try {
                setSecretKey(_configManager.getParam(oConfig, "secretkey"));
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'secretkey' found", e);
            }

            try {
                setAuthsp4Signing(_configManager.getParam(oConfig, "authsp4signing"));
            } catch (ASelectConfigException e) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config item 'authsp4signing' found", e);
            }

        } catch (ASelectException e) {
            throw e;
        } catch (Exception e) {
            _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Could not initialize", e);
            throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e);
        }
    }

    /**
     * Process incoming request.<br>
     * 
     * @param servletRequest
     *            HttpServletRequest.
     * @param servletResponse
     *            HttpServletResponse.
     * @return the request state
     * @throws ASelectException
     *             If processing of  data request fails.
     */
    public RequestState process(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
            throws ASelectException {
        String sMethod = "process";
        String uid = defaultUID;
        String extractedAselect_credentials = null;

        extractedAselect_credentials = servletRequest.getParameter("aselect_credentials");

        if (extractedAselect_credentials == null) { // For now we don't care about previous authentication, let aselect handle that

            // authenticate to the aselect server
            String ridReqURL = aselectServerURL;
            String ridSharedSecret = sharedSecret;
            String ridAselectServer = _sMyServerID;
            String ridrequest = "authenticate";
            String ridAppURL = getIdpfEndpointUrl();

            //               String ridCheckSignature = verifySignature; 

            String ridResponse = "";
            // Send data 
            BufferedReader in = null;
            try {
                //Construct request data 
                String ridURL = ridReqURL + "?" + "shared_secret=" + URLEncoder.encode(ridSharedSecret, "UTF-8")
                        + "&a-select-server=" + URLEncoder.encode(ridAselectServer, "UTF-8") + "&request="
                        + URLEncoder.encode(ridrequest, "UTF-8") + "&uid=" + URLEncoder.encode(uid, "UTF-8") +
                        // RM_30_01
                        "&app_url=" + URLEncoder.encode(ridAppURL, "UTF-8") +
                        //                         "&check-signature=" + URLEncoder.encode(ridCheckSignature, "UTF-8") +
                        "&app_id=" + URLEncoder.encode(appID, "UTF-8");
                _systemLogger.log(Level.FINER, MODULE, sMethod, "Requesting rid through: " + ridURL);

                URL url = new URL(ridURL);

                in = new BufferedReader(new InputStreamReader(url.openStream()));

                String inputLine = null;
                while ((inputLine = in.readLine()) != null) {
                    ridResponse += inputLine;
                }
                _systemLogger.log(Level.FINER, MODULE, sMethod, "Requesting rid response: " + ridResponse);
            } catch (Exception e) {
                _systemLogger.log(Level.SEVERE, MODULE, sMethod,
                        "Could not retrieve rid from aselectserver: " + ridAselectServer);
                throw new ASelectCommunicationException(Errors.ERROR_ASELECT_IO, e);
            } finally {
                if (in != null)
                    try {
                        in.close();
                    } catch (IOException e) {
                        _systemLogger.log(Level.WARNING, MODULE, sMethod,
                                "Could not close stream to aselectserver : " + ridAselectServer);
                    }
            }

            String extractedRid = ridResponse.replaceFirst(".*rid=([^&]*).*$", "$1");
            _systemLogger.log(Level.FINER, MODULE, sMethod, "rid retrieved: " + extractedRid);

            _htSessionContext = _oSessionManager.getSessionContext(extractedRid);
            if (_htSessionContext == null) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "No session found for RID: " + extractedRid);
                throw new ASelectException(Errors.ERROR_ASELECT_SERVER_INVALID_REQUEST);
            }
            _htSessionContext = setupSessionContext(_htSessionContext);

            String javaxSessionid = servletRequest.getSession().getId();
            _systemLogger.log(Level.FINER, MODULE, sMethod, "idpfsessionid: " + javaxSessionid);

            _htSessionContext.put("idpfsessionid", javaxSessionid);

            _oSessionManager.updateSession(extractedRid, _htSessionContext);

            String loginrequest = "login1";

            //Construct request data 
            String redirectURL = null;
            try {
                redirectURL = ridReqURL + "?" + "request=" + URLEncoder.encode(loginrequest, "UTF-8")
                        + "&a-select-server=" + URLEncoder.encode(ridAselectServer, "UTF-8") + "&rid="
                        + extractedRid;
                _systemLogger.log(Level.FINER, MODULE, sMethod,
                        "Requesting login through redirect with redirectURL: " + redirectURL);

                servletResponse.sendRedirect(redirectURL);
            } catch (UnsupportedEncodingException e1) {
                _systemLogger.log(Level.SEVERE, MODULE, sMethod,
                        "Could not URLEncode to UTF-8, this should not happen!");
                throw new ASelectCommunicationException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e1);
            } catch (IOException e) {
                _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Could not redirect to: " + redirectURL);
                throw new ASelectCommunicationException(Errors.ERROR_ASELECT_IO, e);
            }
        } else { // This should be a return from the aselect server
            // This should be the aselectserver response

            // check the session for validity
            String javaxSessionid = servletRequest.getSession().getId();
            _systemLogger.log(Level.FINEST, MODULE, sMethod, "javaxSessionid: " + javaxSessionid);

            String org_javaxSessionid = (String) _htSessionContext.get("idpfsessionid");
            if (!javaxSessionid.equals(org_javaxSessionid)) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod, "Invalid sessionid found");
                throw new ASelectException(Errors.ERROR_ASELECT_SERVER_INVALID_REQUEST);
            }

            _systemLogger.log(Level.INFO, MODULE, sMethod, "Handle the aselectserver response");

            String finalResult = verify_credentials(servletRequest, extractedAselect_credentials);
            _systemLogger.log(Level.INFO, MODULE, sMethod, "finalResult after verify_credentials: " + finalResult);

            String extractedAttributes = finalResult.replaceFirst(".*attributes=([^&]*).*$", "$1");
            String extractedResultCode = finalResult.replaceFirst(".*result_code=([^&]*).*$", "$1");

            String urlDecodedAttributes = null;
            ;
            String decodedAttributes = null;
            try {
                urlDecodedAttributes = URLDecoder.decode(extractedAttributes, "UTF-8");
                decodedAttributes = URLDecoder.decode(new String(
                        org.apache.commons.codec.binary.Base64.decodeBase64(urlDecodedAttributes.getBytes())),
                        "UTF-8");
                String attribs[] = decodedAttributes.split("&");
                for (int i = 0; i < attribs.length; i++) {
                    _systemLogger.log(Level.FINER, MODULE, sMethod,
                            "Retrieved attribute from aselectserver: " + attribs[i]);
                }
            } catch (UnsupportedEncodingException e2) {
                _systemLogger.log(Level.SEVERE, MODULE, sMethod,
                        "Could not URLDecode from UTF-8, this should not happen!");
                throw new ASelectCommunicationException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e2);
            }

            String userSelectedClaimedId = null;
            //           userSelectedId =  finalResult.replaceFirst(".*uid=([^&]*).*$", "$1");
            //         _systemLogger.log(Level.INFO, MODULE, sMethod, "Retrieved uid from aselect query string (userSelectedId): " + userSelectedId);

            //           userSelectedClaimedId =  decodedAttributes.replaceFirst(".*uid=([^&]*).*$", "$1");
            userSelectedClaimedId = decodedAttributes
                    .replaceFirst(".*" + Pattern.quote(elected_uid_attributename) + "=([^&]*).*$", "$1"); // configurable passed_uid
            _systemLogger.log(Level.FINER, MODULE, sMethod, "Retrieved: " + elected_uid_attributename
                    + " (elected_uid_attributename) from aselect attributes: " + userSelectedClaimedId);

            Boolean authenticatedAndApproved = false;
            try {
                authenticatedAndApproved = Boolean.valueOf(Integer.parseInt(extractedResultCode) == 0);
            } catch (NumberFormatException nfe) {
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "Resultcode from aselectserver was non-numeric: " + extractedResultCode);
            }

            if (authenticatedAndApproved) {
                // If authenticatedAndApproved then send off the user with either POST or GET
                // (Only POST for now)
                if (getPostTemplate() != null) {
                    String sSelectForm = Utils.loadTemplateFromFile(_systemLogger, _configManager.getWorkingdir(),
                            null, getPostTemplate(), _sUserLanguage, _configManager.getOrgFriendlyName(),
                            Version.getVersion());

                    String sInputs = generatePostForm(userSelectedClaimedId);

                    // Keep logging short:
                    _systemLogger.log(Level.FINER, MODULE, sMethod,
                            "Template=" + getPostTemplate() + " sInputs=" + sInputs + " ...");

                    handlePostForm(sSelectForm, getEndpointurl(), sInputs, servletRequest, servletResponse);
                } else { // for now we only allow POST
                    _systemLogger.log(Level.SEVERE, MODULE, sMethod, "No POST template found");
                    throw new ASelectException(Errors.ERROR_ASELECT_AGENT_INTERNAL_ERROR);
                }

            } else {
                _systemLogger.log(Level.WARNING, MODULE, sMethod,
                        "Could not aythenticate user, authentication failed with resultcode: "
                                + extractedResultCode);
                throw new ASelectException(Errors.ERROR_ASELECT_SERVER_USER_NOT_ALLOWED);
            }

        }
        return null;
    }

    /**
     * @param userSelectedClaimedId
     * @return
     * @throws ASelectException
     */
    private String generatePostForm(String userSelectedClaimedId) throws ASelectException {
        String a = String.valueOf(CryptoEngine.nextRandomInt()); // some random number
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // We might have to put in some time zone info here if other party is in another timezone (or use UTC)
        String b = formatter.format(new Date()); // generate currenttime in format "yyyy-MM-dd HH:mm:ss"
        String c = userSelectedClaimedId;
        String d = a + "," + b + "," + c;
        String ssoCredentials = generateInlogindicatie(d, getSecretKey(), getAuthsp4Signing());
        String sInputs = buildHtmlInput(passed_credentials_attributename, ssoCredentials);
        return sInputs;
    }

    /**
     * @param sMethod
     */
    protected HashMap setupSessionContext(HashMap htSessionContext) {
        String sMethod = "setupSessionContext";

        return htSessionContext;
    }

    /**
     * @param request
     * @param extracted_credentials
     * @param sMethod
     * @param extractedAselect_credentials
     * @return 
     * @throws ASelectCommunicationException
     */
    private String verify_credentials(HttpServletRequest request, String extracted_credentials)
            throws ASelectCommunicationException {
        String sMethod = "verify_credentials";
        // This could be done by getting request parametermap
        String queryData = request.getQueryString();
        String extractedRid = queryData.replaceFirst(".*rid=([^&]*).*$", "$1");
        String finalReqURL = aselectServerURL;
        String finalReqSharedSecret = sharedSecret;
        String finalReqAselectServer = _sMyServerID;
        String finalReqrequest = "verify_credentials";

        //Construct request data
        String finalRequestURL = null;
        try {
            finalRequestURL = finalReqURL + "?" + "shared_secret="
                    + URLEncoder.encode(finalReqSharedSecret, "UTF-8") + "&a-select-server="
                    + URLEncoder.encode(finalReqAselectServer, "UTF-8") + "&request="
                    + URLEncoder.encode(finalReqrequest, "UTF-8") + "&aselect_credentials=" + extracted_credentials
                    +
                    //                        "&check-signature=" + URLEncoder.encode(ridCheckSignature, "UTF-8") +
                    "&rid=" + extractedRid;
        } catch (UnsupportedEncodingException e3) {
            _systemLogger.log(Level.SEVERE, MODULE, sMethod,
                    "Could not URLEncode to UTF-8, this should not happen!");
            throw new ASelectCommunicationException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e3);
        }
        String finalResult = "";

        //Send data
        _systemLogger.log(Level.INFO, MODULE, sMethod, "Retrieving attributes through: " + finalRequestURL);

        BufferedReader in = null;
        try {
            URL url = new URL(finalRequestURL);

            in = new BufferedReader(new InputStreamReader(url.openStream()));

            String inputLine = null;
            while ((inputLine = in.readLine()) != null) {
                finalResult += inputLine;
            }
            _systemLogger.log(Level.FINER, MODULE, sMethod, "Retrieved attributes in: " + finalResult);

        } catch (Exception e) {
            _systemLogger.log(Level.SEVERE, MODULE, sMethod,
                    "Could not retrieve attributes from aselectserver: " + finalReqAselectServer);
            throw new ASelectCommunicationException(Errors.ERROR_ASELECT_IO, e);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    _systemLogger.log(Level.WARNING, MODULE, sMethod,
                            "Could not close stream to aselectserver : " + finalReqAselectServer);
                }
        }
        return finalResult;
    }

    public String generateInlogindicatie(String d, String secretKey) throws ASelectException {
        return generateInlogindicatie(d, secretKey, null);
    }

    public String generateInlogindicatie(String d, String secretKey, String authsp4singing)
            throws ASelectException {
        CryptoEngine c = CryptoEngine.getHandle();
        String signature = c.generateSignature(authsp4singing, d);
        String inlogindicatie = c.generate3DES(d + "," + signature, secretKey);

        return inlogindicatie;

    }

    public void destroy() {
    }

    public synchronized String getIdpfEndpointUrl() {
        return idpfEndpointUrl;
    }

    public synchronized void setIdpfEndpointUrl(String idpfEndpointUrl) {
        this.idpfEndpointUrl = idpfEndpointUrl;
    }

    public synchronized String getEndpointurl() {
        return endpointurl;
    }

    public synchronized void setEndpointurl(String endpointurl) {
        this.endpointurl = endpointurl;
    }

    public synchronized String getPostTemplate() {
        return _sPostTemplate;
    }

    public synchronized void setPostTemplate(String sPostTemplate) {
        _sPostTemplate = sPostTemplate;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public synchronized String getAuthsp4Signing() {
        return authsp4Signing;
    }

    public synchronized void setAuthsp4Signing(String authsp4Signing) {
        this.authsp4Signing = authsp4Signing;
    }

}