In my server application, I want to consume some third party API using a MicroProfile REST client. To do so, I need to send an Authorization Header with a bearer token.
I don't want to always get a token before I make any call so I need a mechanism to only retrieve a new token if there is no token yet or if the token expired. The token could then be stored and used in each call until it expires. The next call to the API which would cause a HTTP 401 Unauthorized shall then cause a new token to be obtained.
Unfortunately so far I wasn't able to find any resources on how to consume OAuth secured APIs using the MicroProfile REST client. I hope anybody can give me any tips. I'm using Kotlin and Quarkus but Java related documentation would be fine as well. Anything helps.
Here is my rather simple client:
#RegisterRestClient
#Produces(MediaType.APPLICATION_JSON)
interface SomeThirdPartyApiClient {
#POST
#Path("/some/random/url")
fun someRandomUrl(body: SomeJsonRequestObject, #HeaderParam("Authorization") bearer: String): SomeJsonResponseObject
}
As discussed with iabughosh, there seems to be no automatic way of doing what I want to do. Instead I have written the code myself as suggested by iabughosh. I went with the route of catching errors in the call. If the error has a 401 status, then I retrieve a new token and retry the call.
When the application starts and has no token yet, the first call always causes a 401 and then I get the first token. The next 401 appears only when the token expires (or was removed by a server admin prematurely) so then I simply get the token and do the call again.
As for now this seems to work just fine. I'll have to see how it turns out in production when there are a lot of (parallel) calls. If I find a better solution, I'll try to remember this question and update it accordingly.
There isn't any way to pass it at annotation level, through eclipse microprofile configuration, the only way to pass a dynamic token is by adding
#HeadParameter("Authorization") authString
in your rest call, in case you are using jwt, usually you can inject the JsonWebToken and do all the checks with this object, so you wouldn't need that parameter, however, you can add it and just ignore, than in your rest client method declaration you have to add it too (as I seen your case you did it already, just assure the order of parameters is the same), and the restclient will be able to pass the token though the header (you need to pass "Bearer "+tokenString), but you need to access to the code of your rest service.
Related
I am calling below API to get bearer access token.
POST https://idcs-xxxx.identity.c9dev2.oc9qadev.com/oauth2/v1/token
Once the token is retrieved i will use the same token in below APIs. These APIs are part of single transaction. But every time I call these APIs,I have to pass the token for authorization. I dont want to generate token again and again because It is valid for 60 min. How can I check whether token is expired or not. .If it is expired then only I want to generate again, else i want to use the existing one. I am not using any framework to call the APIs in java.I am using HttpUrlConnection.
GET https://idcs-xxxx.identity-t0.data.digitalassistant.oci.oc-test.com/api/v1/skills
GET https://idcs-xxxx-t0.data.digitalassistant.oci.oc-test.com/api/v1/skills/dynamicEntities
POST https://idcs-xxxx.identity-t0.data.digitalassistant.oci.oc-test.com/api/v1/bots/xxx/v2/yyy
PATCH https://idcs-xxxx.identity-t0.data.digitalassistant.oci.oc-test.com/api/v1/bots/xxx
PUT https://idcs-xxxx.identity-t0.data.digitalassistant.oci.oc-test.com/api/v1/bots/xxx/DONE
Possible concept: Write a Helper class to do the API request (e.g. MyAPIClient.class). Most APIs will return a 401 HTTP error when the token is expired. Check this behaviour for this specific api. If this is the case, get a new token within this helper class and repeat the request with the new token. Cache this token for 60min after you got it (different Java Frameworks have different kind of Cache providers you can use for this). Use the helper class everywhere you want to access the api
I am using spring and enabled csrf with HttpSessionCsrfTokenRepository, I clearly know if the client is sending the csrf token either as _csrf parameter or X-CSRF-TOKEN header for the request spring picks up the token and validates with the token which was generated using generateToken(HttpServletRequest request)
But my question is how does spring does this internally.
My reason for this question being:
1.I have a Rest POST call which takes credentials and validates the
identity of the user. But Since I want to add a csrf token to the
rest call as a layer of security I wanted to add it in the post body
to prevent csrf token leak.
So if I know how spring security filters these tokens internally it would be helpful. I revised the spring documentation but it is mostly how we can use CSRF token in a form with hidden field or meta tags and Ajax call with a header.
And I also would like to hear any comments on my design if it is good to have the token in body( I am convinced because it would not be a simple url parameter to leak the token ) or should I have it in the header. I just dont want to lean to use header just because its simple. Looking for the best solution.
Please shed some light.
There're multiple implementations for CsrfTokenRepository in spring if you want to look into into it. for eg:
https://github.com/rwinch/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/HttpSessionCsrfTokenRepository.java
https://github.com/rwinch/spring-security/blob/master/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java
https://github.com/rwinch/spring-security/tree/master/web/src/main/java/org/springframework/security/web/csrf
https://docs.spring.io/spring-security/site/docs/4.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html
https://docs.spring.io/spring-security/site/docs/4.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html
IMO its good (safer - may be?) to keep Tokens on the header because of few reasons that i can think of..
You cannot set token on a body for your GET request. You want to be consistent of all your endpoints (you may not need it today but things change really fast)
Tomorrow if you want to change your Auth model, you dont want to to change your request body. when request body changes you break the contract with clients
If you change your auth model to a authorization server, you can add proxy server (like ngnix?) before your service and lets call it auth-proxy. You can leave all security related things to this auth-proxy and it will inspect the header and do the validations for you. You don't want the proxy to look into your request body and you can focus on your business implementation
Request body is completely related to your business so you can focus on it vs dealing with security related things in your body.
Everytime you create a new Request for a new endpoint you don't want to keep adding tokens in all the requests
It's just my opinion based on my experience.
I'm trying to create a REST API following the HTTP method semantics but I got stuck with the DELETE method.
In my use case, the service is behind a gateway that authenticates the user. This service uses a SSO token that then is used to authenticate the user and get his details. From this point, I'm trying to make a call to my service where I use the id of the resource I want to delete as a path variable but then I don't know how to pass the id of the user for validation.
I've read many posts about the problems of adding a body to a DELETE method. I also think adding a custom header to identify the user is not the right way. Out of the options I have, I think only 2 are sensible:
Issue a POST request with the user id as the body. I don't like this one because I'm basically using POST with an identified resource and because semantically sounds wrong to me.
Make the request so the user id is a path variable. It would look like this. path/to/service/resourceId/{resourceId}/userId/{userId}. My problem with this one is that in the POST and PUT requests, the userId is part of the body. The API wouldn't look consistent but I guess I could still change the other 2 so the user id is also part of the url.
Any suggestions?
You should use HTTP header param for passing user token.
#DELETE
#Path("/{id}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Info deleteInfo(
#HeaderParam("Authorization") String token,
#PathParam("id") Long id){
}
HTTP authentication, maybe? That's what it is for, no? See RFC 7235.
Using :
spring-security 3.2.5
spring-security-oauth 2.0.7
I have a working oauth2 provider built with spring-security-oauth (oauth2).
I have my client configured in it to use authorization_code grant type.
The provider works perfectly :
Testing with curl, I can get an authorization code and exchange it for an access token.
So on the service provider part, all is fine.
Now I'm trying to implements the client application, also with spring-security-oauth.
I'm using xml configuration, strongly based on the example here, but using my own provider (mentionned above) instead of google.
When I make a call to a protected resource on my client, the OAuth2ClientAuthenticationProcessingFilter tries to obtain an access token, so it redirect to my service provider. That one force the user to log in, as expected, and then redirect him to the configured redirect_uri (the redirect uri is the one configured for my OAuth2ClientAuthenticationProcessingFilter : something like http://myClient/context/external/login).
The problem is : the client never read the authorization code in the request returned from the service provider. So the OAuth2ClientAuthenticationProcessingFilter restarts the flow, asking for an authorization code.
I've been able to make it work by modifying the OAuth2ClientAuthenticationProcessingFilter to read the request and set the authorization code in the AccessTokenRequest. Here is the snippet :
OAuth2AccessToken accessToken;
try {
String code = request.getParameter("code");
if(code != null) {
restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAuthorizationCode(code);
}
accessToken = restTemplate.getAccessToken();
...
Before trying this, I tried to make a "call hierarchy" on the method org.springframework.security.oauth2.client.token.AccessTokenRequest.setAuthorizationCode(), to find where in the code spring does call the method, but it returned nothing.
Is that a bug ?
I really would like not to have to replace the OAuth2ClientAuthenticationProcessingFilter with my own.
Does someone made it work ( in that version or another) ?
Update
It's the setAuthorizationCode() method that is never called (error in my initial question). But I digged a little more and I realized this is not the problem.
I can assert that the OAuth2ClientContextFilter is called before OAuth2ClientAuthenticationProcessingFilter (I checked that with a debugger).
What I found, but don't know if it is normal :
The default constructor of DefaultAccessTokenRequest is only called once : at the application startup. The other constructor (the one taking the parameter's map), is never called. Since I've seen in RestTemplateBeanDefinitionParser that the access token request is scoped 'request', I would expect the constructor taking the parameter's map to be called on each new http request to my client application.
In the RestTemplateBeanDefinitionParser :
BeanDefinitionBuilder request = BeanDefinitionBuilder.genericBeanDefinition(DefaultAccessTokenRequest.class);
request.setScope("request");
request.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
request.addConstructorArgValue("#{request.parameterMap}");
request.addPropertyValue("currentUri", "#{request.getAttribute('currentUri')}");
That can explain my problem with the authorization code never read from the request. The hack I mentionned in my initial question just pushed back the problem. Now I get csrf protection errors because the AccessTokenRequest always remembers some stateKey when I presume it does not need anymore once I get the access token.
Again, maybe I just misunderstand the hole think, so feel free to tell me :)
I did not post my configuration because it's pretty the same as that one here.
You need an OAuth2ClientContextFilter and it needs to fire before the authentication processing filter (it basically does that stuff you have in your custom filter). I can't tell from the code you posted if you have one and it isn't firing or you don't have one.
Sorry for all of you that spent precious time trying to help me. I was so focused debugging that I missed a configuration problem.
Do never configure Oauth2RestTemplate like this :
<beans:bean id="myRestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<beans:constructor-arg ref="myResourceId"/>
</beans:bean>
That explain why the DefaultAccessTokenRequest was not request scoped, hence it's default controller called instead of the one taking request's parameter map.
Don't do like me and use the xml namespace ! :
<oauth:rest-template id="myRestTemplate" resource="myResourceId"/>
Still wondering why I've done that :P
I know this has been asked already, but I am not able to get it to work.
Here is what I would like to get accomplished:
I am using Spring Security 3.2 to secure a REST-like service. No server side sessions.
I am not using basic auth, because that would mean that I need to store the user's password in a cookie on client side. Otherwise the user would need to login with each page refresh/ change. Storing a token is I guess the lesser evil.
A web client (browser, mobile app) calls a REST-like URL to login "/login" with username and password
The server authenticates the user and sends a token back to the client
The client stores the token and adds it to the http request header with each api call
The server checks the validity of the token and sends a response accordingly
I did not even look at the token generation part yet. I know it is backwards, but I wanted to get the token validation part implemented first.
I am trying to get this accomplished by using a custom filer (implementation of AbstractAuthenticationProcessingFilter), however I seem to have the wrong idea about it.
Defining it like this:
public TokenAuthenticationFilter() {
super("/");
}
will only trigger the filter for this exact URL.
I am sticking to some sample implementation, where it calls AbstractAuthenticationProcessingFilter#requiresAuthentication which does not accept wildcards.
I can of course alter that behavior, but this somehow makes me think that I am on the wrong path.
I also started implementing a custom AuthenticationProvider. Maybe that is the right thing?
Can someone give me a push into the right direction?
I think pre-auth filter is a better fit for your scenario.
Override AbstractPreAuthenticatedProcessingFilter's getPrincipal and getCredentials methods.
In case the token is not present in the header, return null from getPrincipal.
Flow:
User logs in for the first time, no header passed, so no
authentication object set in securityContext, normal authentication
process follows i.e. ExceptionTranslation filter redirtects the user
to /login page based on form-logon filter or your custom authenticationEntryPoint
After successful authentication, user requests secured url, pre-auth filter gets token from header authentication object set in
securityContext, if user have access he is allowed to access secured
url