All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hazelcast.gcp.GcpAuthenticator Maven / Gradle / Ivy
/*
* Copyright 2020 Hazelcast Inc.
*
* Licensed under the Hazelcast Community License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://hazelcast.com/hazelcast-community-license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.hazelcast.gcp;
import com.hazelcast.internal.json.Json;
import com.hazelcast.internal.json.JsonObject;
import com.hazelcast.core.HazelcastException;
import java.io.FileNotFoundException;
import java.util.Base64;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
/**
* Fetches OAuth 2.0 Access Token from Google API.
*
* @see Using OAuth 2.0 for Server to Server
*/
class GcpAuthenticator {
private static final String GOOGLE_AUTH_ENDPOINT = "https://www.googleapis.com/oauth2/v4/token";
private static final String SCOPE = "https://www.googleapis.com/auth/cloud-platform";
private final String endpoint;
GcpAuthenticator() {
this(GOOGLE_AUTH_ENDPOINT);
}
/**
* For test purposes only.
*/
GcpAuthenticator(String endpoint) {
this.endpoint = endpoint;
}
String refreshAccessToken(String privateKeyPath) {
return refreshAccessToken(privateKeyPath, System.currentTimeMillis());
}
String refreshAccessToken(String privateKeyPath, long currentTimeMs) {
try {
String body = createBody(privateKeyPath, currentTimeMs);
String response = callService(body);
return parseResponse(response);
} catch (FileNotFoundException e) {
throw new HazelcastException(String.format("Private key json file not found. "
+ "Please ensure you have stored the json file at the specified file path: %s", privateKeyPath)
, e);
} catch (Exception e) {
throw new HazelcastException("Error while fetching access token from Google API", e);
}
}
private String createBody(String privateKeyPath, long currentTimeMs)
throws Exception {
JsonObject privateKeyJson = Json.parse(new InputStreamReader(new FileInputStream(privateKeyPath), "UTF-8")).asObject();
String privateKey = privateKeyJson.get("private_key").asString();
String clientEmail = privateKeyJson.get("client_email").asString();
String headerBase64 = base64encodeUrlSafe(header());
String claimSetBase64 = base64encodeUrlSafe(claimSet(clientEmail, currentTimeMs));
String signatureBase64 = sign(headerBase64, claimSetBase64, privateKey);
return body(headerBase64, claimSetBase64, signatureBase64);
}
private static String header() {
return "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
}
@SuppressWarnings("checkstyle:magicnumber")
private String claimSet(String clientEmail, long currentTimeMs) {
long currentTimeSeconds = currentTimeMs / 1000L;
long expirationTimeSeconds = currentTimeSeconds + 3600L;
return String.format("{\"iss\":\"%s\",\"scope\":\"%s\",\"aud\":\"%s\",\"iat\":%s,\"exp\":%s}", clientEmail, SCOPE,
endpoint, currentTimeSeconds, expirationTimeSeconds);
}
private static String body(String headerBase64, String claimSetBase64, String signatureBase64) {
String grantType = "urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer";
String assertion = String.format("%s.%s.%s", headerBase64, claimSetBase64, signatureBase64);
return String.format("grant_type=%s&assertion=%s", grantType, assertion);
}
private static String sign(String headerBase64, String claimSetBase64, String privateKeyString)
throws Exception {
String dataToSign = String.format("%s.%s", headerBase64, claimSetBase64);
String clearPrivateKeyString = clear(privateKeyString);
byte[] b1 = Base64.getMimeDecoder().decode(clearPrivateKeyString.getBytes("UTF-8"));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1);
KeyFactory kf = KeyFactory.getInstance("RSA");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
PrivateKey privateKey = kf.generatePrivate(spec);
privateSignature.initSign(privateKey);
privateSignature.update(dataToSign.getBytes("UTF-8"));
return new String(base64encodeUrlSafe(privateSignature.sign()), "UTF-8");
}
private static String clear(String privateKey) {
return privateKey.replaceAll("-----END PRIVATE KEY-----", "")
.replaceAll("-----BEGIN PRIVATE KEY-----", "")
.replaceAll("\\\\n", "");
}
private static String base64encodeUrlSafe(String data)
throws UnsupportedEncodingException {
byte[] encoded = base64encodeUrlSafe(data.getBytes("UTF-8"));
return new String(encoded, "UTF-8");
}
private static byte[] base64encodeUrlSafe(byte[] data) {
byte[] encode = Base64.getEncoder().encode(data);
for (int i = 0; i < encode.length; i++) {
if (encode[i] == '+') {
encode[i] = '-';
} else if (encode[i] == '/') {
encode[i] = '_';
}
}
return encode;
}
private String callService(String body) {
return RestClient.create(endpoint).withBody(body).post();
}
private static String parseResponse(String response) {
return Json.parse(response).asObject().get("access_token").asString();
}
}