Here is my security configuration code:
#EnableWebSecurity
#EnableGlobalMethodSecurity (
prePostEnabled=true
)
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.withUser("chandra").password("{noop}1234").roles("USER").and()
.withUser("admin").password("{noop}admin123").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/addItem","/delete").hasRole("ADMIN")
.antMatchers("/getAllItems").hasRole("USER")
.and().csrf().disable().headers().frameOptions().disable()
.and()
.formLogin();
}
}
But while compiling spring is still generating the password for me.
Using generated security password: 49f04bde-ac1f-4e30-870b-ba0dd93d50f3
I checked whether the configuration is being loaded or not by print statements and found the security config is loading. Is there any change I should make to make it work with the given user ids and passwords.
Thanks in advance.
Just a default hint about plain text passwords, you can imagine, what comes next. :-)
Anyway for testing purposes you could define a no operation password encoder like this in your #Configuration class:
To make your prepended noopworking, be sure to expose the following bean:
#Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
For further information, please consult the respective chapter in the reference manual.
As an alternative you could provide the good old password manager itself:
import org.springframework.security.crypto.password.PasswordEncoder;
[…]
#Bean
public NoOpPasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
Related
Since WebSecurityConfigurerAdapter has been deprecated, I have updated my SecurityConfig class with defining SecurityFilterChain as a bean in my config class but none of the config is working and spring still generates Security Password!
Here's my new WebSecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeHttpRequests()
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/role1/**").hasAnyRole("admin")
.requestMatchers("/role2/**").hasAnyRole("admin")
.requestMatchers("/role3/**").hasAnyRole("admin")
.anyRequest()
.permitAll();
return http.build();
}
}
Spring still generates password:
Using generated security password: ******-****-****-****-**********
This generated password is for development use only. Your security configuration must be updated before running your application in production.
I have tried excluding SecurityAutoConfiguration class from the main application but it did not work.
You can either remove the UserDetailsServiceAutoConfiguration by doing:
#SpringBootApplication(excludes = UserDetailsServiceAutoConfiguration.class) or you can provide a UserDetailsService of your own:
#Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager();
}
I'm trying to configure my webSecurity to use both ldap and basic authentication (jdbc) with the new component-based security configuration (no WebSecurityConfigurerAdapter) but I can't get it to use both.
The required result is for spring to first attempt ldap, and if it doesn't find (or just fails for now is good enough) attempt to login using basic autentication.
The project is a migration from an older Spring-Boot version and with WebSecurityConfigurerAdapter the following code is what worked:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests().antMatchers("/services/**").permitAll().anyRequest().authenticated();
http.httpBasic();
http.formLogin().permitAll().loginPage("/login").defaultSuccessUrl("/customer/overview", true);
http.logout().permitAll();
http.csrf().disable();
http.headers().frameOptions().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetails);
//#formatter:off
auth.ldapAuthentication()
.userSearchFilter("(uid={0})")
.userSearchBase("ou=people")
.groupSearchFilter("(uniqueMember={0})")
.groupSearchBase("ou=groups")
.groupRoleAttribute("cn")
.rolePrefix("ROLE_")
.userDetailsContextMapper(customLdapUserDetailsContextMapper())
.contextSource()
.url(ldapUrl);
//#formatter:on
}
#Bean
CustomLdapUserDetailsContextMapper customLdapUserDetailsContextMapper()
{
CustomLdapUserDetailsContextMapper mapper = new CustomLdapUserDetailsContextMapper();
mapper.setCustomUserDetailsService(userDetailsService());
return mapper;
}
//Implementation of custom contextMapper is not relevant for example i believe, basicly it maps some ldap roles, but for testing i don't use roles yet
}
and this is what my conversion to the new style looks like:
#Configuration
public class WebSecurityConfig
{
#Bean
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager ldapAuthenticationManager) throws Exception
{
// #formatter:off
http.authorizeRequests()
.mvcMatchers("/services/**").permitAll()
.mvcMatchers("/resources/**").permitAll()
.mvcMatchers("/webjars/**").permitAll()
.anyRequest().authenticated();
http.httpBasic();
http.formLogin().permitAll().loginPage("/login").defaultSuccessUrl("/customer/overview", true);
http.logout().permitAll();
http.csrf().disable();
http.authenticationManager(ldapAuthenticationManager); //THIS LINE SEEMS TO BE PROBLEMATIC
// #formatter:on
return http.build();
}
#Bean
public AuthenticationManager ldapAuthenticationManager(BaseLdapPathContextSource ldapContextSource, UserDetailsService userDetailsService)
{
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(ldapContextSource);
UserDetailsServiceLdapAuthoritiesPopulator ldapAuthoritiesPopulator = new UserDetailsServiceLdapAuthoritiesPopulator(userDetailsService);
factory.setUserSearchFilter("(uid={0})");
factory.setUserSearchBase("ou=people");
factory.setLdapAuthoritiesPopulator(ldapAuthoritiesPopulator);
return factory.createAuthenticationManager();
}
}
when in the above new code the line http.authenticationManager(ldapAuthenticationManager); is enabled ldap login works fine (and it even binds roles from database user), but basic login doesn't work. however when the line is disabled basic login works but ldap does not.
Any help on how to get spring to use both logins would be much appreciated.
Instead of creating a custom AuthenticationManager, you can create the AuthenticationProvider that will be used for LDAP authentication.
You can configure the provider on HttpSecurity:
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, LdapAuthenticator authenticator) throws Exception {
// ...
http.authenticationProvider(
new LdapAuthenticationProvider(authenticator, ldapAuthoritiesPopulator));
// ...
return http.build();
}
#Bean
BindAuthenticator authenticator(BaseLdapPathContextSource contextSource) {
BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserSearch(
new FilterBasedLdapUserSearch("ou=people", "(uid={0})", contextSource));
return authenticator;
}
I am using Spring boot and developing REST services and want to integrate with LDAP authentication security mechanism.
I googled a lot but did not get a concrete solution as such. I am looking for a complete example.
Also I am using POSTMAN client and want to know how to use it to test the LDAP authentication.
Thanks in advance..!!
Here is an example using ActiveDirectoryLdapAuthenticationProvider
This was actually surprisingly simple. Thank you, Boot.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/yourstuff/**").permitAll()
.antMatchers("/your/protectedstuff/**").authenticated()
.and()
.httpBasic()
.permitAll();
}
#Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new ActiveDirectoryLdapAuthenticationProvider("DOMAINNAME","LDAP SERVER URI"));
}
}
}
My application serves both API and browser. I've implemented API Token authentication with all custom providers and filter. The configuration now seems to interfere with the browser version.
I have two questions that I need advice on how to solve, as I'm not getting anywhere after digging through the documentation and other examples.
1) My StatelessAuthenticationFilter is being called despite a request
coming from the browser. I have e.g. specified the request matcher to "/api/**". Why is that?
2) The AuthenticationManager have not registered two AuthenticationProviders. This is my conclusion after debugging my StatelessAuthenticationFilter that's being called wrongly.
Here's the configuration classes that I have
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Order(1)
#Configuration
public static class A extends WebSecurityConfigurerAdapter {
#Autowired
TokenAuthenticationProvider tokenAuthenticationProvider;
#Autowired
ApiEntryPoint apiEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
StatelessAuthenticationFilter filter = new StatelessAuthenticationFilter();
AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher("/api/**");
filter.setRequiresAuthenticationRequestMatcher(requestMatcher);
filter.setAuthenticationManager(super.authenticationManager());
http.csrf().disable()
.exceptionHandling().authenticationEntryPoint(apiEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAuthenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/user/register");
}
}
#Configuration
public static class B extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new DaoAuthenticationProvider());
}
}
}
As you can see, B class doesn't specify anything, yet when I access localhost:8080 the StatelessAuthenticationFilter is called. What is going on here?
In class A you are configuring the StatelessAuthenticationFilter to use a requestMatcher. Whatever you do with that, spring does not know or care about that.
You must also restrict your security configuration using
http.antMatcher("/api/**")
otherwise its configured for every URI and the StatelessAuthenticationFilter will be invoked for every request, exactly as you described.
You should also annotate class A and B with #Order as shown in the example at multiple-httpsecurity
I had an interesting situation not long ago which caused an infinite loop (and eventually a stack overflow) in Spring Security's AuthenticationManager. For months, everything worked as expected, but then I decided to transfer my XML configuration to code-only configuration. Here was my basic setup in Java configuration:
#Configuration
#EnableWebMvcSecurity
#ComponentScan(basePackages = { "com.my.company" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Disable default configuration
public SecurityConfig() {
super(true);
}
#Autowired
AuthenticationProviderImpl authenticationProvider;
#Autowired
MyAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter;
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore requests of resources in security
web.ignoring().antMatchers("/resources/**")
// Ignore requests to authentication
.and().ignoring().antMatchers("/auth/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Define main authentication filter
http.addFilterBefore(authenticationTokenProcessingFilter,
UsernamePasswordAuthenticationFilter.class)
// Request path authorization
.authorizeRequests()
.antMatchers("/api/**")
.access("isAuthenticated()")
// Authentication provider
.and()
.authenticationProvider(authenticationProvider)
// Security failure exception handling
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
// Session Management
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// Default security HTTP headers
.and().headers().xssProtection().frameOptions()
.cacheControl().contentTypeOptions();
}
}
However, I soon found out that this configuration causes issues with my AuthenticationProviderImpl (which implements the Spring Security AuthenticationProvider interface). When the implementation's overridden authenticate method throws a BadCredentialsException, the exact same method in that class is called again perpetually until the stack overflows. The good news is that I fixed my configuration by simply overriding configure(AuthenticationManagerBuilder builder) in the SecurityConfig and declaring my implementation of the AuthenticationProvider there instead of in configure(HttpSecurity http). Here is the fixed version:
#Configuration
#EnableWebMvcSecurity
#ComponentScan(basePackages = { "com.my.company" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Disable default configuration
public SecurityConfig() {
super(true);
}
#Autowired
AuthenticationProviderImpl authenticationProvider;
#Autowired
MyAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter;
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder builder) {
// Configure the authentication manager WITH the authentication
// provider. Not overriding this method causes very bad things to
// happen.
builder.authenticationProvider(authenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore requests of resources in security
web.ignoring().antMatchers("/resources/**")
// Ignore requests to authentication
.and().ignoring().antMatchers("/auth/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Define main authentication filter
http.addFilterBefore(authenticationTokenProcessingFilter,
UsernamePasswordAuthenticationFilter.class)
// Request path authorization
.authorizeRequests()
.antMatchers("/api/**")
.access("isAuthenticated()")
.and()
// Security failure exception handling
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
// Session Management
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// Default security HTTP headers
.and().headers().xssProtection().frameOptions()
.cacheControl().contentTypeOptions();
}
}
Though I believe my problem is solved with the fixed configuration, I still have no idea why the application was infinitely calling authenticate() when an exception was thrown by my implementation of AuthenticationProvider? I tried stepping through and examining the Spring Security classes, but I was not finding a logical answer. Thanks ahead for your expertise!
A few weeks ago I reproduced this behavior, too, see this thread on stackoverflow.
Dealing with the question I figured out that loops occur when the AuthenticationManager internally iterates through it's list of associated AuthenticationProviders, then finds a custom provider and tries to do the authentication using the provider that has been found. If the provider delegates the authentication back to the AuthenticationManager by calling authenticate(), you are in the loop. I guess your AuthenticationProviderImpl does something like that?
The order of your in the providers inside the java.util.List of the AuthenticationManager matters. The order is given by your configuration, e.g. by doing what you tried at first:
// Authentication provider
.and()
.authenticationProvider(authenticationProvider)
By changing your configuration, you influenced the internally managed list of providers attached to your manager, which in the end will solve your code.