Spring Security for SOAP web services- Token based authentication - spring

I'm developing SOAP web services using spring-ws framework and it is required to implement authentication for web service access.I'm trying to implement token based authentication as follows.
There is a separate web method to user authentication. If user credentials are valid, system generated token will be returned to the client. Token will have limited validity period.
When user accessing rest of the web methods, its required to provide username with the valid token which is returned by the authentication method.
Once the token expired, user need to get the valid token again and again through the authentication web service.
Please advice, what are the available methods in spring framework to implement such a scenario. Since I'm newer to spring web-service security, its better if I can have simple guideline on how to implement.
Thank you.

Here you can use Wss4jSecurityInterceptor - an EndpointInterceptor which can be used to perform security operations on request messages (of course before calling the Endpoint)
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="UsernameToken Encrypt" />
</bean>

Related

Spring Security multiple calls to different OAuth servers requiring multiple tokens in SecurityContext

I have a spring application that verifies a JWT token on the rest endpoint.
Using SecurityChain
.oAuth2ResourceServer()
.jwt()
This seems to create a JwtAuthenticationToken in the ReactiveSecurityContextHolder.
I then want to flow the input from this endpoint where the client is authenticated by checking the bearer token. And then call another rest service using a webClient. This web client needs to authenticate with grant type password with the external service using a different OAuth server and get is own bearer token.
The problem is that the web client uses the ReactiveSecurityContextHolder that contains the authenticated JWT. And tries to use this information rather than connect and authenticate my app to the rest endpoint.
I have set up the Yaml to register my client
spring:
security:
oauth2:
client:
registration:
Myapp:
client-id:
client-secret:
token-uri:
authorization-grant-type:
Then adding a filter function of
ServerOAuth2AuthorizedClientExchangeFilterFunction
But I get principalName cannot be empty as it seems to reuse the security context from verifying the caller on the rest endpoint in my application.
How should it be designed or samples to show how you can use different security contexts or get tokens differently between service to service calls?
You are correct that the design of ServerOAuth2AuthorizedClientExchangeFilterFunction is designed to be based on the currently-authorized client, which you've explained that you don't want to use in this case.
You've indicated that you want to use the client's credentials as the username and password for the Resource Owner Password Grant. However, there's nothing in Spring Security that is going to do that.
However, you can use WebClientReactivePasswordTokenResponseClient directly in order to formulate the custom request yourself.
Briefly, this would be a custom ExchangeFilterFunction that would look something like:
ClientRegistrationRespository clientRegistrations;
ReactiveOAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest>
accessTokenResponseClient = new WebClientReactivePasswordTokenResponseClient();
Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
return this.clientRegistrations.findByRegistrationId("registration-id")
.map(clientRegistration -> new OAuth2PasswordGrantRequest(
clientRegistration,
clientRegistration.getClientId(),
clientRegistration.getClientSecret())
.map(this.accessTokenResponseClient::getTokenResponse)
.map(tokenResponse -> ClientRequest.from(request)
.headers(h -> h.setBearerAuth(tokenResponse.getAccessToken().getTokenValue())
.build())
.flatMap(next::exchange);
}
(For brevity, I've removed any error handling.)
The above code takes the following steps:
Look up the appropriate client registration -- this contains the provider's endpoint as well as the client id and secret
Construct an OAuth2PasswordGrantRequest, using the client's id and secret as the resource owner's username and password
Perform the request using the WebClientReactivePasswordTokenResponseClient
Set the access token as a bearer token for the request
Continue to the next function in the chain
Note that to use Spring Security's OAuth 2.0 Client features, you will need to configure your app also as a client. That means at least changing your DSL to include .oauth2Client() in addition to .oauth2ResourceServer(). It will also mean configuring a ClientRegistrationRepository. To keep my comment focused on filter functions, I've left that detail out, but I'd be happy to help there, too, if necessary.

Spring double SessionManagement in application

I have application with #Controller for web-view and #RestController for api layer.
Controller layer needs session, using cookies with JSESSIONID.
As for api layer, I've created JWT token, and used filterBefore that provides auth with given token
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
Now I have problem:
token auth needs sessionCreationPolicy(SessionCreationPolicy.STATELESS)
web-view still need JSESSIONID
Ofcause api can be used such a way, but in final it uses JSESSIONID instead of token, so if I change token in Authorization header (for ex. using another user), it will still using credentials of previously authorized user.
Are there any abilities to make session be STATELESS for one group of endpoints (for ex: /api/**), and ALWAYS on other endpoints.
Or maybe there is any kind of possibility to make #Controller work with token-based auth?
Thatnk you for any ideas.

Implementing JWT, JWE and JWS (signed JWT) with Keycloak in Spring Boot

I try to implement a simple OAuth2 "Client Authentication with Signed JWT" Demo App using Spring Boot and Keycloak as AuthService.
The idea is:
one secured REST service "The Producer"
offering an endpoint GET /person for all users/principals with the role "read_person"
offering an endpoint POST /person for all users/principals with the role "write_person"
another (unsecured) REST service "The Consumer"
offering an enpoint /api open for everybody
calling internal the "producer" viaFeignclient using an RequestInterceptor to pass the AccessToken (signed JWT / JWS)
I read about the docs:
http://www.keycloak.org/docs/latest/securing_apps/topics/oidc/java/client-authentication.html
saying:
Once the client application is started, it allows to download its public >key in JWKS format using a URL such as http://myhost.com/myapp/k_jwks, >assuming that http://myhost.com/myapp is the base URL of your client >application. This URL can be used by Keycloak (see below).
During authentication, the client generates a JWT token and signs it with >its private key and sends it to Keycloak in the particular backchannel >request (for example, code-to-token request) in the client_assertion >parameter.
I googled a lot to find tutorials/demos or docs about this topic but failed so far.
So here my questions:
How do I implement this "k_jwk" endpoint? Do I simple build a #RestController by myself in "the Producer"? How do I configure Keycloak to get aware of this URL?
How do I implement my "Consumer" to get fresh signed JWT from Keycloak?
Update
Removed irritating PS statement.
You don't need to implement the k_jwk endpoint, this is handled by the adapter. Keycloak will by default look at http:///your.app.com/k_jwk(but if needed you can override that in the console).
Then you need to configure your Spring Boot client, just use the same properties as the keycloak.json but in the application.properties format:
...
keycloak.credentials.jwt.client-keystore-file=classpath:keystore-client.jks
keycloak.credentials.jwt.client-keystore-type=JKS
etc ...
You need a token to call the producerbut as you said the entry point will be an insecured endpoint so you might want to use a Service Account for this.
I hope this will help.
Update
I couldnt solve this issue but learned some things about singned JWT in the mean time:
create a so called "Bearer Token" by creating a Json Structure with all necessary claims (sub, nbf, exp ...) by yourself and sign/certificate it with your JKS/Private Key from Keycloak. There are some nice third party libs beside Keycloak to do this.
To get a real AccessToken (JWE/JWS) from Keycloak: send this static final Bearer Token to Keycloak at /auth/realms/$realm/protocol/openid-connect/token/introspect
with QueryParams:
grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=$BEARER_TOKEN
Use the received real AccessToken to access the ResourceServer...

How does Spring Security/OAuth figure out the AuthenticationPrincipal

I have a spring project that uses spring-oauth2 and spring-security for authentication using an LDAP auth provider.
In controllers I can access the current principal's UserDetails using the #AuthenticationPrincipal annotation.
However, when I hit the endpoint with a client_credential token the #AuthenticationPrincipal is a String which is the OAuth client id. I understand that there's no notion of user when you authenticate with client_credentials, but I would like to have my Principal be a richer datatype. How does spring decide to set my principal as a String and can I override that behavior?
From the Oauth2 specs
The client credentials (or other forms of client authentication) can
be used as an authorization grant when the authorization scope is
limited to the protected resources under the control of the client,
or to protected resources previously arranged with the authorization
server. Client credentials are used as an authorization grant
typically when the client is acting on its own behalf (the client is
also the resource owner) or is requesting access to protected
resources based on an authorization previously arranged with the
authorization server.
because client can also be a resource owner, therefore spring will create authentication based on your client information.
I assume that you have setup org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter which is used to create authentication for the client.
You can create your own custom org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService or create your own org.springframework.security.authentication.AuthenticationProvider to override how the authentication object is created, but I prefer to use org.springframework.security.oauth2.provider.token.TokenEnhancer to add additional information to the token generated.

How to use two authentication providers in the same request with Spring Security?

I have two authentication providers configured in my application, one using LDAP and other looking in the database:
<sec:authentication-manager>
<sec:ldap-authentication-provider server-ref="ldapServer" />
<sec:authentication-provider user-service-ref="dbUserDetailsService" />
</sec:authentication-manager>
Spring tries to use LDAP first, and if it does not find the user there, it tries my custom provider.
What I want to do is force Spring to authenticate the user in all available providers. In this case, it will only try my custom provider if it can perform the login in the LDAP server first. If the authentication in the custom provider fails, the entire authentication fails.
Is it possible to achive this with Spring Security?
I think you can implement your own authentication provider, in which you inject two instances - one of LdapAuthenticationProvider and the other is DaoAuthenticationProvider.
You will have to implement a method
public Authentication authenticate(Authentication authentication) throws AuthenticationException
where you can proxy authentication call at first to LdapAuthenticationProvider and if it is successful then you call DaoAuthenticationProvider.

Resources