All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.nosql.driver.iam.InstancePrincipalsProvider Maven / Gradle / Ivy

/*-
 * Copyright (c) 2011, 2020 Oracle and/or its affiliates.  All rights reserved.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 *  https://oss.oracle.com/licenses/upl/
 */

package oracle.nosql.driver.iam;

import static oracle.nosql.driver.iam.Utils.findField;
import static oracle.nosql.driver.iam.Utils.getIAMURL;
import static oracle.nosql.driver.iam.Utils.logTrace;
import static oracle.nosql.driver.util.HttpConstants.APPLICATION_JSON;
import static oracle.nosql.driver.util.HttpConstants.AUTHORIZATION;
import static oracle.nosql.driver.util.HttpConstants.CONTENT_TYPE;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import oracle.nosql.driver.Region;
import oracle.nosql.driver.Region.RegionProvider;
import oracle.nosql.driver.httpclient.HttpClient;
import oracle.nosql.driver.iam.CertificateSupplier.DefaultCertificateSupplier;
import oracle.nosql.driver.iam.CertificateSupplier.URLResourceDetails;
import oracle.nosql.driver.iam.SessionKeyPairSupplier.DefaultSessionKeySupplier;
import oracle.nosql.driver.iam.SessionKeyPairSupplier.JDKKeyPairSupplier;
import oracle.nosql.driver.util.HttpRequestUtil;
import oracle.nosql.driver.util.HttpRequestUtil.HttpResponse;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;

import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;

