Spring Security work with Chrome but allow GET from Postman without authorization - spring

i have problem with my spring security implemntation.
I have some basic configuration of UserDetails and UserDetailsService.I've done some Endpoints and some Security Configuration with WebSecurityConfigurerAdapter.
Everything works fine on chrome - if you try to access an secured endpoint security cofniugration redirects you to login form and after login redirects you to yours /api.
But in postman when sending even GET request authorization not working and you can fetch reposonse with all data that sould be availabe only for admin or after authorization.
Here is my Security Configuration
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableWebSecurity
#EnableTransactionManagement
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
AuthenticationSuccessHandler successHandler;
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http./*sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
and().*/
authorizeRequests()
.antMatchers("/api/players").hasAnyRole("ADMIN")
.antMatchers("/api/organizers").hasAnyRole("ADMIN")
.antMatchers("/api/events").permitAll()
.antMatchers("/h2-console/**").permitAll()
.and()
.formLogin()
.successHandler(successHandler)
.permitAll()
.and()
.logout()
.permitAll()
/*.and()
.csrf().disable()*/;
}
#Bean
public PasswordEncoder getPasswordEncoder() {return NoOpPasswordEncoder.getInstance();}
}
and configuration for sample GET endpoint
#RestController
#RequestMapping(value="/api",produces = MediaType.APPLICATION_JSON_VALUE)
#RequiredArgsConstructor
public class UserViewRestContoller {
#NonNull
private final UserQuery query;
#GetMapping(value="/players")
#PreAuthorize("hasRole('ADMIN')")
List<PlayerView> getPlayers() {
return query.listPlayers();
}
#GetMapping(value="players/{userId}",produces = MediaType.APPLICATION_JSON_VALUE)
#PreAuthorize("#userId == authentication.principal.userId or hasRole('ADMIN')")
PlayerDetails getPlayer(#PathVariable UUID userId){
return query.getPlayerDetails(userId);
}
So in browser accesing /api/players you will see
and in POSTMAN

Did you enable global method security?
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
Also I don't see any JWT token implementation in the code. How are you getting admin role and authorize it. Where do you get Admin role?

I have found the problem, it was the definition of antMatchers:
.antMatchers("/api/players")
It only secures /api/players not /api/players/ and /api/players/**.
The proper ant matchers should be:
.antMatchers("/api/players/**").hasAnyRole("ADMIN")

Related

Adding WebSecurityConfig causes a 404 error

When I add in my websecurityconfig file, I get a 404 error. My Websecurityconfig looks like the following. What is annoying is this works locally but not when deployed. I try to hit the head of my application which I would expect to redirect to the login page but it 404's before logging in
package org.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.example.demo.LoginSuccessHandler;
import javax.sql.DataSource;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/abc").hasAnyAuthority("ROLE_one")
.antMatchers("/def").hasAnyAuthority("ROLE_one")
.antMatchers("/ghi").hasAnyAuthority("ROLE_one")
.antMatchers("/jkl").hasAnyAuthority("ROLE_one")
.antMatchers("/mno").hasAnyAuthority("ROLE_one")
.antMatchers("/pqr").hasAnyAuthority("ROLE_one")
.antMatchers("/stu").hasAnyAuthority("ROLE_two")
.antMatchers("/vwx").hasAnyAuthority( "ROLE_two")
.antMatchers("/yza").hasAnyAuthority("ROLE_two")
.antMatchers("/bcd").hasAnyAuthority("ROLE_two")
.antMatchers("/").permitAll()
.and().formLogin()
.successHandler(successHandler)
.and().logout().permitAll();
}
#Autowired private LoginSuccessHandler successHandler;
}
I have tried removing it which gets rid of the 404 error but I need the security to be set up.
A 404 means no page has been found for the url you are trying to access. You have the below setting for your HttpSecurity, meaning anyone can access the root of your application and it looks like no page or index.html is defined for it -
.antMatchers("/").permitAll()
Do you have a different package you deploy and locally you have the a page defined for root url which is why you do not see a 404?
turns out I did not have my application.properties file filled out correctly to connect with my database. fixing that fixed the error.
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=create
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/<application_name>
spring.datasource.username=<username>
spring.datasource.password=<password>
and I needed to use Controller and not RestController everywhere

Why am I redirected directly to login page instead of index.html in Spring?

I am learning to design a login page in Spring Boot. I have not created any file named login, instead I have created an index page but by default it is redirecting me to login page?
package com.main.medipp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#SuppressWarnings("deprecation")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Bean
public UserDetailsService userDetailsService() {
return (UserDetailsService) new CustomUserDetailsService();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/sign_up").permitAll()
.antMatchers("/users").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.usernameParameter("email")
.defaultSuccessUrl("/users")
.permitAll()
.and()
.logout().logoutSuccessUrl("/").permitAll();
}
}
This is the code , i used , please help me with what changes should i make now!!
If you have secured your / endpoint, you will get redirected to the default login page. To fix that, add a rule to the / endpoint to disable authentication and redirect to the index page via a Controller.

POST operation on /logout and getting No mapping for GET /login

I'm trying to perform logout so I send POST on /logout but what I get is:
{
"timestamp": 1590427554418,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/login"
}
I'm using POSTMAN. Despite having error logout perform correclly, because I cannot make any actions on other endpoints when I'm not logged.
The point is when code is uploaded on the server I got timeout:
I thought it might be somehow related.
WebSecurityConfiguration
package odd.jobs.configuration;
import odd.jobs.configuration.authentication.JsonObjectAuthenticationFilter;
import odd.jobs.configuration.authentication.RestAuthenticationFailureHandler;
import odd.jobs.configuration.authentication.RestAuthenticationSuccessHandler;
import odd.jobs.services.user.UserCrudService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.Collections;
#Configuration
#EnableWebSecurity()
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final UserCrudService userService;
private final RestAuthenticationSuccessHandler authenticationSuccessHandler;
private final RestAuthenticationFailureHandler authenticationFailureHandler;
#Autowired
public WebSecurityConfiguration(UserCrudService userService, RestAuthenticationSuccessHandler authenticationSuccessHandler, RestAuthenticationFailureHandler authenticationFailureHandler) {
this.userService = userService;
this.authenticationSuccessHandler = authenticationSuccessHandler;
this.authenticationFailureHandler = authenticationFailureHandler;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll();
http.cors();
}
#Bean
public JsonObjectAuthenticationFilter authenticationFilter() throws Exception {
JsonObjectAuthenticationFilter filter = new JsonObjectAuthenticationFilter();
filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
filter.setAuthenticationFailureHandler(authenticationFailureHandler);
filter.setAuthenticationManager(super.authenticationManagerBean());
return filter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.unmodifiableList(Arrays.asList("*")));
configuration.setAllowedMethods(Collections.unmodifiableList(Arrays.asList("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH")));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(Collections.unmodifiableList(Arrays.asList("Authorization", "Cache-Control", "Content-Type")));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
It seems you used postman but with wrong method type as postman exception implies
Please change postman HTTP method from GET to POST from here :
Hope it should work!
If you want to use POST /logout, configure Spring Security with new AntPathRequestMatcher("/logout", "POST") instead of new AntPathRequestMatcher("/logout") (GET is used by default)

Spring security Azure active directory

Could you please suggest how to increase the timeout. I am getting below exception and this is not coming every time. I have Angular 5 as front end and in back end using Spring Boot 2.0.4 and azure active directory release 2.0.5 (latest).
com.nimbusds.jose.RemoteKeySourceException: Couldn't retrieve remote JWK set: Read timed out.Below is my source code.
Thank in advance.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.microsoft.azure.spring.autoconfigure.aad.AADAuthenticationFilter;
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AADAuthenticationFilter aadAuthFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/ppo/dashboard/dashboardstats").permitAll();
http.authorizeRequests().antMatchers("/api/ppo/dashboard/castats").permitAll();
http.authorizeRequests().antMatchers("/api/ppo/authenticate/privileges").permitAll();
http.authorizeRequests().antMatchers("/api/ppo/**").authenticated();
//http.authorizeRequests().antMatchers("/api/ppo/autenticate/**").permitAll();
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").deleteCookies("JSESSIONID").invalidateHttpSession(true);
//http.authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
http.cors();
// http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/ppo/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}

Thymeleaf tries to authenticate again when loading template from a controller

I want to render a navigation view from a controller using Thymeleaf. However, the navigation should be based on user's authorities so I do not want to exclude it from Spring Security. I therefore use a UrlTemplateResolver:
package it.vertyze.platform.web.controllers;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.templateresolver.UrlTemplateResolver;
#Configuration
public class VZMVCConfig extends WebMvcConfigurerAdapter {
#Autowired
private SpringTemplateEngine templateEngine;
#PostConstruct
public void templateResolverExtension(){
UrlTemplateResolver urlTemplateResolver = new UrlTemplateResolver();
urlTemplateResolver.setOrder(20);
templateEngine.addTemplateResolver(urlTemplateResolver);
}
}
However, when I log into my site, the link does not even get resolved. Instead, I am being redirected to the login page. When I disable the security, I get a template not found error, so the template resolver does not render the controller's output, but when I navigate to it, it renders precisely the HTML I want.
Here is my security config:
package it.vertyze.platform.web.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#Configuration
#EnableWebMvcSecurity
public class VZWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
VZUserDetailsService userDetailsService;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
public PasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
}
And here is where I call the link in the enclosing template:
<div th:replace="${topNavLinks.getHref()}"></div>

Resources