I don't have much expertise with Spring Security and I have a question that could be a bit silly. I've been trying to solve an issue for few days and maybe I misunderstood the way to configure my app. I'd appreciate if anyone can bring some light into this.
I implemented a REST API with Spring and I wanted to add security to it. From the Spring Security docs I read ...
It’s generally considered good security practice to adopt a "deny-by-default" where you explicitly specify what is allowed and disallow everything else.
...
which I agree. So I added that Authentication requirement to my configuration.
However, I'd like to make few of the calls to the API public (from my GUI), so I thought that Anonymous Authentication would work. Again, from the docs I read...
no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user
so, all good.
However, when I execute those calls, I get a 403 response (AbstractSecurityInterceptor throws an AccessDeniedException on decide about the Authentication). So, I leave here several questions + my configuration lines in case you know what problems and misunderstandings I have.
Config...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().and()
.anonymous().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.POST, "/users/login").permitAll()
.anyRequest().authenticated().and()
// We filter the api/login requests
.addFilterBefore(new JwtLoginFilter("/users/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
Questions...
1) AnonymousAuthenticationToken is still authenticated, right?
2) Is the anonymous() line needed if I don't customize the configuration for Anonymous Authentication? The Anonymous token is there (when I debug) when an authentication is missing
3) Is there anything missing in the configuration to accept those requests?
4) The docs mention the ExceptionTranslatorFilter that should process the AccessDeniedException to the AuthenticationEntryPoint. Do I need to define an AuthenticationEntryPoint? If so, with what purpose?
I've tried to be as much precise as possible. I hope someone can reply.
Thank you very much for your help!
You need to put this into your configuration file:
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
Do you have unauthenticated access to the root '/'? I ask this because looks like is what you intend to with the line:
.antMatchers("/").permitAll()
I guess in order to allow unauthenticated request (or anonymous authenticated request, note that for Spring Anonymous and unauthenticated is basically the same) you will need to add the ant match for those paths, something like:
.antMatchers("/public-page").permitAll()
Related
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.
I have created a set of spring boot microservices having followed along roughly with the tutorial I found here. I've had success getting my project up and going without any attempt to secure the rest endpoint or the user interface. But eventually I need to secure everything using LDAP, and I will need to conditionally allow access to user interface sections based upon user roles. For the time being, without involving LDAP, I have tried roughly a score of tutorials on how to use in-memory authentication in conjunction with OAuth2 and I cannot understand what it is exactly that I need to do to make this go.
I have created a github repository that contains two branches. The first branch is called no-authentication which demonstrates a simplified version of my project before any attempt to add authentication is begun. The README describes the project makeup, but it is essentially a configuration server, a service registry, one rest resource with two endpoints that are not authenticated, and a user interface module that access the two endpoints.
The idea is that the first endpoint will eventually require one group membership ("USER"), and the other endpoint another group membership ("ADMIN"). But I haven't gotten so far yet.
The second branch is called oauth-server. This branch adds another spring boot module called oauth2-server, and that module contains the code that my user interface is forwarded to in order authenticate.
I am presented with a login page as I would hope, but when I enter valid credentials (user/user or admin/admin) I see an error on the page:
OAuth Error
error="invalid_grant", error_description="Invalid redirect: http://localhost:8084/authtest/login does not match one of the registered values."
I am totally new to this area, and I have been really just playing whack-a-mole with my various attempts to get this working. You can view the code directly, and you will need to be well versed in order to understand the setup. Here is roughly how the authentication is set up to work.
There ui that needs to be authenticated is called authentication-test-ui. Its configuration can be found in its resources/bootstrap.yml, and the rest of its configuration comes from the control-center/config-server module's classpath, the source located at resources/config-repo/authentication-test-ui.yml. This is the security config:
gateway-server: 'http://localhost:8901/authserver'
security:
oauth2:
client:
client-id: ui
client-secret: uisecret
scope: ui
access-token-uri: ${gateway-server}/oauth/token
user-authorization-uri: ${gateway-server}/oauth/authorize
pre-established-redirect-uri: http://localhost:8084/authtest
resource:
user-info-uri: ${gateway-server}/userInfo
The UI's application class is annotated with #EnableOAuth2Sso.
The authorization server is in the module services/oauth2-server. This is annotated with #EnableAuthorizationServer and follows a similar configuration pattern as the ui (has a bootstrap.yml in its own module and a yml on the config server). The code performs in-memory authentication like this:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("ui")
.secret(passwordEncoder.encode("uisecret"))
.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token")
.scopes("ui")
.redirectUris(
"http://localhost:8084/authtest"
);
}
And the security configuration looks like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("admin").password(passwordEncoder().encode("admin")).roles("USER", "ADMIN")
.and()
.withUser("user").password(passwordEncoder().encode("user")).roles("USER");
}
I most likely have not provided the right information to be able to understand the issue simply by looking at the snippets I've pasted, so looking at the project is probably the only way to fully get it.
If anyone can help me with this I would greatly appreciate it. I've been on this for nearly a week and feel like I can't be too far off the mark. I'm really looking for the simplest way to get authenticated.
You configured redirect uri as http://localhost:8084/authtest but while calling you specified redirect uri as http://localhost:8084/authtest/login so it is failing.
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.
When I develop a non-reactive application and use rememberMe feature in authentication, I just extending WebSecurityConfigurerAdapter class and overriding configure(HttpSecurity httpSecurity) method. In that case, I have a rememberMe() method in a httpSecurity object.
But there is a difference when I use Spring WebFlux. As far as I know, all I have to do is defining a SecurityWebFilterChain bean using the instance of ServerHttpSecurity class, by invoking chain like:
serverHttpSecurity.authorizeExchange()
.anyExchange().authenticated()
.and()
.httpBasic()
.build();
But there is no method to handle rememberMe cookie here like in the HttpSecurity object where I could handle it in that way:
httpSecurity.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.rememberMe()
Do you know any solution?
Unfortunately, it seems impossible to do this.
There is an old issue on github and unfortunately, it is not known when it is going to be solved.
The comments recommend using a longer session expiration and offloading the sessions into an external data store (i.e. Redis). This way, you can store information in a database instead of in cookies.
They recommend using the Spring Session project.
The comments say that using a longer session expiration and offloading the sessions into an external data store (i.e. Redis). This way, you can store information in a database instead of in cookies.
They say use the Spring Session project.
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/