I have secured an enterprise application with Keycloak using standard wildfly based Keycloak adapters. Issue that I am facing is that the rest web services when invoked, needs to know the username that is currently logged in. How do I get the logged in user information from Keycloak?
I tried using SecurityContext
, WebListener
etc. But none of them are able to give me the required details.
You get all user information from the security context.
Example:
public class Greeter {
@Context
SecurityContext sc;
@GET
@Produces(MediaType.APPLICATION_JSON)
public String sayHello() {
// this will set the user id as userName
String userName = sc.getUserPrincipal().getName();
if (sc.getUserPrincipal() instanceof KeycloakPrincipal) {
KeycloakPrincipal<KeycloakSecurityContext> kp = (KeycloakPrincipal<KeycloakSecurityContext>) sc.getUserPrincipal();
// this is how to get the real userName (or rather the login name)
userName = kp.getKeycloakSecurityContext().getIdToken().getPreferredUsername();
}
return "{ message : \"Hello " + userName + "\" }";
}
For the security context to be propagated you have to have a security domain configured as described in the:
JBoss/Wildfly Adapter configuration
You may also set the principal-attribute
property in the keycloak.json
file of your web app to preferred_username
.
Need to add standalone.xml next line:
<principal-attribute>preferred_username</principal-attribute>
Example:
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
<secure-deployment name="war-name.war">
<realm>realm-name</realm>
<resource>resource-name</resource>
<public-client>true</public-client>
<auth-server-url>https://keycloak-hostname/auth</auth-server-url>
<ssl-required>EXTERNAL</ssl-required>
<principal-attribute>preferred_username</principal-attribute>
</secure-deployment>
</subsystem>
In Keycloak 3.4.3 (may also work on earlier versions) I was able to map username to the sub
token claim name. From the Keycloak admin interface this is done under Clients > [your-client] > Mappers > username
and then enter sub
in the Token Claim Name
field. This has the advantage of actually changing the contents of the ID token
returned by Keycloak rather than adjusting client-side as in the other answer. This is particularly nice when you're using a standard OpenID Connect library rather than an adapter provided by Keycloak.
In my case i was taking the preferred user name from the token like this
keycloakPrincipal.getKeycloakSecurityContext().getToken();
token.getPreferredUsername();
To work i had to go to keycloak and add on my client template the add builtins if not added preferred username came null.
Check the username on the built ins, client template -> mappers.
After that if worked!