Error in Spring Security with status code 404 - java

I'm facing some problems with the spring security /login endpoint
I would like to have a auth api but
when I do any post request to the
localhost:8080/login
this is the response
{
"timestamp":"2020-11-12T17:00:32.691+00:00",
"status":404,
"error":"Not Found",
"message":"",
"path":"/login"
}
This is my configuration class
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApplicationWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private ApplicationUserService applicationUserService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

I found out why!!
I was using this dependency
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
and the right one for my purpose its
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Add formlogin() to your configuration:
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and().formLogin();
You will not need .antMatchers("/login").permitAll().
Your error looks like there is no login-endpoint at all. formLogin() takes care of its generation.

I had a similar problem before, and I solved it by adding a "/" at the end of the URL.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login/").permitAll()
.anyRequest().authenticated();
}

Please check your controller that you are entering the correct path. There is no issue with the Security Configuration.

Related

how to ignore request parameters in spring security

I want to implement AuthenticationFailureHandler with the following configuration:
// Auth failure handler
#Bean
public AuthenticationFailureHandler appAuthenticationFailureHandler() {
ExceptionMappingAuthenticationFailureHandler failureHandler = new ExceptionMappingAuthenticationFailureHandler();
Map<String, String> failureUrlMap = new HashMap<>();
failureUrlMap.put(BadCredentialsException.class.getName(), "/login?error");
failureUrlMap.put(AccountExpiredException.class.getName(), "/login?expired");
failureUrlMap.put(LockedException.class.getName(), "/login?locked");
failureUrlMap.put(DisabledException.class.getName(), "/login?disabled");
failureHandler.setExceptionMappings(failureUrlMap);
return failureHandler;
}
and in class SecurityConfiguration extends WebSecurityConfigurerAdapter I have:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/register", "/confirm").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
// username password
.usernameParameter("username")
.passwordParameter("password")
// success and failure handlers
.successHandler(appAuthenticationSuccessHandler())
.failureHandler(appAuthenticationFailureHandler())
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.invalidateHttpSession(true)
.clearAuthentication(true)
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler())
;
}
with this, all mentioned above is not redirecting to relevant failure URL, but if I remove
.anyRequest()
.authenticated()
then it is being redirected to relevant failure URL, but that is not good practice now the question is how I can configure the configure() to ignore /login?request parameter and implement further logic accordingly?
As I understand, the issue is that urls like "/login?.*" are available only after authorization. According to spring examples, you can exclude paths from authorized access with the following code in Config file:
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}

Spring Security not serving static content

