How to get other claims from Keycloak AuthzClient - java

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()

Related

How to get the Roles and Attributes of a Keycloak User

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) {
...
}

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

Google Cloud Platform - cloud functions API - 401 Unauthorized

I'm struggling with invoking GCP cloud functions via REST API using Java.
The steps that I've performed to do it were:
create a service account with role "Cloud Functions Invoker"
download JSON key file for the newly created service account
in my code, obtain an access token using the following method:
private String getAuthToken() {
File credentialsPath = new File(PATH_TO_JSON_KEY_FILE);
GoogleCredentials credentials;
try (FileInputStream serviceAccountStream = new FileInputStream(credentialsPath)) {
credentials = ServiceAccountCredentials.fromStream(serviceAccountStream);
return credentials
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"))
.refreshAccessToken()
.getTokenValue();
} catch (IOException e) {
throw new RuntimeException("Action could not be performed");
}
}
perform a REST call, using the created token:
public <Payload, Response> ResponseEntity<Response> callCloudFunction(
String endpoint,
Payload payload,
Class<Response> klazz
) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
String url = gCloudUrl + endpoint;
String token = getAuthToken();
String payloadString = null;
if (payload != null) {
try {
ObjectMapper objectMapper = new ObjectMapper();
payloadString = objectMapper.writeValueAsString(payload);
} catch (JsonProcessingException e) {
System.out.println(e.getMessage());
throw new RuntimeException("Could not perform action");
}
}
headers.add("Authorization", String.format("Bearer %s", token));
HttpEntity<String> entity = new HttpEntity<>(payloadString, headers);
return restTemplate.exchange(url, HttpMethod.POST, entity, klazz);
}
The implementation looks fine, but in response I'm getting 401 Unauthorized.
Unfortunately, GCP documentation is not really helpful. I think I've searched through all the possible places.
First of all, agree, it's not clear...
Then, you have to know (and it's not clear again) that you need an access token to call Google Cloud API, but and identity token to call IAP (on App Engine for example) or private Cloud Function and Cloud Run. And this identity token need to be signed by Google.
And, as mentioned in the code, you need to have a service account on your computer, but I recommend you to avoid this on GCP, it's not required if you use default authentication (see my code, on your computer set the GOOGLE_APPLICATION_CREDENTIALS env var that points to the service account key file). The best way is to not use service account key file on your computer also, but it's not yet possible (that is a security issue IMO, and I'm discussing with Google on this...)
Anyway, here a code snippet which works in Java (nowhere in the documentation...)
String myUri = "https://path/to/url";
// You can use here your service account key file. But, on GCP you don't require a service account key file.
// However, on your computer, you require one because you need and identity token and you can generate it with your user account (long story... I'm still in discussion with Google about this point...)
Credentials credentials = GoogleCredentials.getApplicationDefault().createScoped("https://www.googleapis.com/auth/cloud-platform");
IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
.setIdTokenProvider((IdTokenProvider) credentials)
.setTargetAudience(myUri).build();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
NOTE If you want to continue to use RestTemplate object and set manually your token, you can generate it like this
String token = ((IdTokenProvider) credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
System.out.println(token);

Problems with Google API authentication

I'm trying to run the following example
https://developers.google.com/identity/sign-in/web/server-side-flow#step_1_create_a_client_id_and_client_secret
Everything runs correctly until step 7. I get the following exception
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "redirect_uri_mismatch",
"error_description" : "Bad Request"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest.execute(GoogleAuthorizationCodeTokenRequest.java:158)
at {package}.service.SecurityService.getProfile(SecurityService.java:55)
.....
My code looks as followed:
public Result getProfile(User auth){
Result result = new Result();
try {
// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.developers.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "client_secret.json";
GoogleClientSecrets clientSecrets = loadSecret(CLIENT_SECRET_FILE);
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
"https://www.googleapis.com/oauth2/v4/token",
clientSecrets.getDetails().getClientId(),
clientSecrets.getDetails().getClientSecret(),
auth.getCode(),"http://localhost:8080/api/security/googleAPICallback")
.execute();
String accessToken = tokenResponse.getAccessToken();
// Use access token to call API
//GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
auth.setAccessToken(accessToken);
auth.setUuid(payload.getSubject()); // Use this value as a key to identify a user.
auth.setEmail(payload.getEmail());
auth.setVerifiedEmail(payload.getEmailVerified());
auth.setName(String.valueOf(payload.get("name")));
auth.setPictureURL(String.valueOf(payload.get("picture")));
auth.setLocale(String.valueOf(payload.get("locale")));
auth.setFamilyName(String.valueOf(payload.get("family_name")));
auth.setGivenName(String.valueOf(payload.get("given_name")));
HashMap<String,Object> map = new HashMap<>();
Field[] fields = auth.getClass().getDeclaredFields();
for(Field field : fields){
field.setAccessible(true);
map.put(field.getName(), PropertyUtils.getSimpleProperty(field.getName(), field.getName()));
}
logger.info(auth.toString());
result.setCode(Result.OK);
result.setMessage("¡Exito!");
result.setVarious(false);
result.setData(map);
}catch (Exception e){
e.printStackTrace();
result.setCode(Result.BAD_REQUEST);
result.setMessage("¡No hay access_token!");
result.setVarious(false);
}
return result;
}
I already tried adding different endpoints from both a local an production server. Both links accept GET and POST methods and returned a "OK" json response. Also both links are already added in Google Console in the Authorized URI redirect form.
If I leave an empty string it throws and error saying It needs a redirect_uri, and I omit that space I throws and error saying it missing a scheme for my token.
Extra:
Every time I change something in Google Console, I re download my client-secret.json

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