Skip to content

Commit a736475

Browse files
author
Piyush Sadangi (EXT)
committed
LDAP cahcing
1 parent b6f644f commit a736475

File tree

3 files changed

+176
-6
lines changed

3 files changed

+176
-6
lines changed

publish-service/pom.xml

+32
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,38 @@
8181
</exclusion>
8282
</exclusions>
8383
</dependency>
84+
<dependency>
85+
<groupId>org.springframework.security</groupId>
86+
<artifactId>spring-security-test</artifactId>
87+
<version>5.7.4</version>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>org.springframework.security</groupId>
92+
<artifactId>spring-security-ldap</artifactId>
93+
<version>5.7.4</version>
94+
</dependency>
95+
<dependency>
96+
<groupId>com.github.ben-manes.caffeine</groupId>
97+
<artifactId>caffeine</artifactId>
98+
<version>3.1.8</version>
99+
</dependency>
100+
<dependency>
101+
<groupId>org.springframework.security</groupId>
102+
<artifactId>spring-security-config</artifactId>
103+
<version>5.7.4</version>
104+
</dependency>
105+
<dependency>
106+
<groupId>org.springframework.ldap</groupId>
107+
<artifactId>spring-ldap-core</artifactId>
108+
<version>2.4.1</version>
109+
</dependency>
110+
<dependency>
111+
<groupId>org.springframework.boot</groupId>
112+
<artifactId>spring-boot-starter-cache</artifactId>
113+
<version>${springboot.version}</version>
114+
</dependency>
115+
84116
<dependency>
85117
<groupId>io.springfox</groupId>
86118
<artifactId>springfox-swagger-ui</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.ericsson.eiffel.remrem.publish.config;
2+
3+
import org.springframework.cache.concurrent.ConcurrentMapCache;
4+
import org.springframework.security.authentication.BadCredentialsException;
5+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
6+
import org.springframework.security.core.Authentication;
7+
import org.springframework.security.core.userdetails.UserCache;
8+
import org.springframework.security.core.userdetails.UserDetails;
9+
import org.springframework.security.core.userdetails.cache.NullUserCache;
10+
import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache;
11+
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
12+
import org.springframework.security.ldap.authentication.LdapAuthenticator;
13+
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
14+
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
15+
import org.springframework.stereotype.Component;
16+
import org.springframework.util.StringUtils;
17+
18+
public class CachingLdapAuthenticationProvider extends LdapAuthenticationProvider {
19+
20+
private UserCache userCache = new NullUserCache();
21+
22+
/**
23+
* Create an instance with the supplied authenticator and authorities populator
24+
* implementations.
25+
*
26+
* @param authenticator the authentication strategy (bind, password comparison, etc)
27+
* to be used by this provider for authenticating users.
28+
* @param authoritiesPopulator the strategy for obtaining the authorities for a given
29+
*/
30+
31+
public CachingLdapAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) {
32+
super(authenticator, authoritiesPopulator);
33+
}
34+
35+
public void setUserCache(UserCache userCache) {
36+
this.userCache = userCache;
37+
}
38+
39+
40+
@Override
41+
public Authentication authenticate(Authentication authentication) {
42+
String userName = authentication.getName();
43+
UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication;
44+
UserDetails userDetailsFromCache = userCache.getUserFromCache(userName);
45+
if (userDetailsFromCache != null) {
46+
additionalAuthenticationChecks(userDetailsFromCache, userToken);
47+
return createSuccessfulAuthentication(userToken, userDetailsFromCache);
48+
} else {
49+
Authentication authenticationFromProvider = super.authenticate(authentication);
50+
userCache.putUserInCache((UserDetails)authenticationFromProvider.getPrincipal());
51+
return authenticationFromProvider;
52+
}
53+
54+
}
55+
56+
protected void additionalAuthenticationChecks(UserDetails userDetails,
57+
UsernamePasswordAuthenticationToken authentication) {
58+
Object credentials = authentication.getCredentials();
59+
if (!StringUtils.isEmpty(credentials)) {
60+
String presentedPassword = authentication.getCredentials().toString();
61+
if (userDetails.getPassword().equals(presentedPassword)) {
62+
// password matches
63+
return;
64+
}
65+
}
66+
throw new BadCredentialsException(messages.getMessage(
67+
"AbstractUserDetailsAuthenticationProvider.badCredentials",
68+
"Bad credentials"));
69+
}
70+
}

publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/SecurityConfig.java

