Whitelist Multipart file upload in Spring Security - spring

This is my first post on stackoverflow. Please bear with me. I am having an issue allowing files to be uploaded without needing authorization as it is part of a registration process. I have added the path to my upload in the antMatchers.permitAll() but Spring still throws a 401 Unauthorized when I try to do an upload. Can somebody please assist me? I have been struggling with this for a while now.
This is my security config
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/v0/business-registration", "/api/v0/business-registration/file","/api/v0/admin/register", "/api/v0/admin/login")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

Related

How to disable multiple logins for same user in spring security + spring boot

I have the below spring configuration :-
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((request, response,
authException) ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,
"/api/v2/customers/**").permitAll()
.antMatchers(HttpMethod.OPTIONS,
"/oauth/**").permitAll()
.antMatchers(HttpMethod.GET, "/saml/**").permitAll()
.antMatchers(HttpMethod.GET,
"/api/internal/v2/**").permitAll()
.antMatchers("/**").authenticated()
.antMatchers("/api/admin/**").authenticated()
.and()
.httpBasic()
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(SR);
}
I was expecting sessionManagement().maximumSessions(1) to disable multiple login for the same user. It is working, but first user logout the application, so i am trying login in another browser but it showing This account is already using by someone.
Try this. you are not clearing/ closing the previous session properly.
#EnableWebMvcSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/expired").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/expired")
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry());
}
#Bean
public SessionRegistry sessionRegistry() {
SessionRegistry sessionRegistry = new SessionRegistryImpl();
return sessionRegistry;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
// Register HttpSessionEventPublisher
#Bean
public static ServletListenerRegistrationBean httpSessionEventPublisher() {
return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
}
}
Missing is .expiredUrl("/expired").maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry());

Spring Security Concurrent Session Control

