From 2d6a02664dd1d6d70b5c51329955dde3fe5c0add Mon Sep 17 00:00:00 2001 From: brinn <brinn> Date: Wed, 23 Jan 2013 19:33:16 +0000 Subject: [PATCH] Make the CachingAuthenticationService available as a Spring bean and make it the default in the template service.properties. Change timeout and caching durations to support the formats fo DateTimeUtils.parseDurationString(). SVN: 28173 --- .../crowd/CrowdConfiguration.java | 18 ++- .../CachingAuthenticationConfiguration.java | 150 ++++++++++++++++++ .../file/CachingAuthenticationService.java | 59 +++++-- .../ldap/LDAPDirectoryConfiguration.java | 21 ++- ...uthenticationServiceInvalidLoginTests.java | 2 + ...hingAuthenticationServiceSuccessTests.java | 2 + common/source/java/genericCommonContext.xml | 24 ++- openbis/dist/server/service.properties | 26 ++- 8 files changed, 262 insertions(+), 40 deletions(-) create mode 100644 authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationConfiguration.java diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/crowd/CrowdConfiguration.java b/authentication/source/java/ch/systemsx/cisd/authentication/crowd/CrowdConfiguration.java index 6f0c159ffa7..97cdd3f2965 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/crowd/CrowdConfiguration.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/crowd/CrowdConfiguration.java @@ -18,6 +18,8 @@ package ch.systemsx.cisd.authentication.crowd; import org.apache.commons.lang.StringUtils; +import ch.systemsx.cisd.common.time.DateTimeUtils; + /** * A configuration object for Crowd. * @@ -80,9 +82,10 @@ public class CrowdConfiguration { return Integer.toString(port); } - + /** - * Sets the port (as String) that the Crowd service is running on. Only set if a positive integer. + * Sets the port (as String) that the Crowd service is running on. Only set if a positive + * integer. */ public void setPortStr(String portStr) { @@ -111,7 +114,7 @@ public class CrowdConfiguration return null; } } - + /** * Returns the application name that this application sends to the Crowd service. */ @@ -151,7 +154,7 @@ public class CrowdConfiguration } /** - * Returns the timeout, i.e. how long to wait for a result from Crowd (in ms). + * Returns the timeout, i.e. how long to wait for a result from Crowd (in ms). */ public int getTimeout() { @@ -167,7 +170,8 @@ public class CrowdConfiguration } /** - * Sets the timeout, i.e. how long to wait for a result from Crowd (as String, in s). + * Sets the timeout, i.e. how long to wait for a result from Crowd as a String in a format + * understood by {@link DateTimeUtils#parseDurationToMillis(String)}. */ public void setTimeoutStr(String timeoutStr) { @@ -175,14 +179,14 @@ public class CrowdConfiguration { try { - setTimeout(Integer.parseInt(timeoutStr) * 1000); + setTimeout((int) DateTimeUtils.parseDurationToMillis(timeoutStr)); } catch (NumberFormatException ex) { // Not set. } } } - + /** * Returns the timeout, i.e. how long to wait for a result from Crowd (as String, in s). */ diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationConfiguration.java b/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationConfiguration.java new file mode 100644 index 00000000000..0c0c03c18fa --- /dev/null +++ b/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationConfiguration.java @@ -0,0 +1,150 @@ +/* + * Copyright 2013 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.authentication.file; + +import org.apache.commons.lang.StringUtils; + +import ch.systemsx.cisd.authentication.IAuthenticationService; +import ch.systemsx.cisd.common.time.DateTimeUtils; + +/** + * A configuration object for the {@link CachingAuthenticationService}. + * + * @author Bernd Rinn + */ +public class CachingAuthenticationConfiguration +{ + private String passwordCacheFile; + + private IAuthenticationService delegate; + + private long cacheTime = CachingAuthenticationService.CACHE_TIME_MILLIS; + + private long cacheTimeNoRevalidation = + CachingAuthenticationService.CACHE_TIME_MILLIS_NO_REVALIDATION; + + /** + * Returns the path of the password cache file. + */ + public String getPasswordCacheFile() + { + return passwordCacheFile; + } + + /** + * Sets the path of the password cache file. + */ + public void setPasswordCacheFile(String passwordCacheFile) + { + this.passwordCacheFile = passwordCacheFile; + } + + /** + * Returns the delegate authentication service. + */ + public IAuthenticationService getDelegate() + { + return delegate; + } + + /** + * Sets the delegate authentication service. + */ + public void setDelegate(IAuthenticationService delegate) + { + this.delegate = delegate; + } + + /** + * Returns the cache time (in ms). + */ + public long getCacheTime() + { + return cacheTime; + } + + /** + * Sets the cache time (in ms). + */ + public void setCacheTime(long cacheTime) + { + this.cacheTime = cacheTime; + } + + /** + * Returns the cache time (in s, as String). + */ + public String getCacheTimeStr() + { + return Long.toString(getCacheTime() / 1000); + } + + /** + * Sets the cache time as String in a format understood by + * {@link DateTimeUtils#parseDurationToMillis(String)}. + */ + public void setCacheTimeStr(String cacheTimeStr) + { + if (isResolved(cacheTimeStr)) + { + setCacheTime(DateTimeUtils.parseDurationToMillis(cacheTimeStr)); + } + } + + /** + * Returns the time to return cache value without triggering revalidation (in ms). + */ + public long getCacheTimeNoRevalidation() + { + return cacheTimeNoRevalidation; + } + + /** + * Sets the time to return cache value without triggering revalidation (in ms). + */ + public void setCacheTimeNoRevalidation(long cacheTimeNoRevalidation) + { + this.cacheTimeNoRevalidation = cacheTimeNoRevalidation; + } + + /** + * Returns the time to return cache value without triggering revalidation (in s, as String). + */ + public String getCacheTimeNoRevalidationStr() + { + return Long.toString(getCacheTimeNoRevalidation() / 1000); + } + + /** + * Sets the time to return cache value without triggering revalidation as String in a format + * understood by {@link DateTimeUtils#parseDurationToMillis(String)}.. + */ + public void setCacheTimeNoRevalidationStr(String cacheTimeNoRevalidationStr) + { + if (isResolved(cacheTimeNoRevalidationStr)) + { + setCacheTimeNoRevalidation(DateTimeUtils + .parseDurationToMillis(cacheTimeNoRevalidationStr)); + } + } + + private static boolean isResolved(String name) + { + return StringUtils.isNotBlank(name) && name.startsWith("${") == false; + } + +} diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationService.java b/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationService.java index d9ca05b94a0..af4294eb60a 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationService.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationService.java @@ -31,6 +31,7 @@ import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; +import ch.systemsx.cisd.common.time.DateTimeUtils; import ch.systemsx.cisd.common.utilities.ITimeProvider; import ch.systemsx.cisd.common.utilities.SystemTimeProvider; @@ -67,9 +68,9 @@ public class CachingAuthenticationService implements IAuthenticationService public final static long ONE_HOUR = 60 * ONE_MINUTE; - private final static long CACHE_TIME_MILLIS_NO_REVALIDATION = ONE_HOUR; + public final static long CACHE_TIME_MILLIS_NO_REVALIDATION = ONE_HOUR; - private final static long CACHE_TIME_MILLIS = 28 * ONE_HOUR; + public final static long CACHE_TIME_MILLIS = 28 * ONE_HOUR; private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, CachingAuthenticationService.class); @@ -211,7 +212,7 @@ public class CachingAuthenticationService implements IAuthenticationService userId)); } } - + @Override public void run() { @@ -230,7 +231,7 @@ public class CachingAuthenticationService implements IAuthenticationService } } - /** A simple interface to authenticate by one type of id. */ + /** A interface with one method to authenticate by one type of id (userid or email). */ interface IAuthenticator { Principal tryGetAndAuthenticate(String id, String passwordOrNull); @@ -252,20 +253,22 @@ public class CachingAuthenticationService implements IAuthenticationService private final ITimeProvider timeProvider; - CachingAuthenticationService(IAuthenticationService delegate, + private final boolean caching; + + public CachingAuthenticationService(IAuthenticationService delegate, String passwordCacheFileName) { this(delegate, createUserStore(passwordCacheFileName)); } - CachingAuthenticationService(IAuthenticationService authenticationService, + public CachingAuthenticationService(IAuthenticationService authenticationService, IUserStore<UserCacheEntry> store) { this(authenticationService, store, CACHE_TIME_MILLIS_NO_REVALIDATION, CACHE_TIME_MILLIS); } - CachingAuthenticationService(IAuthenticationService delegate, + public CachingAuthenticationService(IAuthenticationService delegate, String passwordCacheFileName, long cacheTimeNoRevalidationMillis, long cacheTimeMillis) @@ -274,7 +277,7 @@ public class CachingAuthenticationService implements IAuthenticationService cacheTimeNoRevalidationMillis, cacheTimeMillis); } - CachingAuthenticationService(IAuthenticationService delegate, + public CachingAuthenticationService(IAuthenticationService delegate, IUserStore<UserCacheEntry> userStore, long cacheTimeNoRevalidationMillis, long cacheTimeMillis) @@ -283,6 +286,12 @@ public class CachingAuthenticationService implements IAuthenticationService SystemTimeProvider.SYSTEM_TIME_PROVIDER); } + public CachingAuthenticationService(CachingAuthenticationConfiguration config) + { + this(config.getDelegate(), createUserStore(config.getPasswordCacheFile()), config + .getCacheTimeNoRevalidation(), config.getCacheTime()); + } + // For unit tests. CachingAuthenticationService(IAuthenticationService delegate, IUserStore<UserCacheEntry> userStore, @@ -315,18 +324,36 @@ public class CachingAuthenticationService implements IAuthenticationService this.cacheTimeMillis = cacheTimeMillis; this.validationQueue = new LinkedBlockingQueue<ValidationRequest>(); this.timeProvider = timeProvider; - if (startRevalidationThread) + this.caching = (cacheTimeMillis > 0); + if (startRevalidationThread && caching) { final Thread t = new Thread(new RevalidationRunnable()); t.setName(getClass().getSimpleName() + " - Validator"); t.setDaemon(true); t.start(); } + if (operationLog.isInfoEnabled()) + { + if (caching) + { + operationLog.info(String.format( + "Caching authentication results for %s, revalidating after %s.", + DateTimeUtils.renderDuration(cacheTimeMillis), + DateTimeUtils.renderDuration(cacheTimeNoRevalidationMillis))); + } else + { + operationLog.info("Authentication caching is switched off."); + } + } } static IUserStore<UserCacheEntry> createUserStore( final String passwordCacheFileName) { + if (StringUtils.isBlank(passwordCacheFileName)) + { + return null; + } final ILineStore lineStore = new FileBasedLineStore(new File(passwordCacheFileName), "Password cache file"); return new LineBasedUserStore<UserCacheEntry>(lineStore, @@ -386,9 +413,13 @@ public class CachingAuthenticationService implements IAuthenticationService { return null; } - final UserCacheEntry user = - new UserCacheEntry(p, passwordOrNull, timeProvider.getTimeInMilliseconds()); - userStore.addOrUpdateUser(user); + if (caching) + { + final UserCacheEntry user = + new UserCacheEntry(p, passwordOrNull, + timeProvider.getTimeInMilliseconds()); + userStore.addOrUpdateUser(user); + } return p; } default: @@ -409,7 +440,7 @@ public class CachingAuthenticationService implements IAuthenticationService private CacheEntryStatus getStatus(UserCacheEntry entry, boolean requirePassword, long now) { - if (entry == null) + if (entry == null || caching == false) { return CacheEntryStatus.NO_ENTRY; } @@ -579,7 +610,7 @@ public class CachingAuthenticationService implements IAuthenticationService @Override public boolean isConfigured() { - return delegate.isConfigured(); + return (userStore != null) && (delegate != null) && delegate.isConfigured(); } } diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java index 51bffb56957..45730730a99 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java @@ -20,6 +20,8 @@ import javax.naming.Context; import org.apache.commons.lang.StringUtils; +import ch.systemsx.cisd.common.time.DateTimeUtils; + /** * The configuration for an LDAP directory server. Example: * @@ -335,13 +337,14 @@ public final class LDAPDirectoryConfiguration } /** - * Set the read timeout (in s). + * Set the read timeout as String in a format understood by + * {@link DateTimeUtils#parseDurationToMillis(String)}. */ - public void setTimeoutStr(String timeoutMillis) + public void setTimeoutStr(String timeoutStr) { - if (isResolved(timeoutMillis)) + if (isResolved(timeoutStr)) { - this.timeout = Long.parseLong(timeoutMillis) * 1000L; + this.timeout = DateTimeUtils.parseDurationToMillis(timeoutStr); } } @@ -364,13 +367,15 @@ public final class LDAPDirectoryConfiguration } /** - * Set the time to wait after failure before retrying (in ms). + * Set the time to wait after failure before retrying as a String in a format understood by + * {@link DateTimeUtils#parseDurationToMillis(String)}. */ - public void setTimeToWaitAfterFailureStr(String timeToWaitOnFailureMillis) + public void setTimeToWaitAfterFailureStr(String timeToWaitOnFailureStr) { - if (isResolved(timeToWaitOnFailureMillis)) + if (isResolved(timeToWaitOnFailureStr)) { - this.timeToWaitAfterFailure = Long.parseLong(timeToWaitOnFailureMillis) * 1000L; + this.timeToWaitAfterFailure = + DateTimeUtils.parseDurationToMillis(timeToWaitOnFailureStr); } } diff --git a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceInvalidLoginTests.java b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceInvalidLoginTests.java index 2cebf278273..1b6b390f709 100644 --- a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceInvalidLoginTests.java +++ b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceInvalidLoginTests.java @@ -37,6 +37,7 @@ import org.testng.annotations.Test; import ch.systemsx.cisd.authentication.IAuthenticationService; import ch.systemsx.cisd.authentication.Principal; import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.logging.LogInitializer; import ch.systemsx.cisd.common.utilities.ITimeProvider; /** @@ -96,6 +97,7 @@ public class CachingAuthenticationServiceInvalidLoginTests @BeforeClass public void setUp() { + LogInitializer.init(); FileUtilities.deleteRecursively(workingDirectory); workingDirectory.mkdirs(); context = new Mockery(); diff --git a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceSuccessTests.java b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceSuccessTests.java index 1cbc9842f92..20ba4fccc80 100644 --- a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceSuccessTests.java +++ b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/file/CachingAuthenticationServiceSuccessTests.java @@ -37,6 +37,7 @@ import org.testng.annotations.Test; import ch.systemsx.cisd.authentication.IAuthenticationService; import ch.systemsx.cisd.authentication.Principal; import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.logging.LogInitializer; import ch.systemsx.cisd.common.utilities.ITimeProvider; /** @@ -103,6 +104,7 @@ public class CachingAuthenticationServiceSuccessTests @BeforeClass public void setUp() { + LogInitializer.init(); FileUtilities.deleteRecursively(workingDirectory); workingDirectory.mkdirs(); context = new Mockery(); diff --git a/common/source/java/genericCommonContext.xml b/common/source/java/genericCommonContext.xml index ac6e0a8a304..f862d3cf6d8 100644 --- a/common/source/java/genericCommonContext.xml +++ b/common/source/java/genericCommonContext.xml @@ -76,7 +76,7 @@ <property name="timeoutStr" value="${ldap.timeout}" /> <property name="timeToWaitAfterFailureStr" value="${ldap.timeToWaitAfterFailure}" /> </bean> - + <bean id="ldap-authentication-service" class="ch.systemsx.cisd.authentication.ldap.LDAPAuthenticationService"> <constructor-arg ref="ldap-directory-configuration" /> @@ -97,7 +97,8 @@ </constructor-arg> </bean> - <bean id="file-ldap-authentication-service" class = "ch.systemsx.cisd.authentication.stacked.StackedAuthenticationService"> + <bean id="file-ldap-authentication-service" + class = "ch.systemsx.cisd.authentication.stacked.StackedAuthenticationService"> <constructor-arg> <list> <ref bean="file-authentication-service" /> @@ -106,7 +107,8 @@ </constructor-arg> </bean> - <bean id="stacked-authentication-service" class = "ch.systemsx.cisd.authentication.stacked.StackedAuthenticationService"> + <bean id="ldap-crowd-authentication-service" + class = "ch.systemsx.cisd.authentication.stacked.StackedAuthenticationService"> <constructor-arg> <list> <ref bean="ldap-authentication-service" /> @@ -114,7 +116,23 @@ </list> </constructor-arg> </bean> + + <bean id="authentication-cache-configuration" + class="ch.systemsx.cisd.authentication.file.CachingAuthenticationConfiguration"> + <property name="delegate" ref="ldap-crowd-authentication-service" /> + <property name="passwordCacheFile" value="etc/password_cache" /> + <property name="cacheTimeStr" value="${authentication.cache.time}" /> + <property name="cacheTimeNoRevalidationStr" value="${authentication.cache.time-no-revalidation}" /> + </bean> + + <bean id="file-ldap-crowd-caching-authentication-service" + class = "ch.systemsx.cisd.authentication.file.CachingAuthenticationService"> + <constructor-arg ref="authentication-cache-configuration" /> + </bean> + <!-- Keep this for backward compatibility with old service.properties files. --> + <alias name="ldap-crowd-authentication-service" alias="stacked-authentication-service"/> + <!-- // Implementation of IRequestContextProvider --> diff --git a/openbis/dist/server/service.properties b/openbis/dist/server/service.properties index b5258b60310..bc20f392eb9 100644 --- a/openbis/dist/server/service.properties +++ b/openbis/dist/server/service.properties @@ -31,10 +31,20 @@ database.active-connections-log-interval = # 'crowd-authentication-service' # 'file-crowd-authentication-service' # 'file-ldap-authentication-service' -# 'stacked-authentication-service' : ldap - crowd -# For a detailed description please have a look at the Installation and Administrator +# 'ldap-crowd-authentication-service' +# 'file-ldap-crowd-caching-authentication-service' +# For a detailed description, have a look at the Installation and Administrator # Guide of the openBIS Server: https://wiki-bsse.ethz.ch/x/oYIUBQ -authentication-service = file-authentication-service +authentication-service = file-ldap-crowd-caching-authentication-service + +# --------------------------------------------------------------------------- +# Caching configuration (only used with 'file-ldap-crowd-caching-authentication-service') +# --------------------------------------------------------------------------- +# The time that the authentication cache keeps entries. Default: 28h +authentication.cache.time = 28h +# The time that the authentication cache does not perform re-validation on a cache entry. +# Default: 1h +authentication.cache.time-no-revalidation = 1h # --------------------------------------------------------------------------- # Crowd configuration @@ -45,9 +55,9 @@ authentication-service = file-authentication-service crowd.service.host = # The Crowd service port. Default: 443 crowd.service.port = -# The timeout (in s) to wait for a Crowd query to return, -1 for "wait indefinitely". Default: 10. +# The timeout (in s) to wait for a Crowd query to return, -1 for "wait indefinitely". Default: 10s. crowd.service.timeout = -# The Crowd application name. +# The Crowd application name. The value 'openbis' is just a suggestion. # Mandatory. crowd.application.name = openbis # The Crowd application password. @@ -96,10 +106,10 @@ ldap.queryEmailForAliases = true ldap.queryTemplate = # The number of times a failed LDAP query is retried at the max. Default: 1. ldap.maxRetries = -# The timeout (in s) to wait for an LDAP query to return, -1 for "wait indefinitely". Default: 10. +# The timeout (in s) to wait for an LDAP query to return, -1 for "wait indefinitely". Default: 10s. ldap.timeout = -# Time time (in s) to wait after a failure before retrying the query. Default: 10. -ldap.timeToWaitAfterFailure= +# The time (in s) to wait after a failure before retrying the query. Default: 10s. +ldap.timeToWaitAfterFailure = # --------------------------------------------------------------------------- # Anonymous login configuration (optional) -- GitLab