SpringSecurity RememberMeServices is not injected via annotations - java

I am trying to configure SpringSecurity to work with Remember Me authentication.
Here is my Java configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
DatabasePersistentTokeRepositoryImpl databasePersistentTokeRepositoryImpl;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authenticationProvider(rememberMeAuthenticationProvider())
.rememberMe().tokenRepository(databasePersistentTokeRepositoryImpl).tokenValiditySeconds((int) TimeUnit.SECONDS.convert(7, TimeUnit.DAYS))
.and()
.csrf().disable();
}
#Bean()
public AuthenticationProvider rememberMeAuthenticationProvider() {
return new RememberMeAuthenticationProvider("KEY");
}
#Bean()
public TokenBasedRememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("KEY", userDetailsService);
rememberMeServices.setAlwaysRemember(true);
return rememberMeServices;
}
}
I see that rememberMeServices is not injected in RememberMeConfigurer. And that results in creating RememberMeAuthenticationFilter which refers to wrong rememberMeServices.
There is a section in Spring Security documentation describing this process using XML.
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#session-mgmt
What is wrong with my injection and is it possible do to this without XML after all?

You aren't injecting it. There is no autowiring for the RememberMeConfigurer. Also why are you configuring so many beans?
The RememberMeAuthenticationProvider is already created for you, if you want to use a different key specify it using key("KEY"). This in turn will be used to create the RememberMeServices.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
DatabasePersistentTokeRepositoryImpl databasePersistentTokeRepositoryImpl;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.key("KEY")
.tokenRepository(databasePersistentTokeRepositoryImpl)
.tokenValiditySeconds((int) TimeUnit.SECONDS.convert(7, TimeUnit.DAYS))
.and()
.csrf().disable();
}
}
If you really need to set the alwaysRemember property to true you could use an ObjectPostProcessor to post process the filter and configure the RememberMeServices from there.
You would also have injected the wrong type of RememberMeServices as the one configured doesn't use the PersistentTokeRepository.

Just to provide an example of the code that #m-deinum's suggestion of an ObjectPostProcessor that sets alwaysRemember to true would look like would look like:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.key("KEY")
.tokenRepository(databasePersistentTokeRepositoryImpl)
.tokenValiditySeconds((int) TimeUnit.SECONDS.convert(7, TimeUnit.DAYS))
.withObjectPostProcessor( new ObjectPostProcessor<RememberMeAuthenticationFilter>() {
#Override
public <O extends RememberMeAuthenticationFilter> O postProcess( O object) {
RememberMeAuthenticationFilter rmaf = (RememberMeAuthenticationFilter)
PersistentTokenBasedRememberMeServices rms = (PersistentTokenBasedRememberMeServices)rmaf.getRememberMeServices();
rms.setAlwaysRemember( true );
return object;
}
})
.and()
.csrf().disable();
}

Related

Multiple WebSecurityConfig only takes #Order(1)

