i am trying to implement a simple Spring security project but I am facing an issue where the behavior of http.authorizeRequests().anyRequest().authenticated(); is not understandable. what i expect from this method is to prevent all incoming requests until the user is authenticated but in my case all the requests are go through and no interception happened. the normal behavior of preventing request to go through took a place when I un-comment the lines which include hasAnyAuthority.
Below is My security configs
#Override
protected void configure(HttpSecurity http) throws Exception {
CustomAuthFilter customAuthFilter = new CustomAuthFilter(authenticationManagerBean());
//override behavior of url for our api
customAuthFilter.setFilterProcessesUrl("/api/login");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/api/login/**").permitAll();
http.authorizeRequests().antMatchers("/register/**").permitAll();
/////http.authorizeRequests().antMatchers(GET,"/api/users/").hasAnyAuthority("ROLE_USER");
//////http.authorizeRequests().antMatchers(POST,"/api/user/save/**").hasAnyAuthority("ROLE_ADMIN");
http.authorizeRequests().anyRequest().authenticated();
http.addFilter(customAuthFilter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
i have resolved the issue , it was just a miss-understanding of how authenticated method works.
so first Spring security checks if the user authenticated and and then checks if this endpoint need any type of authorization. if authenticated and not authorization exist the user would be redirected to the endpoint. it make sense for me now.
Thank you.
Related
I want to make a config file to configure TLS and Oauth2 in my SecureConfig.java
The tls config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
}
The Oauth2.0 config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requiresChannel()
.anyRequest()
.requiresSecure();
}
What is the better way to use these two in the same config file and method? Does the and() work fine?
Like that:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
.requiresChannel()
.anyRequest()
.requiresSecure();
}
Issue with your two filter chain approach (Regardless of what your configure inside the methods
Spring security is a chain of filters see Filters in Spring Security Filter Chain
By implementing configure(HttpSecurity http) twice, you have created two spring-security-filter-chains.
Since you are not providing http.requestMatcher(...), both chains are applicable to every url. And it is a problem for spring security as it will only apply one filter chain to a particular request. So if you try to start up your app, it will fail to start with an error
You can make your app start by defining an #Order annotation so spring security chooses the one with the lower number applicable for a url. But since both chains are applicable to every url as per your config, the filter chain with lower #Order overrides the filter chain with higher #Order making it useless
Solution
Use one class that extends WebSecurityConfigurerAdapter so you have one security filter chain
Channel Security vs Authentication vs Authorisation
Security is mainly 4 aspects. Authentication, Authorisation, Integrity and Confidentiality. Rest API under https security
What you have in the filter is about authentication. You may have also defined some urls need some roles which is Authorisation. So that config was about those 2 aspects
By requiresSecure() you are addressing Confidentiality. i.e If you use requiresSecure() without the first one, you know you are not talking to some middle man but you won't know who you are talking to because that is what the purpose of authentication.
Since they are complimentary security aspects, They can be combined together and spring will create one filter chain where the first filter ensures you are first talking over https by placing ChannelProcessingFilter as the first barrier
I have override the configure method of WebSecurityConfigurerAdapter class as:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin();
}
I have APIs as /admin, /admin/user, /admin/user/test. When i login as admin i can access all the three URLs. I just wanted to know the difference between '/admin/**' and '/admin',
In case of /api/**, hasRole(...) will be authorized to all the requests that starts with the pattern /api.
And in case of /api, hasRole(...) will be authorized to only one request i.e. /api
In the above question only the '/admin' request is authorized to 'ADMIN' role. We can also access the other URLs because other URLs just need to be authenticated ignoring the role. We can also access the '/admin/user' or '/admin/user/test' while logging with user. If we have used antPattern as '/admin/**', then we won't be able to access those APIs through the session of user.
I am new to Spring Security and i was about to post the question but after spending some time, i came to know a little about it, so i also included my understanding for suggestions.
I wrote one program using spring security framework and used JDBC approach using DataSource. Following is piece of code.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/users/**").hasRole("USER")
.antMatchers(HttpMethod.POST, "/users/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/users/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/users/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/users/**").hasRole("ADMIN")
.and().httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
}
This program is using default table what spring framework expect.
Now my question, because here I am using httpBasic authentication approach when I will come GET /users url, does spring framework hit the table on every request and valid user with credential or after first authentication it cache and validate against that cache.
Could someone help me to understand it.
Thanks in advance
If you use stateless HTTP Basic, the database will by default be "hit" on every request. If you find that a problem you can set a cache like this:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).userCache(userCache);
}
See UserCache javadoc for details about which cache implementations you can use.
Because you're using httpBasic(), then the query would be performed each time - this is the nature of stateless authentication, which is what folks using httpBasic() are typically driving at.
You could cache the JDBC query results with an L2 cache or similar.
Or, if you are okay with some authentication state, then you could
add session management, as another answer indicates. Doing this means that the first request would include credentials in the Authorization header and its response would include a session cookie. Subsequent requests would send that session cookie back, instead of the Authorization header, until the session expires.
use a token (like an OAuth token). You can instead present your credentials to an Authorization Server. The Authorization Server will exchange this for a token that you can then supply to the Authorization header (Authorization: Bearer) instead of the user's credentials (Authorization: Basic).
This behaviour is configured by sessionManagement().sessionCreationPolicy() when configuring HttpSecurity.
Unless you set it to sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) ,its default value is IF_REQUIRED which will cache the authentication result (i.e. SecurityContext) in the HttpSession.Subsequent requests from the same session will simply get the authentication result from the session rather than hitting the database to validate the credential .
In this application I dont want any spring authentication because Authentication is being done by a SSO service, the SSO sends me the the userId and role
Now, I want to use the role being sent for authorisation. The code to set the role is in the implementation of the UserDetailsService
The problem I have is that the UserDetailsService only gets called if I add formLogin to the security config. And of course I dont want formLogin at all as I dont want authentication. So how can I do authorisation without calling formLogin?
#Override
protected void configure(HttpSecurity http) throws Exception{
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
http
.addFilterBefore(encodingFilter,CsrfFilter.class)
.addFilterAfter(new MdcFilter(), SwitchUserFilter.class)
.addFilterAfter(new ParameterSanitizerFilter(), MdcFilter.class)
.authorizeRequests()
.antMatchers("/**").hasAnyRole(StringConstants.USER_ROLE, StringConstants.MANAGER_ROLE);
//.formLogin();
}
**** EDIT
Thanks for the help, pczeus' link seems to be the same issue. However still struggling!
I set up a controller on RequestMapping path "/" but it doesnt get fired (the purpose of the controller is to get the role from session and set it in a new UserAuthenticationInfoService - as per pczeus link)
so I need the controller to execute before this line:
.antMatchers("/**").hasAnyRole(StringConstants.USER_ROLE, StringConstants.MANAGER_ROLE);
how can I do it?
I am using the following Java Config with Spring Security:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
Based on this configuration, all requests are authenticated. When you hit a controller without being authenticated, the AnonymousAuthenticationFilter will create an Authentication object for you with username=anonymousUser, role=ROLE_ANONYMOUS.
I am trying to provide anonymous access to a a specific controller method and have tried to use each of the following:
#Secured("ROLE_ANONYMOUS")
#Secured("IS_AUTHENTICATED_ANONYMOUSLY")
When the controller methods get invoked, the following response is given:
"HTTP Status 401 - Full authentication is required to access this resource"
Can someone help me understand why we are receiving this message and why ROLE_ANONYMOUS/IS_AUTHENTICATED_ANONYMOUSLY don't seem to work using this configuration?
Thanks,
JP
Your security configuration is blocking all unauthenticated requests.
You should allow access to the controller with
.antMatchers("/mycontroller").permitAll()
See also:
http://spring.io/blog/2013/07/03/spring-security-java-config-preview-web-security/