I'm trying to get spring security to allow the serving of static files like .css .js etc. without need to login first.
I've tried creating MVC config with resource handler and changing rules in spring security config, but nothing seems to be working.
MvcConfig.java:
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**")
.addResourceLocations("/assets/");
}
}
SecurityConfig.java:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/assets/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/assets/**");
}
}
When I go to http://localhost:8080/assets/js/particles.min.js I'm expecting it to return the file contents but every time I try links like localhost:8080/assets/* it returns the content of login.html
My assets files
My project files
Supposing that your static files are under src/main/resources:
There are two main pieces to configure:
Implement the WebMvcConfigurer interface to discover your static resources:
#Configuration
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/assets/**")) {
registry.addResourceHandler("/assets/**")
.addResourceLocations("/assets/");
}
}
}
Setup your security configuration to allow static resources (such as CSS, JavaScripts and images) to be publicly accessible:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// Your settings
#Override
protected void configure(HttpSecurity http) throws Exception {
// Your AuthN handlers and filter chain...
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/js/**").permitAll()
.anyRequest().authenticated();
// Logout handler...
}
}
Supposing that you have a CSS file as follows:
src/main/resources/assets/css/layout.css
The web server will make it accessible at:
http://<root_url>:<port>/css/layout.css
Try to change to:
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/assets/").permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
web.ignoring().antMatchers("/assets/**");
The statement above will tell spring security to Ignore any request that starts with “/assets/”. So if i were you, i will remove all the following configuration:
.antMatchers("/", "/assets/**")
.permitAll()
fom the configure(HttpSecurity http) method.

Spring security configuration: enable/disable authentication

my question is like this:
I want to disable and enable authentication through configuration in class which extends WebSecurityConfigurerAdapter. I have test which expects that status is unauthroized if there is no login info provided. This is configuration class:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public static final String USER = "workshop-user";
public static final String ADMIN = "workshop-admin";
#Value("${WORKSHOP_USER_PASSWORD:user}")
private String userPassword;
#Value("${WORKSHOP_ADMIN_PASSWORD:admin}")
private String administratorPassword;
#Value("${features.security.disable}")
private boolean securityDisable;
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder(9);
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(USER)
.password(encoder().encode(userPassword))
.roles("CLIENT_APP")
.and()
.withUser(ADMIN)
.password(encoder().encode(administratorPassword))
.roles("CLIENT_APP", "ADMINISTRATOR");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
if(!securityDisable) {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().permitAll()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
else{
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().authenticated()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
}
and this is my flag from application.properties
features.security.disable = true
I have tried to find another way to do it through configuration but couldn't come to another answer. The thing is that i know it is very simple becaues of if/else statement. One is authenticated and the other permitAll entries. Do you know is there a way that uses "better aproach" which does not pollute code with duplication like this? I tried to look in documentation and other posts but couldn't find any relevant information for me.
You can create two security configurations
#Configuration
#Profile("prod")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().authenticated()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
}
#Configuration
#Profile("test")
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/import").hasRole("ADMINISTRATOR")
.antMatchers("/api-docs/**", "/swagger-resources/**", "/v2/api-docs", "/**/favicon.ico", "/webjars/**", "/api/admin/health").permitAll()
.anyRequest().permitAll()
//replace .permitAll() with .authenticated() for authentiaction
//replace .authenticated() with .permitAll() for disabling security
.and()
.csrf().disable()
.headers().disable()
.httpBasic();
}
}
Run based on your requirement
-Dspring.profiles.active=prod
-Dspring.profiles.active=test

Swagger-ui with Spring security

I have a simple REST application with authentication service. I tried to add swagger and swagger-ui to it, but I can only see my endpoints in /v2/api-docs.
In swagger-ui.html I see only groups of endpoints but I am unable to extend any list.
In chrome debug I see:
Failed to load resource: the server responded with a status of 401 ()
Uncaught TypeError: Cannot read property 'indexOf' of undefined
and on a terminal with a server:
ERROR 10020 --- [nio-5001-exec-3] c.t.r.a.p.JwtAuthenticationEntryPoint : Responding with unauthorized error. Message - Full authentication is required to access this resource
It looks like my config files are missing something, I tried few solutions I found on a web but still nothing work.
This is my code:
pom
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
controller
#RestController
#PreAuthorize("hasRole('USER')")
#RequestMapping(path = "restaurant")
#Api(value="restaurant", description="Example operations for restaurants")
public class RestaurantController {
// endpoints
}
swagger bean
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.tablebooker.restaurantservice.restaurant"))
.paths(PathSelectors.any())
.build();
}
}
SecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//other methods
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/restaurant/**")
.hasRole("USER")
.anyRequest()
.authenticated();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**");
}
}
Any ideas how can I make my configuration work?
For me, there was no issue in traditional Weblogic deployment without any mention of #Override public void configure(WebSecurity web) throws Exception ...Only #Override protected void configure(HttpSecurity http) throws Exception was enough and UI was visible on swagger.
But the same code was not working on Apache Tomcat server so below code was needed ,
#Override public void configure(WebSecurity web) throws Exception { web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**"); // ignore swagger web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs","/webjars/**"); }
/webjars/** being missing in answer by AokoQin.
Answering here because I didn't faced any issues on Weblogic without above code but only Tomcat. I already had resources added via ResourceHandlerRegistry in mvc config.
First you should registry swagger's resources.
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
}
}
Then cause you're using Spring Security,maybe you should shutdown privileges.
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**");
// ignore swagger
web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs");
}
And maybe it's better for you to use swagger which the version is under 2.8.0,or you may have to face to lots of bugs.
The previous answers helped me, but are not quite complete / outdated. I was facing the same issue and it's working now:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs", "/webjars/**");
}
...
}

CrossOrigin annotation doesn't work with spring security

When i enable the spring-boot-starter-security dependency. CORS support doesn't work.
This is my SecurityConfiguration Class:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return authentication -> {
// ...
};
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf()
// Disabling CSRF
.disable()
// Disabling Session Management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
// Adding custom REST Authentication filter
.addFilterBefore(new RestAuthenticationFilter(authenticationManager()), LogoutFilter.class)
// Authorizing requests
.authorizeRequests()
.antMatchers("/", "/frontend/login")
.permitAll()
.antMatchers("/api/**", "/frontend/**")
.authenticated()
.antMatchers("/**")
.permitAll();
}
}
My Controller Class has a CrossOrigin Annotation:
#CrossOrigin
#RequestMapping("/frontend")
#RestController
public class FrontEndController extends BaseController {
I can handle CORS with custom CORS Filter but I want to use just one Annoation.
I found 2 methods for adding CORS support to spring-security enabled spring-boot project. We can add spring-web CorsFilter to security filter chain. The following example belongs to token based authentication project. So we used a custom RestAuthenticationFilter.
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
source.registerCorsConfiguration("/**", config);
http.csrf()
// Disabling CSRF
.disable()
// Disabling Session Management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
// Adding spring-web CORS filter
.addFilterBefore(new CorsFilter(source), LogoutFilter.class)
// Adding custom REST Authentication filter
.addFilterBefore(new RestAuthenticationFilter(authenticationManager()), LogoutFilter.class)
// Authorizing requests
.authorizeRequests()
.antMatchers("/", "/frontend/login")
.permitAll()
.antMatchers("/api/**", "/frontend/**")
.authenticated()
.antMatchers("/**")
.permitAll();
}
}
But in the above example our CrossOrigin annotations in the controllers are redundant. So we should give the ability to control CORS requests to spring-web layer. Therefore we can allow CORS pre-flight (OPTIONS HTTP Methods).
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf()
// Disabling CSRF
.disable()
// Disabling Session Management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
// Adding custom REST Authentication filter
.addFilterBefore(new RestAuthenticationFilter(authenticationManager()), LogoutFilter.class)
// Authorizing requests
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.antMatchers("/", "/frontend/login")
.permitAll()
.antMatchers("/api/**", "/frontend/**")
.authenticated()
.antMatchers("/**")
.permitAll();
}
}
With the help of above configuration we can use both #CrossOrigin annotations and spring-security configuration.

Categories