Setting a DefaultAuthenticationEventPublisher in WebSecurityConfigurerAdapter for Spring Security 5 - spring

I've updated some of our services to Spring Security 5 from a SS 4 version where it had external support for OAuth2. I've been able to update our services for the most part.
Previously our WebSecurityConfigurerAdapter had the following configure function where we set an applicationEventPublisher on a OAuth2AuthenticationProcessingFilter so we can output logs messages about AuthenticationEvents.
But OAuth2AuthenticationProcessingFilter went away in SS5 because OAuth2 support is now directly supported.
Is their an easier way of setting the AuthenticationEventPublisher without creating my own filter and recreating the part of checking authentication to just have it done again by Spring?
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
OAuth2AuthenticationProcessingFilter filter = new OAuth2AuthenticationProcessingFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setStateless(true);
filter.setAuthenticationEventPublisher(
new DefaultAuthenticationEventPublisher(applicationEventPublisher));
filter.afterPropertiesSet();
http.csrf()
.disable()
.anonymous()
.disable()
.httpBasic()
.disable()
.logout()
.disable()
.formLogin()
.disable()
.addFilterBefore(filter, SessionManagementFilter.class)
.antMatcher("/actuator/**")
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS)
.permitAll()
.antMatchers("/actuator/**")
.access("#oauth2.hasScope('auditor')")
.anyRequest()
.authenticated()
.accessDecisionManager(accessDecisionManager);
}
#Bean
public ApplicationListener<AuditApplicationEvent> onEventListener() {
return (AuditApplicationEvent event) -> {
LoggingUtil loggingFormat = new LoggingUtil();
loggingFormat.setUser(event.getAuditEvent().getPrincipal());
loggingFormat.setEvent("Resource Authentication");
loggingFormat.setOutcome(event.getAuditEvent().getType());
loggingFormat.setMessage(
event.getAuditEvent().getData().containsKey("message")
? event.getAuditEvent().getData().get("message").toString()
: "");
String info = loggingFormat.toString();
logger.info(info);
};
}
For our SS 5 we have
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
SessionManagementFilter as;
//TODO how do we setup the authenticationEventPublisher
//filter.setAuthenticationEventPublisher(
// new DefaultAuthenticationEventPublisher(applicationEventPublisher));
http.csrf()
.disable()
.anonymous()
.disable()
.httpBasic()
.disable()
.logout()
.disable()
.formLogin()
.disable()
// .addFilterBefore(filter, SessionManagementFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS)
.permitAll()
.antMatchers("/actuator/**").hasAuthority("SCOPE_auditor")
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer().jwt();
}

Related

Spring Web Security Incorrect Configuration

I am trying to enable basic http authentication for the actuator endpoints while keeping the jwt authentication for the api endpoints. I tried the following configuration for this:
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.anonymous()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/service/actuator/**")
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/service/api/**")
.authenticated()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint);
http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
However, it appears that I can use the JWT token and basic auth as well for the actuator endpoints while no authentication also works for all the api endpoints.
Did I mess up the order? Is there a better way to do this?
the following worked for me
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.anonymous()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/service/actuator/**")
.permitAll()
.and()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/service/api/**")
.authenticated()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint);
http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
}

Disable multiple logins for same user in spring boot

HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
protected void configure(final HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers(
"/getUser",
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/swagger-ui.html",
"/webjars/**"
,"/**/user/reset-password-first-attempt"
,"/**/user/forget-password-email"
,"/**/user/forget-password"
).permitAll()
.mvcMatchers(
"/css/**",
"/images/**",
"/fonts/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(this.successHandler())
.failureHandler(this.customAuthenticationHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler())
.and()
.exceptionHandling()
.accessDeniedHandler(this.accessDeniedHandler())
.authenticationEntryPoint(this.authenticationEntryPoint())
.and()
.sessionManagement()
.maximumSessions(1).maxSessionsPreventsLogin(true);}
this is the code that i am using to disable multiple logins. i saw some several examples and i tried most of them. but those didnt work in my application. is there any other solution or is there any wrong with my code. thanks in advance

Why the character ';' is added the end of request in OAuth2

