Skip to content

Commit 5947994

Browse files
authored
Add support for session token auth
Cloud only: added session token authentication support - SignatureProvider.createWithSessionToken() - SignatureProvider.createWithSessionToken(String profile) - SignatureProvider.createWithSessionToken(String configFilePath, String profile)
1 parent ec02ea7 commit 5947994

File tree

11 files changed

+406
-30
lines changed

11 files changed

+406
-30
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
55
## Unreleased
66

77
### Added
8+
- Cloud only: added session token authentication support
9+
- SignatureProvider.createWithSessionToken()
10+
- SignatureProvider.createWithSessionToken(String profile)
11+
- SignatureProvider.createWithSessionToken(String configFilePath, String profile)
12+
- Cloud only: added support to read region from system environment variable
13+
OCI_REGION if using user principal or session token authentication
814
- Cloud only: added new OCI regions (NAP, AVZ, AGA, VAP)
915

1016
### Changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ public class Quickstart {
250250
private final static boolean useUserPrincipal = true;
251251
private final static boolean useInstancePrincipal = false;
252252
private final static boolean useResourcePrincipal = false;
253+
private final static boolean useSessionToken = false;
253254
254255
private Quickstart(String[] args) {
255256
/*
@@ -327,6 +328,12 @@ public class Quickstart {
327328
privateKeyFile, // File
328329
passphrase); // char[]
329330
*/
331+
} else if (useSessionToken) {
332+
/*
333+
* There are additional constructors for Session Token,
334+
* see the javadoc
335+
*/
336+
authProvider = SignatureProvider.createWithSessionToken();
330337
} else {
331338
if (compartment == null) {
332339
throw new IllegalArgumentException(
@@ -473,7 +480,7 @@ public class Quickstart {
473480
System.out.println("\t" + res);
474481
}
475482
}
476-
483+
477484
/*
478485
* Drop the table
479486
*/

driver/pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@
142142
StoreAccessTokenProviderTest.java, ResourcePrincipalProviderTest.java,
143143
ConfigFileTest.java, SignatureProviderTest.java,
144144
UserProfileProviderTest.java, InstancePrincipalsProviderTest.java,
145-
HandleConfigTest.java, JsonTest.java, ValueTest.java
145+
HandleConfigTest.java, JsonTest.java, ValueTest.java,
146+
SessionTokenProviderTest.java
146147
</included.tests>
147148
</properties>
148149
</profile>

driver/src/main/java/oracle/nosql/driver/Region.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ public String endpoint() {
358358
return OC24_EP_BASE.format(new Object[] { regionId });
359359
}
360360
throw new IllegalArgumentException(
361-
"Unable to find endpoint for unknwon region" + regionId);
361+
"Unable to find endpoint for unknown region" + regionId);
362362
}
363363

364364
/**

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package oracle.nosql.driver.iam;
99

10+
import static oracle.nosql.driver.iam.OCIConfigFileReader.*;
1011
import static oracle.nosql.driver.util.CheckNull.requireNonNullIAE;
1112

1213
import java.io.File;
@@ -41,21 +42,6 @@
4142
class OCIConfigFileProvider
4243
implements UserAuthenticationProfileProvider, RegionProvider {
4344

44-
/**
45-
* Default configuration file at <code>~/.oci/config</code>
46-
*/
47-
public static final String DEFAULT_FILE_PATH =
48-
System.getProperty("user.home") + File.separator +
49-
".oci" + File.separator + "config";
50-
public static final String DEFAULT_PROFILE_NAME = "DEFAULT";
51-
52-
static final String FINGERPRINT_PROP = "fingerprint";
53-
static final String TENANCY_PROP = "tenancy";
54-
static final String USER_PROP = "user";
55-
static final String KEY_FILE_PROP = "key_file";
56-
static final String PASSPHRASE_PROP = "pass_phrase";
57-
static final String REGION_PROP = "region";
58-
5945
private final SimpleProfileProvider delegate;
6046

