diff --git a/publish-service/pom.xml b/publish-service/pom.xml index e9c90a4c..bd17d423 100644 --- a/publish-service/pom.xml +++ b/publish-service/pom.xml @@ -81,6 +81,33 @@ + + org.springframework.security + spring-security-test + 5.7.4 + test + + + org.springframework.security + spring-security-ldap + 5.7.4 + + + org.springframework.security + spring-security-config + 5.7.4 + + + org.springframework.ldap + spring-ldap-core + 2.4.1 + + + org.springframework.boot + spring-boot-starter-cache + ${springboot.version} + + io.springfox springfox-swagger-ui diff --git a/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/CachingLdapAuthenticationProvider.java b/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/CachingLdapAuthenticationProvider.java new file mode 100644 index 00000000..df959c43 --- /dev/null +++ b/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/CachingLdapAuthenticationProvider.java @@ -0,0 +1,79 @@ +package com.ericsson.eiffel.remrem.publish.config; + +import org.springframework.cache.concurrent.ConcurrentMapCache; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserCache; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.cache.NullUserCache; +import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache; +import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; +import org.springframework.security.ldap.authentication.LdapAuthenticator; +import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; +import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +public class CachingLdapAuthenticationProvider extends LdapAuthenticationProvider { + + private UserCache userCache = new NullUserCache(); + + /** + * Create an instance with the supplied authenticator and authorities populator + * implementations. + * + * @param authenticator the authentication strategy (bind, password comparison, etc) + * to be used by this provider for authenticating users. + * @param authoritiesPopulator the strategy for obtaining the authorities for a given + */ + + public CachingLdapAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) { + super(authenticator, authoritiesPopulator); + } + + public void setUserCache(UserCache userCache) { + this.userCache = userCache; + } + + + @Override + public Authentication authenticate(Authentication authentication) { + String userName = authentication.getName(); + UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication; + UserDetails userDetailsFromCache = userCache.getUserFromCache(userName); + if (userDetailsFromCache != null) { + System.out.println("+++---> user in cache"); + System.out.println("+++---> usercache data: " + userDetailsFromCache); + additionalAuthenticationChecks(userDetailsFromCache, userToken); + return createSuccessfulAuthentication(userToken, userDetailsFromCache); + } else { + System.out.println("+++---> user not in cache"); + Authentication authenticationFromProvider = super.authenticate(authentication); + userCache.putUserInCache((UserDetails)authenticationFromProvider.getPrincipal()); + return authenticationFromProvider; + } + + } + + protected void additionalAuthenticationChecks(UserDetails userDetails, + UsernamePasswordAuthenticationToken authentication) { + if (StringUtils.isEmpty(authentication.getCredentials())) { + System.out.println("+++---> I am in additional checks"); + System.out.println("Authentication failed: no credentials provided"); + + throw new BadCredentialsException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.badCredentials", + "Bad credentials")); + } + String presentedPassword = authentication.getCredentials().toString(); + System.out.println("+++---> I am in additional checks"); + System.out.println("+++---> passowrd" + presentedPassword); + if (!StringUtils.isEmpty(userDetails.getPassword()) && (!presentedPassword.equals(userDetails.getPassword()))) { + System.out.println("Authentication failed: password does not match stored value"); + throw new BadCredentialsException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.badCredentials", + "Bad credentials")); + } + } +} \ No newline at end of file diff --git a/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/SecurityConfig.java b/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/SecurityConfig.java index ab4fe376..0ef124a3 100644 --- a/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/SecurityConfig.java +++ b/publish-service/src/main/java/com/ericsson/eiffel/remrem/publish/config/SecurityConfig.java @@ -29,6 +29,33 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.concurrent.ConcurrentMapCache; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserCache; +import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.ldap.authentication.BindAuthenticator; +import org.springframework.security.ldap.authentication.LdapAuthenticator; +import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; +import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; +import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; /** * This class is used to enable the ldap authentication based on property @@ -74,20 +101,44 @@ public Integer getTimeOut() { @Autowired private CustomAuthenticationEntryPoint customAuthenticationEntryPoint; - @Autowired - protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + @Bean + public UserCache userCache() { + // Adjust cache settings as necessary + return new SpringCacheBasedUserCache(new ConcurrentMapCache("authenticationCache")); + } + + @Bean + public LdapAuthoritiesPopulator ldapAuthoritiesPopulator() { + return new DefaultLdapAuthoritiesPopulator(ldapContextSource(), null); // Adjust the second parameter based on your group search base + // Additional configuration can be set here if necessary + } + + + @Override + public void configure(AuthenticationManagerBuilder auth) throws Exception { final String jasyptKey = RabbitMqPropertiesConfig.readJasyptKeyFile(jasyptKeyFilePath); if (managerPassword.startsWith("{ENC(") && managerPassword.endsWith("}")) { managerPassword = DecryptionUtils.decryptString( managerPassword.substring(1, managerPassword.length() - 1), jasyptKey); } LOGGER.debug("LDAP server url: " + ldapUrl); - auth.ldapAuthentication() - .userSearchFilter(userSearchFilter) - .contextSource(ldapContextSource()); + + BindAuthenticator bindAuthenticator = new BindAuthenticator(ldapContextSource()); + bindAuthenticator.setUserSearch(new FilterBasedLdapUserSearch("", userSearchFilter, ldapContextSource())); + + + LdapAuthoritiesPopulator ldapAuthoritiesPopulator = ldapAuthoritiesPopulator(); + + // Create and use the caching LDAP authentication provider + CachingLdapAuthenticationProvider cachingProvider = + new CachingLdapAuthenticationProvider(bindAuthenticator, ldapAuthoritiesPopulator); + + cachingProvider.setUserCache(userCache()); + auth.authenticationProvider(cachingProvider); + } - public BaseLdapPathContextSource ldapContextSource() { + public LdapContextSource ldapContextSource() { LdapContextSource ldap = new LdapContextSource(); ldap.setUrl(ldapUrl); ldap.setBase(rootDn);