I have a custom authenticator (ie. a class that extends Authenticator and does some custom authentication in authenticate(Response res, Request req)) that I then want to pass a value to the function that handles the actual API call. I thought adding an argument like #Context Request request could work but I don't think so.
Anyone know how I can pass an object from Authenticator to resource?
Thanks,
Daniel
jax-rs has a mechanism for that. You can create a custom context that implements SecurityContext. This security context returns your your user object as Principal.
Your authenticator which probably works as a filter can then set the security context of your request. From there on you can access your User object via the SecurityContext.
While not perfect, I have a working piece of code on github that can get you started.
Related
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.
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.
We'd like to secure our rest api using an api key. Here are the requirements:
Public-facing services require an api key.
"Private" services can only accept a call from within the cluster,
not the outside world.
Each api identifies a user, and the User object must be available to
the rest service.
Is there some standard way to do this in a JAX-RS app? (We're using Resteasy.)
I've read all about filters, interceptors and basic auth, but it isn't clear to me what's the best approach.
In an earlier version of the app we had a roll-your-own solution in which public services ran on a public port and private ones on a private port. There was a custom api key lookup that set the User object as a variable into the rest service object.
I can't figure out how to do either of these things using standard JAX-RS.
Using a filter to intercept the request
This kind of authentication could be achieved with a ContainerRequestFilter, intercepting the requests to your resource methods.
The filter will be used to extract the API key from the request and validate it. If the API key is not valid, the request will be refused. Otherwise, the request will proceed to the resource methods.
Have a look at the following piece of code. The ContainerRequestContext API can be used to extract information from the HTTP request:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Extract and validate the API key from the request
String apiKey = requestContext.getHeaderString("API-Key");
...
}
}
Also have a look at this answer I wrote a while ago about authentication with tokens in JAX-RS. There you will find plenty of details that can be useful to address the situation you described in your question.
Identifying the user
During the authentication process, you must be able to identify the user who is performing the request. To propagate this information to your resource classes/methods you could:
Override the SecurityContext and inject it into your resource classes/methods.
Use a CDI Event and a producer method to create an object that contains the user identifier that can be injected in your resource classes/methods.
For more details on the these approaches, refer to the answer I mentioned above.
Binding the filter to some resource classes/methods
By default, the filters are global (it means they are executed for all the resource methods of your application). To bind the filter to a subset of resource methods or classes, you could use name binding annotations.
Not giving a detailed answer, but just a suggestion. Check for CustomInvokers and register the invoker for the services. Validate the api-key and throw an error if it's not valid. If there is an error then your client gets an error. The Service code won't be called.
For the actual security framework, please check netflix zuul.
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.
I'm using XFire as the Web Services provider for Spring Remoting. I'm using an AbstractHandler to authenticate the SOAP request. The idea is to identify the request by the originating server's domain and an API key (a-la Google Maps). The only problem is that I can't seem to find a way to fetch the ServletRequest object from within the invoke() method, which only accepts a MessageContext object.
The only idea I can think of is using a Filter and storing the request object inside a ThreadLocal variable, but I'd really prefer to avoid this solution.
Any ideas?
Cheers
Shai
I haven't tested this but I have the source for XFire handy so I dug into the classes to see if this would be easy. From within the call to invoke you should be able to get the ServletRequest with the following code:
ServletRequest request = (ServletRequest) context.getProperty(org.codehaus.xfire.transport.http.XFireServletController.HTTP_SERVLET_REQUEST);