+74-6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,37 @@
2929
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
3030
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
3131
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
32+
import org.springframework.cache.annotation.Cacheable;
33+
import org.springframework.beans.factory.annotation.Autowired;
34+
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
36+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
37+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
38+
39+
import org.springframework.beans.factory.annotation.Autowired;
40+
import org.springframework.beans.factory.annotation.Value;
41+
import org.springframework.cache.concurrent.ConcurrentMapCache;
42+
import org.springframework.context.annotation.Bean;
43+
import org.springframework.context.annotation.Configuration;
44+
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
45+
import org.springframework.ldap.core.support.LdapContextSource;
46+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
47+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
48+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
49+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
50+
import org.springframework.security.core.userdetails.UserCache;
51+
import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache;
52+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
53+
import org.springframework.security.crypto.password.PasswordEncoder;
54+
import org.springframework.security.ldap.authentication.BindAuthenticator;
55+
import org.springframework.security.ldap.authentication.LdapAuthenticator;
56+
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
57+
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
58+
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
59+
import org.springframework.cache.CacheManager;
60+
import org.springframework.cache.caffeine.CaffeineCacheManager;
61+
import com.github.benmanes.caffeine.cache.Caffeine;
62+
import java.util.concurrent.TimeUnit;
3263

3364
/**
3465
* This class is used to enable the ldap authentication based on property
@@ -64,6 +95,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
6495
@Value("${activedirectory.connectionTimeOut:#{127000}}")
6596
private Integer ldapTimeOut = DEFAULT_LDAP_CONNECTION_TIMEOUT;
6697

98+
@Value("${LdapCacheTTL}")
99+
private Integer LdapCacheTTL;
100+
67101
// built in connection timeout value for ldap if the network issue happens
68102
public static final Integer DEFAULT_LDAP_CONNECTION_TIMEOUT = 127000;
69103

@@ -74,20 +108,54 @@ public Integer getTimeOut() {
74108
@Autowired
75109
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
76110

77-
@Autowired
78-
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
111+
@Bean
112+
public UserCache userCache() {
113+
if (cacheManager().getCache("authenticationCache") == null) {
114+
throw new IllegalStateException ("Cache 'authenticationCache' is required but not available");
115+
}
116+
return new SpringCacheBasedUserCache(cacheManager().getCache("authenticationCache"));
117+
}
118+
119+
@Bean
120+
public CacheManager cacheManager() {
121+
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
122+
cacheManager.setCaffeine(Caffeine.newBuilder()
123+
.expireAfterWrite(LdapCacheTTL, TimeUnit.MINUTES));
124+
return cacheManager;
125+
}
126+
127+
@Bean
128+
public LdapAuthoritiesPopulator ldapAuthoritiesPopulator() {
129+
LdapContextSource contextSource = ldapContextSource();
130+
return new DefaultLdapAuthoritiesPopulator(contextSource, null);
131+
}
132+
133+
@Override
134+
public void configure(AuthenticationManagerBuilder auth) throws Exception {
79135
final String jasyptKey = RabbitMqPropertiesConfig.readJasyptKeyFile(jasyptKeyFilePath);
80136
if (managerPassword.startsWith("{ENC(") && managerPassword.endsWith("}")) {
81137
managerPassword = DecryptionUtils.decryptString(
82138
managerPassword.substring(1, managerPassword.length() - 1), jasyptKey);
83139
}
84140
LOGGER.debug("LDAP server url: " + ldapUrl);
85-
auth.ldapAuthentication()
86-
.userSearchFilter(userSearchFilter)
87-
.contextSource(ldapContextSource());
141+
LdapContextSource contextSource = ldapContextSource();
142+
BindAuthenticator bindAuthenticator = new BindAuthenticator(contextSource);
143+
bindAuthenticator.setUserSearch(new FilterBasedLdapUserSearch("", userSearchFilter, contextSource));
144+
145+
146+
LdapAuthoritiesPopulator ldapAuthoritiesPopulator = ldapAuthoritiesPopulator();
147+
148+
// Create and use the caching LDAP authentication provider
149+
CachingLdapAuthenticationProvider cachingProvider =
150+
new CachingLdapAuthenticationProvider(bindAuthenticator, ldapAuthoritiesPopulator);
151+
152+
cachingProvider.setUserCache(userCache());
153+
auth.authenticationProvider(cachingProvider);
154+
88155
}
89156

90-
public BaseLdapPathContextSource ldapContextSource() {
157+
@Bean
158+
public LdapContextSource ldapContextSource() {
91159
LdapContextSource ldap = new LdapContextSource();
92160
ldap.setUrl(ldapUrl);
93161
ldap.setBase(rootDn);

0 commit comments

Comments
 (0)