I have /my-app/login url and I want to permitAll() for this URL. But this page under /my-app/** pattern which permit access only for registered user.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/**").access("hasRole('USER')")
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
How to do it?
Add .antMatchers("/my-app/login").permitAll() BEFORE .antMatchers("/my-app/**")... . The request matchers are stored in an list (ordered by the order in which they are defined), and Spring security will use the first rule thats matchers match to the current request. So put the most specific first and the common rules afterwards.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/login").permitAll()
.antMatchers("/my-app/**").access("hasRole('USER')")
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
If my-app is the name of your application, and therefore the url that is by your application server (Tomcat) to map the url to the application, then you have to ommit it in the antMatcher because the antMatcher is configured "only" by the application relative url: /my-app/login become /login and /my-app/** become /**
add .anyRequest().permitAll() as last "matcher" of authorizeRequests()
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/**").access("hasRole('USER')")
.anyRequest().permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
But to be honest: you use some kind of black listing (allow all URLs except some black listed) - and this is not the recommended way (from some security perspective). Because if you forget to add or misspell one URL that should been protected, then it is accessible for every body. The more secure way is to deny every url and allow only some (white list).
Related
I'm trying to use Spring Security in my project, here is the code:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
//super.configure(auth);
//auth.inMemoryAuthentication().withUser("admin").password("1111").roles("USER");
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username, password, 1 from users where username=?")
.authoritiesByUsernameQuery("select users_username, roles_id from roles_users where users_username=?")
.rolePrefix("ROLE_");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
http
.httpBasic();
http
.authorizeRequests()
.anyRequest().authenticated();
http
.authorizeRequests()
.antMatchers("/users/all").hasRole("admin")
.and()
.formLogin();
http
.exceptionHandling().accessDeniedPage("/403");
}
Here is the problem:
Imagine we have two users (one with the user role and the other one with the admin role) in our database one admin and the second is a user, the problem is when I connect as user (which has only user role) it can access to admin resources (and this is not the expected behavior).
I think the problem in this query:
"select username, password, 1 from users where username=?"
According that username is the primary key?
If anyone has an idea how I can resolve this problem?
Your first matcher anyRequest() is always applied, because the order of matchers is important, see HttpSecurity#authorizeRequests:
Note that the matchers are considered in order. Therefore, the following is invalid because the first matcher matches every request and will never get to the second mapping:
http.authorizeRequests().antMatchers("/**").hasRole("USER").antMatchers("/admin/**")
.hasRole("ADMIN")
Your modified and simplified configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/users/all").hasRole("admin")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling().accessDeniedPage("/403");
}
The problem is with the ordering of your rules when you configure your HttpSecurity. What's happening is when the request comes in and hits the
authorizeRequests().anyRequest().authenticated()
and since the user is authenticated it never makes it to the
.antMatchers("/users/all").hasRole("admin")
Here is an example of how you can configure it:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/public").permitAll()
.antMatchers("/user").hasRole("USER")
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling().accessDeniedPage("/403");
}
It uses the chain of responsibility pattern. It will go through the chain of rules until it finds a rule that matches. Any rules that come after the rule that matches are never reached. Generally when writing the rules for authenticated requests, the more specific rule will come first.
I use spring boot 2.6.7 with spring security and thymeleaf
I put my favicon in
resources/static/
I see only the icon when the user is connected
I added this code to permit all
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers(HttpMethod.POST, "/printdownload**").permitAll()
.antMatchers(
"/",
"/help**",
"/css/**",
"/js/**",
"**/favicon.ico",
"/img/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.successHandler(customAuthenticationSuccessHandler)
.and()
.logout();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "**/favicon.ico");
}
But get same result.
If i try to display: http://localhost:8080/favicon.ico
that return me to the login page
You need to use /**/favicon.ico instead of **/favicon.ico.
According to the Javadoc of Spring's AntPathMatcher:
A pattern and a path must both be absolute or must both be relative in order for the two to match. Therefore it is recommended that users of this implementation to sanitize patterns in order to prefix them with "/" as it makes sense in the context in which they're used.
That you can use ** as short-cut for /** to match all requests is a special case. It doesn't work if ** is used at the beginning of a pattern.
I'm trying to use Spring Security in my project, here is the code:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
//super.configure(auth);
//auth.inMemoryAuthentication().withUser("admin").password("1111").roles("USER");
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username, password, 1 from users where username=?")
.authoritiesByUsernameQuery("select users_username, roles_id from roles_users where users_username=?")
.rolePrefix("ROLE_");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
http
.httpBasic();
http
.authorizeRequests()
.anyRequest().authenticated();
http
.authorizeRequests()
.antMatchers("/users/all").hasRole("admin")
.and()
.formLogin();
http
.exceptionHandling().accessDeniedPage("/403");
}
Here is the problem:
Imagine we have two users (one with the user role and the other one with the admin role) in our database one admin and the second is a user, the problem is when I connect as user (which has only user role) it can access to admin resources (and this is not the expected behavior).
I think the problem in this query:
"select username, password, 1 from users where username=?"
According that username is the primary key?
If anyone has an idea how I can resolve this problem?
Your first matcher anyRequest() is always applied, because the order of matchers is important, see HttpSecurity#authorizeRequests:
Note that the matchers are considered in order. Therefore, the following is invalid because the first matcher matches every request and will never get to the second mapping:
http.authorizeRequests().antMatchers("/**").hasRole("USER").antMatchers("/admin/**")
.hasRole("ADMIN")
Your modified and simplified configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/users/all").hasRole("admin")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling().accessDeniedPage("/403");
}
The problem is with the ordering of your rules when you configure your HttpSecurity. What's happening is when the request comes in and hits the
authorizeRequests().anyRequest().authenticated()
and since the user is authenticated it never makes it to the
.antMatchers("/users/all").hasRole("admin")
Here is an example of how you can configure it:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/public").permitAll()
.antMatchers("/user").hasRole("USER")
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling().accessDeniedPage("/403");
}
It uses the chain of responsibility pattern. It will go through the chain of rules until it finds a rule that matches. Any rules that come after the rule that matches are never reached. Generally when writing the rules for authenticated requests, the more specific rule will come first.
URL patter with /login should go through the LoginFilter where the user id and password is validated - working fine
URL pattern with /users/register should not go through any of the filer but it is always passing through the JWTAuthentication filter - not working fine
All other URL pattern should go through the JWTAuthentication filter for authorization - working fine
Below is my code for Security Configuration. Kindly help me with what I am missing in this code. How do I configure the filter such that JWT authentication happens for the URL pattern other than /login and /register
Spring-security-core:4.2.3, spring-boot:1.5.4
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.antMatchers(HttpMethod.POST, "/users/register").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new LoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new NoLoginAuthenticationFilter("/users/register"), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter("/**", authenticationManager()),
UsernamePasswordAuthenticationFilter.class);
}
What you want is to ignore certain URLs.
For this override the configure method that takes WebSecurity object and ignore the pattern.
Try adding below method override to your config class.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/users/register/**");
}
I work on a JEE project, using the Spring Boot framework.
For the authentification, I use Spring Security, and I specified the pages in my template.
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/token", "/index", "/index.html", "/main", "/main.html", "/main2", "/main2.html", "/recent1", "/recent1.html", "/recent2", "/recent2.html").hasRole("USER");
http
.csrf()
.disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/index");
http
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
The issue is that when I run the application and I wrote the URL with uppercase letters like: localhost:8080/INDEX.HTML or I add two letters localhost/index.httml, the page does appear without authantification.
If I understand correctly, here is the desired logic:
/login does not need to be secured by Spring Security (no roles are required)
All the other pages have to be secured with "USER" role.
To implement this, you could try the following:
#Override
public void configure(WebSecurity web) throws Exception {
// configuring here URLs for which security filters
// will be disabled (this is equivalent to using
// security="none")
web
.ignoring()
.antMatchers(
"/login"
)
;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().hasRole("USER");
http.csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/index");
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
So item 1 (no security on /login) is moved to configure(WebSecurity), and item 2 is left in the original configure(HttpSecurity).