Skip to content

Commit b643bbd

Browse files
committed
Add new SignatureProvider constructor for instance principal delegation tokens.
1 parent eb22ff3 commit b643bbd

File tree

3 files changed

+142
-1
lines changed

3 files changed

+142
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
1717
- For successful operations, retry stats can be retrieved using Result.getRetryStats().
1818
- Otherwise, the original Request may have retry stats available via Request.getRetryStats() (for example, after an exception was thrown).
1919
- Cloud only: New regions: ap-chiyoda-1, me-dubai-1, uk-cardiff-1 and sa-santiago-1
20+
- Cloud only: Added new SignatureProvider constructors to allow use of an instance
21+
principal with a delegation token for authorization and authentication:
22+
- SignatureProvider.createInstancePrincipalForDelegation()
2023

2124
### Fixed
2225
- Ensure that TableLimits is always null in TableResult on-premise.

driver/src/main/java/oracle/nosql/driver/iam/SignatureProvider.java

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ public class SignatureProvider
9999
implements AuthorizationProvider, RegionProvider {
100100

101101
private static final String SIGNING_HEADERS = "(request-target) host date";
102+
private static final String SIGNING_HEADERS_WITH_OBO =
103+
"(request-target) host date opc-obo-token";
104+
private static final String OBO_TOKEN_HEADER = "opc-obo-token";
102105

103106
/* Cache key name */
104107
private static final String CACHE_KEY = "signature";
@@ -113,6 +116,9 @@ public class SignatureProvider
113116
private final AuthenticationProfileProvider provider;
114117
private final PrivateKeyProvider privateKeyProvider;
115118

119+
/* Delegation token specified for signing */
120+
private String delegationToken;
121+
116122
private final LruCache<String, SignatureDetails> signatureCache;
117123

118124
/* Refresh timer */
@@ -377,6 +383,79 @@ public static SignatureProvider createWithInstancePrincipal(Region region) {
377383
return provider;
378384
}
379385

386+
/**
387+
* Creates a SignatureProvider using an instance principal with a
388+
* delegation token. This constructor may be used when calling the
389+
* Oracle NoSQL Database Cloud Service from an Oracle Cloud compute
390+
* instance. It authenticates with the instance principal and uses a
391+
* security token issued by IAM to do the actual request signing.
392+
* The delegation token allows the instance to assume the privileges
393+
* of the user for which the token was created.
394+
* <p>
395+
* When using an instance principal the compartment id (OCID) must be
396+
* specified on each request or defaulted by using
397+
* {@link NoSQLHandleConfig#setDefaultCompartment}. If the compartment id
398+
* is not specified for an operation an exception will be thrown.
399+
* <p>
400+
* See <a href="https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm">Calling Services from Instances</a>.
401+
*
402+
* @param delegationToken this token allows an instance to assume the
403+
* privileges of a specific user and act on-behalf-of that user
404+
*
405+
* @return SignatureProvider
406+
*/
407+
public static SignatureProvider
408+
createWithInstancePrincipalForDelegation(String delegationToken) {
409+
410+
SignatureProvider provider = new SignatureProvider(
411+
InstancePrincipalsProvider.builder().build());
412+
provider.setDelegationToken(delegationToken);
413+
return provider;
414+
}
415+
416+
/**
417+
* Creates a SignatureProvider using an instance principal with a
418+
* delegation token. This constructor may be used when calling the
419+
* Oracle NoSQL Database Cloud Service from an Oracle Cloud compute
420+
* instance. It authenticates with the instance principal and uses a
421+
* security token issued by IAM to do the actual request signing.
422+
* The delegation token allows the instance to assume the privileges
423+
* of the user for which the token was created.
424+
* <p>
425+
* When using an instance principal the compartment id (OCID) must be
426+
* specified on each request or defaulted by using
427+
* {@link NoSQLHandleConfig#setDefaultCompartment}. If the compartment id
428+
* is not specified for an operation an exception will be thrown.
429+
* <p>
430+
* See <a href="https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm">Calling Services from Instances</a>.
431+
*
432+
* @param iamAuthUri The URI is usually detected automatically, specify
433+
* the URI if you need to overwrite the default, or encounter the
434+
* <code>Invalid IAM URI</code> error.
435+
* @param region the region to use, it may be null
436+
* @param delegationToken this token allows an instance to assume the
437+
* privileges of a specific user and act on-behalf-of that user
438+
* @param logger the logger used by the SignatureProvider.
439+
*
440+
* @return SignatureProvider
441+
*/
442+
public static SignatureProvider
443+
createWithInstancePrincipalForDelegation(String iamAuthUri,
444+
Region region,
445+
String delegationToken,
446+
Logger logger) {
447+
448+
SignatureProvider provider = new SignatureProvider(
449+
InstancePrincipalsProvider.builder()
450+
.setFederationEndpoint(iamAuthUri)
451+
.setLogger(logger)
452+
.setRegion(region)
453+
.build());
454+
provider.setLogger(logger);
455+
provider.setDelegationToken(delegationToken);
456+
return provider;
457+
}
458+
380459
/**
381460
* Creates a SignatureProvider using a resource principal. This
382461
* constructor may be used when calling the Oracle NoSQL Database
@@ -486,6 +565,9 @@ public void setRequiredHeaders(String authString,
486565
headers.add(AUTHORIZATION, sigDetails.getSignatureHeader());
487566
headers.add(DATE, sigDetails.getDate());
488567

568+
if (delegationToken != null) {
569+
headers.add(OBO_TOKEN_HEADER, delegationToken);
570+
}
489571
String compartment = request.getCompartment();
490572
if (compartment == null) {
491573
/*
@@ -579,6 +661,11 @@ public String getResourcePrincipalClaim(String key) {
579661
return rpp.getClaim(key);
580662
}
581663

664+
/* visible for testing */
665+
void setDelegationToken(String token) {
666+
this.delegationToken = token;
667+
}
668+
582669
private void logMessage(Level level, String msg) {
583670
if (logger != null) {
584671
logger.log(level, msg);
@@ -611,8 +698,10 @@ synchronized SignatureDetails getSignatureDetailsInternal() {
611698
return null;
612699
}
613700

701+
String signingHeader = (delegationToken == null)
702+
? SIGNING_HEADERS : SIGNING_HEADERS_WITH_OBO;
614703
String sigHeader = String.format(SIGNATURE_HEADER_FORMAT,
615-
SIGNING_HEADERS,
704+
signingHeader,
616705
keyId,
617706
RSA,
618707
signature,
@@ -631,6 +720,11 @@ String signingContent(String date) {
631720
.append(HOST).append(HEADER_DELIMITER)
632721
.append(serviceHost).append("\n")
633722
.append(DATE).append(HEADER_DELIMITER).append(date);
723+
724+
if (delegationToken != null) {
725+
sb.append("\n").append(OBO_TOKEN_HEADER)
726+
.append(HEADER_DELIMITER).append(delegationToken);
727+
}
634728
return sb.toString();
635729
}
636730

driver/src/test/java/oracle/nosql/driver/iam/InstancePrincipalsProviderTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package oracle.nosql.driver.iam;
99

1010
import static org.junit.Assert.assertEquals;
11+
import static org.junit.Assert.assertTrue;
1112
import static org.junit.Assert.fail;
1213

1314
import java.io.ByteArrayInputStream;
@@ -22,9 +23,12 @@
2223

2324
import oracle.nosql.driver.DriverTestBase;
2425
import oracle.nosql.driver.FreePortLocator;
26+
import oracle.nosql.driver.NoSQLHandleConfig;
2527
import oracle.nosql.driver.Region;
2628
import oracle.nosql.driver.iam.CertificateSupplier.DefaultCertificateSupplier;
2729
import oracle.nosql.driver.iam.CertificateSupplier.URLResourceDetails;
30+
import oracle.nosql.driver.ops.Request;
31+
import oracle.nosql.driver.ops.TableRequest;
2832

2933
import org.junit.AfterClass;
3034
import org.junit.Before;
@@ -35,6 +39,9 @@
3539
import com.sun.net.httpserver.HttpHandler;
3640
import com.sun.net.httpserver.HttpServer;
3741

42+
import io.netty.handler.codec.http.DefaultHttpHeaders;
43+
import io.netty.handler.codec.http.HttpHeaders;
44+
3845
public class InstancePrincipalsProviderTest extends DriverTestBase {
3946
private static final FreePortLocator portLocator =
4047
new FreePortLocator("localhost", 4242, 14000);
@@ -168,6 +175,43 @@ public void testBasic()
168175
assertEquals("ST$" + securityToken(), provider.getKeyId());
169176
}
170177

178+
@Test
179+
public void testDelegationToken()
180+
throws Exception {
181+
182+
CertificateSupplier leaf = new DefaultCertificateSupplier(
183+
getURLDetails(base + "/instance?cert.pem"),
184+
getURLDetails(base + "/instance?key.pem"),
185+
(char[]) null);
186+
187+
CertificateSupplier inter = new DefaultCertificateSupplier(
188+
getURLDetails(base + "/instance?intermediate.pem"),
189+
null,
190+
(char[]) null);
191+
192+
InstancePrincipalsProvider provider =
193+
InstancePrincipalsProvider.builder()
194+
.setFederationEndpoint(base)
195+
.setLeafCertificateSupplier(leaf)
196+
.setIntermediateCertificateSuppliers(Collections.singleton(inter))
197+
.setTenantId(tenantId)
198+
.build();
199+
200+
SignatureProvider sp = new SignatureProvider(provider);
201+
String delegationToken = "fake-token";
202+
sp.setServiceHost(new NoSQLHandleConfig("http://test"));
203+
sp.setDelegationToken(delegationToken);
204+
205+
Request request = new TableRequest();
206+
request.setCompartmentInternal("compartment");
207+
String authzString = sp.getAuthorizationString(request);
208+
assertTrue(authzString.contains("opc-obo-token"));
209+
210+
HttpHeaders headers = new DefaultHttpHeaders();
211+
sp.setRequiredHeaders(authzString, request, headers);
212+
assertEquals(headers.get("opc-obo-token"), delegationToken);
213+
}
214+
171215
@Test
172216
public void testDefaultCertificateSupplier()
173217
throws Exception {

0 commit comments

Comments
 (0)