There are Authorization Server(UAA) and Resource Server and Gateway applications that have been working correctly. The scenario for authentication is authorization_code. In the first time after authentication, the end of request is added ;jesessionid=[value], so its result is exception from HttpFirewall of Gateway application, because of having ';' in the request.
My question is that what is it and why jessionid is added the end of request? and how is it adaptable with HttpFirewall.
I have found a way around but I know it has some risks. It is like this:
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirwall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowSemicolon(true);
return firewall;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.headers().cacheControl().disable()
.and()
.headers()
.cacheControl()
.disable()
.frameOptions()
.sameOrigin()
.and()
.httpBasic().disable()
.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.mvcMatchers("/uaa/**", "/login**", "/favicon.ico", "/error**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.httpFirewall(allowUrlEncodedSlashHttpFirwall());
}
As above configuration, the ; is skipped but it is not right and it has some risks.
What is the correct way and config to solve this problem?

How to log out sucessfully

My login page is http://localhost:8080/nradmin/welcome
and my home page (after successful log in) is http://localhost:8080/nradmin/home
I'd like to log out and not anymore be able anymore to access any other page like the home page but only the welcome (login) page. If I type http://localhost:8080/nradmin/home on the browser after logout I continue to have access to the home page without logging in.
I've implemented the following methods overriden from the abstract class WebSecurityConfigurerAdapter:
#Override
protected void configure(HttpSecurity http) throws Exception { http
.authorizeRequests()
.antMatchers("/welcome").permitAll()
.antMatchers("/home", "/account/**", "/price/**").hasRole("ADMIN")
.antMatchers("/home", "/account/**", "/price/**").access("hasRole('ROLE_ADMIN')")
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/welcome")
.defaultSuccessUrl("/home")
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/welcome")
.logoutUrl("/welcome")
.deleteCookies()
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/welcome")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() .withUser("username").password(passwordEncoder().encode("12345")).roles(LoginDataConstants.ROLE_ADMIN)
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Does anyone have an idea how to do it?
I guess it may be due to having the same url in the methods logoutUrl and logoutSuccessUrl.
I suggest you to change logoutUrl to other path, for example just /logout and then try to perform the logout hitting that url. It should complete the logout task and the redirect to the logoutSuccessUrl, which is /welcome
Add CSRF
Reference from spring docs.
Will perform logout with the URL /logout is requested with any HTTP method
#Override protected void configure(HttpSecurity http) throws Exception {
http.
logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
}
You can also reference a good example on stack overflow using this same method here
When I had this issue I used this line
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
Where
.logoutSuccessUrl("/login") was the page the user will be redirected to.
You could re-factor your code to something like this
#Override
protected void configure(HttpSecurity http) throws Exception { http
.authorizeRequests()
.antMatchers("/welcome").permitAll()
.antMatchers("/home", "/account/**", "/price/**").hasRole("ADMIN")
.antMatchers("/home", "/account/**", "/price/**").access("hasRole('ROLE_ADMIN')")
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/welcome")
.defaultSuccessUrl("/home")
.and()
.logout()
.and() // This section is re-factored.
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/welcome").deleteCookies("JSESSIONID") //Or try .logoutSuccessUrl("/nradmin/welcome")
.invalidateHttpSession(true)
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/welcome")
.and()
.sessionManagement()
.sessio hinCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
Update : This is a modified version. This is essentially what I use in my project except for this portion:
.and()
.exceptionHandling()
.accessDeniedPage("/welcome")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
So, I believe it should work; otherwise, I believe it may be a setup issue/configuration that resides somewhere else in your project. Please try the below example.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/nradmin/welcome", "/home", "/account/**", "/price/**").hasRole("ADMIN")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/nradmin/welcome")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/nradmin/welcome").deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/nradmin/welcome")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}

questions for spring security config

I`ve tried to config Spring Security.
This is my sucurity config.
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.antMatchers("/api/**", "/denied**").permitAll()
.anyRequest().denyAll()
.and()
.exceptionHandling().accessDeniedPage("/denied")
.and()
.csrf().disable();
// #formatter:on
}
When I access url "localhost:8080/admin", I expect "/denied" page.
But it shows default 403 page provided spring security.
Is there any problem my configuration?
Update:
Change .anyRequest().denyAll() to .anyRequest().authenticated()
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.antMatchers("/api/**", "/denied**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedPage("/denied")
.and()
.csrf().disable();
// #formatter:on
}
If u need to use requiresSecure(), just add .requiresChannel().anyRequest().requiresSecure().and() after .and()

Resources