view src/main/java/de/intevation/lada/util/auth/OpenIDAuthentication.java @ 544:04e254571b8a openid

First non-functional implementation of openid verification Uses the openid4j package to extract openid information provided by the client as a HTTP Header. Currently the statelessness of the services prevents the exchange of discovery information between client and server. It is only useful for evaluation and testing.
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 25 Feb 2015 16:03:35 +0100
parents
children
line wrap: on
line source
/* Copyright (C) 2015 by Bundesamt fuer Strahlenschutz
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU GPL (v>=3) 
 * and comes with ABSOLUTELY NO WARRANTY! Check out 
 * the documentation coming with IMIS-Labordaten-Application for details. 
 */
package de.intevation.lada.util.auth;

import java.util.Map;
import java.util.List;
import java.util.LinkedHashMap;
import java.net.URLDecoder;

import javax.inject.Inject;
import javax.ejb.Stateless;
import javax.ws.rs.core.HttpHeaders;

import de.intevation.lada.util.annotation.AuthenticationConfig;

import org.openid4java.association.AssociationSessionType;
import org.openid4java.association.AssociationException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.InMemoryConsumerAssociationStore;
import org.openid4java.consumer.InMemoryNonceVerifier;
import org.openid4java.message.ParameterList;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.message.MessageException;
import org.openid4java.message.AuthRequest;

import org.apache.log4j.Logger;

public class OpenIDAuthentication implements Authentication {

    /** The name of the header field used to transport OpenID parameters.*/
    private static final String OID_HEADER_FIELD= "X-OPENID-PARAMS";

    /** The identity provider we accept here. */
    private static final String IDENTITY_PROVIDER =
        "http://localhost:8087/account";

    /** This is currently a faked dummy */
    private static final String RETURN_URL =
        "http://localhost:8086/consumer-servlet/consumer?is_return=true";

    private static final Logger logger =
        Logger.getLogger(OpenIDAuthentication.class);

    private ConsumerManager manager;

    private Map<String,String> idParams;

    boolean discoveryDone = false;

    private DiscoveryInformation discovered;

    private boolean discoverServer() {
        /* Perform discovery on the configured IDENTITY_PROVIDER */
        List discoveries = null;
        try {
            discoveries = manager.discover(IDENTITY_PROVIDER);
        } catch (DiscoveryException e) {
            logger.debug("Discovery failed: " + e.getMessage());
            return false;
        }

        if (discoveries == null || discoveries.isEmpty()) {
            logger.error(
                    "Failed discovery step. OpenID provider unavailable?");
            return false;
        }

        /* Add association for the discovered information */
        discovered = manager.associate(discoveries);

        /* Validate the parameters. */
        logger.debug("After discovery.");
        try {
            AuthRequest authReq = manager.authenticate(discovered, RETURN_URL);
            logger.debug("Authenticate with: " + authReq.getDestinationUrl(true));
        } catch (MessageException e) {
            logger.debug("Failed to create the Authentication request: " +
                    e.getMessage());
        } catch (ConsumerException e) {
            logger.debug("Error in consumer manager: " +
                    e.getMessage());
        }
        logger.debug("After authenticate.");
        return true;
    }

    public OpenIDAuthentication() {
        manager = new ConsumerManager();
        /* TODO: Check for alternative configs. */
        manager.setAssociations(new InMemoryConsumerAssociationStore());
        manager.setNonceVerifier(new InMemoryNonceVerifier(50000));
        manager.setMinAssocSessEnc(AssociationSessionType.DH_SHA256);
        discoveryDone = discoverServer();
    }

    /** Split up the OpenID response query provided in the header.
     *
     * @param responseQuery The query provided in the header field.
     * @return The query as ParameterList or null on error.
     */
    private ParameterList splitParams(String responseQuery) {
        Map<String, String> queryMap =
            new LinkedHashMap<String, String>();
        final String[] pairs = responseQuery.split("&");
        for (String pair : pairs) {
            final int idx = pair.indexOf("=");
            if (idx <= 0) {
                logger.debug("Invalid query.");
                return null;
            }
            try {
                final String key = URLDecoder.decode(
                        pair.substring(0, idx), "UTF-8");

                if (queryMap.containsKey(key)) {
                    logger.debug("Invalid query. Duplicate key: " + key);
                    return null;
                }
                final String value = URLDecoder.decode(
                        pair.substring(idx + 1), "UTF-8");
                queryMap.put(key, value);
            } catch (java.io.UnsupportedEncodingException e) {
                logger.error("UTF-8 unkown?!");
                return null;
            }
        }
        if (queryMap.isEmpty()) {
            logger.debug("Empty query.");
            return null;
        }
        return new ParameterList(queryMap);
    }

    private boolean checkOpenIDHeader(HttpHeaders headers) {
        /* First check if there are is anything provided */
        List<String> oidParamString = headers.getRequestHeader(
                OID_HEADER_FIELD);
        if (oidParamString == null) {
            logger.debug("Header " + OID_HEADER_FIELD + " not provided.");
            return false;
        }
        if (oidParamString.size() != 1) {
            logger.debug("Found " + oidParamString.size() + " openid headers.");
            return false;
        }

        /* Parse the parameters. Do it first to avoid a useless discovery. */
        ParameterList oidParams = splitParams(oidParamString.get(0));
        if (oidParams == null) {
            return false;
        }

        VerificationResult verification = null;
        try {
            verification = manager.verify(RETURN_URL, oidParams, discovered);
        } catch (MessageException e) {
            logger.debug("Verification failed: " + e.getMessage());
            return false;
        } catch (DiscoveryException e) {
            logger.debug("Verification discovery exception: " + e.getMessage());
            return false;
        } catch (AssociationException e) {
            logger.debug("Verification assoc exception: " + e.getMessage());
            return false;
        }


        /* See what could be verified */
        Identifier verified = verification.getVerifiedId();
        if (verified == null) {
            logger.debug("Failed to verify Identity information: " +
                    verification.getStatusMsg());
            return false;
        }

        logger.debug("Verified user: " + verified);

        return true;
    }

    @Override
    public boolean isAuthenticated(HttpHeaders headers) {
        if (!discoveryDone) {
            discoveryDone = discoverServer();
        }
        if (!discoveryDone) {
            return false;
        }
        if (checkOpenIDHeader(headers)) {
            /** Successfully authenticated. */
            return true;
        } else {

            return false;
        }
    }
}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)