Skip to content

Commit 437d4a2

Browse files
authored
Retry request on specific authentication errors. (#37)
Retry request on specific authentication errors. In some Instance Principal cases, the security token returned from OCI Identity may have a very short expiration. This change removes the expiration check, and allows a single retry on requests that get specific authN errors. It also adds trace-level logging of authentication token details.
1 parent bfe1d11 commit 437d4a2

File tree

4 files changed

+44
-19
lines changed

4 files changed

+44
-19
lines changed

driver/src/main/java/oracle/nosql/driver/http/Client.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,12 @@ public Result execute(Request kvRequest) {
717717
throw new NoSQLException("Unexpected exception: " +
718718
rae.getMessage(), rae);
719719
} catch (InvalidAuthorizationException iae) {
720-
/* allow a single retry on clock skew errors */
721-
if (iae.getMessage().contains("clock skew") == false ||
722-
kvRequest.getNumRetries() > 0) {
720+
/*
721+
* Allow a single retry for invalid/expired auth
722+
* This includes "clock skew" errors
723+
* This does not include permissions-related errors
724+
*/
725+
if (kvRequest.getNumRetries() > 0) {
723726
/* same as NoSQLException below */
724727
kvRequest.setRateLimitDelayedMs(rateDelayedMs);
725728
statsControl.observeError(kvRequest);

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

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,18 @@ private synchronized String refreshAndGetTokenInternal() {
174174
}
175175
SecurityToken token = getSecurityTokenFromIAM();
176176
token.validate(minTokenLifetime);
177+
178+
/*
179+
* Allow logging of token expiration details
180+
*/
181+
long tokenLifetime = token.getExpiryMS() - token.getCreationTime();
182+
logTrace(logger, "New security token: lifetime=" + tokenLifetime +
183+
", expiry=" + token.getExpiryMS() + ", creation=" +
184+
token.getCreationTime());
185+
if (tokenLifetime < minTokenLifetime) {
186+
logTrace(logger, "token:\n" + token.getSecurityToken());
187+
}
188+
177189
return token.getSecurityToken();
178190
}
179191

@@ -265,10 +277,17 @@ String getStringClaim(String key) {
265277
return tokenClaims.get(key);
266278
}
267279

280+
long getCreationTime() {
281+
return creationTime;
282+
}
283+
284+
long getExpiryMS() {
285+
return expiryMS;
286+
}
287+
268288
/*
269-
* Validate the token, also check if the lifetime of token
270-
* is longer than specified minimal lifetime, throws IAE
271-
* if any validation fails.
289+
* Validate the token.
290+
* Throws IAE if any validation fails.
272291
*/
273292
void validate(long minTokenLifetime) {
274293
if (tokenClaims == null) {
@@ -288,19 +307,9 @@ void validate(long minTokenLifetime) {
288307
}
289308

290309
/*
291-
* This is just a safety check, shouldn't happen in OCI environment,
292-
* because security tokens always have more than one hour lifetime.
293-
* It would only be thrown if short-living token being used or
294-
* signature cache is misconfigured. To fix, must adjust the cache
295-
* duration in both cases.
310+
* Note: expiry check removed, as some tokens may have very short
311+
* expirations.
296312
*/
297-
long tokenLifetime = expiryMS - creationTime;
298-
if (tokenLifetime < minTokenLifetime) {
299-
throw new IllegalArgumentException(
300-
"Security token has less lifetime than signature cache " +
301-
"duration, reduce signature cache duration less than " +
302-
tokenLifetime + " milliseconds, token:\n" + securityToken);
303-
}
304313

305314
/*
306315
* Next compare the public key inside the JWT is the same

driver/src/main/java/oracle/nosql/driver/ops/QueryRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ public QueryRequest setConsistency(Consistency consistency) {
651651
*
652652
* @return this
653653
*
654-
* @since 5.3.0
654+
* @since 5.4.0
655655
*/
656656
public QueryRequest setDurability(Durability durability) {
657657
setDurabilityInternal(durability);

driver/src/main/java/oracle/nosql/driver/ops/TableResult.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ public String getDdl() {
111111
* the on-premise service.
112112
*
113113
* @return the table OCID
114+
*
115+
* @since 5.4
114116
*/
115117
public String getTableId() {
116118
return tableOcid;
@@ -122,6 +124,8 @@ public String getTableId() {
122124
* Returns compartment id of the target table
123125
*
124126
* @return the compartment id if set
127+
*
128+
* @since 5.4
125129
*/
126130
public String getCompartmentId() {
127131
return compartmentOrNamespace;
@@ -135,6 +139,8 @@ public String getCompartmentId() {
135139
* is in a namespace.
136140
*
137141
* @return the namespace id if set
142+
*
143+
* @since 5.4
138144
*/
139145
public String getNamespace() {
140146
return compartmentOrNamespace;
@@ -155,6 +161,8 @@ public String getTableName() {
155161
* Returns the JSON-formatted schema of the table if available and null if
156162
* not
157163
* @return the schema
164+
*
165+
* @since 5.4
158166
*/
159167
public String getSchema() {
160168
return schema;
@@ -177,6 +185,8 @@ public TableLimits getTableLimits() {
177185
* if available, or null otherwise.
178186
*
179187
* @return the FreeFormTags
188+
*
189+
* @since 5.4
180190
*/
181191
public FreeFormTags getFreeFormTags() {
182192
return freeFormTags;
@@ -189,6 +199,8 @@ public FreeFormTags getFreeFormTags() {
189199
* if available, or null otherwise.
190200
*
191201
* @return the DefinedTags
202+
*
203+
* @since 5.4
192204
*/
193205
public DefinedTags getDefinedTags() {
194206
return definedTags;
@@ -204,6 +216,7 @@ public DefinedTags getDefinedTags() {
204216
* optimistic concurrency control mechanism.
205217
*
206218
* @return the matchETag
219+
*
207220
* @since 5.4
208221
*/
209222
public String getMatchETag() {

0 commit comments

Comments
 (0)