Spring Security LDAP Authentication does not work with Java 8 - spring

I am trying to use LDAP Authentication provided by Spring Security. Everything compiles fine. I get the following error on deploying the application.
Caused by: java.lang.RuntimeException: Could not postProcess org.springframework.security.ldap.server.ApacheDSContainer#54a76efa of type class org.springframework.security.ldap.server.ApacheDSContainer
at org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor.postProcess(AutowireBeanFactoryObjectPostProcessor.java:70)
at org.springframework.security.config.annotation.SecurityConfigurerAdapter$CompositeObjectPostProcessor.postProcess(SecurityConfigurerAdapter.java:123)
at org.springframework.security.config.annotation.SecurityConfigurerAdapter.postProcess(SecurityConfigurerAdapter.java:82)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer.access$400(LdapAuthenticationProviderConfigurer.java:58)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer$ContextSourceBuilder.build(LdapAuthenticationProviderConfigurer.java:555)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer$ContextSourceBuilder.access$500(LdapAuthenticationProviderConfigurer.java:446)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer.getContextSource(LdapAuthenticationProviderConfigurer.java:606)
at org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer.build(LdapAuthenticationProviderConfigurer.java:76)
Spring Core version is 4.3.2. Spring Security LDAP version is 4.1.1.
My Google research listed a 2013 post which says that the issue is because of incompatibility between Spring Security LDAP and Java 8. The same article said it has been fixed in some Spring Boot version. It does not talk about any fix for non-Spring boot libraries.
Has anybody tried Spring Security LDAP Authentication using Java 8? Please help.

Here's my working config using Java 8 and Spring Security LDAP. We're connecting our Spring Web app to an Active Directory instance to secure access by URL.
If I recall correctly, it took longer than I expected to get this working.
You'll need to change the "Base" for the LDAP context path, and note that the ldap.user is the full LDAP CN, not just a username. You can use and LDAP browser like JXplorer (http://jxplorer.org/) to get the LDAP settings correct.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
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;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfig.class);
#Value("ldap://${ldap.host}:${ldap.port:389}")
private String url;
#Value("${ldap.user}")
private String user;
#Value("${ldap.password}")
private String password;
#Override
protected void configure(HttpSecurity http) throws Exception {
LOGGER.info("Configuring security...");
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/index.html").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userSearchFilter("(&(objectClass=user)(sAMAccountName={0}))")
.contextSource(ldapContextSource());
}
#Bean
public BaseLdapPathContextSource ldapContextSource() {
LOGGER.info("LDAP: {}", url);
LdapContextSource bean = new LdapContextSource();
bean.setUrl(url);
bean.setBase("DC=CORP,DC=MyCompany,DC=com");
bean.setUserDn(user);
bean.setPassword(password);
bean.setPooled(true);
bean.setReferral("follow");
return bean;
}
}
This assumes you have your LDAP settings in a configuration file that looks something like this
ldap.host=ldap.mycompany.com
ldap.user=CN=MyUser,OU=Service Accounts,OU=New-York,DC=CORP,DC=MyCompany,DC=com
# Encrypt using Jasypt or something
ldap.password=B1gS3cr3t

Related

Why does Spring try to access a property instead of the method when trying to manage session-timeout?

Im fairly new to coding in general, and currently I'm trying to configure Session-Timeouts in Spring.
package ch.upreg.registermanagement.config;
import org.springframework.context.annotation.Configuration;
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;
#Configuration
#EnableWebSecurity
public class SessionTimeoutConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.invalidSessionUrl("/invalidSession.html")
.expiredUrl("/sessionExpired.html");
}
}
This is what I currently have. However, instead of being able to configure the expired URL, the Property by the name "expiredUrl" in the class "SessionManagementConfigurer" is trying to be accessed and I get an error.
public SessionManagementConfigurer<H>.ConcurrencyControlConfigurer expiredUrl(String expiredUrl) {
SessionManagementConfigurer.this.expiredUrl = expiredUrl;
return this;
}
This is the method of said class that I'm trying to access.
'expiredUrl' has private access in 'org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer'
I tried to change the order of the Builder-Properties, however, that didn't work either. I'm honestly clueless as to what to do now.

SpringBoot (Webflux) 2.7.3 disable WebSecurity

