Mercurial > dive4elements > river
comparison gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/Assertion.java @ 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 | |
children | a51adfc957bf |
comparison
equal
deleted
inserted
replaced
5939:407cff3b03ab | 5940:05da3cfa4054 |
---|---|
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde | |
2 * Software engineering by Intevation GmbH | |
3 * | |
4 * This file is Free Software under the GNU AGPL (>=v3) | |
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the | |
6 * documentation coming with Dive4Elements River for details. | |
7 */ | |
8 | |
9 package org.dive4elements.river.client.server.auth.saml; | |
10 | |
11 import java.text.ParseException; | |
12 import java.text.SimpleDateFormat; | |
13 import java.util.Calendar; | |
14 import java.util.Date; | |
15 import java.util.List; | |
16 import java.util.LinkedList; | |
17 import java.util.TimeZone; | |
18 import javax.xml.namespace.QName; | |
19 import javax.xml.xpath.XPathConstants; | |
20 | |
21 import org.apache.log4j.Logger; | |
22 | |
23 import org.w3c.dom.Element; | |
24 import org.w3c.dom.NodeList; | |
25 | |
26 /** | |
27 * Represents a SAML assertion about a user. | |
28 */ | |
29 public class Assertion { | |
30 | |
31 private static Logger logger = Logger.getLogger(Assertion.class); | |
32 | |
33 private Element assertion; | |
34 private LinkedList<String> roles; | |
35 private String user_id; | |
36 private String name_id; | |
37 private String group_id; | |
38 private String group_name; | |
39 private Date notbefore; | |
40 private Date notonorafter; | |
41 | |
42 private static final String ATTR_CONT_USER_ID = | |
43 "urn:conterra:names:sdi-suite:policy:attribute:user-id"; | |
44 private static final String ATTR_CONT_GROUP_ID = | |
45 "urn:conterra:names:sdi-suite:policy:attribute:group-id"; | |
46 private static final String ATTR_CONT_GROUP_NAME = | |
47 "urn:conterra:names:sdi-suite:policy:attribute:group-name"; | |
48 private static final String ATTR_CONT_ROLE = | |
49 "urn:conterra:names:sdi-suite:policy:attribute:role"; | |
50 | |
51 | |
52 public Assertion(Element assertion) { | |
53 this.assertion = assertion; | |
54 this.roles = new LinkedList<String>(); | |
55 this.parseCondition(); | |
56 this.parseAttributeStatement(); | |
57 } | |
58 | |
59 private void parseCondition() { | |
60 Element conditions = (Element)XPathUtils.xpathNode(this.assertion, | |
61 "saml:Conditions"); | |
62 if (conditions == null) { | |
63 logger.error("Cannot find Assertion conditions element"); | |
64 return; | |
65 } | |
66 | |
67 this.notbefore = parseDateAttribute(conditions, "NotBefore"); | |
68 if (this.notbefore == null) { | |
69 logger.warn("Could not extract NotBefore date."); | |
70 } | |
71 this.notonorafter = parseDateAttribute(conditions, "NotOnOrAfter"); | |
72 if (this.notonorafter == null) { | |
73 logger.warn("Could not extract NotOnOrAfter date."); | |
74 } | |
75 } | |
76 | |
77 private Date parseDateAttribute(Element element, String name) { | |
78 SimpleDateFormat dateformat = new SimpleDateFormat(); | |
79 // format should be "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" but that's | |
80 // only available in java 7+. However, parsing without the | |
81 // time-zone yields Date values in the local time-zone, | |
82 // therefore we need to convert to GMT ourselves. | |
83 dateformat.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); | |
84 | |
85 String value = element.getAttribute(name); | |
86 try { | |
87 return toGMT(dateformat.parse(value)); | |
88 } | |
89 catch(ParseException e) { | |
90 logger.error("Cannot parse Condition attribute " | |
91 + name + " with value " + value | |
92 + " (" + e.getLocalizedMessage() + ")"); | |
93 } | |
94 return null; | |
95 } | |
96 | |
97 private Date toGMT(Date date) { | |
98 Calendar cal = Calendar.getInstance(); | |
99 cal.setTime(date); | |
100 cal.set(Calendar.ZONE_OFFSET, 0); | |
101 cal.set(Calendar.DST_OFFSET, 0); | |
102 return cal.getTime(); | |
103 } | |
104 | |
105 private void parseAttributeStatement() { | |
106 Element attrstatement = (Element)XPathUtils.xpathNode(this.assertion, | |
107 "saml:AttributeStatement"); | |
108 if (attrstatement == null) { | |
109 logger.error("Cannot find Assertion AttributeStatement element"); | |
110 return; | |
111 } | |
112 | |
113 this.name_id = XPathUtils.xpathString(attrstatement, | |
114 "saml:Subject" | |
115 + "/saml:NameIdentifier"); | |
116 | |
117 this.user_id = getAttrValue(attrstatement, ATTR_CONT_USER_ID); | |
118 this.group_id = getAttrValue(attrstatement, ATTR_CONT_GROUP_ID); | |
119 this.group_name = getAttrValue(attrstatement, ATTR_CONT_GROUP_NAME); | |
120 this.roles = getAttrValues(attrstatement, ATTR_CONT_ROLE); | |
121 } | |
122 | |
123 static Object getAttrObject(Element attrs, String name, QName returnType) { | |
124 return XPathUtils.xpath(attrs, | |
125 "saml:Attribute[@AttributeName='" + name + "']" | |
126 + "/saml:AttributeValue", | |
127 returnType); | |
128 } | |
129 | |
130 static String getAttrValue(Element attrs, String name) { | |
131 return (String)getAttrObject(attrs, name, XPathConstants.STRING); | |
132 } | |
133 | |
134 static LinkedList<String> getAttrValues(Element attrs, String name) { | |
135 LinkedList<String> strings = new LinkedList<String>(); | |
136 NodeList nodes = (NodeList)getAttrObject(attrs, name, | |
137 XPathConstants.NODESET); | |
138 for (int i = 0; i < nodes.getLength(); i++) { | |
139 strings.add(nodes.item(i).getTextContent()); | |
140 } | |
141 | |
142 return strings; | |
143 } | |
144 | |
145 public List<String> getRoles() { | |
146 return this.roles; | |
147 } | |
148 | |
149 public String getUserID() { | |
150 return this.user_id; | |
151 } | |
152 | |
153 public String getNameID() { | |
154 return this.name_id; | |
155 } | |
156 | |
157 public String getGroupID() { | |
158 return this.group_id; | |
159 } | |
160 | |
161 public String getGroupName() { | |
162 return this.group_name; | |
163 } | |
164 | |
165 public Date getFrom() { | |
166 return this.notbefore; | |
167 } | |
168 | |
169 public Date getUntil() { | |
170 return this.notonorafter; | |
171 } | |
172 | |
173 /** | |
174 * Returns whether the ticket to which the assertion belongs is | |
175 * valid at the time the method is called. The method returns true, | |
176 * if both dates (notbefore and notonorafter) have been determined | |
177 * successfully and the current date/time is between both. | |
178 * @return Whether the ticket is valid now. | |
179 */ | |
180 public boolean isValidNow() { | |
181 Date now = new Date(); | |
182 return (this.notbefore != null && this.notonorafter != null | |
183 && now.after(this.notbefore) | |
184 && !this.notonorafter.before(now)); | |
185 } | |
186 } | |
187 // vim: set fileencoding=utf-8 ts=4 sw=4 et si tw=80: |