1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.dom.message.token;
21
22 import java.time.Instant;
23 import java.time.ZoneOffset;
24 import java.time.ZonedDateTime;
25 import java.time.format.DateTimeFormatter;
26 import java.time.format.DateTimeParseException;
27 import java.time.temporal.ChronoField;
28
29 import org.apache.wss4j.common.bsp.BSPEnforcer;
30 import org.apache.wss4j.common.bsp.BSPRule;
31 import org.apache.wss4j.common.ext.WSSecurityException;
32 import org.apache.wss4j.common.util.DOM2Writer;
33 import org.apache.wss4j.common.util.DateUtil;
34 import org.apache.wss4j.common.util.WSCurrentTimeSource;
35 import org.apache.wss4j.common.util.WSTimeSource;
36 import org.apache.wss4j.common.util.XMLUtils;
37 import org.apache.wss4j.dom.WSConstants;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.Text;
42
43
44
45
46
47 public class Timestamp {
48
49 private Element element;
50 private Instant created;
51 private Instant expires;
52 private String createdString;
53
54
55
56
57
58
59
60
61
62 public Timestamp(Element timestampElement, BSPEnforcer bspEnforcer) throws WSSecurityException {
63
64 element = timestampElement;
65
66 String strExpires = null;
67
68 for (Node currentChild = element.getFirstChild();
69 currentChild != null;
70 currentChild = currentChild.getNextSibling()
71 ) {
72 if (Node.ELEMENT_NODE == currentChild.getNodeType()) {
73 Element currentChildElement = (Element) currentChild;
74 if (WSConstants.CREATED_LN.equals(currentChild.getLocalName())
75 && WSConstants.WSU_NS.equals(currentChild.getNamespaceURI())) {
76 if (createdString == null) {
77 String valueType = currentChildElement.getAttributeNS(null, "ValueType");
78 if (valueType != null && valueType.length() != 0) {
79
80 bspEnforcer.handleBSPRule(BSPRule.R3225);
81 }
82 createdString = ((Text)currentChildElement.getFirstChild()).getData();
83 } else {
84
85 bspEnforcer.handleBSPRule(BSPRule.R3203);
86 }
87 } else if (WSConstants.EXPIRES_LN.equals(currentChild.getLocalName())
88 && WSConstants.WSU_NS.equals(currentChild.getNamespaceURI())) {
89 if (createdString == null) {
90
91 bspEnforcer.handleBSPRule(BSPRule.R3221);
92 }
93 if (strExpires != null) {
94
95 bspEnforcer.handleBSPRule(BSPRule.R3224);
96 } else {
97 String valueType = currentChildElement.getAttributeNS(null, "ValueType");
98 if (valueType != null && valueType.length() != 0) {
99
100 bspEnforcer.handleBSPRule(BSPRule.R3226);
101 }
102 strExpires = ((Text)currentChildElement.getFirstChild()).getData();
103 }
104 } else {
105 bspEnforcer.handleBSPRule(BSPRule.R3222);
106 }
107 }
108 }
109
110
111 if (createdString == null) {
112 bspEnforcer.handleBSPRule(BSPRule.R3203);
113 }
114
115
116 if (createdString != null) {
117 try {
118 ZonedDateTime createdDateTime = ZonedDateTime.parse(createdString);
119 if (!ZoneOffset.UTC.equals(createdDateTime.getZone())) {
120 bspEnforcer.handleBSPRule(BSPRule.R3217);
121 }
122
123 created = createdDateTime.toInstant();
124 } catch (DateTimeParseException e) {
125 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
126 }
127
128 if (created.getNano() > 0) {
129 int milliseconds = created.get(ChronoField.MILLI_OF_SECOND);
130 if (milliseconds * 1000000 != created.getNano()) {
131 bspEnforcer.handleBSPRule(BSPRule.R3220);
132 }
133 }
134 }
135
136 if (strExpires != null) {
137 try {
138 ZonedDateTime expiresDateTime = ZonedDateTime.parse(strExpires);
139 if (!ZoneOffset.UTC.equals(expiresDateTime.getZone())) {
140 bspEnforcer.handleBSPRule(BSPRule.R3223);
141 }
142
143 expires = expiresDateTime.toInstant();
144 } catch (DateTimeParseException e) {
145 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
146 }
147
148 if (expires.getNano() > 0) {
149 int milliseconds = expires.get(ChronoField.MILLI_OF_SECOND);
150 if (milliseconds * 1000000 != expires.getNano()) {
151 bspEnforcer.handleBSPRule(BSPRule.R3229);
152 }
153 }
154 }
155 }
156
157
158
159
160
161
162
163
164
165 public Timestamp(boolean milliseconds, Document doc, int ttl) {
166 this(milliseconds, doc, new WSCurrentTimeSource(), ttl);
167 }
168
169
170
171
172
173
174
175
176 public Timestamp(boolean milliseconds, Document doc, WSTimeSource timeSource, int ttl) {
177
178 element =
179 doc.createElementNS(
180 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
181 );
182
183 Element elementCreated =
184 doc.createElementNS(
185 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
186 );
187 created = timeSource.now();
188
189 DateTimeFormatter formatter = DateUtil.getDateTimeFormatter(milliseconds);
190 elementCreated.appendChild(doc.createTextNode(created.atZone(ZoneOffset.UTC).format(formatter)));
191
192 element.appendChild(elementCreated);
193 if (ttl != 0) {
194 expires = created.plusSeconds(ttl);
195
196 Element elementExpires =
197 doc.createElementNS(
198 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
199 );
200 elementExpires.appendChild(doc.createTextNode(expires.atZone(ZoneOffset.UTC).format(formatter)));
201 element.appendChild(elementExpires);
202 }
203 }
204
205
206
207
208
209 public void addWSUNamespace() {
210 element.setAttributeNS(XMLUtils.XMLNS_NS, "xmlns:" + WSConstants.WSU_PREFIX, WSConstants.WSU_NS);
211 }
212
213
214
215
216
217
218 public Element getElement() {
219 return element;
220 }
221
222
223
224
225
226
227 public String toString() {
228 return DOM2Writer.nodeToString(element);
229 }
230
231
232
233
234
235
236 public Instant getCreated() {
237 return created;
238 }
239
240
241
242
243
244
245 public String getCreatedString() {
246 return createdString;
247 }
248
249
250
251
252
253
254 public Instant getExpires() {
255 return expires;
256 }
257
258
259
260
261
262 public void setID(String id) {
263 element.setAttributeNS(WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":Id", id);
264 }
265
266
267
268
269 public String getID() {
270 return element.getAttributeNS(WSConstants.WSU_NS, "Id");
271 }
272
273
274
275
276
277 public boolean isExpired() {
278 if (expires != null) {
279 Instant rightNow = Instant.now();
280 return expires.isBefore(rightNow);
281 }
282 return false;
283 }
284
285
286
287
288
289
290
291
292
293
294 public boolean verifyCreated(
295 int timeToLive,
296 int futureTimeToLive
297 ) {
298 return DateUtil.verifyCreated(created, timeToLive, futureTimeToLive);
299 }
300
301
302 @Override
303 public int hashCode() {
304 int result = 17;
305 if (created != null) {
306 result = 31 * result + created.hashCode();
307 }
308 if (expires != null) {
309 result = 31 * result + expires.hashCode();
310 }
311 return result;
312 }
313
314 @Override
315 public boolean equals(Object object) {
316 if (!(object instanceof Timestamp)) {
317 return false;
318 }
319 Timestamp timestamp = (Timestamp)object;
320 if (!compare(timestamp.getCreated(), getCreated())) {
321 return false;
322 }
323 return compare(timestamp.getExpires(), getExpires());
324 }
325
326 private boolean compare(Instant item1, Instant item2) {
327 if (item1 == null && item2 != null) {
328 return false;
329 } else if (item1 != null && !item1.equals(item2)) {
330 return false;
331 }
332 return true;
333 }
334
335 }