1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.ws.security.cache;
21
22 import java.util.Collections;
23 import java.util.Date;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Set;
27
28 /**
29 * A simple in-memory HashSet based cache to prevent against replay attacks. The default TTL is 5 minutes
30 * and the max TTL is 60 minutes.
31 */
32 public class MemoryReplayCache implements ReplayCache {
33
34 public static final long DEFAULT_TTL = 60L * 5L;
35 public static final long MAX_TTL = DEFAULT_TTL * 12L;
36 private Set<ReplayCacheIdentifier> cache =
37 Collections.synchronizedSet(new HashSet<ReplayCacheIdentifier>());
38
39 /**
40 * Add the given identifier to the cache. It will be cached for a default amount of time.
41 * @param identifier The identifier to be added
42 */
43 public void add(String identifier) {
44 add(identifier, DEFAULT_TTL);
45 }
46
47 /**
48 * Add the given identifier to the cache to be cached for the given time
49 * @param identifier The identifier to be added
50 * @param timeToLive The length of time to cache the Identifier in seconds
51 */
52 public void add(String identifier, long timeToLive) {
53 if (identifier == null || "".equals(identifier)) {
54 return;
55 }
56 ReplayCacheIdentifier cacheIdentifier = new ReplayCacheIdentifier();
57 cacheIdentifier.setIdentifier(identifier);
58
59 long ttl = timeToLive;
60 if (ttl < 0 || ttl > MAX_TTL) {
61 ttl = DEFAULT_TTL;
62 }
63
64 Date expires = new Date();
65 long currentTime = expires.getTime();
66 expires.setTime(currentTime + (ttl * 1000L));
67 cacheIdentifier.setExpiry(expires);
68
69 cache.add(cacheIdentifier);
70 }
71
72 /**
73 * Return true if the given identifier is contained in the cache
74 * @param identifier The identifier to check
75 */
76 public boolean contains(String identifier) {
77 processTokenExpiry();
78
79 if (identifier != null && !"".equals(identifier)) {
80 ReplayCacheIdentifier cacheIdentifier = new ReplayCacheIdentifier();
81 cacheIdentifier.setIdentifier(identifier);
82 return cache.contains(cacheIdentifier);
83 }
84 return false;
85 }
86
87 protected void processTokenExpiry() {
88 Date current = new Date();
89 synchronized (cache) {
90 Iterator<ReplayCacheIdentifier> iterator = cache.iterator();
91 while (iterator.hasNext()) {
92 if (iterator.next().getExpiry().before(current)) {
93 iterator.remove();
94 }
95 }
96 }
97 }
98
99 private static class ReplayCacheIdentifier {
100
101 private String identifier;
102 private Date expires;
103
104 /**
105 * Set the (String) identifier
106 * @param identifier the (String) identifier
107 */
108 public void setIdentifier(String identifier) {
109 this.identifier = identifier;
110 }
111
112 /**
113 * Set when this identifier is to be removed from the cache
114 * @param expires when this identifier is to be removed from the cache
115 */
116 public void setExpiry(Date expires) {
117 this.expires = expires;
118 }
119
120 /**
121 * Get when this identifier is to be removed from the cache
122 * @return when this identifier is to be removed from the cache
123 */
124 public Date getExpiry() {
125 return expires;
126 }
127
128 @Override
129 public boolean equals(Object o) {
130 if (this == o) {
131 return true;
132 }
133 if (!(o instanceof ReplayCacheIdentifier)) {
134 return false;
135 }
136
137 ReplayCacheIdentifier replayCacheIdentifier = (ReplayCacheIdentifier)o;
138
139 if (identifier == null && replayCacheIdentifier.identifier != null) {
140 return false;
141 } else if (identifier != null && !identifier.equals(replayCacheIdentifier.identifier)) {
142 return false;
143 }
144
145 return true;
146 }
147
148 @Override
149 public int hashCode() {
150 return identifier != null ? identifier.hashCode() : 0;
151 }
152 }
153
154 }