Discussion:
How to get username of authenticated user to create a token for a downstream call
Burkard Stephan
2018-08-03 13:13:21 UTC
Permalink
Hi

I try to accomplish something I thought is quite a standard use case. I was probably wrong since I did not found a complete example for it.

Goal: Build a secured CXF/SpringBoot webservice that calls other secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring Security (4.2.x)

**What I want to accomplish**

- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.

- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor (no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring SecurityContext from the UsernameToken and authenticate the user against LDAP.

- My CXF/SpringBoot webservice must call a downstream webservice that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't know where to get it.

Question: In my Spring SecurityContext I have the authenticated user. But how can I "hand over" the username to the TokenInterceptor?

Question: Let's assume I do two downstream calls to finally create the response for the initial service request. Are these calls individual "contexts" from a CXF point of view or is there some kind of "management" around that holds all data of all the calls?

Thanks
Stephan
Andrei Shakirin
2018-08-06 20:45:23 UTC
Permalink
Hi,

Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from SecurityContext, you can simply set property in client call context and read this property in your client Token interceptor:


((BindingProvider)proxy).getRequestContext().put("thread.local.request.context", "true");
myUser = securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);


...
public class TokenInterceptor extends AbstractPhaseInterceptor<Message>
{


public void handleMessage(Message message) {
String username = message.getContextualProperty("authenticatedUser");
...
}

Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token for a
downstream call
Hi
I try to accomplish something I thought is quite a standard use case. I was
probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring Security (4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with AuthenticationManager,
UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor (no
password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring SecurityContext
from the UsernameToken and authenticate the user against LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice that
accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends AbstractTokenInterceptor to
add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't know where to get it.
Question: In my Spring SecurityContext I have the authenticated user. But how
can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create the response
for the initial service request. Are these calls individual "contexts" from a CXF
point of view or is there some kind of "management" around that holds all data
of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data will be on our systems. Please see our contacts privacy notice at Talend, Inc. <https://www.talend.com/contacts-privacy-policy/>
Burkard Stephan
2018-08-07 15:14:46 UTC
Permalink
Yes, you understood it correct.

Thanks a lot, I was able to find a solution with the help of your code snippets.

Interesting enough: since I use Apache Camel I can simply set an ExchangeProperty on the Camel Exchange and Camel automatically copies it on the CXF RequestContext. Very convenient!

In my TokenInterceptor I can read the property in the addToken method and use it to create the token.

Thanks a lot
Stephan


-----Ursprüngliche Nachricht-----
Von: Andrei Shakirin <***@talend.com>
Gesendet: Montag, 6. August 2018 22:45
An: ***@cxf.apache.org
Betreff: RE: How to get username of authenticated user to create a token for a downstream call

Hi,

Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from SecurityContext, you can simply set property in client call context and read this property in your client Token interceptor:


((BindingProvider)proxy).getRequestContext().put("thread.local.request.context", "true"); myUser = securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);


...
public class TokenInterceptor extends AbstractPhaseInterceptor<Message> {


public void handleMessage(Message message) {
String username = message.getContextualProperty("authenticatedUser");
...
}

Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring Security (4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice that
accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create the
response for the initial service request. Are these calls individual
"contexts" from a CXF point of view or is there some kind of
"management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data will be on our systems. Please see our contacts privacy notice at Talend, Inc. <https://www.talend.com/contacts-privacy-policy/>
Colm O hEigeartaigh
2018-08-13 11:07:08 UTC
Permalink
An alternative could be to set the principal on the returned Credential
object in your validator, for example:

credential.setPrincipal(securityContext.getAuthentication().getPrincipal());

CXF will use this to set up a SecurityContext object which returns this
principal via "securityContext.getUserPrincipal()". This is stored in the
current message via the key "SecurityContext.class" so you could retrieve
this object in your interceptor and extract the principal from it.

Colm.
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically copies it on
the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken method and
use it to create the token.
Thanks a lot
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a token
for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context and
((BindingProvider)proxy).getRequestContext().put("thread.local.request.context",
"true"); myUser = securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);
...
public class TokenInterceptor extends AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring Security (4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice that
accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create the
response for the initial service request. Are these calls individual
"contexts" from a CXF point of view or is there some kind of
"management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data will be
on our systems. Please see our contacts privacy notice at Talend, Inc. <
https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaigh

Talend Community Coder
http://coders.talend.com
Burkard Stephan
2018-08-13 12:26:05 UTC
Permalink
Hi Colm

Sounds great. But where do I get the "securityContext" from in my validator?

And who has it created? Another interceptor that is called earlier?

Thanks
Stephan


-----Ursprüngliche Nachricht-----
Von: Colm O hEigeartaigh <***@apache.org>
Gesendet: Montag, 13. August 2018 13:07
An: ***@cxf.apache.org
Betreff: Re: How to get username of authenticated user to create a token for a downstream call

An alternative could be to set the principal on the returned Credential object in your validator, for example:

credential.setPrincipal(securityContext.getAuthentication().getPrincipal());

CXF will use this to set up a SecurityContext object which returns this principal via "securityContext.getUserPrincipal()". This is stored in the current message via the key "SecurityContext.class" so you could retrieve this object in your interceptor and extract the principal from it.

Colm.
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically copies
it on the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken method
and use it to create the token.
Thanks a lot
Stephan
-----Ursprüngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a
token for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context
((BindingProvider)proxy).getRequestContext().put("thread.local.request
.context", "true"); myUser =
securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);
...
public class TokenInterceptor extends
AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring
Security
(4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice
that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create
the response for the initial service request. Are these calls
individual "contexts" from a CXF point of view or is there some kind
of "management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data
will be on our systems. Please see our contacts privacy notice at
Talend, Inc. < https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaig
Colm O hEigeartaigh
2018-08-13 14:44:04 UTC
Permalink
Post by Burkard Stephan
Sounds great. But where do I get the "securityContext" from in my validator?
You don't. You just set the principal on the Credential Object that the
Validator returns, and CXF takes care of populating the SecurityContext for
you.
Post by Burkard Stephan
And who has it created? Another interceptor that is called earlier?
It's created by the WSS4JInInterceptor after processing the security
requirements:

https://github.com/apache/cxf/blob/c7eee85aaebdfaae988adfcf8cc43206e568fda8/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java#L558
https://github.com/apache/cxf/blob/master/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/DefaultWSS4JSecurityContextCreator.java

Colm.
Post by Burkard Stephan
Thanks
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 13. August 2018 13:07
Betreff: Re: How to get username of authenticated user to create a token
for a downstream call
An alternative could be to set the principal on the returned Credential
credential.setPrincipal(securityContext.getAuthentication().
getPrincipal());
CXF will use this to set up a SecurityContext object which returns this
principal via "securityContext.getUserPrincipal()". This is stored in the
current message via the key "SecurityContext.class" so you could retrieve
this object in your interceptor and extract the principal from it.
Colm.
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically copies
it on the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken method
and use it to create the token.
Thanks a lot
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a
token for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context
((BindingProvider)proxy).getRequestContext().put("thread.local.request
.context", "true"); myUser =
securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);
...
public class TokenInterceptor extends
AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other
secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring
Security
(4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice
that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't
know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create
the response for the initial service request. Are these calls
individual "contexts" from a CXF point of view or is there some kind
of "management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data
will be on our systems. Please see our contacts privacy notice at
Talend, Inc. < https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
--
Colm O hEigeartaigh

Talend Community Coder
http://coders.talend.com
Colm O hEigeartaigh
2018-08-13 14:45:05 UTC
Permalink
Post by Colm O hEigeartaigh
You don't. You just set the principal on the Credential Object that the
Validator returns, and CXF takes care of populating the SecurityContext for
you.
Ah you mean in this line?

credential.setPrincipal(securityContext.getAuthentication().getPrincipal());

That's the Spring SecurityContext not the CXF one.

Colm.
Post by Colm O hEigeartaigh
Post by Burkard Stephan
And who has it created? Another interceptor that is called earlier?
It's created by the WSS4JInInterceptor after processing the security
https://github.com/apache/cxf/blob/c7eee85aaebdfaae988adfcf8cc432
06e568fda8/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/
WSS4JInInterceptor.java#L558
https://github.com/apache/cxf/blob/master/rt/ws/security/
src/main/java/org/apache/cxf/ws/security/wss4j/
DefaultWSS4JSecurityContextCreator.java
Colm.
Post by Burkard Stephan
Thanks
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 13. August 2018 13:07
Betreff: Re: How to get username of authenticated user to create a token
for a downstream call
An alternative could be to set the principal on the returned Credential
credential.setPrincipal(securityContext.getAuthentication().
getPrincipal());
CXF will use this to set up a SecurityContext object which returns this
principal via "securityContext.getUserPrincipal()". This is stored in
the current message via the key "SecurityContext.class" so you could
retrieve this object in your interceptor and extract the principal from it.
Colm.
On Tue, Aug 7, 2018 at 4:14 PM, Burkard Stephan <
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically copies
it on the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken method
and use it to create the token.
Thanks a lot
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a
token for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context
((BindingProvider)proxy).getRequestContext().put("thread.local.request
.context", "true"); myUser =
securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);
...
public class TokenInterceptor extends
AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other
secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring
Security
(4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against
LDAP.
Post by Burkard Stephan
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice
that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't
know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create
the response for the initial service request. Are these calls
individual "contexts" from a CXF point of view or is there some kind
of "management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data
will be on our systems. Please see our contacts privacy notice at
Talend, Inc. < https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
--
Colm O hEigeartaigh

Talend Community Coder
http://coders.talend.com
Burkard Stephan
2018-09-13 09:27:53 UTC
Permalink
Hi Colm

I tried this, but the SecurityContext is always null. I am surely missing something.

My web service is configured with the WSS username/password validator:

endpoint.getInInterceptors().add(wss4JInInterceptor);
endpoint.getProperties().put(SecurityConstants.USERNAME_TOKEN_VALIDATOR, wssPasswordValidator);

The "wssPasswordValidator" creates the Spring-Security principal and retuns it to CXF as you suggested:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
// Authenticate against Spring-Security
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Pass principal back to CXF
credential.setPrincipal(authentication);


My client for the downstream backend call is configured to use a custom token interceptor:

Dispatch<Source> dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
Client client = ((org.apache.cxf.jaxws.DispatchImpl)dispatch).getClient();
client.getOutInterceptors().add(new MyCustomSecurityTokenInterceptor());

And the token interceptor tries to get the principal from the security context (ugly conditionals to show what I get):

protected void addToken(SoapMessage message) {
String username = "default";
SecurityContext cxfSecurityContext = message.get(SecurityContext.class);
Principal principal = null;

if(cxfSecurityContext == null) {
logger.info("CXF security context is null");
} else {
principal = cxfSecurityContext.getUserPrincipal();
}
if(principal == null) {
logger.info("CXF principle is null");
} else {
if(StringUtils.hasText(principal.getName())) {
logger.info("Using username from CXF context: " + username);
username = principal.getName();
}
}

Output:
CXF security context is null
CXF principle is null

Do I need to "transport" the SecurityContext somehow from in the incoming call to the downstream call?

Thanks
Stephan


-----Ursprüngliche Nachricht-----
Von: Colm O hEigeartaigh <***@apache.org>
Gesendet: Montag, 13. August 2018 13:07
An: ***@cxf.apache.org
Betreff: Re: How to get username of authenticated user to create a token for a downstream call

An alternative could be to set the principal on the returned Credential object in your validator, for example:

credential.setPrincipal(securityContext.getAuthentication().getPrincipal());

CXF will use this to set up a SecurityContext object which returns this principal via "securityContext.getUserPrincipal()". This is stored in the current message via the key "SecurityContext.class" so you could retrieve this object in your interceptor and extract the principal from it.

Colm.
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically copies
it on the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken method
and use it to create the token.
Thanks a lot
Stephan
-----Ursprüngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a
token for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context
((BindingProvider)proxy).getRequestContext().put("thread.local.request
.context", "true"); myUser =
securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);
...
public class TokenInterceptor extends
AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring
Security
(4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice
that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create
the response for the initial service request. Are these calls
individual "contexts" from a CXF point of view or is there some kind
of "management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data
will be on our systems. Please see our contacts privacy notice at
Talend, Inc. < https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaigh

Talend C
Colm O hEigeartaigh
2018-09-13 11:20:28 UTC
Permalink
Yes trying to retrieve the SecurityContext from the Message in a separate
interceptor chain won't work. You could try adding an interceptor on the
receiving side to store the Security Context principal so that it's
accessible to your client somehow. I'm not sure if storing it on the
message exchange as opposed to the message might work.

Colm.
Post by Burkard Stephan
Hi Colm
I tried this, but the SecurityContext is always null. I am surely missing something.
endpoint.getInInterceptors().add(wss4JInInterceptor);
endpoint.getProperties().put(SecurityConstants.USERNAME_TOKEN_VALIDATOR,
wssPasswordValidator);
The "wssPasswordValidator" creates the Spring-Security principal and
UsernamePasswordAuthenticationToken token = new
UsernamePasswordAuthenticationToken(username, password);
// Authenticate against Spring-Security
Authentication authentication =
authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Pass principal back to CXF
credential.setPrincipal(authentication);
Dispatch<Source> dispatch = service.createDispatch(portName,
Source.class, Service.Mode.PAYLOAD);
Client client =
((org.apache.cxf.jaxws.DispatchImpl)dispatch).getClient();
client.getOutInterceptors().add(new
MyCustomSecurityTokenInterceptor());
And the token interceptor tries to get the principal from the security
protected void addToken(SoapMessage message) {
String username = "default";
SecurityContext cxfSecurityContext =
message.get(SecurityContext.class);
Principal principal = null;
if(cxfSecurityContext == null) {
logger.info("CXF security context is null");
} else {
principal = cxfSecurityContext.getUserPrincipal();
}
if(principal == null) {
logger.info("CXF principle is null");
} else {
if(StringUtils.hasText(principal.getName())) {
logger.info("Using username from CXF context: " + username);
username = principal.getName();
}
}
CXF security context is null
CXF principle is null
Do I need to "transport" the SecurityContext somehow from in the incoming
call to the downstream call?
Thanks
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 13. August 2018 13:07
Betreff: Re: How to get username of authenticated user to create a token
for a downstream call
An alternative could be to set the principal on the returned Credential
credential.setPrincipal(securityContext.getAuthentication().getPrincipal());
CXF will use this to set up a SecurityContext object which returns this
principal via "securityContext.getUserPrincipal()". This is stored in the
current message via the key "SecurityContext.class" so you could retrieve
this object in your interceptor and extract the principal from it.
Colm.
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically copies
it on the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken method
and use it to create the token.
Thanks a lot
Stephan
-----UrsprÃŒngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a
token for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context
((BindingProvider)proxy).getRequestContext().put("thread.local.request
.context", "true"); myUser =
securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser", myUser);
...
public class TokenInterceptor extends
AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a token
for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other
secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring
Security
(4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and WSS4JInInterceptor
(no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice
that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't
know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create
the response for the initial service request. Are these calls
individual "contexts" from a CXF point of view or is there some kind
of "management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data
will be on our systems. Please see our contacts privacy notice at
Talend, Inc. < https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
--
Colm O hEigeartaigh

Talend Community Coder
http://coders.talend.com
Burkard Stephan
2018-09-14 08:06:30 UTC
Permalink
Ah, then I am fine. I thought that it *should* work but I am doing something wrong.

So, I simply get the username from Spring Security that "wraps" the whole service call orchestration.

Thanks a lot
Stephan

-----Ursprüngliche Nachricht-----
Von: Colm O hEigeartaigh <***@apache.org>
Gesendet: Donnerstag, 13. September 2018 13:20
An: Burkard Stephan <***@visana.ch>
Cc: ***@cxf.apache.org
Betreff: Re: How to get username of authenticated user to create a token for a downstream call

Yes trying to retrieve the SecurityContext from the Message in a separate interceptor chain won't work. You could try adding an interceptor on the receiving side to store the Security Context principal so that it's accessible to your client somehow. I'm not sure if storing it on the message exchange as opposed to the message might work.

Colm.
Post by Burkard Stephan
Hi Colm
I tried this, but the SecurityContext is always null. I am surely missing something.
endpoint.getInInterceptors().add(wss4JInInterceptor);
endpoint.getProperties().put(SecurityConstants.USERNAME_TOKEN_VALIDATO
R,
wssPasswordValidator);
The "wssPasswordValidator" creates the Spring-Security principal and
UsernamePasswordAuthenticationToken token = new
UsernamePasswordAuthenticationToken(username, password);
// Authenticate against Spring-Security
Authentication authentication =
authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Pass principal back to CXF
credential.setPrincipal(authentication);
Dispatch<Source> dispatch = service.createDispatch(portName,
Source.class, Service.Mode.PAYLOAD);
Client client =
((org.apache.cxf.jaxws.DispatchImpl)dispatch).getClient();
client.getOutInterceptors().add(new
MyCustomSecurityTokenInterceptor());
And the token interceptor tries to get the principal from the security
protected void addToken(SoapMessage message) {
String username = "default";
SecurityContext cxfSecurityContext =
message.get(SecurityContext.class);
Principal principal = null;
if(cxfSecurityContext == null) {
logger.info("CXF security context is null");
} else {
principal = cxfSecurityContext.getUserPrincipal();
}
if(principal == null) {
logger.info("CXF principle is null");
} else {
if(StringUtils.hasText(principal.getName())) {
logger.info("Using username from CXF context: " + username);
username = principal.getName();
}
}
CXF security context is null
CXF principle is null
Do I need to "transport" the SecurityContext somehow from in the
incoming call to the downstream call?
Thanks
Stephan
-----Ursprüngliche Nachricht-----
Gesendet: Montag, 13. August 2018 13:07
Betreff: Re: How to get username of authenticated user to create a
token for a downstream call
An alternative could be to set the principal on the returned
credential.setPrincipal(securityContext.getAuthentication().getPrincip
al());
CXF will use this to set up a SecurityContext object which returns
this principal via "securityContext.getUserPrincipal()". This is
stored in the current message via the key "SecurityContext.class" so
you could retrieve this object in your interceptor and extract the principal from it.
Colm.
On Tue, Aug 7, 2018 at 4:14 PM, Burkard Stephan
Post by Burkard Stephan
Yes, you understood it correct.
Thanks a lot, I was able to find a solution with the help of your code snippets.
Interesting enough: since I use Apache Camel I can simply set an
ExchangeProperty on the Camel Exchange and Camel automatically
copies it on the CXF RequestContext. Very convenient!
In my TokenInterceptor I can read the property in the addToken
method and use it to create the token.
Thanks a lot
Stephan
-----Ursprüngliche Nachricht-----
Gesendet: Montag, 6. August 2018 22:45
Betreff: RE: How to get username of authenticated user to create a
token for a downstream call
Hi,
Not 100% sure that I understood your use case correctly.
If you have authenticated user in your service implementation from
SecurityContext, you can simply set property in client call context
((BindingProvider)proxy).getRequestContext().put("thread.local.reque
st
.context", "true"); myUser =
securityContext.getAuthentication().getPrincipal();
((BindingProvider)proxy).getRequestContext().put("authenticatedUser"
,
myUser);
...
public class TokenInterceptor extends
AbstractPhaseInterceptor<Message> {
public void handleMessage(Message message) {
String username = message.getContextualProperty(
"authenticatedUser");
...
}
Regards,
Andrei.
-----Original Message-----
Sent: Freitag, 3. August 2018 15:13
Subject: How to get username of authenticated user to create a
token for a downstream call
Hi
I try to accomplish something I thought is quite a standard use case.
I was probably wrong since I did not found a complete example for it.
Goal: Build a secured CXF/SpringBoot webservice that calls other
secured webservice(s).
Setup: SpringBoot (1.5.x), CXF (3.1.x), WSS4J (2.1.x), Spring
Security
(4.2.x)
**What I want to accomplish**
- My CXF/SpringBoot webservice must authenticate requests against LDAP.
=> I have a working Spring Security setup with
AuthenticationManager, UserDetailsService etc.
=> This setup depends on the Spring SecurityContext.
- My CXF/SpringBoot webservice must accept WSS Username/Password (Plaintext).
=> I use a combination of SAAJInInterceptor and
WSS4JInInterceptor (no password callback!) to create a UsernameToken from the WSS header.
=> I use a custom "ws-security.ut.validator" to create a Spring
SecurityContext from the UsernameToken and authenticate the user against
LDAP.
- My CXF/SpringBoot webservice must call a downstream webservice
that accepts a proprietary token type.
=> This requires another CXF (client) endpoint configuration.
=> I use a custom out-interceptor that extends
AbstractTokenInterceptor to add the proprietary token to the request.
=> However, currently the username is hardcoded because I don't
know where to get it.
Question: In my Spring SecurityContext I have the authenticated user.
But how can I "hand over" the username to the TokenInterceptor?
Question: Let's assume I do two downstream calls to finally create
the response for the initial service request. Are these calls
individual "contexts" from a CXF point of view or is there some
kind of "management" around that holds all data of all the calls?
Thanks
Stephan
As a recipient of an email from Talend, your contact personal data
will be on our systems. Please see our contacts privacy notice at
Talend, Inc. < https://www.talend.com/contacts-privacy-policy/>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com
--
Colm O hEigeartaigh
Loading...