1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.security.xwss.callback;
18
19 import java.text.ParseException;
20 import java.text.SimpleDateFormat;
21 import java.util.Calendar;
22 import java.util.Date;
23 import java.util.GregorianCalendar;
24
25 import com.sun.xml.wss.impl.callback.TimestampValidationCallback;
26
27
28
29
30
31
32
33
34 public class DefaultTimestampValidator implements TimestampValidationCallback.TimestampValidator {
35
36 public void validate(TimestampValidationCallback.Request request)
37 throws TimestampValidationCallback.TimestampValidationException {
38 if (request instanceof TimestampValidationCallback.UTCTimestampRequest) {
39 TimestampValidationCallback.UTCTimestampRequest utcRequest =
40 (TimestampValidationCallback.UTCTimestampRequest) request;
41 Date created = parseDate(utcRequest.getCreated());
42
43 validateCreationTime(created, utcRequest.getMaxClockSkew(), utcRequest.getTimestampFreshnessLimit());
44
45 if (utcRequest.getExpired() != null) {
46 Date expired = parseDate(utcRequest.getExpired());
47 validateExpirationTime(expired, utcRequest.getMaxClockSkew());
48 }
49 }
50 else {
51 throw new TimestampValidationCallback.TimestampValidationException("Unsupport request: [" + request + "]");
52 }
53 }
54
55 private Date getFreshnessAndSkewAdjustedDate(long maxClockSkew, long timestampFreshnessLimit) {
56 Calendar c = new GregorianCalendar();
57 long offset = c.get(Calendar.ZONE_OFFSET);
58 if (c.getTimeZone().inDaylightTime(c.getTime())) {
59 offset += c.getTimeZone().getDSTSavings();
60 }
61 long beforeTime = c.getTimeInMillis();
62 long currentTime = beforeTime - offset;
63
64 long adjustedTime = currentTime - maxClockSkew - timestampFreshnessLimit;
65 c.setTimeInMillis(adjustedTime);
66
67 return c.getTime();
68 }
69
70 private Date getGMTDateWithSkewAdjusted(Calendar calendar, long maxClockSkew, boolean addSkew) {
71 long offset = calendar.get(Calendar.ZONE_OFFSET);
72 if (calendar.getTimeZone().inDaylightTime(calendar.getTime())) {
73 offset += calendar.getTimeZone().getDSTSavings();
74 }
75 long beforeTime = calendar.getTimeInMillis();
76 long currentTime = beforeTime - offset;
77
78 if (addSkew) {
79 currentTime = currentTime + maxClockSkew;
80 }
81 else {
82 currentTime = currentTime - maxClockSkew;
83 }
84
85 calendar.setTimeInMillis(currentTime);
86 return calendar.getTime();
87 }
88
89 private Date parseDate(String date) throws TimestampValidationCallback.TimestampValidationException {
90 SimpleDateFormat calendarFormatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
91 SimpleDateFormat calendarFormatter2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSS'Z'");
92
93 try {
94 try {
95 return calendarFormatter1.parse(date);
96 }
97 catch (ParseException ignored) {
98 return calendarFormatter2.parse(date);
99 }
100 }
101 catch (ParseException ex) {
102 throw new TimestampValidationCallback.TimestampValidationException("Could not parse request date: " + date,
103 ex);
104 }
105 }
106
107 private void validateCreationTime(Date created, long maxClockSkew, long timestampFreshnessLimit)
108 throws TimestampValidationCallback.TimestampValidationException {
109 Date current = getFreshnessAndSkewAdjustedDate(maxClockSkew, timestampFreshnessLimit);
110
111 if (created.before(current)) {
112 throw new TimestampValidationCallback.TimestampValidationException(
113 "The creation time is older than currenttime - timestamp-freshness-limit - max-clock-skew");
114 }
115
116 Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(), maxClockSkew, true);
117 if (currentTime.before(created)) {
118 throw new TimestampValidationCallback.TimestampValidationException(
119 "The creation time is ahead of the current time.");
120 }
121 }
122
123 private void validateExpirationTime(Date expires, long maxClockSkew)
124 throws TimestampValidationCallback.TimestampValidationException {
125 Date currentTime = getGMTDateWithSkewAdjusted(new GregorianCalendar(), maxClockSkew, false);
126 if (expires.before(currentTime)) {
127 throw new TimestampValidationCallback.TimestampValidationException(
128 "The current time is ahead of the expiration time in Timestamp");
129 }
130 }
131
132 }