6147
/**
@@ -127,10 +113,7 @@ private OCIConfigFileProvider(OCIConfigFile configFile) {
127113
}
128114

129115
/* region is optional */
130-
String regionValue = configFile.get(REGION_PROP);
131-
if (regionValue != null) {
132-
builder.region(Region.fromRegionId(regionValue));
133-
}
116+
builder.region(OCIConfigFileReader.getRegionFromConfigFile(configFile));
134117
this.delegate = builder.build();
135118

136119
}
@@ -169,9 +152,4 @@ public String getKeyId() {
169152
public Region getRegion() {
170153
return this.delegate.getRegion();
171154
}
172-
173-
private String missing(String propertyName) {
174-
return "Required property " + propertyName +
175-
" is missing from OCI configuration file";
176-
}
177155
}

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
package oracle.nosql.driver.iam;
99

10-
import static oracle.nosql.driver.iam.OCIConfigFileProvider.DEFAULT_PROFILE_NAME;
11-
1210
import java.io.BufferedReader;
1311
import java.io.File;
1412
import java.io.FileInputStream;
@@ -20,6 +18,8 @@
2018
import java.util.HashMap;
2119
import java.util.Map;
2220

21+
import oracle.nosql.driver.Region;
22+
2323
/**
2424
* Cloud service only.
2525
* <p>
@@ -42,6 +42,22 @@
4242
* </pre>
4343
*/
4444
public class OCIConfigFileReader {
45+
/**
46+
* Default configuration file at <code>~/.oci/config</code>
47+
*/
48+
public static final String DEFAULT_FILE_PATH =
49+
System.getProperty("user.home") + File.separator +
50+
".oci" + File.separator + "config";
51+
public static final String DEFAULT_PROFILE_NAME = "DEFAULT";
52+
53+
static final String FINGERPRINT_PROP = "fingerprint";
54+
static final String TENANCY_PROP = "tenancy";
55+
static final String USER_PROP = "user";
56+
static final String KEY_FILE_PROP = "key_file";
57+
static final String PASSPHRASE_PROP = "pass_phrase";
58+
static final String REGION_PROP = "region";
59+
static final String SESSION_TOKEN_FILE_PROP = "security_token_file";
60+
static final String OCI_REGION_ENV_VAR_NAME = "OCI_REGION";
4561

4662
/**
4763
* Create a new instance using a file at a given location.
@@ -125,6 +141,29 @@ public static OCIConfigFile parse(InputStream configStream,
125141
return new OCIConfigFile(accumulator, profile);
126142
}
127143

144+
static String missing(String propertyName) {
145+
return "Required property " + propertyName +
146+
" is missing from OCI configuration file." +
147+
" For more information about OCI configuration file and" +
148+
" how to get required information," +
149+
" see https://docs.oracle.com" +
150+
"/en-us/iaas/Content/API/Concepts/sdkconfig.htm";
151+
}
152+
153+
static Region getRegionFromConfigFile(OCIConfigFile configFile) {
154+
Region region = null;
155+
String regionId = configFile.get(REGION_PROP);
156+
if (regionId == null || regionId.isEmpty()) {
157+
/* Attempts to read region id from env variable */
158+
regionId = System.getenv(OCI_REGION_ENV_VAR_NAME);
159+
}
160+
161+
if (regionId != null && !regionId.isEmpty()) {
162+
return Region.fromRegionId(regionId);
163+
}
164+
return region;
165+
}
166+
128167
private OCIConfigFileReader() {}
129168

