diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java
index 565d0ec..02454e8 100644
--- a/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java
+++ b/cas-client-core/src/main/java/org/jasig/cas/client/jaas/CasLoginModule.java
@@ -34,6 +34,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
@@ -84,10 +85,8 @@ import org.jasig.cas.client.validation.TicketValidator;
* for JAAS providers that attempt to periodically reauthenticate to renew principal.
* Since CAS tickets are one-time-use, a cached assertion must be provided on reauthentication.
*
cacheTimeout (optional) - Assertion cache timeout in minutes.
- * cacheTimeoutUnits (optional) - Assertion cache timeout units.
- * MUST be one of following:
- * Calendar.HOUR(10), Calendar.MINUTE(12), Calendar.SECOND(13), Calendar.MILLISECOND(14).
- * Default unit is minutes.
+ * cacheTimeoutUnit (optional) - Assertion cache timeout unit. Must be one of {@link TimeUnit} enumeration
+ * names, e.g. DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS. Default unit is MINUTES.
*
*
*
@@ -139,7 +138,7 @@ public class CasLoginModule implements LoginModule {
public static final int DEFAULT_CACHE_TIMEOUT = 480;
/** Default assertion cache timeout unit is minutes. */
- public static final int DEFAULT_CACHE_TIMEOUT_UNITS = Calendar.MINUTE;
+ public static final TimeUnit DEFAULT_CACHE_TIMEOUT_UNIT = TimeUnit.MINUTES;
/**
* Stores mapping of ticket to assertion to support JAAS providers that
@@ -191,16 +190,8 @@ public class CasLoginModule implements LoginModule {
/** Assertion cache timeout in minutes */
protected int cacheTimeout = DEFAULT_CACHE_TIMEOUT;
- /**
- * Units of cache timeout. Must be one of following {@link Calendar} time unit constants:
- *
- * - {@link Calendar#HOUR}
- * - {@link Calendar#MINUTE}
- * - {@link Calendar#SECOND}
- * - {@link Calendar#MILLISECOND}
- *
- */
- protected int cacheTimeoutUnits = DEFAULT_CACHE_TIMEOUT_UNITS;
+ /** Units of cache timeout. */
+ protected TimeUnit cacheTimeoutUnit = DEFAULT_CACHE_TIMEOUT_UNIT;
/**
* Initializes the CAS login module.
@@ -222,17 +213,20 @@ public class CasLoginModule implements LoginModule {
* which by default are single use, reauthentication fails. Assertion caching addresses this
* behavior.
* cacheTimeout (optional) - assertion cache timeout in minutes.
- * cacheTimeoutUnits (optional) - Assertion cache timeout units.
- * MUST be one of following:
- * Calendar.HOUR(10), Calendar.MINUTE(12), Calendar.SECOND(13), Calendar.MILLISECOND(14).
- * Default unit is minutes.
+ * cacheTimeoutUnit (optional) - Assertion cache timeout unit. Must be one of {@link TimeUnit} enumeration
+ * names, e.g. DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS. Default unit is MINUTES.
*
*/
- public final void initialize(final Subject subject, final CallbackHandler handler, final Map state, final Map options) {
+ public final void initialize(
+ final Subject subject,
+ final CallbackHandler handler,
+ final Map state,
+ final Map options) {
+
this.assertion = null;
this.callbackHandler = handler;
this.subject = subject;
- this.sharedState = (Map) state;
+ this.sharedState = (Map) state;
this.sharedState = new HashMap(state);
String ticketValidatorClass = null;
@@ -268,15 +262,9 @@ public class CasLoginModule implements LoginModule {
} else if ("cacheTimeout".equals(key)) {
this.cacheTimeout = Integer.parseInt((String) options.get(key));
log.debug("Set cacheTimeout=" + this.cacheTimeout);
- } else if ("cacheTimeoutUnits".equals(key)) {
- final int units = Integer.parseInt((String) options.get(key));
- if (units == Calendar.HOUR || units == Calendar.MINUTE ||
- units == Calendar.SECOND || units == Calendar.MILLISECOND) {
- this.cacheTimeoutUnits = units;
- log.debug("Set cacheTimeoutUnits=" + this.cacheTimeoutUnits);
- } else {
- throw new IllegalArgumentException("Invalid time unit constant " + units);
- }
+ } else if ("cacheTimeoutUnit".equals(key)) {
+ this.cacheTimeoutUnit = Enum.valueOf(TimeUnit.class, (String) options.get(key));
+ log.debug("Set cacheTimeoutUnit=" + this.cacheTimeoutUnit);
}
}
@@ -325,20 +313,19 @@ public class CasLoginModule implements LoginModule {
throw (LoginException) new LoginException("IO exception in callback handler: " + e).initCause(e);
} catch (final UnsupportedCallbackException e) {
log.info("Login failed due to unsupported callback: " + e);
- throw (LoginException) new LoginException("Callback handler does not support PasswordCallback and TextInputCallback.").initCause(e);
+ throw (LoginException) new LoginException(
+ "Callback handler does not support PasswordCallback and TextInputCallback.").initCause(e);
}
if (ticketCallback.getPassword() != null) {
this.ticket = new TicketCredential(new String(ticketCallback.getPassword()));
- final String service = CommonUtils.isNotBlank(serviceCallback.getName()) ? serviceCallback.getName() : this.service;
+ final String service = CommonUtils.isNotBlank(
+ serviceCallback.getName()) ? serviceCallback.getName() : this.service;
if (this.cacheAssertions) {
- // Multiple threads may be accessing the static cache concurrently
- synchronized (ASSERTION_CACHE) {
- if (ASSERTION_CACHE.get(ticket) != null) {
- log.debug("Assertion found in cache.");
- this.assertion = ASSERTION_CACHE.get(ticket);
- }
+ this.assertion = ASSERTION_CACHE.get(ticket);
+ if (this.assertion != null) {
+ log.debug("Assertion found in cache.");
}
}
@@ -346,7 +333,8 @@ public class CasLoginModule implements LoginModule {
log.debug("CAS assertion is null; ticket validation required.");
if (CommonUtils.isBlank(service)) {
log.info("Login failed because required CAS service parameter not provided.");
- throw new LoginException("Neither login module nor callback handler provided required service parameter.");
+ throw new LoginException(
+ "Neither login module nor callback handler provided required service parameter.");
}
try {
if (log.isDebugEnabled()) {
@@ -413,7 +401,8 @@ public class CasLoginModule implements LoginModule {
throw new LoginException("Ticket credential not found.");
}
- final AssertionPrincipal casPrincipal = new AssertionPrincipal(this.assertion.getPrincipal().getName(), this.assertion);
+ final AssertionPrincipal casPrincipal = new AssertionPrincipal(
+ this.assertion.getPrincipal().getName(), this.assertion);
this.subject.getPrincipals().add(casPrincipal);
// Add group containing principal as sole member
@@ -458,10 +447,7 @@ public class CasLoginModule implements LoginModule {
if (log.isDebugEnabled()) {
log.debug("Caching assertion for principal " + this.assertion.getPrincipal());
}
- // Multiple threads may be accessing the static cache concurrently
- synchronized (ASSERTION_CACHE) {
- ASSERTION_CACHE.put(this.ticket, this.assertion);
- }
+ ASSERTION_CACHE.put(this.ticket, this.assertion);
}
} else {
// Login must have failed if there is no assertion defined
@@ -522,10 +508,12 @@ public class CasLoginModule implements LoginModule {
* @return Ticket validator with properties set.
*/
private TicketValidator createTicketValidator(final String className, final Map propertyMap) {
- CommonUtils.assertTrue(propertyMap.containsKey("casServerUrlPrefix"), "Required property casServerUrlPrefix not found.");
+ CommonUtils.assertTrue(
+ propertyMap.containsKey("casServerUrlPrefix"), "Required property casServerUrlPrefix not found.");
final Class validatorClass = ReflectUtils.loadClass(className);
- final TicketValidator validator = ReflectUtils.newInstance(validatorClass, propertyMap.get("casServerUrlPrefix"));
+ final TicketValidator validator = ReflectUtils.newInstance(
+ validatorClass, propertyMap.get("casServerUrlPrefix"));
try {
final BeanInfo info = Introspector.getBeanInfo(validatorClass);
@@ -570,7 +558,8 @@ public class CasLoginModule implements LoginModule {
} else if (long.class.equals(pd.getPropertyType())) {
return new Long(value);
} else {
- throw new IllegalArgumentException("No conversion strategy exists for property " + pd.getName() + " of type " + pd.getPropertyType());
+ throw new IllegalArgumentException(
+ "No conversion strategy exists for property " + pd.getName() + " of type " + pd.getPropertyType());
}
}
@@ -598,21 +587,18 @@ public class CasLoginModule implements LoginModule {
if (log.isDebugEnabled()) {
log.debug("Cleaning assertion cache of size " + ASSERTION_CACHE.size());
}
- // Multiple threads may be accessing the static cache concurrently
- synchronized (ASSERTION_CACHE) {
- final Iterator> iter = ASSERTION_CACHE.entrySet().iterator();
- final Calendar cutoff = Calendar.getInstance();
- cutoff.add(this.cacheTimeoutUnits, -this.cacheTimeout);
- while (iter.hasNext()) {
- final Assertion assertion = iter.next().getValue();
- final Calendar created = Calendar.getInstance();
- created.setTime(assertion.getValidFromDate());
- if (created.before(cutoff)) {
- if (log.isDebugEnabled()) {
- log.debug("Removing expired assertion for principal " + assertion.getPrincipal());
- }
- iter.remove();
+ final Iterator> iter = ASSERTION_CACHE.entrySet().iterator();
+ final Calendar cutoff = Calendar.getInstance();
+ cutoff.setTimeInMillis(System.currentTimeMillis() - this.cacheTimeoutUnit.toMillis(this.cacheTimeout));
+ while (iter.hasNext()) {
+ final Assertion assertion = iter.next().getValue();
+ final Calendar created = Calendar.getInstance();
+ created.setTime(assertion.getValidFromDate());
+ if (created.before(cutoff)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Removing expired assertion for principal " + assertion.getPrincipal());
}
+ iter.remove();
}
}
}
diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java
index 1f84d23..ede32b0 100644
--- a/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java
+++ b/cas-client-core/src/test/java/org/jasig/cas/client/jaas/CasLoginModuleTests.java
@@ -208,8 +208,8 @@ public class CasLoginModuleTests {
final String FAILURE_RESPONSE = "Ticket ST-12345-ABCDEFGHIJKLMNOPQRSTUVWXYZ-hosta not recognized";
options.put("cacheAssertions", "true");
- // Cache timeout is 1 second (Calendar.SECOND=13)
- options.put("cacheTimeoutUnits", "13");
+ // Cache timeout is 1 second
+ options.put("cacheTimeoutUnit", "SECONDS");
options.put("cacheTimeout", "1");
server.content = SUCCESS_RESPONSE.getBytes(server.encoding);