Spring security: REST with MVC - java

Im begginer in spring security! I have MVC + REST application written on Spring Boot. I have a code for securing my app:
#Configuration
#EnableWebSecurity
#EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {
#Bean
#Order(1)
public SecurityFilterChain apiFilterChain(
HttpSecurity httpSecurity) throws Exception {
return httpSecurity.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(
SessionCreationPolicy.STATELESS).and()
.securityMatcher("/api/**")
.authorizeHttpRequests(authorize ->
authorize.requestMatchers("/api/user/**").hasRole("ROOT")
.anyRequest().authenticated())
.httpBasic(basic ->
basic.authenticationEntryPoint(
(request, response, exp)->
response.setStatus(401)))
.build();
}
#Bean
public SecurityFilterChain formFilterChain(
HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.authorizeHttpRequests(authorize ->
authorize.requestMatchers("/login*", "/web-res/**").permitAll()
.anyRequest().authenticated())
.formLogin(form ->
form.loginPage("/login")
.failureUrl("/login?error"))
.logout(logout ->
logout.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
.deleteCookies("JSESSIONID"))
.build();
}
}
Thats work fine, but when i trying getting data from MVC (that was authorized with formFilterChain) with ajax to /api/** (that controls by apiFilterChain) - i need use basic auth.
How i can fix that to take data from /api/** with authorized by form login method?

My method after reading documentation:
#Configuration
#EnableWebSecurity
#EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {
private final Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>
.AuthorizationManagerRequestMatcherRegistry> securedRequests = authorize -> {
authorize.requestMatchers("/login*", "/web-res/**").permitAll()
.requestMatchers("/api/user/**").hasRole("ROOT")
.anyRequest().authenticated();
};
#Bean
#Order(1)
public SecurityFilterChain apiFilterChain(
HttpSecurity httpSecurity) throws Exception {
return httpSecurity.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(
SessionCreationPolicy.NEVER).and()
.authorizeHttpRequests(securedRequests)
// checking for "Authorization" header
.securityMatcher(request ->
request.getHeader("Authorization") != null)
.httpBasic(basic ->
basic.authenticationEntryPoint(
(request, response, exp)->
response.setStatus(401)))
.build();
}
#Bean
public SecurityFilterChain formFilterChain(
HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.authorizeHttpRequests(securedRequests)
.formLogin(form ->
form.loginPage("/login")
.failureUrl("/login?error"))
.logout(logout ->
logout.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
.deleteCookies("JSESSIONID"))
.build();
}
}
First filter will working if request has header "Authorization"
// checking for "Authorization" header
...
.securityMatcher(request ->
request.getHeader("Authorization") != null)
...
If header "Authorization" not found - then executing formFilterChain.

Related

Query on Http Basic Authentication in Spring Security

Being new to Spring security, was trying a simple REST GET call with HTTP Basic Authentication. Scenario :
For correct usr/pwd, gives http ok. Then I change only the pwd. For incorrect pwd also it gives 200 ok. And the server log says :
o.s.s.w.a.i.FilterSecurityInterceptor : Did not re-authenticate
Question - how do I reauth every time and send http 401 unauthorized to the client?
Code :
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
log.info("In securityFilterChain with HttpSecurity");
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()//Customizer.withDefaults())
.authenticationEntryPoint(authEntryPoint);
return http.build();
}
#Bean
public UserDetailsService initUser() {
UserDetails user = User.builder()
.username("basic")
.password(encoder.encode("basic123"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
#Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(initUser())
.and()
.build();
}

Spring Boot fails to boot up after add #EnableWebSecurity

I'm trying to add security headers to my Spring Boot application.
It already had a Java class with multiple filters extending from WebSecurityConfigurerAdapter. But whenever I try to add the annotation #EnableWebSecurity to this class or even with a new custom one I always receive NullPointerException for the bean springSecurityFilterChain.
Changing the order to add some filters seems to solve this problem but whenever I try to enter the app I can't because it seems the HTTP Authorization header field is null (which I recover inside one of my custom filters).
Do any have a clue of what is happening?
EDIT: After some days of cheking this I noted that the Authorization header was not the problem as the code is built to let that call enter without it and before any change it was already sent without header.
Still with the same call and the changes I'm receiving a 403 FORBIDDEN (before any change this call was receiving 302 FOUND).
This happens before even reaching the controller and I can only get debugging until the filter.
As there were no other changes in the code except the #EnableWebSecurity and the way to add one filter I suspect the problem is around here but i can't find what is causing it exactly.
EDIT: I'm adding the code in case anyone need to see it.
This is the class that has the multiple filters:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity //ADDED THIS ONE
public class MultipleEntryPointsSecurityConfig {
#Configuration
#Order(1)
public class OauthSecurityAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private OAuth2RestTemplate restTemplate;
#Bean
public CustomFilterOneFilter customFilterOneFilter() {
final CustomFilterOneFilter filter = new CustomFilterOneFilter ("/testLogin");
filter.setRestTemplate(restTemplate);
return filter;
}
#Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<OAuth2ClientContextFilter>();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.antMatcher("/login")
.cors()
.and()
.csrf().disable()
//CHANGED THIS
// .addFilterAfter(openIdConnectFilter(), OAuth2ClientContextFilter.class)
//FOR THESE TWO
.addFilterAfter(new OAuth2ClientContextFilter(), AbstractPreAuthenticatedProcessingFilter.class)
.addFilterAfter(openIdConnectFilter(), OAuth2ClientContextFilter.class)
.httpBasic()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/testLogin"))
.and()
.logout()
.logoutSuccessUrl("/logout")
.permitAll()
.and()
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated();
// #formatter:on
}
}
#Configuration
#Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public JwtSecurityFilter authenticationJwtTokenFilter() {
return new JwtSecurityFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.cors()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated();
http
.addFilterAfter(new UsernamePasswordAuthenticationFilter(), AbstractPreAuthenticatedProcessingFilter.class)
.addFilterAfter(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//CHANGED THE BELOW ONE FOR THE TWO ABOVE
//http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
#Configuration
#Order(3)
public static class PublicConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/**").permitAll()
.antMatchers("/api/v1/login/**").permitAll();
}
}
}
And this is the custom filter where I try to recover the Authorization header:
#Component
public class JwtSecurityFilter extends OncePerRequestFilter{
#Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
//FAILS HERE!
if(authHeader == null || !authHeader.startsWith("Bearer ")) {
SecurityContextHolder.getContext().setAuthentication(null);
chain.doFilter(request, response);
return;
}
...
}
}

Swagger POST return 403 Forbidden Spring boot Spring security

i am getting 403 status Forbidden in swagger only for POST method request.
I tried all spring security cfg to solve this but only works on the GET methods.
I am using spring boot, spring security and swagger.
¿ Could someone please help me ?
Here's swagger cfg:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
And here's the spring security cfg:
#Configuration
#EnableWebSecurity
public class SecurityCFG extends WebSecurityConfigurerAdapter{
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = encoder();
auth
.inMemoryAuthentication()
.withUser("carlos")
.password(encoder.encode("admin123"))
.roles("USER")
.and()
.withUser("carlos2")
.password(encoder.encode("admin123"))
.roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html",
"/webjars/**" ,
/*Probably not needed*/ "/swagger.json")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs/**");
web.ignoring().antMatchers("/swagger.json");
web.ignoring().antMatchers("/swagger-ui.html");
web.ignoring().antMatchers("/swagger-resources/**");
web.ignoring().antMatchers("/webjars/**");
}
}
Thank for reading!
I had a similar issue the other week, this is how i got mine to work, i needed to add a bunch more matchers than i thought and add in the csrf disable but it seems to work ok.
#Bean(name="configure")
#Conditional(DevConditional.class)
public SecurityWebFilterChain configureDev(ServerHttpSecurity http) throws Exception {
return http
.csrf().disable()
.authorizeExchange()
.pathMatchers("/v2/api-docs").permitAll()
.pathMatchers("/configuration/ui").permitAll()
.pathMatchers("/swagger-resources/**").permitAll()
.pathMatchers("/configuration/security").permitAll()
.pathMatchers("/swagger-ui.html").permitAll()
.pathMatchers("/swagger-ui/*").permitAll()
.pathMatchers("/webjars/**").permitAll()
.pathMatchers("/v2/**").permitAll()
.and().cors()
.and().oauth2ResourceServer()
.jwt().and().and().build();
}
I got this ".csrf().disable()" answer from : Spring boot with WebFlux always throw 403 status in tests

Webflux : ServerAuthenticationEntryPoint - ReactiveSecurityContextHolder is empty

I was trying to get SecurityContext::getAuthentication as follow:
#Component
public class AuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
#Override
public Mono<Void> commence(ServerWebExchange serverWebExchange, AuthenticationException authException) {
return ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.flatMap(a -> { return Mono.empty();});}
however, the context is empty. looks like the reactive chain was broken.
here is a snippet of the securityconfig:
#EnableReactiveMethodSecurity
public class SecurityConfig {
private AuthenticationEntryPoint authenticationEntryPoint;
#Bean
public SecurityWebFilterChain configure(final ServerHttpSecurity http) {
http
.csrf().disable()
.authorizeExchange()
...
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
...
return http.build();
}
wonder if there is anything missing or if there is another way to get the context within the authenticationEntryPoint.

spring security: BadCredendtials exception not handled by the chain and not returning 401

Good morning,
I was following this tutorial, in order to make spring security works with jwt token.
* my environment versions*
spring boot : 2.0.1 RELEASE
Spring security config
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.cors().configurationSource(request -> getCorsConfiguration())
.and()
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(provider)
.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS)
.authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
}
#Bean
TokenAuthenticationFilter restAuthenticationFilter() throws Exception {
final TokenAuthenticationFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
return filter;
}
#Bean
SimpleUrlAuthenticationSuccessHandler successHandler() {
final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
successHandler.setRedirectStrategy((HttpServletRequest request, HttpServletResponse response, String url) -> {
// no redirection strategy
});
return successHandler;
}
/**
* Disable Spring boot automatic filter registration.
*/
#Bean
FilterRegistrationBean disableAutoRegistration(final TokenAuthenticationFilter filter) {
final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
#Bean
AuthenticationEntryPoint forbiddenEntryPoint() {
return new HttpStatusEntryPoint(FORBIDDEN);
}
Context:
Token authentication filter is throwing BadCredentialsException, in case the token does not match expectation.
Expected behaviour:
spring chain will catch this error and return 401 error back to the user.
Current Behaviour:
the server crashes with 500 error. the error is not handled by spring security.

Categories