130169
/**
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*-
2+
* Copyright (c) 2011, 2023 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* Licensed under the Universal Permissive License v 1.0 as shown at
5+
* https://oss.oracle.com/licenses/upl/
6+
*/
7+
8+
package oracle.nosql.driver.iam;
9+
10+
import static oracle.nosql.driver.iam.OCIConfigFileReader.*;
11+
import static oracle.nosql.driver.util.CheckNull.requireNonNullIAE;
12+
13+
import java.io.File;
14+
import java.io.FileNotFoundException;
15+
import java.io.IOException;
16+
import java.io.InputStream;
17+
import java.util.Scanner;
18+
import java.util.function.Supplier;
19+
20+
import oracle.nosql.driver.Region;
21+
import oracle.nosql.driver.Region.RegionProvider;
22+
23+
/**
24+
* @hidden
25+
* Internal use only
26+
* <p>
27+
* The authentication profile provider used to call service API using token
28+
* based authentication.
29+
*/
30+
class SessionTokenProvider
31+
implements AuthenticationProfileProvider, RegionProvider{
32+
33+
private final String sessionTokenFilePath;
34+
private final String tenantId;
35+
private final Supplier<InputStream> privateKeySupplier;
36+
private final char[] passphrase;
37+
private final Region region;
38+
39+
/**
40+
* Creates a new instance using the config file at the default location and
41+
* the default profile.
42+
*/
43+
SessionTokenProvider() {
44+
this(DEFAULT_FILE_PATH, DEFAULT_PROFILE_NAME);
45+
}
46+
47+
/**
48+
* Creates a new instance using the config file at the default location,
49+
* @param profile profile to load
50+
*/
51+
SessionTokenProvider(String profile) {
52+
this(DEFAULT_FILE_PATH, profile);
53+
}
54+
55+
/**
56+
* Creates a new instance.
57+
*
58+
* @param configFilePath path to the OCI configuration file
59+
* @param profile profile to load, optional
60+
*/
61+
SessionTokenProvider(String configFilePath, String profile) {
62+
final OCIConfigFile configFile;
63+
try {
64+
configFile = OCIConfigFileReader.parse(configFilePath, profile);
65+
} catch (IOException e) {
66+
throw new IllegalArgumentException(
67+
"Error parsing config file " + configFilePath +
68+
": " + e.getMessage());
69+
}
70+
71+
this.sessionTokenFilePath = configFile.get(SESSION_TOKEN_FILE_PROP);
72+
requireNonNullIAE(sessionTokenFilePath, missing(SESSION_TOKEN_FILE_PROP));
73+
this.tenantId = configFile.get(TENANCY_PROP);
74+
requireNonNullIAE(tenantId, missing(TENANCY_PROP));
75+
final String keyFilePath = configFile.get(KEY_FILE_PROP);
76+
requireNonNullIAE(tenantId, missing(KEY_FILE_PROP));
77+
this.privateKeySupplier = new PrivateKeyFileSupplier(
78+
new File(Utils.expandUserHome(keyFilePath)));
79+
this.region = getRegionFromConfigFile(configFile);
80+
81+
/* Optional parameters */
82+
final String passphraseString = configFile.get(PASSPHRASE_PROP);
83+
this.passphrase = (passphraseString != null) ?
84+
passphraseString.toCharArray() : null;
85+
}
86+
87+
private String refreshAndGetTokenInternal() {
88+
final File sessionTokenFile = new File(
89+
Utils.expandUserHome(sessionTokenFilePath));
90+
final StringBuilder token = new StringBuilder();
91+
92+
try (Scanner reader = new Scanner(sessionTokenFile)) {
93+
while (reader.hasNextLine()) {
94+
token.append(reader.nextLine());
95+
}
96+
} catch (FileNotFoundException e) {
97+
throw new IllegalArgumentException(
98+
"Session token file " + sessionTokenFilePath + " not found");
99+
}
100+
101+
return token.toString();
102+
}
103+
104+
public String getTenantId() {
105+
return this.tenantId;
106+
}
107+
108+
@Override
109+
public Region getRegion() {
110+
return this.region;
111+
}
112+
113+
@Override
114+
public String getKeyId() {
115+
return "ST$" + refreshAndGetTokenInternal();
116+
}
117+
118+
@Override
119+
public InputStream getPrivateKey() {
120+
return privateKeySupplier.get();
121+
}
122+
123+
@Override
124+
public char[] getPassphraseCharacters() {
125+
return passphrase;
126+
}
127+
}

0 commit comments

Comments
 (0)