OpenAPI generate interface for Spring code that accepts the Authentication object? - spring

There are various ways to access the authentication information in a Spring REST application, as outlined here: https://www.baeldung.com/get-user-in-spring-security
At the moment, I use openapi-generator to generate spring interfaces for my REST API and then I obtain a reference to the Authentication by writing code in the implementation like:
SecurityContextHolder.getContext().getAuthentication()
As shown in the referenced article in Section 2.
I'd prefer to use the mechanism shown in Section 3 of the referenced article.
That is, I want the openapi-generator to add an Authentication parameter to the interfaces it generates, like:
#RequestMapping(value = "/username", method = RequestMethod.GET)
#ResponseBody
public String currentUserName(Authentication authentication) {
return authentication.getName();
}
How do I tell the openapi-generator to add Authentication parameters to the interface methods that it generates?

Related

Where do the Spring Security Authentication and Principal objects come from in a controller's methods?

I have some methods in a Spring Boot #RestController that magically seem to have access to the Spring Security Authentication or Principal objects when I add them as arguments. I am wondering, how do my methods work with these arguments? Where do they come from?
Here is an example:
#GetMapping("/someEndpoint")
public ObjectNode someEndpoint(Authentication authentication) {
...
CustomAuthentication customAuthentication = (CustomAuthentication) authentication;
logger.debug("Name: {}", customAuthentication.getName());
...
}
or
#GetMapping("/anotherEndpoint)
public ObjectNode anotherEndpoint(Principal principal) {
logger.debug(principal.getName());
...
}
It isn't just these Authentication and Principal objects either. I've also seen HttpServletRequest and other arguments sometimes in these controller endpoints. Where do they come from and why are they optional? Is there a list somewhere of these objects I can get in my methods?
Answer to all your questions are available in the Spring Reference Documentation
For Authentication related question do read through to understand on a highlevel how it is made available in the session. Read on AbstractAuthenticationProcessingFilter
Read through the documentation for the list of supported controller method arguments here
Spring MVC Reference documentation
Spring Security Reference

Spring Security: How to use a UserDetailsService with JwtAuthenticationProvider?

I have a REST service, written using Spring MVC. The server is an OAuth2 resource server and I am using the JwtAuthenticationProvider to have the JWT parsed and turned into the Principal. This all works fine.
However, what I really want to do is to load user details from a database, using the username provided from a Claim in the JWT. Then that new Principal should replace or (ideally) wrap the Jwt so that it is available directly from the SecurityContext.
I am really struggling to see how to do this. The JwtAuthenticationProvider does not seem to work with a UserDetailsService. I also looked at doing this with a Converter - but it is not easy to extend JwtAuthenticationConverter because the convert method is final (why?).
So to be very clear, here is what I ideally want to happen:
Bearer token is presented to service.
Parse Jwt and extract claims
Use one of these claims as a key to my user database, where I can look up attributes, entitlements etc
Turn these into a new Principal object which is available in the SecurityContext's Authentication object.
The configure method in my WebSecurityConfigurerAdapter has this:
http.authorizeRequests().antMatchers("/api/*").authenticated().and().oauth2ResourceServer().jwt();
I cannot be the only person who wants to use a user database along with OAuth2, so I must be missing something fundamental? I am using Spring Security 5.2.0.
The JwtAuthenticationProvider does not support an UserDetailsService because in theory you are not supposed to have UserDetails in an application that does not manage credentials. I'm not saying that you cannot have any type of user, but the UserDetailsService will not be used or autowired by Spring Security.
You could register a bean of type JwtAuthenticationConverter, do whatever you need in the convert method and return your custom authentication token, like so:
#Component
public class JwtAuthenticationConverterAdapter implements Converter<Jwt, AbstractAuthenticationToken> {
private JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
#Override
public AbstractAuthenticationToken convert(Jwt jwt) {
var token = this.jwtAuthenticationConverter.convert(jwt);
// build your custom token with the properties from the token above
return customToken;
}
}
I agree with your concerns - and I have found it useful to override Spring's default processing. There is a claims extensibility pattern I use with some providers, where JWT handling is only one part.
I have a Spring Boot code sample that you can run - it uses a custom filter and Connect2Id classes - OAuth integration is described here. Happy to answer any follow up questions if it helps

Prevent direct call to my spring boot rest API

I have several REST services (on spring boot) used by a javascript file (website) and these services can be called directly by anyone (and you can see the API url/parameters with the developper console on any browser).
So I would like to prevent the direct calls to the API, exept of course from the front side of my app.
I saw that I can use an API key with spring security but is it reliable? Since I think you can see the key if you intercept the message with developper console.
What you can do are the following :
Disable CORS in your springboot application by setting the following globally or per endpoint as you wish.
To set the CORS per endpoint :
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Test testing(#RequestParam(required=false, defaultValue="Test") String name) {
System.out.println("in test");
return new Testing(10, String.format(template, name));
}
You can use spring security to preauthorize your controller endpoints to make sure that only the authorized has access to the controller.
Like for example :
#RestController
#RequestMapping({"/v2/"})
public class ExampleTestController {
#PreAuthorize("hasAuthority('ROLE_ADMIN')")
#RequestMapping(value = "/test", method = RequestMethod.GET)
String test() {
return "Hello";
}
}
Using spring security is safe, as the user is always validated before access is granted . Even while using Oath2 the key generated is after validating the user login and the key can be used to validate every request to the controller by passing it in the header or using it in the rest template.
Another way of isolating your rest endpoints is by using the load balancer (or ngnix or anything) to block requests to these endpoints from outside your domain.

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.

How can I extend the parameters of the OAuth2 authorization endpoint?

I'm having some trouble regarding the authorization endpoint of my Spring based OAuth2 provider. I need more information from the client than there is currently possible. This is what I want to achieve:
I need the custom parameter in the authentication process later on. Is there any simple way to extend the default parameters with my custom one or do I need to implement a certain class myself?
Did some research on how the authentication endpoint works in the current Spring code. I found that the Authorization Endpoint uses a method named authorize that takes all the parameter that are being set and converts then into an AuthorizationRequest. While looking further into the AuthorizationRequest class I found that it holds a map with extensions that is being filled throughout the authorization process. But it does not seem to get filled with my custom parameter (as shown above). This is in fact by only looking at the code, so I might be wrong.
Would it be a good idea to extend the AuthorizationEndpoint with my custom implementation or is there a better and cleaner way to do this?
Update #1 (07-10-2015)
The place where I'd like to use the custom parameter is in my own implementation of the AuthenticationProvider. I need to information to be available inside the authenticate method of this class.
Update #2 (07-10-2015)
It seems that the AuthorizationProvider gets called before the AuthorizationEndpoint. This means that the custom parameter is obtained after the class where I need it (so that's too late).
Maybe I can get the referral Url by either extending part of the Spring security classes or by obtaining it in the HTML through JavaScript. Is this a good idea or should I use another approach?
So I managed to fix the problem myself by searching some more on Google.
What you need to do is speak to the HttpSessionRequestCache to get the referral URL. This is how I solved it in my own implementation of the AuthenticationProvider
#Component
public class CustomProvider implements AuthenticationProvider {
#Autowired
private HttpServletRequest httpRequest;
#Autowired
private HttpServletResponse httpResponse;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(httpRequest, httpResponse);
logger.info("Referral URL: " + savedRequest.getRedirectUrl());
logger.info("Parameters: " + savedRequest.getParameterMap().keySet().toString());
}
}
This will print out the URL of the request that was called before heading to the login page of spring security. The second log method prints out the parameters that where found in this URL. This question and answer helped me in creating a solution for my problem.

Resources