This topic describes how to connect Java applications to Identity as a Service (IDaaS).
For more information about how the connection works and the call process, see Overview.
You must complete the following one or two steps to implement account synchronization:
Signature verification
Decryption (optional)
After the preceding procedure is completed, the application receives the request of this event and handles the request.
1. Signature Verification
Obtain the public key endpoint from the synchronization configuration of the application. For more information, see Account synchronization - Synchronize IDaaS accounts on an application.
In this topic, a Java utility class that obtains the public key directly from the public key endpoint is provided. If the programming language that you use requires public key information, you may need to click the public key endpoint URL to obtain the public key, and store the public key in a .pem file locally.
The following code provides an example of a public key:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "KEY3PdQDx97WFk8G6pfzh83p8husNSC9AKMH",
"n": "rLUnH5PNeGUZE-J4IUIJOvUGGIxyM5O7TDdaG4jUCjO2LzKD9mV1CjE8hVHBxXM96IcCCH_1xmUZEZRp_MBP6m2XeNWUXanCpeyuIAD2kxmaQAqituZdIlT4l3-q9gtccdY-khaE-OfH9qYZhlxFcYj0gVtOvKZFIkuGhME4IQJd_RAWS3OPXxtbGhO2fZYCiuuc8NWub5mcVQnqsy5aJPLwHbVwVUwYNOmaq97_m2TtPcIVWtw7AOzX8O78UrYnYt_QPrv7uVdJMbHleSOx2A1IXqrAkJWecwFfvTsBTCUOPPDeVRQEHzzwmf3zpz5KMgHZU1I5pyqi0KJ6BuMHWw"
}
]
}
The following example shows how to add dependencies to your Maven project:
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
<version>0.7.9</version>
</dependency>
The following code is for the utility class that is used to obtain the public key from the IDaaS public key endpoint and verify the signature. You can directly copy and use the code.
import org.apache.commons.codec.binary.StringUtils;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.lang.JoseException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class JwtUtil {
private final static ConcurrentMap<String, JsonWebKeySet> IDAAS_SIGN_JWK_SET_MAP = new ConcurrentHashMap<>();
public static JwtConsumer createJwtConsumerFromUrl(String jwkUrl, String appId) {
try {
final JsonWebKeySet jsonWebKeySet = getJsonWebKeySetByUrl(jwkUrl);
return createJwtConsumer(jsonWebKeySet, appId);
} catch (Exception e) {
throw new RuntimeException("Fetch JWKs from url failed: " + e.getMessage() + ", " + jwkUrl, e);
}
}
public static JwtConsumer createJwtConsumer(JsonWebKeySet jsonWebKeySet, String appId) {
final JwtConsumerBuilder jwtConsumerBuilder = new JwtConsumerBuilder();
jwtConsumerBuilder.setExpectedIssuer("urn:alibaba:idaas:app:event");
jwtConsumerBuilder.setRequireExpirationTime();
jwtConsumerBuilder.setRequireJwtId();
jwtConsumerBuilder.setRequireIssuedAt();
jwtConsumerBuilder.setRequireExpirationTime();
jwtConsumerBuilder.setMaxFutureValidityInMinutes(1);
jwtConsumerBuilder.setAllowedClockSkewInSeconds(120);
jwtConsumerBuilder.setExpectedAudience(appId);
jwtConsumerBuilder.setVerificationKeyResolver((jws, nestingContext) -> {
final String signKeyId = jws.getKeyIdHeaderValue();
for (JsonWebKey jsonWebKey : jsonWebKeySet.getJsonWebKeys()) {
if (StringUtils.equals(jsonWebKey.getKeyId(), signKeyId)) {
return jsonWebKey.getKey();
}
}
throw new RuntimeException("Cannot find verification key: " + signKeyId);
});
return jwtConsumerBuilder.build();
}
synchronized private static JsonWebKeySet getJsonWebKeySetByUrl(String jwkUrlString) throws IOException, JoseException {
JsonWebKeySet jsonWebKeySet = IDAAS_SIGN_JWK_SET_MAP.get(jwkUrlString);
if (jsonWebKeySet == null) {
jsonWebKeySet = innerGetJsonWebKeySetByUrl(jwkUrlString);
IDAAS_SIGN_JWK_SET_MAP.put(jwkUrlString, jsonWebKeySet);
}
return jsonWebKeySet;
}
private static JsonWebKeySet innerGetJsonWebKeySetByUrl(String jwkUrlString) throws IOException, JoseException {
final URL jwkUrl = new URL(jwkUrlString);
final URLConnection urlConnection = jwkUrl.openConnection();
urlConnection.setConnectTimeout(50000);
urlConnection.setReadTimeout(50000);
final String jwkSetJson = new String(readAll(urlConnection.getInputStream()), StandardCharsets.UTF_8);
return new JsonWebKeySet(jwkSetJson);
}
public static byte[] readAll(InputStream inputStream) throws IOException {
final byte[] buffer = new byte[1024 * 8];
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int len; ((len = inputStream.read(buffer)) != -1); ) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
}
}
The following code provides an example for the call:
// Public key -> Obtain the public key by accessing the public key endpoint in the synchronization configuration of the application on IDaaS.
String publicKey = "{\n"
+ " \"keys\": [\n"
+ " {\n"
+ " \"kty\": \"RSA\",\n"
+ " \"e\": \"AQAB\",\n"
+ " \"use\": \"sig\",\n"
+ " \"kid\": \"KEYHH4yFa1cpZdrs1HqNo1nJ7nM2FR3595P1\",\n"
+ " \"n\": \"oy_xxxxxxxxxxxxxxxxxxxxxxx95d1padSEABqIbcTKcnlTaET3WHaR"
+ "-3MvsooeZWluv94GQEp-U2jzM1adgTqBl_7KPjUk0dwrZbob_8pOLX5UQMF7Oo_nH5-H5EyL9-yGGhFA4oeuA"
+ "-b73qXShxP7eHs5xTT1kiYEu2NE3rBZdtrRwUiC_h1DvZMtyWFOPwm3dpLiwCcdlgcKvVuSEXyCBj6Gjevn3_G1guVQ2kHlNOVyNn6Ky1iGQJzXctJCEJ5fnBRs4XZZbPNSciYMD2-__cRdbYPtGyyuoEAfouw\"\n"
+ " }\n"
+ " ]\n"
+ "}";;
// Application ID -> Find the ID of the application in the application list.
String appId = "app_mjavzivahje6zxxxx";
// JwtUtil -> The JwtUtil utility class is provided below.
JwtConsumer jwtConsumer = JwtUtil.createJwtConsumer(new JsonWebKeySet(publicKey),appId);
// Obtain the payload after the JSON Web Token (JWT) signature is verified.
// The value of the event parameter -> The parameter value received by the API operation.
JwtClaims jwtClaims=jwtConsumer.processToClaims ("The value of the event parameter");
// Obtain the specific payload.
Map<String, Object> map = jwtClaims.getClaimsMap();
// Process the business based on the specific data.
2. Decryption (optional)
Data decryption
If Service Data Encryption is enabled for the application, the event data is encrypted and transmitted in cipher_data. The application must decrypt the value of cipher_data to obtain the event data.
You can enter an encryption key or click Generate Key to generate an encryption key.
Copy the key and use it during decryption.
The following example shows how to add dependencies to your Maven project:
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
<version>0.7.9</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
The following code provides an example for the decryption:
public String decrypte(String cipherData,String key) throws JoseException {
String alg = "AES";
// Generate KeySpec by using the key.
SecretKeySpec secretKeySpec = new SecretKeySpec(Hex.decode(key), alg);
JsonWebKey jsonWebKey = JsonWebKey.Factory.newJwk(secretKeySpec);
JsonWebEncryption receiverJwe = new JsonWebEncryption();
// Set the encryption and decryption mechanisms.
AlgorithmConstraints algConstraints = new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.PERMIT, new String[]{"dir"});
receiverJwe.setAlgorithmConstraints(algConstraints);
AlgorithmConstraints encConstraints = new AlgorithmConstraints(
AlgorithmConstraints.ConstraintType.PERMIT, new String[]{"A256GCM", "A192GCM", "A128GCM"});
receiverJwe.setContentEncryptionAlgorithmConstraints(encConstraints);
// Specify the key and the ciphertext.
receiverJwe.setKey(jsonWebKey.getKey());
receiverJwe.setCompactSerialization(cipherData);
// Return the decrypted content.
return new String(receiverJwe.getPlaintextBytes(), StandardCharsets.UTF_8);
}