How to disable the Springboot Websecurity in Springboot 2.7.3 when Webflux is in use.
This does not disable the webflux security but acts as a very bad workaround for now.
#EnableWebFluxSecurity
class WebfluxSecurityConfig {
#Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain? {
http.authorizeExchange()
.pathMatchers("/**").permitAll()
return http.build()
}
}
Remove dependency spring-boot-starter-security in your pom.xml or build.gradle .
Excluding security dependencies from your project doesn't seem like the best idea, since you probably will need than at some point in time.
The best way will be to introduce the feature flag (simple configuration property) for enabling/disabling the security configurations in your project.
Please check my example security configuration below:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
#Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${api.security.enabled:false}")
private Boolean enabled;
#Override
protected void configure(HttpSecurity http) throws Exception {
if (this.enabled) {
// your configuration for enabled security
} else {
((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)http.authorizeRequests().anyRequest()).permitAll();
log.warn("Security is disabled");
}
}
}
We such configuration you will need to have such property in your application.yml or application.property file:
api:
security:
enabled: false
By default, security will be disabled. If you will need to enable it at some point in time or on some specific environment or profile, all you need to do is simply assign the true value to this property in your configs.

Spring Boot Starter GraphQL OPTIONS Pre-Flight request rejected with HTTP 403

I've recently converted a GraphQL API from SpringBoot Web to WebFlux. In the previous version, the #RequestMapping was annotated with #CrossOrigin, which seemed to cover the OPTIONS HTTP verb.
In the new version, I am using the #MutationMapping / #QueryMapping annotations to map the schema to my methods, and responding to them reactively.
The problem is that for some of our frontend's, an OPTIONS preflight is sent and rejected with a 403 by this new implementation.
Is there an annotation or configuration I can enable where this preflight will not be rejected?
I've attempted to use the GraphQlWebFluxAutoConfiguration.GraphQlEndpointCorsConfiguration object however I can't seem to get it configured correctly. Any advice would be much appreciated, as I'm relatively new to the WebFlux stack.
Here's how I solved it - the issue was caused by my local dev environment having tomcat9, and the staging/qa environment I was deploying to having tomcat7 (not supporting WebFlux properly).
Please note that the app.enable-cors is a property defined in my application.properties file - you will need to add this if you are just copying+pasting this code.
I created two configuration classes, overriding both the Mvc and WebFlux Configurer.addCorsMapping(CorsRegistry registry) method. Depending on which auto configuration is loaded, the correct overriden method will be run. Code as follows:
First, the WebFlux version
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
#Configuration
#ConditionalOnProperty(name = "app.enable-cors", havingValue = "true")
public class GraphQLWebFluxConfiguration implements WebFluxConfigurer {
#Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("*");
}
}
Secondly the MVC version
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#ConditionalOnProperty(name = "app.enable-cors", havingValue = "true")
public class GraphQLWebMvcConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("*");
}
}
I obviously have this disabled for the prod environment, but as a workaround for your QA/local environment it works well.

Can not switch off SecurityConfig in SpringBootApplication

I have a SecurityConfig and I authorize requests with JWT tokens. The issue is that I would like to switch off the security config for testing my websockets, because somehow I always receiving 401...
I added:
#SpringBootApplication(exclude = SecurityConfig.class)
#EnableAutoConfiguration
public class MyApp {
but it is still authoraizing the requests from websockets and basically rest also...
anyone know how to switch of security in spring, or maybe how to allow websockets messages?
regards
You should add
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/**");
}
}

How to override default Spring Boot Login page?

I'm totally new with Spring Boot 2 and I have this simple application that I'm trying to run. Unfortunately, each time I run my service, I end up with this login form from Spring Boot. Is there any way I can override this?
I've already tried the solution from this question but it didn't work for me:
How to override Spring Security default configuration in Spring Boot
Here is what I have so far for the code:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Defines the application, supports service registry, circuit breaker
* for Spring Boot application.
*
* #EnableJpaRepositories - add this to enable
*
* #author himanshu sharma
* #since June 2017
*/
#EnableDiscoveryClient
#EnableCircuitBreaker
#EnableHystrixDashboard
#EnableSwagger2
#EnableCaching
#SpringBootApplication
#ImportResource("classpath:service-config.xml")
#ComponentScan(basePackages = "com.manulife.ap.*, io.swagger")
public class Application{
#Autowired
DiscoveryClient discoveryClient;
/**
* Application start point.
* #param args
*/
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#RequestMapping(value="/greeting", method=RequestMethod.GET)
public String sayHello () {
return "Hello from Spring Boot!";
}
}
--EDIT:#devshawn--
I tried the solution of excluding the SecurityAutoConfiguration.class but I somehow got this error message when I tried to access my endpoint:
I'm assuming you're using Spring Boot 2, as you did not mention which version of Spring you are using. In spring boot 2, you cannot disable the default login via properties files as you could in spring boot 1. There's a few ways of doing this depending on what you're trying to achieve.
Permit All Access, Secure Endpoints Later
Add a class titled SecurityConfig that looks like this:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
This removes authentication on all endpoints in your service. Later on, you can configure security further via this class.
Remove Security Auto Configuration
When Spring Security is found on the classpath, Spring Boot automatically configures security. You can remove it all together if you don't want it auto configured by changing your #SpringBootApplication annotation.
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class})

Resources