I have 2 class that extends WebSecurityConfigurerAdapter, one with #Order(1) the other with #Order(2).
I want the first one to filter my APIs starting with /user/** and the other to filter /client/** so I can access localhost:8080/client (to have a login page from Salesforce, then it will allow the client to acess some other /client API).
I have :
#EnableWebSecurity
#Configuration
#Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private OpenLdapAuthenticationProvider openLdapAuthenticationProvider;
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private JwtRequestFilter jwtRequestFilter;
public WebSecurityConfig(OpenLdapAuthenticationProvider openLdapAuthenticationProvider,
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint,
JwtRequestFilter jwtRequestFilter) {
this.openLdapAuthenticationProvider = openLdapAuthenticationProvider;
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.jwtRequestFilter = jwtRequestFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(openLdapAuthenticationProvider);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// CORS
httpSecurity.cors().and().antMatcher("/**").csrf().disable().sessionManagement();
httpSecurity
.csrf().disable().headers().frameOptions().deny()
.and()
.authorizeRequests().antMatchers("/user/login").permitAll()
.antMatchers("/user/**").authenticated()
.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// JWT Filter
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
And the second configuration :
#EnableWebSecurity
#Order(2)
#Configuration
public class WebSecurityConfigSF extends WebSecurityConfigurerAdapter {
#Autowired
MyOAuth2UserService myOAuth2UserService;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// Configuration du CORS
httpSecurity.cors().and().antMatcher("/**").csrf().disable().sessionManagement();
httpSecurity.csrf().disable().headers().frameOptions().deny()
.and().authorizeRequests().antMatchers("/client/**","/client").authenticated()
.and()
.oauth2Login();
}
}
What happens is that when I call /user it works (can access all /user APIs), but when I try /client it doesn't (error Oauth2).
When I switch order, I can access localhost8080:/client and log in into Salesforce no problem but all /user APIs are not filtered, meaning I can access them without any JWT in the header.
Is what I want even possible ?

Multiple WebSecurityConfigurerAdapters: JWT authentication and form login in spring security

I have spring boot app with thymeleaf. I am using spring security formLogin method for security and now I need to add JWT for only some APIs.
#EnableWebSecurity
public class SecurityConfigurations {
#Autowired
UserDetailsServiceImpl userDetails;
#Bean
DaoAuthenticationProvider provider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(encoder());
provider.setUserDetailsService(userDetails);
return provider;
}
#Bean
PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Configuration
#Order(1)
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
DaoAuthenticationProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/api/user/authenticate").permitAll()
.antMatchers("/api/user/**").hasRole("USER")
.and().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
#Configuration
public static class FormLoginConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
DaoAuthenticationProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/admins**").hasAnyRole("SADMIN").antMatchers("/admin/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN").antMatchers("/rest/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN", "USER").antMatchers("/user/**").hasAnyRole("USER")
.anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
.loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).and().csrf().disable().cors();
}
}
}
by doing this JWT is working fine as just I need but the formlogin has stopped and calling "/signInProcess" now give 404:
NOTE: if I change the order and make formLogin #order(1) it works again but of course will not work.
Also I tried to combine them both like this now it is both works fine but the problem with exception handling if the JWT authentication error will return formlogin thymeleaf error page :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/admins**").hasAnyRole("SADMIN").antMatchers("/admin/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN").antMatchers("/rest/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN", "USER").antMatchers("/user/**").hasAnyRole("USER")
.antMatchers("/api/user/authenticate").permitAll()
.antMatchers("/api/user/**").hasRole("USER")
.anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
.loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).and().csrf().disable().cors();
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
any suggestions to make this work. thank you.
Your WebSecurityConfigurerAdapters will process the incoming requests in order.
Since JWTSecurityConfig is annotated with #Order(1) it will process the requests first.
You have not specified a antMatcher for this Adapter, so it will match all requests.
This means that a request will never reach FormLoginConfigurationAdapter, since JWTSecurityConfig matches them all.
If you want JWTSecurityConfig to only apply to certain requests, you can specify an antMatcher in your security configuration.
Below is an example:
#EnableWebSecurity
public class SecurityConfigurations {
#Configuration
#Order(1)
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers(matchers -> matchers
.antMatchers("/api/**") // apply JWTSecurityConfig to requests matching "/api/**"
)
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
#Configuration
public class FormLoginConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.formLogin();
}
}
}
For more details on multiple WebSecurityConfigurerAdapter, you can see the multiple HttpSecurity section in the Spring Security reference docs.
For more details on the difference between authorizeRequests() and requestMatchers(), you can see this Stack Overflow question.

Spring Security - multiple security config requirement - adding basic auth to existing REST API Authentication

I have a REST API with the following security config -
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Value("${auth0.audience}")
private String audience;
#Value("${auth0.issuer}")
private String issuer;
#Override
protected void configure(HttpSecurity http) {
try {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/purch").authenticated()
.antMatchers("/purch2").authenticated();
JwtWebSecurityConfigurer
.forRS256(audience, issuer)
.configure(http);
} catch (Exception ex) {
throw new AuthenticationException(ex.getMessage());
}
}
}
I had added Swagger docs for this REST API and I am trying to protect the swagger docs using HTTP Basic Auth using this example
Hence, I updated the above WebSecurityConfig with #Order(1) and added a new WebSecurityConfig with Order(2) as shown below -
#Configuration
#Order(2)
public class SwaggerSecurity extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_LIST = { //
"**/v2/api-docs", //
"**/configuration/ui", //
"**/swagger-resources", //
"**/configuration/security", //
"**/swagger-ui.html", //
"**/webjars/**" //
};
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(AUTH_LIST).authenticated().and().httpBasic();
}
//#Override
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER")
.and()
.withUser("admin").password(passwordEncoder().encode("admin")).roles("USER", "ADMIN");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
This does not seem to have any effect and is NOT prompting for the basic auth credentials.
I tried several combinations of answers from here, here and here... But I am unable to get this working!
I was able to get the standalone Order(2) spring web security config working as expected, just not in combination with Order(1) security config.
As you can see from my question, I am not an expert with Spring Security and tried debugging this as much as I can! its time I sought for help after losing couple of hours on this. Any help is appreciated. Thank you.
Update based on comments:
I already tried combining the Web Security Config classes similar to what is shown here or here. The outcome is that my original REST API which was protected with "Authorization Header" bearer authentication is now overriden with Basic Auth.
May be, my question is - how do I make sure that one Web security config does not override another?
#Configuration
#Order(2)
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Value("${auth0.audience}")
private String audience;
#Value("${auth0.issuer}")
private String issuer;
#Override
protected void configure(HttpSecurity http) {
try {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/purch").authenticated()
.antMatchers("/purch2").authenticated();
JwtWebSecurityConfigurer
.forRS256(audience, issuer)
.configure(http);
} catch (Exception ex) {
throw new AuthenticationException(ex.getMessage());
}
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_LIST = { //
"/v2/api-docs", //
"/configuration/ui", //
"/swagger-resources", //
"/configuration/security", //
"/swagger-ui.html", //
"/webjars/**" //
};
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/purch/**").permitAll().and()
.authorizeRequests()
.antMatchers(AUTH_LIST)
.authenticated()
.and()
.httpBasic();
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER")
.and()
.withUser("admin").password(passwordEncoder().encode("admin")).roles("USER", "ADMIN");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
}
You seem to have mixed up contents gleaned from different sources. Please try a configuration like below.
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// Firs this configuration will apply since the order is 1
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
// configure auth modes and path matchers
}
}
// Since there is no #Order annotation, this will be checked at last
#Configuration
public static class MvcWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
// configure auth modes and path matchers
}
}
}

Multiple WebSecurityConfigurerAdapter in spring boot for multiple patterns

I am trying to set up multiple WebsecurityConfigurerAdapter for my project where the spring boot actuator APIs are secured using basic auth and all other endpoints are authenticated using JWtAuthentication. I am just not able to make it work together, only the config with the lower order works. I am using Spring Boot 2.1.5.RELEASE
Security Config One with JWT Authenticator
#Order(1)
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_WHITELIST = {
"/docs/**",
"/csrf/**",
"/webjars/**",
"/**swagger**/**",
"/swagger-resources",
"/swagger-resources/**",
"/v2/api-docs"
};
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
.antMatchers("/abc/**", "/abc/pdf/**").hasAuthority("ABC")
.antMatchers("/ddd/**").hasAuthority("DDD")
.and()
.csrf().disable()
.oauth2ResourceServer().jwt().jwtAuthenticationConverter(new GrantedAuthoritiesExtractor());
}
}
The basic Auth config with username/password
#Order(2)
#Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
/* #Bean
public UserDetailsService userDetailsService(final PasswordEncoder encoder) {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(
User
.withUsername("user1")
.password(encoder.encode("password"))
.roles("ADMIN")
.build()
);
return manager;
}
#Bean PasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/actuator/**").hasRole("ADMIN")
.and()
.httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("password").authorities("ADMIN");
}
}
I have been trying to make it work for many days but cannot make both of them work together. If i swap the order, only basic auth works and not the JWT Auth Manager.
I have gone through a lot of SOF Questions, like
[https://stackoverflow.com/questions/40743780/spring-boot-security-multiple-websecurityconfigureradapter][1]
[https://stackoverflow.com/questions/52606720/issue-with-having-multiple-websecurityconfigureradapter-in-spring-boot][1]
[https://github.com/spring-projects/spring-security/issues/5593][1]
[https://www.baeldung.com/spring-security-multiple-entry-points][1]
Nothing seems to be working, is this a known issue in Spring?
To use multiple WebsecurityConfigurerAdapter, you need restrict them to specific URL patterns using RequestMatcher.
In your case you can set a higher priority for ActuatorSecurityConfig and limit it only to actuator endpoints:
#Order(-1)
#Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/actuator/**")
.and()
.authorizeRequests().anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}

Basic and form based authentication with Spring security Javaconfig

I'm trying to define two different security configurations for different url patterns, one of them using form login and another one using basic authentication for an api.
The solution I'm looking for is similar to the one explained here http://meera-subbarao.blogspot.co.uk/2010/11/spring-security-combining-basic-and.html but I would like to do it using java config.
Thanks in advance.
This is the configuration I currently have:
#Configuration
#EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore any request that starts with "/resources/".
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginUrl("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/security_check")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll();
http.logout().logoutUrl("/logout");
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
#Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
rememberMeServices.setCookieName("cookieName");
rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
}
The solution I found was to create another class extending WebSecurityConfigurerAdapter inside the first one, like is described https://github.com/spring-projects/spring-security-javaconfig/blob/master/samples-web.md#sample-multi-http-web-configuration
My solution is as follows:
#Configuration
#EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore any request that starts with "/resources/".
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginUrl("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/security_check")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll();
http.logout().logoutUrl("/logout");
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
#Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
rememberMeServices.setCookieName("cookieName");
rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("api").password("pass").roles("API");
}
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls()
.antMatchers("/api/**").hasRole("API")
.and()
.httpBasic();
}
}
}
I would say by simply doing it. Specify a second line with authorizeUrls() but for your URLs that are needed with basic authentication. Instead of formLogin() use httpBasic()
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginUrl("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/security_check")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll();
http.authorizeUrls().antMatchers("/api/*").hasRole("YOUR_ROLE_HERE").and().httpBasic();
http.logout().logoutUrl("/logout");
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
Something like that should work.
Links: HttpSecurity, HttpBasicConfgurer.
You can solve it by adding .antMatcher("/api/**") just after http in your first config to manage only /api urls. You must have it on the first adapter:
http
.antMatcher("/api/*")
.authorizeRequests()
.antMatchers("^/api/.+$").hasRole("ADMIN")
....
Obviously As Spring updates these tend to fade in their applicability. Running spring cloud starter security 1.4.0.RELEASE this is my solution. My use case was a bit different as I'm trying to secure the refresh endpoint using basic auth for cloud configuration and using a gateway with spring session to pass the authentication in all other instances.
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception {
//try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere
auth.inMemoryAuthentication();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/user").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider customAuthenticationProvider;
#Autowired
protected void configureGlobal2(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/refresh").hasRole("SUPER")
.and()
.csrf().disable();
}
}
}
see the spring security docs for further clarification: Spring Security
The basic idea is that the #Order annotation will dictate what order the auth schemes are run. No #Order means that it is last. If the authorizeRequests() section cannot match on the incoming URL then that configuration will pass and the next one will attempt authentication. This will proceed until authentication succeeds or fails.
The other answers in here are relatively old and for example, I can't find authorizeUrls in Spring 4.
In SpringBoot 1.4.0 / Spring 4, I've implemented the basic/form login like this:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
protected void configure (HttpSecurity aHttp) throws Exception
{
aHttp.authorizeRequests ().antMatchers (("/api/**")).fullyAuthenticated ().and ().httpBasic ();
aHttp.formLogin ()
.loginPage ("/login").permitAll ()
.and ().logout ().permitAll ();
}
}
There may be more ellegant ways of writing this - I'm still working on understanding how this builder works in terms of sequence and so forth. But this worked.

Categories

Resources