/**
 * @hidden
 * Internal use only
 * 

* The authentication profile provider used to call service API from OCI * compute instance. It authenticates with instance principal and uses security * token issued by IAM to do the actual request signing. */ class InstancePrincipalsProvider implements AuthenticationProfileProvider, RegionProvider { protected final SecurityTokenSupplier tokenSupplier; protected final DefaultSessionKeySupplier sessionKeySupplier; private final Region region; public InstancePrincipalsProvider(SecurityTokenSupplier tokenSupplier, SessionKeyPairSupplier keyPairSupplier, Region region) { this.tokenSupplier = tokenSupplier; this.sessionKeySupplier = new DefaultSessionKeySupplier(keyPairSupplier); this.region = region; } @Override public String getKeyId() { return "ST$" + tokenSupplier.getSecurityToken(); } @Override public InputStream getPrivateKey() { return new ByteArrayInputStream(sessionKeySupplier.getPrivateKeyBytes()); } @Override public char[] getPassphraseCharacters() { return null; } @Override public Region getRegion() { return region; } public static InstancePrincipalsProviderBuilder builder() { return new InstancePrincipalsProviderBuilder(); } /** * Cloud service only. *

* Builder of InstancePrincipalsProvider */ public static class InstancePrincipalsProviderBuilder { private static final JsonFactory factory = new JsonFactory(); /* Instance metadata service base URL */ private static final String METADATA_SERVICE_BASE_URL = "http://169.254.169.254/opc/v2/"; private static final String FALLBACK_METADATA_SERVICE_URL = "http://169.254.169.254/opc/v1/"; /* The authorization header need to send to metadata service since V2 */ private static final String AUTHORIZATION_HEADER_VALUE = "Bearer Oracle"; private static final String METADATA_SERVICE_HOST = "169.254.169.254"; /* The default value for HTTP request timeouts in milliseconds */ private static final int DEFAULT_TIMEOUT_MS = 120_000; /* The default purpose value in federation requests against IAM */ private static final String DEFAULT_PURPOSE = "DEFAULT"; /* Base metadata service URL */ private String baseMetadataURL = METADATA_SERVICE_BASE_URL; /* * IAM federation endpoint, or null if decting from instance metadata. */ private String federationEndpoint; /* * The leaf certificate, or null if detecting from instance metadata. */ private CertificateSupplier leafCertificateSupplier; /* * Intermediate certificates or null if detecting from instance metadata. */ private Set intermediateCertificateSuppliers; /* * Session key pair supplier. */ private SessionKeyPairSupplier sessSupplier = new JDKKeyPairSupplier(); /* * Tenant id, or null if detecting from instance metadata. */ private String tenantId; private String purpose = DEFAULT_PURPOSE; private int timeout = DEFAULT_TIMEOUT_MS; private Region region; private Logger logger; public String getBaseMetadataURL() { return baseMetadataURL; } public String getFederationEndpoint() { return federationEndpoint; } public InstancePrincipalsProviderBuilder setFederationEndpoint(String federationEndpoint) { this.federationEndpoint = federationEndpoint; return this; } public CertificateSupplier getLeafCertificateSupplier() { return leafCertificateSupplier; } public InstancePrincipalsProviderBuilder setLeafCertificateSupplier(CertificateSupplier supplier) { this.leafCertificateSupplier = supplier; return this; } public String getTenantId() { return tenantId; } public InstancePrincipalsProviderBuilder setTenantId(String tenantId) { this.tenantId = tenantId; return this; } public String getPurpose() { return purpose; } public InstancePrincipalsProviderBuilder setPurpose(String purpose) { this.purpose = purpose; return this; } public SessionKeyPairSupplier getSesssionKeyPairSupplier() { return sessSupplier; } public InstancePrincipalsProviderBuilder setSessionKeyPairSupplier(SessionKeyPairSupplier sessSupplier) { this.sessSupplier = sessSupplier; return this; } public int getTimeout() { return timeout; } public InstancePrincipalsProviderBuilder setTimeout(int timeout) { this.timeout = timeout; return this; } public Logger getLogger() { return logger; } public InstancePrincipalsProviderBuilder setLogger(Logger logger) { this.logger = logger; return this; } public Set getIntermediateCertificateSuppliers() { return intermediateCertificateSuppliers; } public InstancePrincipalsProviderBuilder setIntermediateCertificateSuppliers( Set suppliers) { this.intermediateCertificateSuppliers = suppliers; return this; } public Region getRegion() { return region; } public InstancePrincipalsProviderBuilder setRegion(Region r) { this.region = r; return this; } public InstancePrincipalsProvider build() { if (logger == null) { logger = Logger.getLogger(getClass().getName()); logger.setLevel(Level.WARNING); } autoDetectEndpointUsingMetadataUrl(); autoDetectCertificatesUsingMetadataUrl(); SecurityTokenSupplier tokenSupplier = new SecurityTokenSupplier(federationEndpoint, tenantId, leafCertificateSupplier, intermediateCertificateSuppliers, sessSupplier, purpose, timeout, logger); return new InstancePrincipalsProvider(tokenSupplier, sessSupplier, region); } /* * Auto detects the endpoint that should be used when talking to * IAM, if no endpoint has been configured already. */ private void autoDetectEndpointUsingMetadataUrl() { if (federationEndpoint != null) { return; } String instanceMDURL = getInstanceMetadaURL(); logTrace(logger, "Detecting IAM endpoint using " + instanceMDURL); HttpClient client = null; try { client = new HttpClient(METADATA_SERVICE_HOST, 80, 0, 0, 0, null, "InstanceMDClient", logger); HttpResponse response = HttpRequestUtil.doGetRequest (client, instanceMDURL, headers(METADATA_SERVICE_HOST), timeout, logger); int status = response.getStatusCode(); if (status == 404) { logTrace(logger, "Falling back to v1 metadata URL, " + "resource not found from v2"); this.baseMetadataURL = FALLBACK_METADATA_SERVICE_URL; instanceMDURL = getInstanceMetadaURL(); response = HttpRequestUtil.doGetRequest (client, instanceMDURL, headers(METADATA_SERVICE_HOST), timeout, logger); if (response.getStatusCode() != 200) { throw new IllegalStateException( String.format("Unable to get federation URL from" + "instance metadata " + METADATA_SERVICE_BASE_URL + " or fallback to " + FALLBACK_METADATA_SERVICE_URL + ", status code: %d, output: %s", response.getOutput())); } } else if (status != 200) { throw new IllegalStateException( String.format("Unable to get federation URL from" + "instance metadata " + METADATA_SERVICE_BASE_URL + ", status code: %d, output: %s", response.getStatusCode(), response.getOutput())); } logTrace(logger, "Instance metadata " + response.getOutput()); String insRegion = findRegion(response.getOutput()); logTrace(logger, "Instance region " + insRegion); federationEndpoint = getIAMURL(insRegion); if (federationEndpoint == null) { throw new IllegalStateException( "Invalid IAM URI, unknown region " + region); } } finally { if (client != null) { client.shutdown(); } } } private String getInstanceMetadaURL() { return getBaseMetadataURL() + "instance/"; } private HttpHeaders headers(String host) { return new DefaultHttpHeaders() .add(HttpHeaderNames.HOST, host) .set(CONTENT_TYPE, APPLICATION_JSON) .set(AUTHORIZATION, AUTHORIZATION_HEADER_VALUE); } private String findRegion(String response) { try { JsonParser parser = factory.createParser(response); if (parser.getCurrentToken() == null) { parser.nextToken(); } while (parser.getCurrentToken() != null) { String field = findField(response, parser, "region"); if (field != null) { parser.nextToken(); return parser.getText(); } } throw new IllegalStateException( "Unable to find region in instance metadata " + response); } catch (IOException ioe) { throw new IllegalStateException( "Error parsing instance metadata in response " + response+ " " + ioe.getMessage()); } } /* * Auto detects and configures the certificates needed * using Instance metadata. */ private void autoDetectCertificatesUsingMetadataUrl() { try { if (leafCertificateSupplier == null) { leafCertificateSupplier = new DefaultCertificateSupplier( getURLDetails(getBaseMetadataURL() + "identity/cert.pem"), getURLDetails(getBaseMetadataURL() + "identity/key.pem"), (char[]) null); } if (tenantId == null) { tenantId = Utils.getTenantId(leafCertificateSupplier .getCertificateAndKeyPair().getCertificate()); } if (intermediateCertificateSuppliers == null) { intermediateCertificateSuppliers = new HashSet<>(); intermediateCertificateSuppliers.add( new DefaultCertificateSupplier( getURLDetails(getBaseMetadataURL() + "identity/intermediate.pem"), null, (char[]) null)); } } catch (MalformedURLException ex) { throw new IllegalArgumentException( "The instance metadata service url is invalid.", ex); } } private URLResourceDetails getURLDetails(String url) throws MalformedURLException { return new URLResourceDetails(new URL(url)) .addHeader(AUTHORIZATION, AUTHORIZATION_HEADER_VALUE); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy