I'm using the current release of Spring Security as an OAuth2 client.
It is working fine. But how do I get the value of the expires_in the authentication server sent back along with the Access and Refresh tokens, etc?
Or does Spring Security convert the expires_in to a timestamp with a timeLeft method or similar?
Related
Spring Security version 5.4.0
Usually client-id and client-secret are values supplied by Oauth2 provider and they are permanent for each client and can be specified in the configuration file like this
spring:
security:
oauth2:
client:
registration:
google:
client-id: google-client-id
client-secret: google-client-secret
But in my case I have fixed client-id but client-secret is generated based on some parameters by every attempt to get authentication code.
In the final class ClientRegistration the client-secret is defined as a string value, so it is not possible to adopt this class in my case
My question whether it it possible to use Spring Security in such conditions and if yes, what could be adopted/configured?
It sounds like you might be doing PKCE.
In that case, you can leave the secret empty and Spring Security will generate the code challenge and verifier as part of the /authorize request.
From the docs:
Public Clients are supported using Proof Key for Code Exchange (PKCE). If the client is running in an untrusted environment (eg. native application or web browser-based application) and therefore incapable of maintaining the confidentiality of its credentials, PKCE will automatically be used when the following conditions are true:
client-secret is omitted (or empty)
client-authentication-method is set to "none" (ClientAuthenticationMethod.NONE)
If you are doing something custom, then you might consider standardizing to PKCE.
But, if you can't do that, then Spring Security ships with various hooks for adding custom parameters to the /authorize and /token requests. I'd recommend taking a look at DefaultOAuth2AuthorizationRequestResolver#setAuthorizationRequestCustomizer and DefaultAuthorizationCodeTokenResponseClient#setRequestEntityConverter.
You can register your custom authorization request and token request in the DSL like so:
http
.oauth2Login((oauth2) -> oauth2
.authorizeEndpoint((authorize) -> authorize
.authorizeRequestResolver(...)
)
.tokenEndpoint((token) -> token
.accessTokenResponseClient(...)
)
);
I have two spring-boot processes. I have Spring Security enabled on both, and I'm using Spring Security OAuth2 SSO setup. I'm also using Eureka and Zuul to allows calls into Boot1 to call into services in Boot2. UI is using Angular with REST calls into the services, and the token being used is a Json Web Token.
This all seems to work, certainly in the UI. All the requests use the Authorization header (which contains the JWT) and the spring security filter in the services successfully parse the JWT and extracts the Security Context from it. As part of the Spring Web processing, it adds a JSESSIONID value to the client's cookie.
Recently, I only had Spring security on Boot1. When calling rest services into Boot1, which end up using Zuul to forward requests to Boot2, all I required in the rest client was to include the Authorization header with the JWT and it all worked fine.
However, I have recently added Spring Security to Boot2 (using the #EnableResourceServer annotation) and now rest calls fail unless I have both the Authorization header as well as a Cookie header that contains a JSESSIONID value. Calls don't fail, but they return empty values.
I've enabled logging to Spring Security, and it validates all correctly in Boot1. It's going into the same ZuulFilter. But there's no activity on Boot2.
Is there something in Zuul that requires a JSESSIONID value to be defined in order for it forward the request? Or is this in Boot2, where it is expecting a JSESSIONID header value due to the introduction of Spring Security filters?
--- update ---
I've stepped through boot1. From what I can see, code in the OAuth2TokenRelayFilter is throwing an exception. Specifically, the method getAccessToken is calling restTemplate.getAccessToken().getValue (line 90, version 1.1.0-RELEASE) which throws a UserRedirectRequiredException.
So, while the TokenRelayFilter has a token, it's attempting to refresh it. When it receives an exception, it's throwing a BadCredentialsException instead of using what's already been defined.
--- update 2 ---
Putting a breakpoint in OAuth2RestOperationsConfiguration, making rest calls without the JSESSIONID always ends up with a new DefaultOAuth2ClientContext to be created, as it's trying to create session-scoped beans. With the JSESSIONID, it's using a persisted DefaultOAuth2ClientContext, which will have the context.
So, is it possible to, when constructing the DefaultOAuth2ClientContext, to see if the request contains the token and uses it? Or something like this? We're trying to move to stateless services, and this seems to be a hurdle towards this.
This turned out to be an issue with the client-id values used by the different parts of the system.
Looking at OAuth2TokenRelayFilter, it is attempting to refresh the token if the client-id defined for the resource server (boot1) matches that which is defined as part of the token contained within the token provided with the request. In my case, this was true: the token was defined using the same client-id.
That really is not correct. When I update my rest client to use a token, but using a different client-id when requesting the token, then the request is forwarded correctly as expected, without the need for a jsessionid. This is exactly what I want.
I suspect that this was caused, in the end, by incorrect use of client-id values by the components of my system.
I am using WIF 4.5 to authenticate my user and need to use the Security Token from the WIF 4.5 authentication to call a REST API.
Here is the code I am using to get the IMS Security Token for the currently logged in user.
BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
var myToken = bootstrapContext.SecurityToken;
So, far, so good. The token exists and has the Id, ValidFrom, and ValidTo values. The Security Keys count is zero, but I am not sure if that is relevant.
Now, I need to know how to use this token to then call the REST API.
It seems like I am supposed to use the JWT Handler for this:
https://blogs.msdn.microsoft.com/vbertocci/2012/11/20/introducing-the-developer-preview-of-the-json-web-token-handler-for-the-microsoft-net-framework-4-5/
But, I am having problems getting this to work. The code on the linked to page above actually does not compile as is. Some of the properties have been changed/renamed.
This is my setup:
1 authentication server which gives out JWT token on successfull
authentication.
Multiple API resource servers which gives information (when the user
is authenticated).
Now I want to build my ASP.NET MVC frontend. Is it ok to take the token, which I receive after authentication, and put it in a cookie so I can access it with every secured call I need to make? I use the RestSharp DLL for doing my http calls. If it has a security flaw, then where should I store my token?
I would use this code for the cookie:
System.Web.HttpContext.Current.Response.Cookies.Add(new System.Web.HttpCookie("Token")
{
Value = token.access_token,
HttpOnly = true
});
You’re on the right path! The cookie should always have the HttpOnly flag, setting this flag will prevent the JavaScript environment (in the web browser) from accessing the cookie. This is the best way to prevent XSS attacks in the browser.
You should also use the Secure flag in production, to ensure that the cookie is only sent over HTTPS.
You also need to prevent CSRF attacks. This is typically done by setting a value in another cookie, which must be supplied on every request.
I work at Stormpath and we’ve written a lot of information about front-end security. These two posts may be useful for understanding all the facets:
Token Based Authentication for Single Page Apps (SPAs)
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts/
Are you generating your own JWTs?
If yes, you should consider using a signing algorithm based on asymetric encryption, like "RS256" or "RS512" -- this way you can verify the claims in your client application without sharing the private secret.
Do you really need to pass the JWT into the Cookie?
It might be safer to just put a random id in your Cookie, which references the JWT access token, and do the de-referencing magic on the server which serves your web-app.
How to get access token as json response in implicit call.What custom filter do I need to add in spring-servlet ?
There is no need to add any custom filter to get an access_token in the implicit flow. In the spring security oauth's "oauth:authorization-server" bean configurtion you need to include the type's of flow that your auth server will be accepting. You can refer to a sample application configuration I was playing around here.