How to get the Roles and Attributes of a Keycloak User - java

How do I get the roles and attributes of a user using the Java Client of Keycloak? Below is the code that I have written to get the access token of a user, however, I am not able to find the way to get the roles assigned to that user.
Configuration configuration = new Configuration();
configuration.setRealm("foo");
configuration.setResource("foo");
configuration.setBearerOnly(Boolean.TRUE);
configuration.setAuthServerUrl("http://localhost:8080");
configuration.setCredentials(Map.of("secret", "FV3P4ajYHedAUDtOa55EX5nzK8zc6jUA"));
AuthzClient authzClient = AuthzClient.create(configuration);
AuthorizationRequest request = new AuthorizationRequest();
AuthorizationResponse authorize = authzClient.authorization("john.doe", "john.doe").authorize(request);
String token = authorize.getToken();
log.info("Auth bearer token is {}", token);

You have the token as a String, namely:
String token = authorize.getToken();
now you just need to parse it to get the Realm and Client roles, which are encoded in the token. For that you can use the class TokenVerifier from org.keycloak.TokenVerifier.
For example:
try {
AccessToken token = TokenVerifier.create(tokenString, AccessToken.class).getToken();
System.out.printf("Realm 'foo' = Roles %s%n", token.getRealmAccess().getRoles());
token.getResourceAccess().forEach((k, v) -> System.out.printf("Client '%s' = Roles '%s'%n", k, v.getRoles()));
} catch (VerificationException e) {
...
}

Related

Validation of Azure AD token signature is invalid. The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA

I have a problem regarding the validation of an azure active directory token. I receive the token using my application_id and the username and password of a user. I'll then validate it but it results in an invalid signature. The code fragment for the validation is as follows:
// Request access token from AAD
IAuthenticationResult result = getAccessToken(userName, password);
String auth = result.accessToken();
DecodedJWT jwt = JWT.decode(auth);
JwkProvider provider = null;
Jwk jwk = null;
Algorithm algo = null;
try {
provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/common/discovery/keys"));
jwk = provider.get(jwt.getKeyId());
System.out.println(jwk.getPublicKey());
algo = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
algo.verify(jwt);
} catch (SignatureVerificationException e) {
System.out.println(e.getMessage());
} catch (JwkException e) {
e.printStackTrace();
}
I retrieve the token information with this method
private static IAuthenticationResult getAccessToken(String userName, String password)
throws MalformedURLException, InterruptedException, ExecutionException {
PublicClientApplication pca = PublicClientApplication.builder(
APP_ID).
authority(AUTHORITY).build();
String scopes = "User.Read";
UserNamePasswordParameters parameters = UserNamePasswordParameters.builder(
Collections.singleton(scopes),
userName,
password.toCharArray()).build();
IAuthenticationResult result = pca.acquireToken(parameters).get();
return result;
}
The program always end up catching the SignatureVerificationException. I tried validating the token manually with the jwt.io, where I paste the certificate that I get when i compare the kid claim with the one on https://login.microsoftonline.com/common/discovery/keys but I also get Invalid Signature as a result. Is there something wrong with my token because the validating processes both say the signature is invalid in jwt.io and in my java program or is there another way to validate Azure AD tokens?
EDIT: The solution was changing the scope from "User.Read" to "[client_id]/.default".
Because you are getting the token of the custom api, not the token of the ms graph api. So you need to set the scope to: {api app client_id}/.default

How to get other claims from Keycloak AuthzClient

I'm using AuthzClient to obtain a access token using the following code:
Map<String,Object> clientCredentials = new HashMap<>();
clientCredentials.put("secret", keycloakClientSecret);
Configuration configuration = new Configuration(
keycloakUrl, keycloakRealmName, keycloakClientId, clientCredentials, null
);
AuthzClient authzClient = AuthzClient.create(configuration);
AccessTokenResponse accessTokenResponse = authzClient.obtainAccessToken(
loginRequest.getUsername(), loginRequest.getPassword()
);
System.out.println(accessTokenResponse.getOtherClaims());
I'm getting the access token and refresh token successfully but I can't get the other claims. It's empty.
I've configured Mapper to include my custom attribute from portal. What I'm doing wrong here?
I didnt find any solution about keycloak authzclient. But i am using jwt decode solution as https://github.com/auth0/java-jwt
my example like this with jwt-decoder:
public Claim getClaimByName(String key)
{
try {
DecodedJWT jwt = JWT.decode(this.tokenResponse.getAccessToken()); // just token as String
return jwt.getClaim(key);
} catch (JWTCreationException exception){
return null;
}
}
getClaimByName("site").asString()

Safest way to store an authentication token

I have my custom AuthenticationProvider which call a third party SSO to authenticate a user. If a user is valid I get an authentication token from the SSO service. I have to keep this token during the session for another services which will require this authentication token to verify the user has a valid session.
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String id = authentication.getName();
String password = authentication.getCredentials().toString();
JsonObject response = ssoClient.login(id, password);
JsonObject session = response.getJsonObject("session");
JsonObject user = session.getJsonObject("user");
String email = user.getString("email");
String username = user.getString("username");
String fullname = user.getString("fullname");
String auth_token = session.getString("auth_token");
List<GrantedAuthority> grantedAuths = null;
return new CustomAuthenticationToken(username, auth_token, email,
fullname, grantedAuths);
}
I have extended from AbstractAuthenticationToken to create a custom CustomAuthenticationToken to store this token and another information. Should I sign this token with something like itsdangeous (but in java) or encrypt it? Or should I store the authentication token in any other place? Thanks!

Get user profile from GoogleIdToken

