# HG changeset patch # User Andre Heinecke # Date 1424879772 -3600 # Node ID 8e3f57e2f4af5eb8eb52189153bb72195a0713b0 # Parent 04e254571b8a0bb147a66204fad92867b8038279 Change openID authentication to a filter. Currently authentication works only once as we don't store session information and repeated try to authenticate will use the same nonce. diff -r 04e254571b8a -r 8e3f57e2f4af pom.xml --- a/pom.xml Wed Feb 25 16:03:35 2015 +0100 +++ b/pom.xml Wed Feb 25 16:56:12 2015 +0100 @@ -60,7 +60,11 @@ org.jboss.spec.javax.json jboss-json-api_1.0_spec - + + org.jboss.spec.javax.servlet + jboss-servlet-api_3.0_spec + 1.0.2.Final + com.fasterxml.jackson.core jackson-annotations diff -r 04e254571b8a -r 8e3f57e2f4af src/main/java/de/intevation/lada/rest/ProbeService.java --- a/src/main/java/de/intevation/lada/rest/ProbeService.java Wed Feb 25 16:03:35 2015 +0100 +++ b/src/main/java/de/intevation/lada/rest/ProbeService.java Wed Feb 25 16:56:12 2015 +0100 @@ -67,7 +67,7 @@ /* The authentication module.*/ @Inject - @AuthenticationConfig(type=AuthenticationType.OPENID) + @AuthenticationConfig(type=AuthenticationType.NONE) private Authentication authentication; /* The authorization module.*/ diff -r 04e254571b8a -r 8e3f57e2f4af src/main/java/de/intevation/lada/util/auth/OpenIDAuthentication.java --- a/src/main/java/de/intevation/lada/util/auth/OpenIDAuthentication.java Wed Feb 25 16:03:35 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* 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 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 queryMap = - new LinkedHashMap(); - 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 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; - } - } -} diff -r 04e254571b8a -r 8e3f57e2f4af src/main/java/de/intevation/lada/util/auth/OpenIDFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/intevation/lada/util/auth/OpenIDFilter.java Wed Feb 25 16:56:12 2015 +0100 @@ -0,0 +1,222 @@ +/* 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 org.apache.log4j.Logger; + +import java.util.Map; +import java.util.List; +import java.util.LinkedHashMap; +import java.net.URLDecoder; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpSession; + +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; + +/** ServletFilter used for OpenID authentification. */ +@WebFilter("/*") +public class OpenIDFilter implements Filter +{ + private static Logger logger = Logger.getLogger(OpenIDFilter.class); + + private ConsumerManager manager; + + /* This should be moved into a map discovered> + * as we currently only supporting one server this is static. */ + boolean discoveryDone = false; + private DiscoveryInformation discovered; + private String authRequestURL; + + /** TODO: get this from config. */ + /** 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 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); + authRequestURL = authReq.getDestinationUrl(true); + logger.debug("Authenticate with: " + authRequestURL); + } catch (MessageException e) { + logger.debug("Failed to create the Authentication request: " + + e.getMessage()); + } catch (ConsumerException e) { + logger.debug("Error in consumer manager: " + + e.getMessage()); + } + return true; + } + + /** 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 queryMap = + new LinkedHashMap(); + 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(ServletRequest req) { + + HttpServletRequest hReq = (HttpServletRequest) req; + /* First check if the header is provided at all */ + String oidParamString = hReq.getHeader(OID_HEADER_FIELD); + + if (oidParamString == null) { + logger.debug("Header " + OID_HEADER_FIELD + " not provided."); + return false; + } + + /* Parse the parameters to a map for openid4j */ + ParameterList oidParams = splitParams(oidParamString); + if (oidParams == null) { + return false; + } + + /* Verify against the discovered server. */ + 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 void init(FilterConfig config) + throws ServletException + { + manager = new ConsumerManager(); + /* TODO: Check for alternative configs. */ + manager.setAssociations(new InMemoryConsumerAssociationStore()); + manager.setNonceVerifier(new InMemoryNonceVerifier(50000)); + manager.setMinAssocSessEnc(AssociationSessionType.DH_SHA256); + discoveryDone = discoverServer(); + } + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) + throws IOException, ServletException + { + if (!discoveryDone) { + discoveryDone = discoverServer(); + } + if (discoveryDone && checkOpenIDHeader(req)) { + /** Successfully authenticated. */ + chain.doFilter(req, resp); + } + ((HttpServletResponse) resp).sendError(401, "{\"success\":false,\"message\":\"699\",\"data\":" + + "\"" + authRequestURL + "\",\"errors\":{},\"warnings\":{}," + + "\"readonly\":false,\"totalCount\":0}"); + } + @Override + public void destroy() + { + } +};