changeset 5940:05da3cfa4054

Add new SAML Assertion class based on WAS Assertion.
author Bernhard Herzog <bh@intevation.de>
date Wed, 08 May 2013 17:56:13 +0200
parents 407cff3b03ab
children c1806821860b
files gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java
diffstat 1 files changed, 187 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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 17:56:13 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:

http://dive4elements.wald.intevation.org