1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.message.token;
21
22 import org.apache.ws.security.WSConstants;
23 import org.apache.ws.security.WSSecurityException;
24 import org.apache.ws.security.util.DOM2Writer;
25 import org.apache.ws.security.util.WSSecurityUtil;
26 import org.apache.ws.security.util.XmlSchemaDateFormat;
27 import org.w3c.dom.Document;
28 import org.w3c.dom.Element;
29 import org.w3c.dom.Node;
30 import org.w3c.dom.Text;
31
32 import java.text.ParseException;
33 import java.text.SimpleDateFormat;
34 import java.text.DateFormat;
35 import java.util.ArrayList;
36 import java.util.Date;
37 import java.util.List;
38 import java.util.TimeZone;
39
40
41
42
43
44
45
46 public class Timestamp {
47
48 private static final org.apache.commons.logging.Log LOG =
49 org.apache.commons.logging.LogFactory.getLog(Timestamp.class);
50
51 protected Element element = null;
52 protected List<Element> customElements = null;
53 protected Date createdDate;
54 protected Date expiresDate;
55
56
57
58
59
60
61
62
63 public Timestamp(Element timestampElement) throws WSSecurityException {
64 this(timestampElement, true);
65 }
66
67
68
69
70
71
72
73
74
75 public Timestamp(Element timestampElement, boolean bspCompliant) throws WSSecurityException {
76
77 element = timestampElement;
78 customElements = new ArrayList<Element>();
79
80 String strCreated = null;
81 String strExpires = null;
82
83 for (Node currentChild = element.getFirstChild();
84 currentChild != null;
85 currentChild = currentChild.getNextSibling()
86 ) {
87 if (Node.ELEMENT_NODE == currentChild.getNodeType()) {
88 Element currentChildElement = (Element) currentChild;
89 if (WSConstants.CREATED_LN.equals(currentChild.getLocalName()) &&
90 WSConstants.WSU_NS.equals(currentChild.getNamespaceURI())) {
91 if (strCreated == null) {
92 String valueType = currentChildElement.getAttribute("ValueType");
93 if (bspCompliant && valueType != null && !"".equals(valueType)) {
94
95 throw new WSSecurityException(
96 WSSecurityException.INVALID_SECURITY, "invalidTimestamp"
97 );
98 }
99 strCreated = ((Text)currentChildElement.getFirstChild()).getData();
100 } else {
101
102 throw new WSSecurityException(
103 WSSecurityException.INVALID_SECURITY, "invalidTimestamp"
104 );
105 }
106 } else if (WSConstants.EXPIRES_LN.equals(currentChild.getLocalName()) &&
107 WSConstants.WSU_NS.equals(currentChild.getNamespaceURI())) {
108 if (strExpires != null || (bspCompliant && strCreated == null)) {
109
110
111
112
113 throw new WSSecurityException(
114 WSSecurityException.INVALID_SECURITY, "invalidTimestamp"
115 );
116 } else {
117 String valueType = currentChildElement.getAttribute("ValueType");
118 if (bspCompliant && valueType != null && !"".equals(valueType)) {
119
120 throw new WSSecurityException(
121 WSSecurityException.INVALID_SECURITY, "invalidTimestamp"
122 );
123 }
124 strExpires = ((Text)currentChildElement.getFirstChild()).getData();
125 }
126 } else {
127 if (bspCompliant) {
128 throw new WSSecurityException(
129 WSSecurityException.INVALID_SECURITY, "invalidTimestamp"
130 );
131 }
132 customElements.add(currentChildElement);
133 }
134 }
135 }
136
137
138 if (bspCompliant && strCreated == null) {
139 throw new WSSecurityException(
140 WSSecurityException.INVALID_SECURITY, "invalidTimestamp"
141 );
142 }
143
144
145 DateFormat zulu = new XmlSchemaDateFormat();
146 if (bspCompliant) {
147 zulu.setLenient(false);
148 }
149 try {
150 if (LOG.isDebugEnabled()) {
151 LOG.debug("Current time: " + zulu.format(new Date()));
152 }
153 if (strCreated != null) {
154 createdDate = zulu.parse(strCreated);
155 if (LOG.isDebugEnabled()) {
156 LOG.debug("Timestamp created: " + zulu.format(createdDate));
157 }
158 }
159 if (strExpires != null) {
160 expiresDate = zulu.parse(strExpires);
161 if (LOG.isDebugEnabled()) {
162 LOG.debug("Timestamp expires: " + zulu.format(expiresDate));
163 }
164 }
165 } catch (ParseException e) {
166 throw new WSSecurityException(
167 WSSecurityException.INVALID_SECURITY, "invalidTimestamp", null, e
168 );
169 }
170 }
171
172
173
174
175
176
177
178
179
180 public Timestamp(boolean milliseconds, Document doc, int ttl) {
181
182 customElements = new ArrayList<Element>();
183 element =
184 doc.createElementNS(
185 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
186 );
187
188 DateFormat zulu = null;
189 if (milliseconds) {
190 zulu = new XmlSchemaDateFormat();
191 } else {
192 zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
193 zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
194 }
195 Element elementCreated =
196 doc.createElementNS(
197 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
198 );
199 createdDate = new Date();
200 elementCreated.appendChild(doc.createTextNode(zulu.format(createdDate)));
201 element.appendChild(elementCreated);
202 if (ttl != 0) {
203 expiresDate = new Date();
204 expiresDate.setTime(createdDate.getTime() + ((long)ttl * 1000L));
205
206 Element elementExpires =
207 doc.createElementNS(
208 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
209 );
210 elementExpires.appendChild(doc.createTextNode(zulu.format(expiresDate)));
211 element.appendChild(elementExpires);
212 }
213 }
214
215
216
217
218
219 public void addWSUNamespace() {
220 WSSecurityUtil.setNamespace(element, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
221 }
222
223
224
225
226
227
228 public Element getElement() {
229 return element;
230 }
231
232
233
234
235
236
237 public String toString() {
238 return DOM2Writer.nodeToString((Node) element);
239 }
240
241
242
243
244
245
246 public Date getCreated() {
247 return createdDate;
248 }
249
250
251
252
253
254
255 public Date getExpires() {
256 return expiresDate;
257 }
258
259
260
261
262 public void addCustomElement(Document doc, Element customElement) {
263 customElements.add(customElement);
264 element.appendChild(customElement);
265 }
266
267
268
269
270
271
272 public List<Element> getCustomElements() {
273 return customElements;
274 }
275
276
277
278
279
280 public void setID(String id) {
281 element.setAttributeNS(WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":Id", id);
282 }
283
284
285
286
287 public String getID() {
288 return element.getAttributeNS(WSConstants.WSU_NS, "Id");
289 }
290
291
292
293
294
295 public boolean isExpired() {
296 if (expiresDate != null) {
297 Date rightNow = new Date();
298 return expiresDate.before(rightNow);
299 }
300 return false;
301 }
302
303
304
305
306
307
308
309
310
311
312 public boolean verifyCreated(
313 int timeToLive,
314 int futureTimeToLive
315 ) {
316 Date validCreation = new Date();
317 long currentTime = validCreation.getTime();
318 if (futureTimeToLive > 0) {
319 validCreation.setTime(currentTime + ((long)futureTimeToLive * 1000L));
320 }
321
322 if (createdDate != null && createdDate.after(validCreation)) {
323 if (LOG.isDebugEnabled()) {
324 LOG.debug("Validation of Timestamp: The message was created in the future!");
325 }
326 return false;
327 }
328
329
330 currentTime -= ((long)timeToLive * 1000L);
331 validCreation.setTime(currentTime);
332
333
334 if (createdDate != null && createdDate.before(validCreation)) {
335 if (LOG.isDebugEnabled()) {
336 LOG.debug("Validation of Timestamp: The message was created too long ago");
337 }
338 return false;
339 }
340
341 if (LOG.isDebugEnabled()) {
342 LOG.debug("Validation of Timestamp: Everything is ok");
343 }
344 return true;
345 }
346
347
348 @Override
349 public int hashCode() {
350 int result = 17;
351 if (createdDate != null) {
352 result = 31 * result + createdDate.hashCode();
353 }
354 if (expiresDate != null) {
355 result = 31 * result + expiresDate.hashCode();
356 }
357 return result;
358 }
359
360 @Override
361 public boolean equals(Object object) {
362 if (!(object instanceof Timestamp)) {
363 return false;
364 }
365 Timestamp timestamp = (Timestamp)object;
366 if (!compare(timestamp.getCreated(), getCreated())) {
367 return false;
368 }
369 if (!compare(timestamp.getExpires(), getExpires())) {
370 return false;
371 }
372 return true;
373 }
374
375 private boolean compare(Date item1, Date item2) {
376 if (item1 == null && item2 != null) {
377 return false;
378 } else if (item1 != null && !item1.equals(item2)) {
379 return false;
380 }
381 return true;
382 }
383
384 }