I am using keycloak for authentication in my spring application, how can I set some attribute for a user.
I have already added a custom mapper on admin console.
Please have a look below attached screen shot,in user section there is the tab where you can set the attributes
Now question will be how you will access those user attributes through code?
So here is the code which can be use to access user attributes .
HttpServletRequest httpRequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
KeycloakSecurityContext securityContext = (KeycloakSecurityContext) httpRequest.getAttribute(KeycloakSecurityContext.class.getName());
AccessToken accessToken = securityContext.getToken();
if(null != accessToken ){
Map<String, Object> otherClaims = accessToken.getOtherClaims() ;
tgtToken = securityContext.getTokenString();
String firstUserAtt = otherClaims.get("First_User_Attribute").toString();
String secondUserAtt = otherClaims.get("Second_User_Attribute").toString();
}
Note - First_User_Attribute,Second_User_Attribute are the key you declare in the keycloak's user attribute section.
Related
I am trying to implement SSO in our app using keycloak-spring-security-adapter. The logging itself is working fine, but inside the app we have modules availability based on user roles/groups and i am not able to get user roles from SecurityContext to show users only what they should see.
SecurityContext context = SecurityContextHolder.getContext();
if(context.getAuthentication() != null) {
KeycloakPrincipal principal = (KeycloakPrincipal) context.getAuthentication().getPrincipal();
KeycloakSecurityContext session = principal.getKeycloakSecurityContext();
AccessToken accessToken = session.getToken();
AccessToken.Access realmAccess = accessToken.getRealmAccess();
logger.info("KEYCLOAK ROLES: " + realmAccess.getRoles());
above logger for my user always gives this:
KEYCLOAK ROLES: [offline_access, uma_authorization]
And these are not the roles registered in keycloak server, because the one used for authenticating my user is:
GSAP_APPLICATION_SUPPORT
I am not able to log into the app with user that is not a member of any keycloak-registered groups so thats why i know this process works fine.
Is there a way of getting list of current user roles from keycloak based on userId/token?
Hardcoding the roles checking inside the service is not a best practice, it's a common approach to divide role based functionalities by API like:
api/v1/admin/**, api/v1/user/**
Using this you can restrict the access to API by roles:
http.authorizeExchange()
.pathMatchers("your_endpoint").hasAnyRole("desired_role");
PS Please pay attention that keycloak adds the "ROLE_" prefix to the rolename, so you can
use ROLE_admin, ROLE_user in your configuration
or
use role names without "ROLE_" prefix (admin, user), and implement the JWT auth converter(example for Reactive (webFlux), you can do similar for Tomcat):
:
Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> getJwtAuthenticationConverter() {var converter = new ReactiveJwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
Map<String, Object> realmAccess = jwt.getClaim("realm_access");
Collection<String> roles = (Collection<String>) realmAccess.get("roles");
return Flux.fromIterable(roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.toList());
});
return converter;
}
I can get a token from keycloak given a user and password with the Java API code:
AccessTokenResponse tokenresponse = authzClient.obtainAccessToken(user, password);
How can I get this user's firstname, lastname, as well as other attributes from Keycloak? Such as Id?
The code I've used just gets the info from the AccessToken. This is taken from a JAX-RS service but it isn't clear how you're trying to access it. Perhaps it can still give you some ideas.
#Path("/something")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response aMethod(#Context SecurityContext securityContext) {
Principal principal = securityContext.getUserPrincipal();
KeycloakPrincipal<KeycloakSecurityContext> keycloakPrincipal = (KeycloakPrincipal<KeycloakSecurityContext>) principal;
AccessToken accessToken = keycloakPrincipal.getKeycloakSecurityContext().getToken();
// first name
accessToken.getGivenName()
// last name
accessToken.getFamilyName();
// email
accessToken.getEmail();
// roles
accessToken.getRealmAccess().getRoles();
I need to retrieve the roles associated to user, but I am working with wildfly, I have installed all jar keycloak in wildfly and my Java project, but can I retrieve this list by Java adapter?
Other options is call the rest api like any api by get, post, put, etc. But my first options was Adapters.
I make the authentication by adapters, but I do not find any way to retrieve roles, clients, realms, etc.
I am wrong or the adapter is just to authentications?
Anyone have a good example?
Set the option use-resource-role-mappings : true in keycloak.json
and you should be able to get roles in servlet as follows
KeycloakPrincipal principal = (KeycloakPrincipal)request.getUserPrincipal();
principal.getKeycloakSecurityContext().getToken().getResourceAccess("testclient").getRoles();
You can also get KeycloakPrincipal from context like this
Subject subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container");
Set<KeycloakPrincipal> principals = subject.getPrincipals(KeycloakPrincipal.class);
and then get the roles
Thanks, here other way: (retrieve one role by name)
Keycloak keycloak = Keycloak.getInstance("http://localhost/auth", "realm-name", "client-name", authorization);
RoleRepresentation role = keycloak.realm("realm-name").clients().get(idOfClient).roles().get(roleName).toRepresentation();
To listing all user:
UsersResource users = keycloak.realm("realm-name").users();
And "authorization" is the string token bearer
"getInstance" have other methods to send for example pass and user.
If anyone else is still struggling, here's a complete answer:
Create a security context producer:
#RequestScoped
public class SecurityContextProducer {
#Inject
private HttpServletRequest request;
#Produces
public KeycloakSecurityContext getSecurityContext() {
return ((KeycloakPrincipal) request.getUserPrincipal())
.getKeycloakSecurityContext();
}
}
Use it like this:
#Inject
private KeycloakSecurityContext keycloakSecurityContext;
public List<String> getRolesKeycloak() {
Set<String> roleNames = keycloakSecurityContext.getToken().getRealmAccess().getRoles();
List<String> targetList = new ArrayList<>(roleNames);
return targetList;
}
It's not exactly the topic but I needed to find the roles associated with a specific user and this question pops first with my keywords web search. Here's what worked for me with keycloak client 13.0.1
RealmResource realmResource = keycloak.realm(REALM);
UsersResource usersResource = realmResource.users();
UserResource userResource = usersResource.get(USER_ID);
RoleMappingResource roleMappingResource = userResource.roles();
// either realmLevel or clientLevel
RoleScopeResource roleScopeResource = roleMappingResource.realmLevel();
List<RoleRepresentation> rolesRepresentation = roleScopeResource.listAll();
I didn't find it elsewhere, I hope it can be useful.
I'm using this ContainerRequestFilter to check HTTP Basic credentials.
private class Filter implements ResourceFilter, ContainerRequestFilter {
#Override
public ContainerRequest filter(ContainerRequest request) {
String auth = request.getHeaderValue("Authorization");
if (auth == null || !auth.startsWith("Basic ")) {
throw new NotAuthorizedException("FAILED\n");
}
auth = Base64.base64Decode(auth.substring("Basic ".length()));
String[] vals = auth.split(":");
String username = vals[0];
String password = vals[1];
boolean validUser = database.Users.validate(username, password);
if (!validUser) {
throw new NotAuthorizedException("FAILED\n");
}
return request;
}
...
}
So by the time I get to this point, I've authenticated the user. Now how I can get the username?
#GET
#Path("some_kind_of_report_or_something")
#Produces(MediaType.TEXT_PLAIN)
public String fetchAReportOrSomething() {
// At this point, I know that the user has provided good credentials,
// now I need get the user's username as a String
String username = ???;
}
I suppose I could use HttpContext.getRequest() and do the same thing as in the AuthFilter (I'd move that username/password extraction logic to its own method). In the filter, can I somehow store the extracted username somewhere in the request object so it gets passed on to this handler?
(By the way, is there a better way to extract the username and password than what I've done in the filter? If so, let me know in a comment.)
This blog entry should enlighten you:
http://plaincode.blogspot.pt/2011/07/openid-authentication-example-in-jersey.html
Take a look how it's done in a working application: www.s3auth.com. The source code is available at github. As you can see on the site, facebook and google authentication mechanisms are used. The application is using JAX-RS/Jersey.
I have been digging Spring Social (1.0.2.RELEASE) for Facebook. I couldn't find out how to send apprequest via spring social. I already have an application on facebook with keys and stuff. I can fetch friends etc. but cannot send apprequest to a particular facebook user. Would really appreciate.
The following example should do the trick - i.e. create an app access token and then create the request using a FacebookTemplate which has been initialised using the created app access token
// retrieve app access token
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=<app_id>&client_secret=<app_secret>", String.class);
String appAccessToken = result.replaceAll("access_token=", "");
// create the request
FacebookTemplate appRequestTemplate = new FacebookTemplate(appAccessToken);
String userId = "1234567890";
MultiValueMap<String, Object> requestData = new LinkedMultiValueMap<String, Object>();
requestData.set("message", "Sending a request through to you...");
String resultOfApprequest = appRequestTemplate.publish(userId, "apprequests", requestData);
According to the Facebook docs, app requests are sent to users by POSTs to the Graph API. See the "Create" section here:
https://developers.facebook.com/docs/reference/api/user/#apprequests
Spring Social Facebook has a GraphApi class with two methods for sending POSTs, "publish()" which tries to extract an id from the response and "post()" which doesn't:
http://static.springsource.org/spring-social-facebook/docs/1.0.x/api/org/springframework/social/facebook/api/GraphApi.html
So you may need to make a call along the lines of:
Map<String, Object> requestData = new HashMap<String, Object>();
requestData.put("message", "My app's request message");
String requestId = graphApi.publish(userId, "apprequests", requestData);