I'm trying to add web security in spring but I don't want the filter to apply to certain things. How is that done in java?
Overall, what I want to do is this:
/ and /login should not show a HTTP Basic authentication prompt to login, while everything else should go through the filter and pop up a login prompt window.
Through various example I found through spring I was able to come up with this as for a start but it obviously doesn't work:
#Configuration
#EnableWebMvcSecurity
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().antMatcher("/").authorizeRequests().anyRequest().permitAll();
http.csrf().disable().antMatcher("/**").authorizeRequests().anyRequest().hasRole("ADMIN").and().httpBasic();
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
}
Rewrite your configure(HttpSecurity http) method like the following:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.anyRequest().hasRole("ADMIN")
.and()
.csrf()
.disable();
}
"/" and "/login" SHOULD NOT show a httpbasic authentication prompt to
login, while everything else SHOULD go through the filter and pop up a
login prompt window.
If you seriously planning to use HTTP Basic, I guess you wouldn't need a separate /login handler, since browser-based clients can use the default browser based pop up and other clients can send HTTP Basic requests through Authorization header.
Related
I have a Spring Boot application with Spring Security configured as follows:
#EnableWebSecurity
public class AppSecurityConfiguration {
#Configuration
#Order(Constants.DEVSTACK_SECURITY_ORDER - 1)
static class WebHttpSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* Configures Application WebSecurity which involves the full Security pipeline (?)
*
* #param web WebSecurity
*/
#Override
public void configure(WebSecurity web) {
web.ignoring()
// Allow requests to HealthCheck Endpoint without Bearer Token
.antMatchers("/api/healthCheck", "/v3/api-docs/**", "/configuration/**", "/swagger-ui.html",
"/swagger-ui/**", "/webjars/**", "/api/v1/browser/**", "/swagger-resources/**")
// Allow OPTIONS request without Bearer Token (for pre-flight requests)
.antMatchers(HttpMethod.OPTIONS, "/**");
}
/**
* Configures HttpSecurity
*
* #param http HttpSecurity
* #throws Exception if an error occurs
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//Authorize INSECURE request to this endpoint (so Swagger can pull the data)
.antMatcher("/v2/api-docs")
.authorizeRequests()
.anyRequest()
.permitAll();
}
}
}
Here in this Configuration class I'm ignoring certain endpoints from passing through Spring Security, most of them are for Swagger documentation so you can ignore it.
My problem is inside the configure(HttpSecurity) method. I don't know why but the way I wrote it it just works. When I try to understand what I just configured I read it like this:
For every request to "/v2/api-docs", authorize the requests
For any other requests, permit them all.
Now I want to add a Custom Filter to the Spring Security Filter Chain.
This is the Filter class:
public class MyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
log.debug("MyFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
Whenever I try to add the filter to my HttpSecurity, I end up with Spring Security setting my Principal to 'anonymousUser'.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new MyFilter(), WebAsyncManagerIntegrationFilter.class);
}
I've tried many different things like:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new MyFilter(), WebAsyncManagerIntegrationFilter.class)
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.disable()
.formLogin()
.disable();
}
But it still returns 'anonymousUser' when I try to get the user's Principal.
I don't know why having it configured like this works?!?!
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//Authorize INSECURE request to this endpoint (so Swagger can pull the data)
.antMatcher("/v2/api-docs")
.authorizeRequests()
.anyRequest()
.permitAll();
}
Can someone enlighten me and explain me like i'm five years old? Sometimes I just think I'm too stupid to understand Spring
Thanks
It should be:
http
.authorizeRequests()
.antMatchers("/v2/api-docs")
.permitAll()
.and()
.authorizeRequests().antMatchers("/**").authenticated()
The Rest endpoint is protected with OAuth but for some reason, I can hit /users/user without the token. Please let me know what is missing.
In my resource class, I have mentioned below configurations to protect the endpoint.
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/users/**")
.access("hasRole('ADMIN')")
.and()
.exceptionHandling()
.accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
Maybe need more information, but try this:
#Override public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users*//**").access("hasRole('ADMIN')")
.and().exceptionHandling()
.accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
or original pattern "/users/**"
I have the following config method for my WebSecurityConfig that extends WebSecurityConfigurerAdapter:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.and()
.authorizeRequests()
.antMatchers("/signup").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(
new JWTAuthenticationFilter(userDetailsServiceBean()),
UsernamePasswordAuthenticationFilter.class);
}
JWTAuthenticationFilter actually filters requests received on all endpoints, and checks if they have the correct JWT authentication token in their headers.
I don't expect this filter to execute on requests made to the /login endpoint ! Is there a way to ignore the filter for special endpoints ? (here /login and /signup).
Is there any good reason to keep this filter executing on requests made to all endpoints including login and signup ?
You can try adding the following
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/login**", "/signup**");
}
I am trying to give role based authorization for resources. It works with out roles if I do it like
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/hello"),
new AntPathRequestMatcher("/user")
))
.authorizeRequests()
.anyRequest().access("#oauth2.hasScope('read')");
}
#Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.resourceId("openid");
}
}
If I use below method it won't work for test resources.
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.requestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/hello"),
new AntPathRequestMatcher("/user")
))
.authorizeRequests()
.antMatchers("/test").hasRole("ADMIN")
.anyRequest().access("#oauth2.hasScope('read')");
}
It completely ignores token based authorization. How can I implement this? Another issue I am getting is if I remove requestMatcher block, Oauth client can not get the authorization code, after submitting user credentials to login form it reloads login page again. But with the previous block of code it works fine. What I am doing wrong here?
Here is my security configuration class
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/img/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.defaultSuccessUrl("/hello")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout");
}
}
When you use roles in spring you have to use prefix ROLE (for example ROLE_ADMIN) to make it work with default settings.
I want to enable the use of "ROLE_ANONYMOUS" to allow anonymous access to some urls in my app. And I used the below configuration.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestCache()
.requestCache(new NullRequestCache()).and()
.anonymous().authorities("ROLE_ANONYMOUS").and()
.exceptionHandling().and()
.servletApi().and()
.headers().cacheControl().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/profile/image").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/resources/**").permitAll()
//.antMatchers(HttpMethod.GET, "/login/**").permitAll()
//.antMatchers(HttpMethod.GET, "/location/**").permitAll()
.anyRequest().authenticated()/*.and()
.apply(new SpringSocialConfigurer())*/;
// custom Token based authentication based on the header previously given to the client
//.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
}
My controller looks like:
#RestController
#RequestMapping(value="/login", produces="application/json")
public class LoginController {
#Secured( value={"ROLE_ANONYMOUS"})
#RequestMapping(method=RequestMethod.GET)
public String get(){
return "hello";
}
}
But when I try to hit "/login" I get 403 access denied error.
Please help me how I can enable annotation based anonymous access.
This should solve your issue.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.formLogin().loginPage("/login").permitAll()
...
But if you prefer not to use permitAll but to stick to anonymous roled user (it would be the same effect on both situation but yet if that's wht you prefer) then try this in the controller.
#Secured("ROLE_ANONYMOUS")
#RequestMapping(method=RequestMethod.GET)
public String get(){
...
As Faraj Farook wrote, you have to permit access to your login page URL. You commented the relevant line out:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.authorities("ROLE_ANONYMOUS")
.and()
.headers()
.cacheControl()
.and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/profile/image").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers(HttpMethod.GET, "/login/**").permitAll()
.anyRequest().authenticated()
}
But if you prefer not to use permitAll() you could use hasAuthority("ROLE_ANONYMOUS"). In this case you don't need to annotate your method with
#Secured( value={"ROLE_ANONYMOUS"}).