I am trying to restrict user session to one at a time from anywhere. But it doesn't work. When I try to access the application with the same user on two navigator, I have access.
I noticed that when a user connects to the application on two different machines to start printing two different reports, there is an print that comes out instead of the other.
Thanks for help.
My Security config class :
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
/*#Autowired
private DataSource dataSource;*/
private AccessDeniedHandler accessDeniedHandler;
private AuthenticationSuccessHandler authenticationSuccessHandler;
private AuthenticationFailureHandler authenticationFailureHandler;
private UserDetailsService userDetailsService;
#Autowired
public SecurityConfiguration(
#Qualifier("customAccessDeneiedHandler")AccessDeniedHandler accessDeniedHandler,
#Qualifier("customSuccessHandler")AuthenticationSuccessHandler authenticationSuccessHandler,
#Qualifier("customAuthenticationFailureHandler")AuthenticationFailureHandler authenticationFailureHandler,
#Qualifier("customUserDetailsService")UserDetailsService userDetailsService) {
this.accessDeniedHandler = accessDeniedHandler;
this.authenticationSuccessHandler = authenticationSuccessHandler;
this.authenticationFailureHandler = authenticationFailureHandler;
this.userDetailsService = userDetailsService;
}
/* (non-Javadoc)
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder)
*/
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
//super.configure(auth);
auth.userDetailsService(userDetailsService) //auth.userDetailsService(utilisateurDetailsService)
.passwordEncoder(passwordEncoder());
}
//Authorization
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
//.antMatchers("/").permitAll()
.antMatchers("/ajouterassure", "/ajouterattributaire", "/ajouterbeneficiaire", "/ajouterpiecejustificative",
"/creerbordereauemission", "/creerbehorscoordination", "/creerbordereaupaie", "/ajouteravance",
"/creerbeavanceannuelle")
.hasAnyRole("DGA", "DGAA", "DR", "DRA", "CC", "CCA", "CI", "AS", "GUICHET", "CE", "CAP", "ADMIN") //.hasRole("ADMIN")
.antMatchers("/ajoutercentre", "/ajouteretablissementpaie", "/ajoutertypepj", "/ajoutertypedette",
"/ajoutersexe", "/ajoutersituationbeneficiaire", "/ajoutercategoriebeneficiaire",
"/ajoutercategorieattributaire", "/ajouterrevalorisation").hasAnyRole("DGA", "ADMIN") //hasAnyRole("CAP", "ADMIN")
.antMatchers("/payerdecompte").hasAnyRole("CAISSIER", "ADMIN")
.antMatchers("/ajouterutilisateur").hasAnyRole("CI", "ADMIN")
.anyRequest().authenticated()
.and()
//.httpBasic()
.formLogin()
.loginPage("/login")
//.loginProcessingUrl("/login")
.usernameParameter("identifiant")
.passwordParameter("mot_de_passe")
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
//.defaultSuccessUrl("/")
.permitAll()
.and()
.logout().permitAll()
.and()
.sessionManagement() //Session controle concurence access
.maximumSessions(1)
.expiredUrl("/login?expired")
.sessionRegistry(sessionRegistry);
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
//Session controle concurence access
//http.sessionManagement().maximumSessions(1);
}
/* (non-Javadoc)
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.WebSecurity)
*/
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/resources/templates/errors/**", "/static/**", "/css/**", "/images/**", "/var/signatures/**");
//web.ignoring().antMatchers("/static/**");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
#Bean(name = "sessionRegistry")
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Autowired
#Lazy
private SessionRegistry sessionRegistry;
}
[Just in case someone finds it useful.]
Always add hashcode and equals methods in custom UserDetails class along with the below config in the spring security configuration class for the concurrent sessions to work.
protected void configure(HttpSecurity http) throws Exception
{
http.sessionManagement().maximumSessions(1);
}
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher()
{
return new HttpSessionEventPublisher();
}
You need to just add .maxSessionsPreventsLogin(true) after maximumSessions(1) and it stop logging in from other places util session expires here. So your configure method should look like this :-
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
//.antMatchers("/").permitAll()
.antMatchers("/ajouterassure", "/ajouterattributaire", "/ajouterbeneficiaire", "/ajouterpiecejustificative",
"/creerbordereauemission", "/creerbehorscoordination", "/creerbordereaupaie", "/ajouteravance",
"/creerbeavanceannuelle")
.hasAnyRole("DGA", "DGAA", "DR", "DRA", "CC", "CCA", "CI", "AS", "GUICHET", "CE", "CAP", "ADMIN") //.hasRole("ADMIN")
.antMatchers("/ajoutercentre", "/ajouteretablissementpaie", "/ajoutertypepj", "/ajoutertypedette",
"/ajoutersexe", "/ajoutersituationbeneficiaire", "/ajoutercategoriebeneficiaire",
"/ajoutercategorieattributaire", "/ajouterrevalorisation").hasAnyRole("DGA", "ADMIN") //hasAnyRole("CAP", "ADMIN")
.antMatchers("/payerdecompte").hasAnyRole("CAISSIER", "ADMIN")
.antMatchers("/ajouterutilisateur").hasAnyRole("CI", "ADMIN")
.anyRequest().authenticated()
.and()
//.httpBasic()
.formLogin()
.loginPage("/login")
//.loginProcessingUrl("/login")
.usernameParameter("identifiant")
.passwordParameter("mot_de_passe")
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
//.defaultSuccessUrl("/")
.permitAll()
.and()
.logout().permitAll()
.and()
.sessionManagement() //Session controle concurence access
.maximumSessions(1)
.expiredUrl("/login?expired")
.sessionRegistry(sessionRegistry);
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
//Session controle concurence access
//http.sessionManagement().maximumSessions(1);
}

Configure antMatchers in Spring Security

I have this Spring Security configuration in Wildfly server:
#Configuration
#EnableWebSecurity
#Import(value= {Application.class, ContextDatasource.class})
#ComponentScan(basePackages= {"org.rest.api.server.*"})
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthEntryPoint authenticationEntryPoint;
#Autowired
MyUserDetailsService myUserDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(myUserDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/v1/notification")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
I want to configure Spring security to permit all requests send to
http://localhost:8080/war_package/v1/notification but unfortunately I get always Unauthorized. Do you know what is the proper way to configure this?
You need to enable ResourceServer and add configure(HttpSecurity http) there.
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/v1/notification")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
}

Spring security Basic Auth and Form login for the same API

I would like to access all my API's via two authentication mechanisms, Basic Auth & Form login. I know that there are existing questions, but, the answers did not work for me, and my use case is a little bit different.
My config:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
#Configuration
#Order(1)
public static class SecurityConfigBasicAuth extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
public SecurityConfigBasicAuth(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
#Qualifier("customUserDetailsService") UserDetailsService userDetailsService) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
// #Bean authenticationProvider()
// #Bean passwordEncoder()
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin().disable()
.logout().disable();
}
}
#Configuration
public static class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
final private RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler;
final private CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
public SecurityConfigFormLogin(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler,
CustomAuthenticationProvider hashAuthenticationProvider) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.restfulSavedRequestAwareAuthenticationSuccessHandler = restfulSavedRequestAwareAuthenticationSuccessHandler;
this.customAuthenticationProvider = customAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.httpBasic().disable()
.formLogin()
.usernameParameter("id1")
.passwordParameter("Id2")
.loginProcessingUrl("/test/login")
.successHandler(restfulSavedRequestAwareAuthenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
// #Bean myFailureHandler()
}
}
As you can see, I defined two 'WebSecurityConfigurerAdapters', one for Basic Auth, and one for Form login. The Form login is REST compatible (does not redirect, but gives HTTP responses).
The problem is as follows: The first 'WebSecurityConfigurerAdapter' that is loaded works and overrides the second. The above example, makes it possible to use basic auth, but I cannot login on POST '/test/login', I get a:
{
"timestamp": 1534164906450,
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/test/login"
}
Update fixed: the key was to use the 'requestMatchers()', see answer section for solution (as suggested by jzheaux)
Okay, this is how I fixed this:
I configured the Basic Auth configuration as:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/api/**")
.and()
.cors()
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and();
}
If you do not want that the basic authentication returning new cookie with new JSESSIONID, add:
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation()
.migrateSession()
The Form login configuration as:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers(HttpMethod.POST, "/test/login")
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.usernameParameter("id1")
.passwordParameter("id2")
.loginProcessingUrl("/test/login")
.successHandler(authenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
Now, it is possible for me to authenticate via the Form login configuration, and use the cookie session id to call /api/** (configured in the Basic Auth configuration). I can also just use the Basic Auth authentication ofcourse.

Redirect in a filter with Spring Boot

In my configuration Spring Boot WebSecurityConfig have a filter that I need to see if the user has the expired password, if it is enabled on the application ..
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
IdentityService userDetailsService;
#Autowired
AccountFilter accountFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.and()
.authorizeRequests()
.antMatchers("/login", "/recover-credntial",
"/logout", "/resources/**").permitAll()
.and()
.formLogin()
.loginPage("/login").failureUrl("/login?error")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and().addFilterAfter(accountFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder)
throws Exception {
authManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
As you see I have .and().addFilterAfter(Account Filter, UsernamePasswordAuthenticationFilter.class); in the HTTP configuration.
How do I define my filter so that it can perform a redirect to the URL of some of my controller?
I'm using in Java Web Application 'Spring Boot' with Java Configuration, not file xml!
One approach would be as follows using ExceptionMappingAuthenticationFailureHandler. This will mean not using the servlet though.
Configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.failureHandler(authenticationFailureHandler())
.and()
.logout()
.permitAll();
}
Authentication Failure Handler
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
ExceptionMappingAuthenticationFailureHandler exceptionMappingAuthenticationFailureHandler = new ExceptionMappingAuthenticationFailureHandler();
Map<String, String> exMap = new HashMap<String, String>();
exMap.put("org.springframework.security.authentication.CredentialsExpiredException","/loginerror/credentialsexpired.htm");
exceptionMappingAuthenticationFailureHandler.setExceptionMappings(exMap);
return exceptionMappingAuthenticationFailureHandler;
}
Custom User Details Service
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// Check if Password Expired then throw
throw new CredentialsExpiredException("Expired");
}
}

Resources