OracleCloudCredentials.java
/*
* Copyright 2024 Emmanuel Bourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.jsign.jca;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.KeyException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.jsign.DigestAlgorithm;
import net.jsign.PrivateKeyUtils;
/**
* Oracle Cloud credentials loaded from the <code>.oci/config</code> file or from the environment variables.
*
* @since 7.0
*/
public class OracleCloudCredentials {
private String user;
private String tenancy;
private String region;
private String keyfile;
private String fingerprint;
private String passphrase;
private PrivateKey privateKey;
public String getUser() {
return user;
}
public String getTenancy() {
return tenancy;
}
public String getRegion() {
return region;
}
public String getKeyfile() {
return keyfile;
}
public String getFingerprint() {
if (fingerprint == null) {
try {
fingerprint = getFingerprint(getPrivateKey());
} catch (GeneralSecurityException e) {
throw new RuntimeException("Unable to compute the OCI API key fingerprint", e);
}
}
return fingerprint;
}
/**
* Compute the fingerprint of the specified key (i.e. the MD5 hash of the public key in DER format)
* @see <a href="https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#four">How to Get the Key's Fingerprint</a>
*/
String getFingerprint(PrivateKey privateKey) throws GeneralSecurityException {
RSAPrivateCrtKey key = (RSAPrivateCrtKey) privateKey;
RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);
byte[] digest = DigestAlgorithm.MD5.getMessageDigest().digest(publicKey.getEncoded());
return IntStream.range(0, digest.length).mapToObj(i -> String.format("%02x", digest[i])).collect(Collectors.joining(":"));
}
public String getPassphrase() {
return passphrase;
}
public void setPassphrase(String passphrase) {
this.passphrase = passphrase;
}
public String getKeyId() {
return getTenancy() + "/" + getUser() + "/" + getFingerprint();
}
PrivateKey getPrivateKey() {
if (privateKey == null) {
try {
privateKey = PrivateKeyUtils.load(new File(getKeyfile()), getPassphrase());
} catch (KeyException e) {
throw new RuntimeException("Unable to load the private key", e);
}
}
return privateKey;
}
/**
* Loads the credentials from the specified file.
*
* @param file the configuration file (null for the default location)
* @param profile the name of the profile (null for the default profile)
*/
public void load(File file, String profile) throws IOException {
if (file == null) {
file = getConfigFile();
}
if (profile == null) {
profile = getDefaultProfile();
}
Properties properties = new Properties();
// parse le lines of the file
boolean profileFound = false;
for (String line : Files.readAllLines(file.toPath())) {
if (profileFound && line.startsWith("[")) {
break; // end of the profile
}
if (line.equals("[" + profile + "]")) {
profileFound = true;
continue;
}
if (profileFound) {
String[] elements = line.split("=", 2);
if (elements.length == 2) {
properties.setProperty(elements[0].trim(), elements[1].trim());
}
}
}
if (!profileFound) {
throw new IOException("Profile '" + profile + "' not found in " + file);
}
user = properties.getProperty("user");
tenancy = properties.getProperty("tenancy");
region = properties.getProperty("region");
keyfile = properties.getProperty("key_file");
fingerprint = properties.getProperty("fingerprint");
passphrase = properties.getProperty("pass_phrase");
}
/**
* Loads the credentials from the environment variables.
*
* @see <a href="https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clienvironmentvariables.htm">CLI Environment Variables</a>
*/
public void loadFromEnvironment() {
if (getenv("OCI_CLI_USER") != null) {
user = getenv("OCI_CLI_USER");
}
if (getenv("OCI_CLI_TENANCY") != null) {
tenancy = getenv("OCI_CLI_TENANCY");
}
if (getenv("OCI_CLI_REGION") != null) {
region = getenv("OCI_CLI_REGION");
}
if (getenv("OCI_CLI_KEY_FILE") != null) {
keyfile = getenv("OCI_CLI_KEY_FILE");
}
if (getenv("OCI_CLI_FINGERPRINT") != null) {
fingerprint = getenv("OCI_CLI_FINGERPRINT");
}
if (getenv("OCI_CLI_PASS_PHRASE") != null) {
passphrase = getenv("OCI_CLI_PASS_PHRASE");
}
}
/**
* Returns the default Oracle Cloud configuration.
*/
public static OracleCloudCredentials getDefault() throws IOException {
OracleCloudCredentials credentials = new OracleCloudCredentials();
File config = getConfigFile();
if (config.exists()) {
credentials.load(config, getDefaultProfile());
}
credentials.loadFromEnvironment();
return credentials;
}
/**
* Returns the name of the default profile, either the value of the OCI_CLI_PROFILE environment variable or "DEFAULT".
*/
public static String getDefaultProfile() {
String profile = getenv("OCI_CLI_PROFILE");
if (profile == null) {
profile = "DEFAULT";
}
return profile;
}
/**
* Returns the location of the configuration file, either the value of the OCI_CLI_CONFIG_FILE environment variable
* or <code>~/.oci/config</code>.
*/
public static File getConfigFile() {
String config = getenv("OCI_CLI_CONFIG_FILE");
if (config != null) {
return new File(config);
} else {
return new File(System.getProperty("user.home"), ".oci/config");
}
}
static String getenv(String name) {
return System.getenv(name);
}
}