I am trying to implement service to service security into spring boot services using spring oauth2. I want a service to access a secured resource of another service without any user action involved.
There are a lot of examples for authorization code grant type, but not very much about the client credentials grant type, which seems to be the right one for this use case.
I can set up the auth server and use a curl request to get a token.
The tests I found used Http Objects to check status codes.
How can I use the client credentials grant type in a java client with RestTemplate and spring oauth2?
I would think it must be as simple as adding a dependency, an annotation and a config file, yet I can't make it run.
It's quite simple:
Create a Config class which is annotated with #Configuration.
In this class, create an instance implementing the interface OAuth2ProtectedResourceDetails and create a ClientCredentialsResourceDetails instance in that method. Add your values to it and return it.
Create a second instance of type OAuth2RestTemplate in the Configuration class and create in that method a DefaultOAuth2ClientContext instance by calling the default constructor. Then create an OAuth2RestTemplate and add the OAuth2ProtectedResourceDetails instance and the DefaultOAuth2ClientContext instance to it. Subsequently return the OAuth2RestTemplate instance.
Add it with #Autowired in both your Controller and Service instances to use it.
Related
I am working on a spring integration project where I am creating outbound gateway using HttpRequestExecutingMessageHandler class. I want to execute different APIs which are authenticated using bearer authentication tokens using single gateway. I have different RestTemplate configured to handle each type of message.
I could not find how to configure restTemplate per message basis using this class. This class only accepts restTemplate at construction time.
https://docs.spring.io/spring-integration/api/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandler.html
For now, I have created custom gateway class by extended AbstractHttpRequestExecutingMessageHandler which is parent of HttpRequestExecutingMessageHandler and copied contents of exchange method from HttpRequestExecutingMessageHandler class. I am passing restTemplate bean name as message header and resolving it at the start of exchange method.
Is there any better approach?
The "using single gateway" is already a wrong decision from design.
You probably need to think about having different HttpRequestExecutingMessageHandler for those purposes. In your logic you can add then a router to decide to which HTTP Outbound Gateway to send a message.
See more info in docs: https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/message-routing.html#messaging-routing-chapter
I am using Spring RestTemplate for executing HTTP request from my application. There are several services we need to call, some on the internet and some on intranet, some fast and some slow. I have been instructed to configure custom settings for each service, basically, connection timeout, read timeout.
These setting will be extremely specific for example, the services hosted on intranet would have a timeout of ~2-5s while they provide an SLA of 1000ms for 99.9% of requests. While the other third party services with ~10-60s.
As these parameters can be set in the factory for the template only, i am creating a number of beans with different factories differing in timeouts only. Something like this:
#Bean
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setReadTimeout(20000);
factory.setConnectTimeout(5000);
RestTemplate restTemplate = new RestTemplate(factory);
}
I am afraid this will create a maintenance nightmare eventually. Can it be solved in a better ways?
PS: The application is a monolith calling various services.
You will have to create multiple RestTemplates and assign timeouts, connection pool size. Connection pool will improve the performance drastically
I have hard-coded the connection properties, you can pick it from application.properties file
#Configuration
class RestTemplateConfigs {
#Bean
public HttpClient httpClient() {
return HttpClientBuilder.create()
.setMaxConnPerRoute(200)
.setMaxConnTotal(50)
.setConnectionTimeToLive(10L, TimeUnit.SECONDS)
.build();
}
#Bean(name = "restTemplate1")
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
}
You can create multiple RestTemplates and Autowire it using Qualifier name.
Disclaimer: my answer suggests to work with another Http client than Rest Template - If you must use Rest template my answer would be irrelevant.
I dealt with a similar design issue and here is what I did. I wrote my own HttpClient class. It is much simpler in use then most known Http clients. This class could be used on its own or (and this is relevant for your case) it could be used as a parent class for a group of classes (implementing the same interface) where each class will be an Http client for specific Rest Service. On this class you can pre-set the target URL and all the parameters (such as read and connection timeouts etc). Once this class is preset, all you need to do is to invoke sendHttpRequestMethod(). Just to expand a bit - lets say you have a User Rest service with CRUD API implemented by particular URL calls with different HTTP methods and may be different URLs. (say in addition to create (POST) update (PUT) read (GET) and delete (DELETE) methods that are located at HTTP://www.myserver.com:8083/user say you will also have methods activate and deactivate (say both GET) at URLs HTTP://www.myserver.com:8083/user/activate/ and HTTP://www.myserver.com:8083/user/deactivate.
So, in this case, your Http client will set all required timeouts and other configurations and it will also have pre-set target URL HTTP://www.myserver.com:8083/user. and it will have six methods as mentioned above, where each one will simply invoke the parent class method sendHttpRequest(). Of course, for activate and deactivate methods you will need to append "activate" and "deactivate" suffixes for pre-set base URL. So, for each REST service, you can create a dedicated Http client with very minimal effort since the base class already does most of the job. In addition to it, I wrote a self-populating factory for any group of classes that implement the same interface. With that factory, all you will have to do is to write your additional Http client and the factory will detect it and will make it available on its own by predefined name or by the name of the class (based on your choice). All this worked so well for me, that I packaged it into Open Source library called MgntUtils and published it on Maven and Github (with source code and Javadoc. JavaDoc is available here). A detailed explanation on the Self-populating factory can be seen in Javadoc here. Also, the general article about the library can be found here and specific article about the idea and the implementation of self-populating Factory can be found here. Package com.mgnt.lifecycle.management.example in the source code contains a working example. I hope this helps.
Using parameterized construction of the RestTemplate bean solved my problem.
The bean is now configured as:
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public RestTemplate getRestTemplate(String configParam){
int connectionTimeout; //get from config using configParam
int readTimeout; //get from config using configParam
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectionTimeout);
factory.setReadTimeout(readTimeout);
return new RestTemplate(factory);
}
Instead of #Autowiring this field, it can be injected in may be #PostConstruct method like depicted below. The dependent bean can do following:
#Autowire
BeanFactory beanFactory;
RestTemplate restTemplate;
#PostConstruct
public void init(){
restTemplate = beanFactory.getBean(RestTemplate.class, configParam);
}
Here you can have your bean with custom settings injected in restTemplate.
I understand what #Secured DOES but not really sure HOW it does it.
Can someone explain how #Secured grabs the roles? Is it getting it from the authorities-by-username-query? Can I put any String in the params as long as it's in the database?
User's roles are stored in SecurityContext, or to be more specific in Authentication object that is stored in the SecurityContext. When you authenticate, the authentication information is loaded and stored in the security context. The roles can originate from database, depending on your configuration. In your case they are loaded using authorities-by-username-query query.
When the security interceptor processes the authorization (for instance method-level authorization using #Secured annotation) it determines whether the user should be able to access it based on the Authentication stored in the context.
To better understand what happens under the hood, you should look at the Spring Security Filter chain and Architecture section of the reference guide.
SpringSecurity provides and awesome AOP way of securing methods in
Java Application by using #Secured. Spring logically ORs the roles
listed in #Secured annotation. The collection of GrantedAuthorities is obtained from SecurityContextHolder.getContext().getAuthentication().getAuthorities()
AbstractSecurityInterceptor is the abstract class that implements
security interception for secure objects.
Obtain the Authentication object from the SecurityContextHolder.
Determine if the request relates to a secured or public invocation
by looking up the secure object request against the SecurityMetadataSource.
For an invocation that is secured (there is a list of
ConfigAttributes for the secure object invocation):
If either the Authentication.isAuthenticated() returns false, or the alwaysReauthenticate is true, authenticate the request against the configured AuthenticationManager. When authenticated, replace the Authentication object on the SecurityContextHolder with the returned value.
Authorize the request against the configured AccessDecisionManager.
Perform any run-as replacement via the configured RunAsManager.
Pass control back to the concrete subclass, which will actually proceed with executing the object. A InterceptorStatusToken is returned so that after the subclass has finished proceeding with execution of the object, its finally clause can ensure the AbstractSecurityInterceptor is re-called and tidies up correctly using finallyInvocation(InterceptorStatusToken).
The concrete subclass will re-call the AbstractSecurityInterceptor via the afterInvocation (InterceptorStatusToken, Object) method.
If the RunAsManager replaced the Authentication object, return the SecurityContextHolder to the object that existed after the call to AuthenticationManager.
If an AfterInvocationManager is defined, invoke the invocation manager and allow it to replace the object due to be returned to the caller.
Look at the source code for more understanding.
AccessDecisionManager is the interface which is implemented as AffirmativeBased, ConsensusBased or UnanimousBased orchestrates the voters and asks each in turn whether the requesting user should be let through the #Secured annotation or denied.
Is there a way to pass URL parameters to an authentication provider in Spring Security 3?
Our login page will need to receive an email token as a parameter that the authentication system will need to be aware of when it sets the status of the user. Specifically, it will let a user with a correct token log in that would not otherwise be able to.
I have a custom class extending the DaoAuthenticationProvider class. My authentication logic is in that class's authenticate method.
I'm hoping there is some way to pass this data into the authenticate method.
You could inject the HttpServletRequest object on your authentication provider class:
private #Autowired HttpServletRequest request;
Now, you should be able to access the request parameters with APIs such as request.getParameterValues(paramName)
You need to override UsernamePasswordAuthenticationFilter.setDetails() and pass extra information to your custom authentication provider via details property of UsernamePasswordAuthenticationToken.
What are the advantages to get principal as a parameter Principal principal in spring controller and then pass it to service layer over getting principal in the service layer immediately though SecurityContextHolder.getContext().getAuthentication().getPrincipal() ?
What is the best approach to get principal details in service layer without checking getAuthentication() and getPrincipal() objects for null everywhere (something like a custom wrapper)?
Your service API will be more easy to use. You will see dependency on principal directly, so you wan't call some service method by mistake in environment where principal does not exist.
In general less dependencies on SpringSecurity code means less problems in a case of migration to new Spring Security version.
You will be able to reuse your service layer in environment where Spring Security does not exist.
Prepare some wrapper class (for example AuthenticationService). Add getPrincipal() method to it. Implement your checks. Inject AuthenticationService everywhere insted of direct calls to SecurityContextHolder.