Spring Security some time AnonymousUser [closed] - spring-boot

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 days ago.
Improve this question
Spring Boot - Angular Application:
Why does my method return "AnonymousUser" when called from one controller, but the correct user id when called from another controller?
I have a method that returns the logged-in user:
#Override
public String getLoggedUserName() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
When I call it from a controller, it returns the name of the logged-in user, but when I call it from another controller, it returns "AnonymousUser". Why is this happening?
I don't know if it can be useful as additional information but authentication is via Keycloak

I'll answer first to what I guess your actual question is: "how to be sure to have a JwtAuthenticationToken in the security-context of a #ResController?"
Configure your app as resource-server with a JWT decoder
Protect entry-points with isAuthenticated() either form security filter-chain configuration or #PreAuthorize (or equivalent) on controller class or method (with #EnableMethodSecurity somewhere in the config)
Off course, do not explicitly replace the default Authentication implementation for successful authorizations... (when providing an authentication converter for instance)
Now a complete answer to what you formulated and is way wider as the type of Authentication implementation in the security context of controller method invocation varies depending on quite a few factors.
Runtime
Let's start with "real" invocations (spring app up and running, nothing mocked):
request is not authorized, then an AnonymousAuthenticationToken is put in the security context. Depending on the security config, this could be because of missing or invalid access token (expired, wrong issuer or audience, bad signature, ...), missing basic header, etc., or because the type of authorization is not the right one (for instance a Bearer token on a route intercepted by a security filter-chain expecting basic authentication)
request is successfully authorized => default authentication depends on the security conf
resource-server with JWT decoder, then JwtAuthenticationToken is used (can be accessed verridden by configuring http.oauth2ResourceServer().jwt().jwtAuthenticationConver(...)
resource-server with access token introspection, then BearerTokenAuthentication is used ( override with http.oauth2ResourceServer().opaqueToken().authenticationConver(...))
client with oauth2Login, then OAuth2AuthenticationToken is used
etc., the list continues for non OAuth2 authentications (just have a look at Authentication type hierarchy)
Tests
Test security context can be set for tests in plain JUnit using annotations like #WithMockUser or using MockMvc (respectively WebTestClient for reactive apps) and either annotations or request post processors (respectively WebTestClient mutators).
The type of Authentication injected depends on the annotation (or mutator / post-processor) used. For instance, #WithMockUser builds a UsernamePasswordAuthenticationToken which is rarely adapted to an OAuth2 context. Mutators from SecurityMockMvcRequestPostProcessors from spring-security-test or annotations like
#WithMockJwtAuth, #WithMockBearerTokenAuthentication or #WithOAuth2Login from spring-addons are generally better suited.
Tutorials for both runtime config and tests
I wrote some available from there: https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials

Related

How to mock JwtDecoder in Spring Boot for integration testing of authenticated controllers? [duplicate]

This question already has answers here:
How do I test main app without spring security?
(2 answers)
Closed 4 days ago.
In my Spring Boot application, there are some authenticated controllers.
The operation mode is "OAuth2 resource server", so my application relies on some arbitrary OAuth2 authorization server. (Let's say it's Keycloak, though it should not affect the way of mocking)
So, the question is:
What is the right way to mock JwtDecoder, in order to be able to pass some static strings as the bearer tokens?
(Please remember, it's a third party server responsible for the token issuing; So I cannot rely on it in tests. I want to mock it away to be able to run tests offline for example)
An example of what I expect to happen:
I mock JwtDecoder (let's pretend I've created some map of <token string, UserData>)
I make a MockMvc-based http call to the authenticated controller with this static string in the Authorization header (Authorization: Bearer STATIC_STRING). The controller test is decorated with #SpringBootTest and #AutoConfigureMockMvc.
I expect to have JwtAuthenticationToken filled with data from UserData from the map of the mocked JwtDecoder.
I've already tried to just create a bean of JwtDecoder implementation with all the described features. I see this bean is added to the configuration, but still whole test ends up in AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext. So I presume that JwtDecoder is never called (checked that with the debugger), and the whole testing setup is misconfigured, but I don't know for sure what to change.
What do I miss?
With MockMvc (as well as WebTestClient in reactive apps) the Authorization header is just ignored (not decoded, validated, introspected or whatever).
The test security context is to be set directly (SecurityContextHolder.createEmptyContext().setAuthentication(auth);) or with the help of either:
test annotations (like #WithMockUser, but this one is not quite adapted to mocking OAuth2 identities). Refer to those that I created in this lib for OAuth2
Request post-processors for MockMvc
mutators for WebTestClients
More details in this other answers:
How to write unit test for SecurityConfig for spring security
How do I test main app without spring security?

Spring-security 6 - 403 denied because AuthenticationProvider not called

I've recently upgraded a project from using spring-security 6.0.0-M6 to 6.0.0, gradle config if you want to see it.
This project does not use spring-boot.
Context
My securityFilterChain is configured via code and looks approximately like this:
http.
authenticationManager(authnManager).
securityContext().securityContextRepository(securityRepo).
and().
authorizeRequests(). // <-- DEPRECATED
requestMatchers(RAID_V2_API + "/**").fullyAuthenticated().
The full codebase, starting with the FilterChain config, is publicly available.
Note that usage of WebSecurityConfigurerAdapter is deprecated, and I have not been using it since the original usage of 6.0.0-M6. So calling stuff like WebSecurityConfigurerAdapter.authenticationManagerBean() won't work.
This code works fine, but the call to authorizeRequests() causes a deprecation warning that I want to get rid of.
Problem
The deprecation tag says that I should use authorizeHttpRequests() instead, but when I do that - requests that require authorization (via the fullyAuthenticated() specification above) will be denied with a 403 error.
Analysis
It seems this happens because my AuthenticationProvider instances aren't being called,
because the ProviderManager isn't being called. Since the AuthnProviders don't get called, the security context still contains the pre-auth token instead of a verified post-auth token, so the eventual call to AuthorizationStrategy.isGranted() ends up calling isAuthenticated() on the pre-auth token, which (correctly) returns false and the request is denied.
Question
How do I use the authorizeHttpRequests() method but still have the ProviderManager be called so that my security config works?
My workaround is just to ignore the deprecation warning.
First, your security configuration does not specify any kind of authentication, like httpBasic, formLogin, etc. The AuthenticationManager is invoked by the filters created by those authentication mechanisms in order to authenticate credentials.
Second, the application is probably unwittingly relying on FilterSecurityInterceptor (authorizeRequests) to authenticate the user, which is not supported with authorizeHttpRequests. You need to declare an auth mechanism that collects credentials from the request and authenticates the user.
Because you are using JWT, you might want to consider Spring Security's OAuth2 Resource Server support. You can also refer to our samples repository in order to help you with sample configurations.
Here's a rough outline of what I did to to implement the "just use the resource server" suggestion from the answer.
include the oauth2-resource-server libraries in the build.
create an AuthenticationManagerResolver that replaces what the SecuritycontextRepository and the FilterSecurityInterceptor used to do:
#Bean
public AuthenticationManagerResolver<HttpServletRequest>
tokenAuthenticationManagerResolver(
AuthenticationProvider authProvider
) {
return (request)-> {
return authProvider::authenticate;
};
}
change AuthenticationProvider implementations to use the BearerTokenAuthenticationToken class as the pre-auth token, it still works basically the same way it used to: verifying the pre-auth token and returning a post-auth token.
hook up the new resolver class in the securityFilterChain config by replacing the old securityContextRepository() config with the new authenticationManagerResolver() config, which passes in the resolver created in step 2:
http.oauth2ResourceServer(oauth2 ->
oauth2.authenticationManagerResolver(tokenAuthenticationManagerResolver) );
I like this new approach because it makes it more obvious how the security chain works.
It's nice to replace the custom pre-auth token implementation with the built-in class too.
Note that it's likely this config can be simplified, but I needed the custom resolver since the project uses different types of bearer token depending on the endpoint called. Pretty sure the auth providers don't need to be AuthenticationProvider any more; the lambda function returned from the resolver serves that purpose - they can probably just be random spring components and as long as the method is SAM-type compatible.
The spring-security multi-tenancy doco was helpful for this.

Spring: Why is it bad to return a whole OAuth2User in an endpoint?

I'm building an OAuth2 authenticated app using Spring Boot, following this tutorial: https://spring.io/guides/tutorials/spring-boot-oauth2/
At one point, the endpoint /user sends back the currently logged in user.
The guide warns by saying:
"It’s not a great idea to return a whole OAuth2User in an endpoint since it might contain information you would rather not reveal to a browser client."
But it doesn't give any more information - what type of information should I not be revealing to a browser client?
Thanks!
In Spring Security 5.x, the OAuth2User is a specific OAuth2AuthenticatedPrincipal (very similar to a UserDetails but without any notion of a password). Even without a password, exposing it can (and often will) leak sensitive information, implementation details of your authentication scheme, etc. You can expose it if you choose, but the warning in the guide is suggesting that care should be taken so as not to expose anything considered sensitive, and you should consider alternatives before exposing it directly.
For example, you might consider creating a CustomUser class that is populated from claims on the OAuth2User using a custom OAuth2UserService (various examples in the advanced configuration section of the docs). You can also take various steps to decouple the representation of an oauth2 user in Spring Security from the representation of a user in your application (e.g. by using #AuthenticationPrincipal to resolve your own custom user or access claims). If the application itself does not need a custom user, you can simply map claims of the OAuth2User to a response in your custom endpoint, as demonstrated in the guide.
Finally, you can combine all of these techniques to make your /user endpoint a "one liner" again, as in:
#Target({ElementType.PARAMETER, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#AuthenticationPrincipal(expression = "customUser")
public #interface CurrentUser {}
#GetMapping("/user")
public CustomUser user(#CurrentUser CustomUser customUser) {
return customUser;
}

how to implement role-based security in microservices architecture [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have a spring-boot application with 4 microservices, eureka server and a centralized API gateway.
All external traffic is coming via my API gateway to my microservices.
My API gateway (Zuul) is validating and verifying JWT token.
the JWT token is generated by one of my microservices after user login (the users microservice), the token contain the user Id and his roles/authorities.
Now I want to implement role-based security on methods that are present in microservices other than the gateway.
I have tried to use #PreAuthorize but it's not working out of the gateway (obviously in order to make it work I have to set a Spring Security authentication object in the SecurityContextHolder in my microservices and populate it with authorities).
So is there any solution to achieve this type of security?
What is the best design to set up security in microservice architecture?
Authentication at API gateway level and authorization at microservices level?
Do I need to use spring security within the microservices or just pass down the roles (append them to the request) after validating the JWT at API gateway level and for example create my own annotations and use Spring AOP to handle authorization?
In Spring5 microservices you will be able to find a base to develop a microservice architecture with several of the requisites you are looking for:
Registry server using Eureka.
Gateway server with Zuul.
Regarding to security, I have developed two different microservices:
Spring Oauth2 with Jwt
Spring Jwt multi-application security service to work with access and refresh Jwt tokens, with several customizations like: definition of the content of every one, work with JWS or JWE, etc
Most important ones are well documented using Swagger, as you can see here, and all documented APIs are accessible using an unique gateway Url.
For all classes of every microservice, Junit tests were developed.
Security
At this point, I took several decisions:
1. Is not the gateway the microservice that verifies the security.
Because use the gateway as "firewall" is a less flexible approach. I wanted to decide which microservices need security and every one should manage internally the roles can access to every endpoint. In summary, every microservice has to work with the authorization/authentication but it don't need to know how that functionality is done.
2. Specific microservice to deal with the security
As I told you, I developed 2 different ones, because I wanted to "play" with different options/approaches. The most important advantage is the encapsulation, if "tomorrow" I decide to change Jwt by any other option, I will only need to modify those ones, the microservices that use them will keep the same code (I will explain you soon how the integration was done)
Security integration example
I will explain how the security functionality was integrated between:
Pizza service easy microservice developed as part of the architecture.
Spring Jwt
1. Every application that manages user and roles, will include in the security microservice a folder similar to the next one, to define its models, repositories to get the required information, etc
2. Global endpoints of the security microservice are defined here. As you can see, they work basically with 2 Dtos:
AuthenticationInformationDto
UsernameAuthoritiesDto
The main advantage, only the security microservice knows the details about how that functionality was done, the other ones that use it will receive a well known Dtos with the required information.
3. In pizza-service, the security integration is mainly defined in the next 3 classes:
SecurityContextRepository to get authorization token from the header and send it to the SecurityManager.
SecurityManager call to security-jwt-service with the provided "authorization token" (it doesn't know if it is Jwt or any other thing) and receives a well know UsernameAuthoritiesDto (transforming it into an object of the Spring class UsernamePasswordAuthenticationToken)
WebSecurityConfiguration global security configuration.
Now you can include in your endpoints the required role based security:
Controller example
Custom PreAuthorize annotation
Final considerations
pizza-service was developed using Webflux, you can see an equivalent integration based on a MVC microservice one in order-service here (in this case I used the "other security service" but is easy to adapt it).
To improve the security and follow the "Oauth approach", the requests to security-jwt-service need to include the Basic authentication too. As you can see in SecurityManager class:
private String buildAuthorizationHeader(String username, String password) {
String auth = username + ":" + password;
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
return "Basic " + new String(encodedAuth);
}
The table in database to store that information is the same one used to manage the security configuration of every application: security.jwt_client_details
Question is wide at the moment as the nature of the traffic to your microservices is not clear.
Assuming that all external traffic coming via your API gateway to your microservices.
You don't need to validate the JWT twice once in API gateway and then again in your internal microservice. If the JWT is invalid , the request will never reach your microservice
Then API gateway propagate the roles. In your microservice, you initialise the spring security context using the roles passed in the header. It will allow you to use #PreAuthorize etc
Assuming that external traffic can come via your API gateway as well as directly to your microservices.
Now you need to verify it in both API gateway and in your microservices
Update
I don't have knowledge about Zuul API gateway. This is just addressing the following:
I have tried to use #PreAuthorize but it's not working out of the gateway (obviously in order to make it work I have to set a Spring Security authentication object in the SecurityContextHolder in my microservices and populate it with authorities).
public class PreAuthenticatedUserRoleHeaderFilter
extends GenericFilterBean {
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String rolesString = //extract the roles
String userName = // extract the username
List<GrantedAuthority> authorities
= AuthorityUtils.commaSeparatedStringToAuthorityList(rolesString);
PreAuthenticatedAuthenticationToken authentication
= new PreAuthenticatedAuthenticationToken(
userName, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(servletRequest, servletResponse);
}
}
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,
jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
PreAuthenticatedUserRoleHeaderFilter authFilter
= new PreAuthenticatedUserRoleHeaderFilter();
http.
antMatcher("/**")
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(authFilter,
BasicAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
If you'r API gateway is also the one who create's and sign JWT token's with private key's and to authenticate you use public key's from API gateway then you are the one who specifies structure of that JWT token and you should be able to encode roles into that JWT (it could be scope parameter for example but all possible scope's are usually accessible by all users). Then you can configure spring boot to automaticaly resolve group role from that JWT (set SecurityContextHolder role's right) and #PreAuthorize annotation can be used without any modification.
If you'r API gateway is only verifying JWT token's against 3rd party authorization server (the server which signed and structured that JWT) with public key's from this server you must implement some custom mechanism for role-based access. One that come's to my mind is to implement second level Oauth2 authentication which would be only used with request's between your microservice's and API gateway using some kind of 'inner' JWT. For example see following image:
Since you define how structure of inner JWT should look by your API gateway code you can set custom attribute's like role: (admin, user etc..). This can be resolved for example from user name, id, email which you are provided from outer JWT from 3rd party authorization server. Therefore you would need to keep some mapping inside API gateway code like:
(userId: 12563) => Admin group
(userId: 45451) => User group
Since your micro-services use JWT for authentication you can use spring boot resource server to setup authentication and configure it to resolve group's (object you mentioned inside SecurityContextHolder) automatically from your custom structured inner JWT. This way you could simply use #PreAuthorize annotation inside your micro-service's and therefore you would not have to create custom annotation's. Note that this is only supposed to solve second case i have specified in first case you are in control of JWT token already.
Role based authorization is avoided these days and scope based authorization is preferred with something like service1.read, service2.full_access scopes. You could either: move role based authorization into each service and away from identity server, convert to scope based authorization, move role based authorization job to respective service rather than relay on identity server.
You can user reference token flow and invalidate token when changes occurs in your role/rights, this will help explaining it

Custom principal and scopes using Spring OAuth 2.0

I am using SpringBoot 2.0.5 and Spring Security OAuth to implement an OAuth 2.0 server and a set of client microservices.
In the AuthServer:
I have implemented the UserDetailsService so I can provide my custom enriched principal.
For the userInfoUri controller endpoint, I return user (my principal) and authorities as a map.
In the Client:
I have implemented PrincipalExtractor to extract and create my custom principal.
For each of the methods I require the principal, I use the following notation:
public List<Message> listMessages(#AuthenticationPrincipal MyPrincipal user)
This works (and I hope it's the right way) but now I'm having an issue to secure methods using scopes.
For example, if I want to have a controller method which is only accessible by another server (using client_credentials), I mark the method with the following annotation:
#PreAuthorize("#oauth2.hasScope('trust')")
But this results in an access error as I think the scope is not being transferred. I have added the scope to the userInfoUri endpoint but am unsure what I need to do on the client side so the scope is picked up.
Any pointers or example code would be very much appreciated.

Resources