[Dive4elements-commits] [PATCH 3 of 3] merge
Wald Commits
scm-commit at wald.intevation.org
Wed May 8 18:23:56 CEST 2013
# HG changeset patch
# User Tom Gottfried <tom.gottfried at intevation.de>
# Date 1368030230 -7200
# Node ID 259ed81d47e9d74ab7ee8420f97827fc50c18d04
# Parent b819209732a0f6befe4f275f3042842dc9a5debe
# Parent 24dc13ac8e6ce2f8024a3080cb96680bc06231d7
merge
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/AuthenticationServlet.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/AuthenticationServlet.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,89 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.log4j.Logger;
+
+import org.dive4elements.river.client.server.auth.User;
+import org.dive4elements.river.client.server.auth.UserClient;
+
+/**
+ * Base class for servlets performing authentication and login.
+ */
+public class AuthenticationServlet extends HttpServlet {
+
+ private static Logger logger = Logger.getLogger(AuthenticationServlet.class);
+
+ private static final String FLYS_PAGE = "FLYS.html";
+ private static final String LOGIN_PAGE = "login.jsp";
+
+ protected void redirectFailure(HttpServletResponse resp, String path)
+ throws IOException {
+ resp.sendRedirect(path + "/" + LOGIN_PAGE);
+ }
+
+ protected void redirectFailure(HttpServletResponse resp, String path,
+ Exception e) throws IOException {
+ this.redirectFailure(resp, path, e.getMessage());
+ }
+
+ protected void redirectFailure(HttpServletResponse resp, String path,
+ String message) throws IOException {
+ resp.sendRedirect(path + "/" + LOGIN_PAGE + "?error=" + message);
+ }
+
+ protected void redirectSuccess(HttpServletResponse resp, String path,
+ String uri) throws IOException {
+ if (uri == null) {
+ String redirecturl = getServletContext().getInitParameter("redirect-url");
+ if (redirecturl == null) {
+ redirecturl = FLYS_PAGE;
+ }
+ uri = "/" + redirecturl;
+ }
+ resp.sendRedirect(uri);
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ logger.debug("Processing get request");
+ this.redirectFailure(resp, req.getContextPath());
+ }
+
+ protected void performLogin(HttpServletRequest req,
+ HttpServletResponse resp, User user)
+ throws ServletException, IOException {
+ String url = getServletContext().getInitParameter("server-url");
+ UserClient client = new UserClient(url);
+ if (!client.userExists(user)) {
+ logger.debug("Creating db user");
+ if (!client.createUser(user)) {
+ this.redirectFailure(resp, req.getContextPath(),
+ "Could not create new user");
+ return;
+ }
+ }
+
+ HttpSession session = req.getSession();
+ session.setAttribute("user", user);
+
+ String uri = (String)session.getAttribute("requesturi");
+
+ this.redirectSuccess(resp, req.getContextPath(), uri);
+ }
+}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/LoginServlet.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/LoginServlet.java Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/LoginServlet.java Wed May 08 18:23:50 2013 +0200
@@ -12,61 +12,20 @@
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.dive4elements.river.client.server.auth.Authentication;
import org.dive4elements.river.client.server.auth.AuthenticationException;
import org.dive4elements.river.client.server.auth.AuthenticationFactory;
-import org.dive4elements.river.client.server.auth.User;
-import org.dive4elements.river.client.server.auth.UserClient;
import org.dive4elements.river.client.server.features.Features;
-public class LoginServlet extends HttpServlet {
+public class LoginServlet extends AuthenticationServlet {
private static Logger logger = Logger.getLogger(LoginServlet.class);
- private static final String FLYS_PAGE = "FLYS.html";
- private static final String LOGIN_PAGE = "login.jsp";
-
- private void redirectFailure(HttpServletResponse resp, String path)
- throws IOException {
- resp.sendRedirect(path + "/" + LOGIN_PAGE);
- }
-
- private void redirectFailure(HttpServletResponse resp, String path,
- Exception e) throws IOException {
- this.redirectFailure(resp, path, e.getMessage());
- }
-
- private void redirectFailure(HttpServletResponse resp, String path,
- String message) throws IOException {
- resp.sendRedirect(path + "/" + LOGIN_PAGE + "?error=" + message);
- }
-
- private void redirectSuccess(HttpServletResponse resp, String path,
- String uri) throws IOException {
- if (uri == null) {
- String redirecturl = getServletContext().getInitParameter("redirect-url");
- if (redirecturl == null) {
- redirecturl = FLYS_PAGE;
- }
- uri = "/" + redirecturl;
- }
- resp.sendRedirect(uri);
- }
-
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- logger.debug("Processing get request");
- this.redirectFailure(resp, req.getContextPath());
- }
-
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
@@ -90,25 +49,7 @@
this.redirectFailure(resp, req.getContextPath());
return;
}
- User user = aresp.getUser();
-
- String url = getServletContext().getInitParameter("server-url");
- UserClient client = new UserClient(url);
- if (!client.userExists(user)) {
- logger.debug("Creating db user");
- if (!client.createUser(user)) {
- this.redirectFailure(resp, req.getContextPath(),
- "Could not create new user");
- return;
- }
- }
-
- HttpSession session = req.getSession();
- session.setAttribute("user", user);
-
- String uri = (String)session.getAttribute("requesturi");
-
- this.redirectSuccess(resp, req.getContextPath(), uri);
+ this.performLogin(req, resp, aresp.getUser());
}
catch(AuthenticationException e) {
logger.error(e, e);
@@ -123,6 +64,6 @@
Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
String auth = sc.getInitParameter("authentication");
return AuthenticationFactory.getInstance(auth).auth(username, password,
- encoding, features);
+ encoding, features, sc);
}
}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/SamlServlet.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/SamlServlet.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,91 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringBufferInputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.codec.binary.Base64InputStream;
+
+import org.apache.log4j.Logger;
+
+import org.dive4elements.river.client.server.auth.AuthenticationException;
+import org.dive4elements.river.client.server.auth.User;
+import org.dive4elements.river.client.server.auth.saml.TicketValidator;
+import org.dive4elements.river.client.server.auth.saml.Assertion;
+import org.dive4elements.river.client.server.features.Features;
+
+
+public class SamlServlet extends AuthenticationServlet {
+
+ private static Logger logger = Logger.getLogger(SamlServlet.class);
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException
+ {
+ String encoding = req.getCharacterEncoding();
+ String samlTicketXML = req.getParameter("samlTicket");
+
+ logger.debug("Processing post request");
+
+ if (samlTicketXML == null) {
+ logger.debug("No saml ticket provided");
+ this.redirectFailure(resp, req.getContextPath());
+ return;
+ }
+
+ try {
+ User user = this.auth(samlTicketXML);
+ if (user == null) {
+ logger.debug("Authentication not successful");
+ this.redirectFailure(resp, req.getContextPath());
+ return;
+ }
+ this.performLogin(req, resp, user);
+ }
+ catch(AuthenticationException e) {
+ logger.error(e, e);
+ this.redirectFailure(resp, req.getContextPath(), e);
+ }
+ }
+
+ private User auth(String samlTicketXML)
+ throws AuthenticationException, IOException
+ {
+ ServletContext sc = this.getServletContext();
+
+ Assertion assertion = null;
+ try {
+ String keyfile =
+ (String)sc.getInitParameter("saml-trusted-public-key");
+ TicketValidator validator =
+ new TicketValidator(sc.getRealPath(keyfile));
+
+ InputStream in = new StringBufferInputStream(samlTicketXML);
+ assertion = validator.checkTicket(new Base64InputStream(in));
+ }
+ catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ }
+ if (assertion == null) {
+ throw new AuthenticationException("Login failed.");
+ }
+
+ Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
+ return new org.dive4elements.river.client.server.auth.saml.User(
+ assertion, features.getFeatures(assertion.getRoles()), null);
+ }
+}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/Authenticator.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/Authenticator.java Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/Authenticator.java Wed May 08 18:23:50 2013 +0200
@@ -10,11 +10,16 @@
import java.io.IOException;
+import javax.servlet.ServletContext;
+
import org.dive4elements.river.client.server.features.Features;
+
public interface Authenticator {
- public Authentication auth(String username, String password, String encoding, Features features)
+ public Authentication auth(String username, String password,
+ String encoding, Features features,
+ ServletContext context)
throws AuthenticationException, IOException;
}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/plain/Authenticator.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/plain/Authenticator.java Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/plain/Authenticator.java Wed May 08 18:23:50 2013 +0200
@@ -20,6 +20,8 @@
import java.util.ArrayList;
import java.util.List;
+import javax.servlet.ServletContext;
+
import org.apache.log4j.Logger;
import org.dive4elements.river.client.server.features.Features;
@@ -88,7 +90,8 @@
String username,
String password,
String encoding,
- Features features
+ Features features,
+ ServletContext context
)
throws AuthenticationException, IOException
{
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,187 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server.auth.saml;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.TimeZone;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * Represents a SAML assertion about a user.
+ */
+public class Assertion {
+
+ private static Logger logger = Logger.getLogger(Assertion.class);
+
+ private Element assertion;
+ private LinkedList<String> roles;
+ private String user_id;
+ private String name_id;
+ private String group_id;
+ private String group_name;
+ private Date notbefore;
+ private Date notonorafter;
+
+ private static final String ATTR_CONT_USER_ID =
+ "urn:conterra:names:sdi-suite:policy:attribute:user-id";
+ private static final String ATTR_CONT_GROUP_ID =
+ "urn:conterra:names:sdi-suite:policy:attribute:group-id";
+ private static final String ATTR_CONT_GROUP_NAME =
+ "urn:conterra:names:sdi-suite:policy:attribute:group-name";
+ private static final String ATTR_CONT_ROLE =
+ "urn:conterra:names:sdi-suite:policy:attribute:role";
+
+
+ public Assertion(Element assertion) {
+ this.assertion = assertion;
+ this.roles = new LinkedList<String>();
+ this.parseCondition();
+ this.parseAttributeStatement();
+ }
+
+ private void parseCondition() {
+ Element conditions = (Element)XPathUtils.xpathNode(this.assertion,
+ "saml:Conditions");
+ if (conditions == null) {
+ logger.error("Cannot find Assertion conditions element");
+ return;
+ }
+
+ this.notbefore = parseDateAttribute(conditions, "NotBefore");
+ if (this.notbefore == null) {
+ logger.warn("Could not extract NotBefore date.");
+ }
+ this.notonorafter = parseDateAttribute(conditions, "NotOnOrAfter");
+ if (this.notonorafter == null) {
+ logger.warn("Could not extract NotOnOrAfter date.");
+ }
+ }
+
+ private Date parseDateAttribute(Element element, String name) {
+ SimpleDateFormat dateformat = new SimpleDateFormat();
+ // format should be "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" but that's
+ // only available in java 7+. However, parsing without the
+ // time-zone yields Date values in the local time-zone,
+ // therefore we need to convert to GMT ourselves.
+ dateformat.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+
+ String value = element.getAttribute(name);
+ try {
+ return toGMT(dateformat.parse(value));
+ }
+ catch(ParseException e) {
+ logger.error("Cannot parse Condition attribute "
+ + name + " with value " + value
+ + " (" + e.getLocalizedMessage() + ")");
+ }
+ return null;
+ }
+
+ private Date toGMT(Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.set(Calendar.ZONE_OFFSET, 0);
+ cal.set(Calendar.DST_OFFSET, 0);
+ return cal.getTime();
+ }
+
+ private void parseAttributeStatement() {
+ Element attrstatement = (Element)XPathUtils.xpathNode(this.assertion,
+ "saml:AttributeStatement");
+ if (attrstatement == null) {
+ logger.error("Cannot find Assertion AttributeStatement element");
+ return;
+ }
+
+ this.name_id = XPathUtils.xpathString(attrstatement,
+ "saml:Subject"
+ + "/saml:NameIdentifier");
+
+ this.user_id = getAttrValue(attrstatement, ATTR_CONT_USER_ID);
+ this.group_id = getAttrValue(attrstatement, ATTR_CONT_GROUP_ID);
+ this.group_name = getAttrValue(attrstatement, ATTR_CONT_GROUP_NAME);
+ this.roles = getAttrValues(attrstatement, ATTR_CONT_ROLE);
+ }
+
+ static Object getAttrObject(Element attrs, String name, QName returnType) {
+ return XPathUtils.xpath(attrs,
+ "saml:Attribute[@AttributeName='" + name + "']"
+ + "/saml:AttributeValue",
+ returnType);
+ }
+
+ static String getAttrValue(Element attrs, String name) {
+ return (String)getAttrObject(attrs, name, XPathConstants.STRING);
+ }
+
+ static LinkedList<String> getAttrValues(Element attrs, String name) {
+ LinkedList<String> strings = new LinkedList<String>();
+ NodeList nodes = (NodeList)getAttrObject(attrs, name,
+ XPathConstants.NODESET);
+ for (int i = 0; i < nodes.getLength(); i++) {
+ strings.add(nodes.item(i).getTextContent());
+ }
+
+ return strings;
+ }
+
+ public List<String> getRoles() {
+ return this.roles;
+ }
+
+ public String getUserID() {
+ return this.user_id;
+ }
+
+ public String getNameID() {
+ return this.name_id;
+ }
+
+ public String getGroupID() {
+ return this.group_id;
+ }
+
+ public String getGroupName() {
+ return this.group_name;
+ }
+
+ public Date getFrom() {
+ return this.notbefore;
+ }
+
+ public Date getUntil() {
+ return this.notonorafter;
+ }
+
+ /**
+ * Returns whether the ticket to which the assertion belongs is
+ * valid at the time the method is called. The method returns true,
+ * if both dates (notbefore and notonorafter) have been determined
+ * successfully and the current date/time is between both.
+ * @return Whether the ticket is valid now.
+ */
+ public boolean isValidNow() {
+ Date now = new Date();
+ return (this.notbefore != null && this.notonorafter != null
+ && now.after(this.notbefore)
+ && !this.notonorafter.before(now));
+ }
+}
+// vim: set fileencoding=utf-8 ts=4 sw=4 et si tw=80:
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/SamlNamespaceContext.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/SamlNamespaceContext.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,106 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server.auth.saml;
+
+import java.util.Iterator;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+
+
+/**
+ * The namespace context for SAML documents.
+ */
+public class SamlNamespaceContext implements NamespaceContext
+{
+ /**
+ * The URI of the namespace of SAML assertions.
+ */
+ public static final String SAML_NS_ASSERT =
+ "urn:oasis:names:tc:SAML:1.0:assertion";
+
+ /**
+ * The URI of the namespace of the SAML protocol.
+ */
+ public static final String SAML_NS_PROTO =
+ "urn:oasis:names:tc:SAML:1.0:protocol";
+
+ /**
+ * The URI of the namespace for XML signatures.
+ */
+ public static final String XML_SIG_NS =
+ "http://www.w3.org/2000/09/xmldsig#";
+
+ /**
+ * Final instance to be easily used to avoid creation
+ * of instances.
+ */
+ public static final SamlNamespaceContext INSTANCE =
+ new SamlNamespaceContext();
+
+
+ /**
+ * The default constructor.
+ */
+ public SamlNamespaceContext() {
+ }
+
+
+ /**
+ * @see javax.xml.namespace.NamespaceContext#getNamespaceURI(String)
+ * @param prefix The prefix
+ * @return The corresponing URI
+ */
+ public String getNamespaceURI(String prefix) {
+
+ if (prefix == null) {
+ throw new NullPointerException("Null prefix");
+ }
+
+ if ("saml".equals(prefix)) {
+ return SAML_NS_ASSERT;
+ }
+
+ if ("samlp".equals(prefix)) {
+ return SAML_NS_PROTO;
+ }
+
+ if ("ds".equals(prefix)) {
+ return XML_SIG_NS;
+ }
+
+ if ("xml".equals(prefix)) {
+ return XMLConstants.XML_NS_URI;
+ }
+
+ return XMLConstants.NULL_NS_URI;
+ }
+
+
+ /**
+ * @see javax.xml.namespace.NamespaceContext#getPrefix(String)
+ * @param uri The URI
+ * @return nothing.
+ * @throws java.lang.UnsupportedOperationException
+ */
+ public String getPrefix(String uri) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ /**
+ * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String)
+ * @param uri The URI
+ * @return nothing
+ * @throws java.lang.UnsupportedOperationException
+ */
+ public Iterator getPrefixes(String uri) {
+ throw new UnsupportedOperationException();
+ }
+}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/TicketValidator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/TicketValidator.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,162 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server.auth.saml;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Key;
+import java.util.Iterator;
+import java.util.Date;
+import javax.security.cert.X509Certificate;
+import javax.security.cert.CertificateException;
+import javax.xml.crypto.Data;
+import javax.xml.crypto.NodeSetData;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.XMLSignature;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.dom.DOMValidateContext;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.dive4elements.artifacts.httpclient.utils.XMLUtils;
+
+
+/**
+ * Validator for SAML tickets.
+ */
+public class TicketValidator {
+
+ /**
+ * The logger used by the TicketValidator instances.
+ */
+ private static Logger logger = Logger.getLogger(TicketValidator.class);
+
+ /**
+ * The trusted Key for signature checks.
+ */
+ private Key trustedKey;
+
+ /**
+ * Creates a new TicketValidator from a trusted key.
+ * @param trustedKey The trusted key for the signature checks.
+ */
+ public TicketValidator(Key trustedKey) {
+ this.trustedKey = trustedKey;
+ }
+
+ /**
+ * Creates a new TicketValidator, loading the trusted key from a
+ * file.
+ * @param filename The filename of the X509 certificate containing
+ * the trusted public key.
+ */
+ public TicketValidator(String filename) throws IOException,
+ CertificateException {
+ this.trustedKey = loadKey(filename);
+ }
+
+ /**
+ * Loads the public key from a file containing an X509 certificate.
+ */
+ private Key loadKey(String filename) throws IOException,
+ CertificateException {
+ X509Certificate cert = X509Certificate.getInstance(
+ new FileInputStream(filename));
+ cert.checkValidity(new Date());
+ return cert.getPublicKey();
+ }
+
+
+ /**
+ * Check the ticket represented by the given DOM element.
+ * @param root the DOM element under which the signature can be
+ * found.
+ * @return The assertion element from the signed data.
+ */
+ public Assertion checkTicket(Element root) throws Exception {
+ markAssertionIdAttributes(root);
+
+ Node signode = XPathUtils.xpathNode(root, ".//ds:Signature");
+
+ DOMValidateContext context = new DOMValidateContext(this.trustedKey,
+ signode);
+ context.setProperty("javax.xml.crypto.dsig.cacheReference", true);
+
+ XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
+ XMLSignature signature = factory.unmarshalXMLSignature(context);
+ if (!signature.validate(context)) {
+ logger.error("Signature of SAML ticket could not be validated.");
+ return null;
+ }
+
+ Element assertionElement = extractAssertion(signature, context);
+ if (assertionElement == null) {
+ logger.error("Could not extract assertion from signed content.");
+ return null;
+ }
+
+ Assertion assertion = new Assertion(assertionElement);
+ if (!assertion.isValidNow()) {
+ logger.error("Ticket is not valid now"
+ + " (NotBefore: " + assertion.getFrom()
+ + ", NotOnOrAfter: " + assertion.getUntil());
+ return null;
+ }
+
+ return assertion;
+ }
+
+ /**
+ * Check the ticket read from an InputStream containing a SAML
+ * document.
+ * @param xml InputStream with the SAML ticket as XML
+ * @return The assertion element from the signed data.
+ */
+ public Assertion checkTicket(InputStream in) throws Exception {
+ return checkTicket(XMLUtils.readDocument(in).getDocumentElement());
+ }
+
+ /**
+ * Mark the AssertionID attribute of SAML Assertion elements as ID
+ * attribute, so that the signature checker can resolve the
+ * references properly and find the signed data.
+ */
+ private void markAssertionIdAttributes(Element root) {
+ NodeList nodes = XPathUtils.xpathNodeList(root, "saml:Assertion");
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Element el = (Element)nodes.item(i);
+ el.setIdAttribute("AssertionID", true);
+ }
+ }
+
+ private Element extractAssertion(XMLSignature sig,
+ DOMValidateContext context) {
+ for (Object obj: sig.getSignedInfo().getReferences()) {
+ Data data = ((Reference)obj).getDereferencedData();
+ if (data instanceof NodeSetData) {
+ Iterator i = ((NodeSetData)data).iterator();
+ for (int k = 0; i.hasNext(); k++) {
+ Object node = i.next();
+ if (node instanceof Element) {
+ Element el = (Element)node;
+ if (el.getTagName().equals("Assertion"))
+ return el;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/User.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/User.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server.auth.saml;
+
+import java.util.Date;
+import java.util.List;
+
+import org.dive4elements.river.client.server.auth.DefaultUser;
+import org.dive4elements.river.client.server.auth.saml.Assertion;
+
+public class User
+extends DefaultUser
+implements org.dive4elements.river.client.server.auth.User {
+
+ private Assertion assertion;
+
+ public User(Assertion assertion, List<String> features, String password) {
+ this.setName(assertion.getUserID());
+ this.setAccount(assertion.getNameID());
+ this.setRoles(assertion.getRoles());
+ this.assertion = assertion;
+ this.setAllowedFeatures(features);
+ this.setPassword(password);
+ }
+
+ @Override
+ public boolean hasExpired() {
+ // We could check the validity dates of the assertion here, but
+ // when using this for Single-Sign-On this would lead to the
+ // code in GGInAFilter to re-authenticate with the password
+ // stored in the User object, which isn't known in the case of
+ // Single-Sign-On.
+ return false;
+ }
+}
+
+// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/XPathUtils.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/XPathUtils.java Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,85 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.server.auth.saml;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathConstants;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.dive4elements.artifacts.common.utils.XMLUtils;
+
+
+/**
+ * Convenience methods to evaluate XPath queries on SAML documents. The
+ * methods are just front-ends for the {@link XMLUtils.xpath} method.
+ */
+public class XPathUtils
+{
+ /**
+ * Evaluates an XPath query on a given object and returns the result
+ * as a given type, using SamlNamespaceContext as the namespace
+ * context.
+ * @param root The object which is used as the root of the tree to
+ * be searched in.
+ * @param query The XPath query
+ * @param returnType The type of the result.
+ * @return The result of type 'returnType' or null if something
+ * went wrong during XPath evaluation.
+ */
+ public static final Object xpath(Object root, String query,
+ QName returnType) {
+ return XMLUtils.xpath(root, query, returnType,
+ SamlNamespaceContext.INSTANCE);
+ }
+
+
+ /**
+ * Evaluates an XPath query on a given object and returns the result
+ * as a String, using SamlNamespaceContext as the namespace context.
+ * @param root The object which is used as the root of the tree to
+ * be searched in.
+ * @param query The XPath query
+ * @return The result as a String or null if something went wrong
+ * during XPath evaluation.
+ */
+ public static final String xpathString(Object root, String query) {
+ return (String)xpath(root, query, XPathConstants.STRING);
+ }
+
+
+ /**
+ * Evaluates an XPath query on a given object and returns the result
+ * as a Node, using SamlNamespaceContext as the namespace context.
+ * @param root The object which is used as the root of the tree to
+ * be searched in.
+ * @param query The XPath query
+ * @return The result as a Node or null if something went wrong
+ * during XPath evaluation.
+ */
+ public static final Node xpathNode(Object root, String query) {
+ return (Node)xpath(root, query, XPathConstants.NODE);
+ }
+
+
+ /**
+ * Evaluates an XPath query on a given object and returns the result
+ * as a NodeList, using SamlNamespaceContext as the namespace
+ * context.
+ * @param root The object which is used as the root of the tree to
+ * be searched in.
+ * @param query The XPath query
+ * @return The result as a NodeList or null if something
+ * went wrong during XPath evaluation.
+ */
+ public static final NodeList xpathNodeList(Object root, String query) {
+ return (NodeList)xpath(root, query, XPathConstants.NODESET);
+ }
+}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Assertion.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Assertion.java Wed May 08 18:23:41 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.client.server.auth.was;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Iterator;
-import java.util.Date;
-import java.util.List;
-import java.util.LinkedList;
-
-import org.apache.log4j.Logger;
-
-import org.jdom.Element;
-
-public class Assertion {
-
- private static Logger logger = Logger.getLogger(Assertion.class);
-
- private Element assertion;
- private LinkedList<String> roles;
- private String assertion_id;
- private String user_id;
- private String name_id;
- private String group_id;
- private String group_name;
- private Date notbefore;
- private Date notonorafter;
- private Signature signature;
-
- private static final String ATTR_CONT_USER_ID =
- "urn:conterra:names:sdi-suite:policy:attribute:user-id";
- private static final String ATTR_CONT_GROUP_ID =
- "urn:conterra:names:sdi-suite:policy:attribute:group-id";
- private static final String ATTR_CONT_GROUP_NAME =
- "urn:conterra:names:sdi-suite:policy:attribute:group-name";
- private static final String ATTR_CONT_ROLE =
- "urn:conterra:names:sdi-suite:policy:attribute:role";
-
-
- public Assertion(Element assertion) {
- this.assertion = assertion;
- this.roles = new LinkedList<String>();
-
- this.assertion_id = assertion.getAttributeValue("AssertionID");
-
- this.parseContition();
- this.parseAttributeStatement();
- }
-
- private void parseContition() {
- Element condition = this.assertion.getChild("Conditions",
- Namespaces.SAML_NS_ASSERT);
- if (condition != null) {
- SimpleDateFormat dateformat = new SimpleDateFormat();
- // format should be "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" but that's only
- // available in java 7+
- dateformat.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
- String from = condition.getAttributeValue("NotBefore");
- if (from != null) {
- try {
- this.notbefore = dateformat.parse(from);
- }
- catch(ParseException e) {
- logger.error("Unknown datetime format for Condition " +
- "NotBefore " + from);
- }
- }
-
- String until = condition.getAttributeValue("NotOnOrAfter");
- logger.debug("Session is valid until " + until);
- if (until != null) {
- try {
- this.notonorafter = dateformat.parse(until);
- }
- catch(ParseException e) {
- logger.error("Unknown datetime format for Condition " +
- "NotOnOrAfter " + until);
- }
- }
- }
- }
-
- private void parseAttributeStatement() {
- Element attrstatement = this.assertion.getChild("AttributeStatement",
- Namespaces.SAML_NS_ASSERT);
- if (attrstatement != null) {
-
- Element subject = attrstatement.getChild("Subject",
- Namespaces.SAML_NS_ASSERT);
- if (subject != null) {
- this.name_id = subject.getChildText("NameIdentifier",
- Namespaces.SAML_NS_ASSERT);
- }
-
- List attributes = attrstatement.getChildren("Attribute",
- Namespaces.SAML_NS_ASSERT);
- for(Iterator i = attributes.iterator(); i.hasNext();) {
- Element attr = (Element)i.next();
- String attrname = attr.getAttributeValue("AttributeName");
- if (attrname.equals(ATTR_CONT_USER_ID)) {
- this.user_id = this.getAttributeValue(attr);
- }
- else if (attrname.equals(ATTR_CONT_GROUP_ID)) {
- this.group_id = this.getAttributeValue(attr);
- }
- else if (attrname.equals(ATTR_CONT_GROUP_NAME)) {
- this.group_name = this.getAttributeValue(attr);
- }
- else if (attrname.equals(ATTR_CONT_ROLE)) {
- List roles = attr.getChildren("AttributeValue",
- Namespaces.SAML_NS_ASSERT);
- for(Iterator j = roles.iterator(); j.hasNext();) {
- Element role = (Element)j.next();
- this.roles.add(role.getText());
- }
- }
- else {
- logger.debug("Unknown AttributeName " + attrname +
- " found while parsing AttributeStatement.");
- }
- }
- }
- }
-
- private String getAttributeValue(Element attr) {
- return attr.getChildText("AttributeValue", Namespaces.SAML_NS_ASSERT);
- }
-
- public List<String> getRoles() {
- return this.roles;
- }
-
- public Boolean isValid() {
- // TODO:
- // check signature digest
- // check signature value
- // check signature cert
- return false;
- }
-
- public Signature getSiganture() {
- if (this.signature == null) {
- Element signature = this.assertion.getChild("Signature",
- Namespaces.XML_SIG_NS);
- if (signature != null) {
- this.signature = new Signature(signature);
- }
- }
- return this.signature;
- }
-
- public String getUserID() {
- return this.user_id;
- }
-
- public String getNameID() {
- return this.name_id;
- }
-
- public String getGroupID() {
- return this.group_id;
- }
-
- public String getGroupName() {
- return this.group_name;
- }
-
- public String getID() {
- return this.assertion_id;
- }
-
- public Date getFrom() {
- return this.notbefore;
- }
-
- public Date getUntil() {
- return this.notonorafter;
- }
-}
-// vim: set fileencoding=utf-8 ts=4 sw=4 et si tw=80:
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java Wed May 08 18:23:50 2013 +0200
@@ -10,6 +10,7 @@
import java.io.IOException;
import java.security.GeneralSecurityException;
+import javax.servlet.ServletContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
@@ -32,7 +33,8 @@
String username,
String password,
String encoding,
- Features features
+ Features features,
+ ServletContext context
) throws
AuthenticationException,
IOException
@@ -60,7 +62,10 @@
return null;
}
else {
- return new Response(entity, username, password, features);
+ String trustedKey =
+ (String)context.getInitParameter("saml-trusted-public-key");
+ return new Response(entity, username, password, features,
+ context.getRealPath(trustedKey));
}
}
catch(GeneralSecurityException e) {
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Namespaces.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Namespaces.java Wed May 08 18:23:41 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.client.server.auth.was;
-
-import org.jdom.Namespace;
-
-public class Namespaces {
-
- public static final Namespace SAML_NS_ASSERT =
- Namespace.getNamespace("urn:oasis:names:tc:SAML:1.0:assertion");
- public static final Namespace SAML_NS_PROTO =
- Namespace.getNamespace("urn:oasis:names:tc:SAML:1.0:protocol");
- public static final Namespace XML_SIG_NS =
- Namespace.getNamespace("http://www.w3.org/2000/09/xmldsig#");
-
-}
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java Wed May 08 18:23:50 2013 +0200
@@ -18,16 +18,20 @@
import org.apache.log4j.Logger;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.dive4elements.artifacts.httpclient.utils.XMLUtils;
import org.dive4elements.river.client.server.auth.Authentication;
import org.dive4elements.river.client.server.auth.AuthenticationException;
+import org.dive4elements.river.client.server.auth.saml.Assertion;
+import org.dive4elements.river.client.server.auth.saml.XPathUtils;
+import org.dive4elements.river.client.server.auth.saml.TicketValidator;
+import org.dive4elements.river.client.server.auth.saml.User;
import org.dive4elements.river.client.server.features.Features;
+
public class Response implements Authentication {
private static Logger logger = Logger.getLogger(Response.class);
@@ -37,9 +41,12 @@
private String username;
private String password;
private Features features;
+ private String trustedKeyFile;
- public Response(HttpEntity entity, String username, String password, Features features) throws AuthenticationException, IOException {
+ public Response(HttpEntity entity, String username, String password,
+ Features features, String trustedKeyFile)
+ throws AuthenticationException, IOException {
if (entity == null) {
throw new ServiceException("Invalid response");
@@ -47,36 +54,27 @@
String contenttype = entity.getContentType().getValue();
- try {
- InputStream in = entity.getContent();
+ InputStream in = entity.getContent();
- if (!contenttype.equals("application/vnd.ogc.se_xml")) {
- // XXX: Assume base64 encoded content.
- in = new Base64InputStream(in);
- }
+ if (!contenttype.equals("application/vnd.ogc.se_xml")) {
+ // XXX: Assume base64 encoded content.
+ in = new Base64InputStream(in);
+ }
- SAXBuilder builder = new SAXBuilder();
- Document doc = builder.build(in);
- Element root = doc.getRootElement();
- String rname = root.getName();
+ Document doc = XMLUtils.readDocument(in);
+ Element root = doc.getDocumentElement();
+ String rname = root.getTagName();
- if (rname != null && rname.equals("ServiceExceptionReport")) {
- throw new ServiceException(root.getChildText("ServiceException"));
- }
+ if (rname != null && rname.equals("ServiceExceptionReport")) {
+ throw new ServiceException(XPathUtils.xpathString(root,
+ "ServiceException"));
+ }
- this.root = root;
- this.username = username;
- this.password = password;
- this.features = features;
-
- }
- catch(JDOMException e) {
- throw new AuthenticationException(e);
- }
- }
-
- public Element getRoot() {
- return this.root;
+ this.root = root;
+ this.username = username;
+ this.password = password;
+ this.features = features;
+ this.trustedKeyFile = trustedKeyFile;
}
@Override
@@ -86,24 +84,20 @@
}
public String getStatus() {
- Element status = this.root.getChild("Status", Namespaces.SAML_NS_PROTO);
- if (status == null) {
- return null;
- }
- Element statuscode = status.getChild("StatusCode",
- Namespaces.SAML_NS_PROTO);
- if (statuscode == null) {
- return null;
- }
- return statuscode.getAttributeValue("Value");
+ return XPathUtils.xpathString(this.root,
+ "./samlp:Status/samlp:StatusCode/@Value");
}
+
public Assertion getAssertion() {
if (this.assertion == null && this.root != null) {
- Element assertion = this.root.getChild("Assertion",
- Namespaces.SAML_NS_ASSERT);
- if (assertion != null) {
- this.assertion = new Assertion(assertion);
+ try {
+ TicketValidator validator =
+ new TicketValidator(this.trustedKeyFile);
+ this.assertion = validator.checkTicket(this.root);
+ }
+ catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
}
}
return this.assertion;
@@ -119,8 +113,7 @@
this.assertion.getRoles());
logger.debug("User " + this.username + " with features " + features +
" successfully authenticated.");
- return new User(this.username, this.password, assertion.getNameID(),
- this.assertion.getRoles(), assertion, features);
+ return new User(assertion, features, this.password);
}
}
// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Signature.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Signature.java Wed May 08 18:23:41 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.client.server.auth.was;
-
-import java.io.ByteArrayInputStream;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-public class Signature {
-
- private static Logger logger = Logger.getLogger(Signature.class);
-
- private static final String XML_SIG_DIGEST_SHA1 =
- "http://www.w3.org/2000/09/xmldsig#sha1";
- private static final String XML_SIG_SIGNATURE_RSA_SHA1 =
- "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
-
- private final Element signature;
- private Certificate cert;
- private byte[] value;
- private byte[] digestvalue;
- private String reference;
-
- public Signature(Element signature) {
- this.signature = signature;
- this.parseSignatureInfo();
- this.parseSignatureValue();
- this.parseCertificate();
- }
-
- private void parseSignatureInfo() {
- Element signatureinfo = this.signature.getChild("SignedInfo",
- Namespaces.XML_SIG_NS);
- if (signatureinfo != null) {
- Element signaturemethod = signatureinfo.getChild("SignatureMethod",
- Namespaces.XML_SIG_NS);
- String algorithm = signaturemethod.getAttributeValue("Algorithm");
- if (!algorithm.equals(XML_SIG_SIGNATURE_RSA_SHA1)) {
- logger.warn("Unkown signature alorithm " + algorithm);
- }
-
- // There could be several references in XML-Sig spec but for me it
- // doesn't make sense to have more then one in a SAML Assertion
- Element reference = signatureinfo.getChild("Reference",
- Namespaces.XML_SIG_NS);
- // reference must be present but its better to check
- if (reference != null) {
- String digestvalue = reference.getChildText("DigestValue",
- Namespaces.XML_SIG_NS);
- String digestmethod = reference.getChildText("DigestMethod",
- Namespaces.XML_SIG_NS);
- if (!digestmethod.equals(XML_SIG_DIGEST_SHA1)) {
- logger.warn("Unknown digest method " + digestmethod);
- }
- this.digestvalue = Base64.decodeBase64(digestvalue);
-
- String referenceuri = reference.getAttributeValue("URI");
- if (referenceuri.startsWith("#")) {
- this.reference = referenceuri.substring(1);
- }
- else {
- logger.warn("Unkown reference type " + referenceuri);
- this.reference = referenceuri;
- }
- }
- }
- }
-
- private void parseSignatureValue() {
- String signaturevalue = this.signature.getChildText("SignatureValue",
- Namespaces.XML_SIG_NS);
- this.value = Base64.decodeBase64(signaturevalue);
- }
-
- private void parseCertificate() {
- Element keyinfo = this.signature.getChild("KeyInfo",
- Namespaces.XML_SIG_NS);
- if (keyinfo != null) {
- Element data = keyinfo.getChild("X509Data", Namespaces.XML_SIG_NS);
- if (data != null) {
- String base64cert = data.getChildText("X509Certificate",
- Namespaces.XML_SIG_NS);
- if (base64cert != null) {
- byte[] bytes = Base64.decodeBase64(base64cert);
- try {
- CertificateFactory cf = CertificateFactory.getInstance(
- "X.509");
- this.cert = cf.generateCertificate(
- new ByteArrayInputStream(bytes));
- }
- catch(CertificateException e) {
- // should never occur
- logger.error(e);
- }
- }
- }
- }
- }
-
- public Certificate getCertificate() {
- return this.cert;
- }
-
- public byte[] getValue() {
- return this.value;
- }
-
- public String getReference() {
- // In theory there could be several references with digestvalues, ...
- return this.reference;
- }
-
- public byte[] getDigestValue() {
- return this.digestvalue;
- }
-}
-// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/User.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/User.java Wed May 08 18:23:41 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.client.server.auth.was;
-
-import java.util.Date;
-import java.util.List;
-
-import org.dive4elements.river.client.server.auth.DefaultUser;
-
-public class User
-extends DefaultUser
-implements org.dive4elements.river.client.server.auth.User {
-
- private Assertion assertion;
-
- public User(String name,
- String password,
- String account,
- List<String> roles,
- Assertion assertion,
- List<String> features
- ) {
- this.setName(name);
- this.setPassword(password);
- this.setRoles(roles);
- this.assertion = assertion;
- this.setAllowedFeatures(features);
- this.setAccount(account);
- }
-
- @Override
- public boolean hasExpired() {
- Date until = this.assertion.getUntil();
- if (until != null) {
- Date current = new Date();
- return !current.after(until);
- }
- return false;
- }
-}
-
-// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/java/org/dive4elements/river/client/server/filter/GGInAFilter.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/filter/GGInAFilter.java Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/filter/GGInAFilter.java Wed May 08 18:23:50 2013 +0200
@@ -46,6 +46,7 @@
private static final String LOGIN_JSP = "/login.jsp";
private static final String LOGIN_SERVLET = "/flys/login";
+ private static final String SAML_SERVLET = "/flys/saml";
private static final String FLYS_CSS = "/FLYS.css";
@@ -108,6 +109,7 @@
String path = this.sc.getContextPath();
if (requesturi.equals(path + LOGIN_JSP)
|| requesturi.equals(path + LOGIN_SERVLET)
+ || requesturi.equals(path + SAML_SERVLET)
|| requesturi.equals(path + FLYS_CSS)) {
logger.debug("Request for login " + requesturi);
chain.doFilter(req, resp);
@@ -192,7 +194,7 @@
throws AuthenticationException, IOException {
Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
return AuthenticationFactory.getInstance(this.authmethod).auth(
- user.getName(), user.getPassword(), encoding, features);
+ user.getName(), user.getPassword(), encoding, features, sc);
}
/**
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/webapp/WEB-INF/saml-signer-cert.pem
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/webapp/WEB-INF/saml-signer-cert.pem Wed May 08 18:23:50 2013 +0200
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIICDzCCAXigAwIBAgIETQYOHzANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJERTEQMA4GA1UE
+BxMHS29ibGVuejENMAsGA1UEChMEYmFmZzENMAsGA1UECxMEYmFmZzENMAsGA1UEAxMEYmFmZzAe
+Fw0xMDEyMTMxMjE0MjNaFw0xNTExMTcxMjE0MjNaMEwxCzAJBgNVBAYTAkRFMRAwDgYDVQQHEwdL
+b2JsZW56MQ0wCwYDVQQKEwRiYWZnMQ0wCwYDVQQLEwRiYWZnMQ0wCwYDVQQDEwRiYWZnMIGfMA0G
+CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIg0iXqjbFVDCuwiHR06U8+8IZmTl5mVDeH34zjqcCWEKf
+T2W2VS9SJhxyjP+DGDfDS9obqEZkYi8i4kLe533e+CQBWKud5mCHguVEiydOkUpUo0En4jFk9DBb
+kEDK8HV/CFzc1zX/6UJWGI8QL4ewQWhfhJSN/aoWweo0Sjr7mQIDAQABMA0GCSqGSIb3DQEBBQUA
+A4GBALpDcIQ0s+qhP+WvSkiVYiyGS9lnJWkrTMY89Q8kWbeiLr3/YA2fAQFJDqZ1Q8JxgUwadzv9
+6DClAW+6nPCnx3zQuP+tV9jZwQ5MSykHtwK+GAIwpLktx88b3BtIEOvMQjACoaPt3Z/Epm+VYT72
+rrxc7eejd9GfGIrCi4q2j4/j
+-----END CERTIFICATE-----
diff -r b819209732a0 -r 259ed81d47e9 gwt-client/src/main/webapp/WEB-INF/web.xml
--- a/gwt-client/src/main/webapp/WEB-INF/web.xml Wed May 08 18:23:41 2013 +0200
+++ b/gwt-client/src/main/webapp/WEB-INF/web.xml Wed May 08 18:23:50 2013 +0200
@@ -22,6 +22,11 @@
</context-param>
<context-param>
+ <param-name>saml-trusted-public-key</param-name>
+ <param-value>/WEB-INF/saml-signer-cert.pem</param-value>
+ </context-param>
+
+ <context-param>
<param-name>features-file</param-name>
<param-value>/WEB-INF/features.xml</param-value>
</context-param>
@@ -553,6 +558,16 @@
</servlet-mapping>
<servlet>
+ <servlet-name>saml</servlet-name>
+ <servlet-class>org.dive4elements.river.client.server.SamlServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>saml</servlet-name>
+ <url-pattern>/flys/saml</url-pattern>
+ </servlet-mapping>
+
+ <servlet>
<servlet-name>modules</servlet-name>
<servlet-class>org.dive4elements.river.client.server.ModuleServiceImpl</servlet-class>
</servlet>
More information about the Dive4elements-commits
mailing list