1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.security.oauth.provider.nonce;
18
19 import java.util.Iterator;
20 import java.util.TreeSet;
21
22 import org.springframework.security.authentication.CredentialsExpiredException;
23 import org.springframework.security.oauth.provider.ConsumerDetails;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class InMemoryNonceServices implements OAuthNonceServices {
44
45
46
47
48 static final TreeSet<NonceEntry> NONCES = new TreeSet<NonceEntry>();
49
50 private volatile long lastCleaned = 0;
51
52
53 private long validityWindowSeconds = 60 * 10;
54
55 public void validateNonce(ConsumerDetails consumerDetails, long timestamp, String nonce) {
56 if (System.currentTimeMillis() / 1000 - timestamp > getValidityWindowSeconds()) {
57 throw new CredentialsExpiredException("Expired timestamp.");
58 }
59
60 NonceEntry entry = new NonceEntry(consumerDetails.getConsumerKey(), timestamp, nonce);
61
62 synchronized (NONCES) {
63 if (NONCES.contains(entry)) {
64 throw new NonceAlreadyUsedException("Nonce already used: " + nonce);
65 }
66 else {
67 NONCES.add(entry);
68 }
69 cleanupNonces();
70 }
71 }
72
73 private void cleanupNonces() {
74 long now = System.currentTimeMillis() / 1000;
75
76
77
78 if (now - lastCleaned > 1) {
79 Iterator<NonceEntry> iterator = NONCES.iterator();
80 while (iterator.hasNext()) {
81
82
83 NonceEntry nextNonce = iterator.next();
84 long difference = now - nextNonce.timestamp;
85 if (difference > getValidityWindowSeconds()) {
86 iterator.remove();
87 }
88 else {
89 break;
90 }
91 }
92
93 lastCleaned = now;
94 }
95 }
96
97
98
99
100
101
102 public long getValidityWindowSeconds() {
103 return validityWindowSeconds;
104 }
105
106
107
108
109
110
111 public void setValidityWindowSeconds(long validityWindowSeconds) {
112 this.validityWindowSeconds = validityWindowSeconds;
113 }
114
115
116
117
118
119 static class NonceEntry implements Comparable<NonceEntry> {
120 private final String consumerKey;
121
122 private final long timestamp;
123
124 private final String nonce;
125
126 public NonceEntry(String consumerKey, long timestamp, String nonce) {
127 this.consumerKey = consumerKey;
128 this.timestamp = timestamp;
129 this.nonce = nonce;
130 }
131
132 @Override
133 public int hashCode() {
134 return consumerKey.hashCode() * nonce.hashCode() * Long.valueOf(timestamp).hashCode();
135 }
136
137 @Override
138 public boolean equals(Object obj) {
139 if (obj == null || !(obj instanceof NonceEntry)) {
140 return false;
141 }
142 NonceEntry arg = (NonceEntry) obj;
143 return timestamp == arg.timestamp && consumerKey.equals(arg.consumerKey) && nonce.equals(arg.nonce);
144 }
145
146 public int compareTo(NonceEntry o) {
147
148 if (timestamp < o.timestamp) {
149 return -1;
150 }
151 else if (timestamp == o.timestamp) {
152 int consumerKeyCompare = consumerKey.compareTo(o.consumerKey);
153 if (consumerKeyCompare == 0) {
154 return nonce.compareTo(o.nonce);
155 }
156 else {
157 return consumerKeyCompare;
158 }
159 }
160 else {
161 return 1;
162 }
163 }
164
165 @Override
166 public String toString() {
167 return timestamp + " " + consumerKey + " " + nonce;
168 }
169 }
170 }