I'm trying to do this:
https://developers.google.com/identity/sign-in/web/backend-auth#calling-the-tokeninfo-endpoint
I copy pasted the Java code from the example, with my CLIENT_ID, but I can't get any more information than user id, email and email verified. idTokenString verifies OK. Have anyone else got this to work?
I asked for these in OAuth 2.0 Playground:
https://www.googleapis.com/auth/plus.login
https://www.googleapis.com/auth/plus.me
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/plus.moments.write
https://www.googleapis.com/auth/plus.profile.agerange.read
https://www.googleapis.com/auth/plus.profile.language.read
https://www.googleapis.com/auth/plus.circles.members.read
I guess the user.profile is the one i need only?
This is my code:
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Arrays.asList(CLIENT_ID))
.setIssuer("accounts.google.com")
.build();
GoogleIdToken idToken = verifier.verify(idTokenString);
System.out.println("SUCCESS!");
System.out.println(idToken);
if (idToken != null) {
GoogleIdToken.Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = payload.getEmailVerified();
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
System.out.println(email);
System.out.println(emailVerified);
System.out.println(name);
System.out.println(pictureUrl);
System.out.println(locale);
System.out.println(familyName);
System.out.println(givenName);
} else {
System.out.println("Invalid ID token.");
}
} catch (GeneralSecurityException | IOException e) {
System.out.println("ERRRRO! Invalid ID token.");
}
Using: java-api-client 1.20.0
I encountered the same issue today using com.google.api-client:google-api-client:1.22.0
But I was able to solve it.
Problem
When trying to get id token from OAuth2 playground I've noticed that there is this request
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
The Google library has hard coded TOKEN_SERVER_URL in GoogleOAuthConstants with value https://accounts.google.com/o/oauth2/token
Fix
To fix it I've created following class
public class GoogleAuthorizationCodeTokenV4Request extends GoogleAuthorizationCodeTokenRequest {
public GoogleAuthorizationCodeTokenV4Request(HttpTransport transport, JsonFactory jsonFactory, String clientId, String
clientSecret, String code, String redirectUri) {
super(transport, jsonFactory, "https://www.googleapis.com/oauth2/v4/token", clientId, clientSecret,
code, redirectUri);
}
}
And then just invoke it instead the original GoogleAuthorizationCodeTokenRequest
return new GoogleAuthorizationCodeTokenV4Request(new NetHttpTransport(), JacksonFactory.getDefaultInstance(),
clientId, secret, authToken, callBack)
.execute();
With profile scope all information (picture, names, ...) are in id_token

Facebook4j with OAUTH Access Token

Is any one help me to provide a example for OAuth access token for the facebook by getting the user credentials and and allows the fields similar to linkedin API.
I tried to use like
Configuration configuration = createConfiguration();
FacebookFactory facebookFactory = new FacebookFactory(configuration );
Facebook facebookClient = facebookFactory.getInstance();
AccessToken accessToken = null;
try{
OAuthSupport oAuthSupport = new OAuthAuthorization(configuration );
accessToken = oAuthSupport.getOAuthAppAccessToken();
}catch (FacebookException e) {
logger.error("Error while creating access token " + e.getLocalizedMessage(), e);
}
public Configuration createConfiguration() {
ConfigurationBuilder confBuilder = new ConfigurationBuilder();
confBuilder.setDebugEnabled(APIConfiguration.DEBUG_ENABLED);
confBuilder.setOAuthAppId(APIConfiguration.APP_ID);
confBuilder.setOAuthAppSecret(APIConfiguration.APP_SECRET);
confBuilder.setUseSSL(APIConfiguration.USE_SSL);
confBuilder.setJSONStoreEnabled(APIConfiguration.JSON_STORE_ENABLED);
Configuration configuration = confBuilder.build();
return configuration;
}
i got access token but i could search users it shows
SEVERE: Error while getting the facebook users {"error":{"message":"(#200) Must have a valid access_token to access this endpoint","type":"OAuthException","code":200}}
FacebookException [statusCode=403, response=HttpResponse{statusCode=403, responseAsString='{"error":{"message":"(#200) Must have a valid access_token to access this endpoint","type":"OAuthException","code":200}}
', is=sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#1232784a, streamConsumed=true}, errorType=OAuthException, errorMessage=(#200) Must have a valid access_token to access this endpoint, errorCode=200]
at facebook4j.internal.http.HttpClientImpl.request(HttpClientImpl.java:189)
at facebook4j.internal.http.HttpClientWrapper.request(HttpClientWrapper.java:65)
at facebook4j.internal.http.HttpClientWrapper.get(HttpClientWrapper.java:93)
at facebook4j.FacebookImpl.get(FacebookImpl.java:2095)
at facebook4j.FacebookImpl.searchUsers(FacebookImpl.java:1799)
at facebook4j.FacebookImpl.searchUsers(FacebookImpl.java:1795)
How would i get the OAUTH using call back url i tried redirect_uri with http://www.google.com but it does not give any code.
It is my java console application
Define accessToken as following example:
accessToken = new AccessToken("CAACEdEose0cBAFpfeSxd3WFzkUfm4l4PTKtLblS0hpbOFQcanzYciYMCSuFNOgiZBEtjxWZCHvwU0iP4cTe7aHXeNB5nQOC88ECE1lzVvjNKPjXNsGmJfbNfGEULQ0zEfeTla3Puknj6AGcsPy5VKKEQdJ3FbJ20RRemtgAGh05kgXsXnLrdfCPq6e6eFyu8dWxL1ZBv0EZBe9le3m0U");
where the accesToken string is obtained from https://developers.facebook.com/tools/accesstoken/
I inspired by using your code and I had similar mistake. The solution seems to be to register the application properly in the faceboook developer center = https://developers.facebook.com/ where the application must be created, edited, submitted and approved by the center.
I think you're missing this line:
facebookClient.setOAuthAccessToken( accessToken );

Categories