Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion driver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@
<serverType>none</serverType>
<included.tests>
StoreAccessTokenProviderTest.java, ResourcePrincipalProviderTest.java,
ConfigFileTest.java, SignatureProviderTest.java, AuthRetryTest.java,
OAuthAccessTokenProviderTest.java, ConfigFileTest.java,
SignatureProviderTest.java, AuthRetryTest.java,
UserProfileProviderTest.java, InstancePrincipalsProviderTest.java,
HandleConfigTest.java, JsonTest.java, ValueTest.java,
SessionTokenProviderTest.java, RequestTest.java
Expand Down
62 changes: 48 additions & 14 deletions driver/src/main/java/oracle/nosql/driver/http/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import oracle.nosql.driver.httpclient.HttpClient;
import oracle.nosql.driver.httpclient.ResponseHandler;
import oracle.nosql.driver.kv.AuthenticationException;
import oracle.nosql.driver.kv.OAuthAccessTokenProvider;
import oracle.nosql.driver.kv.StoreAccessTokenProvider;
import oracle.nosql.driver.ops.AddReplicaRequest;
import oracle.nosql.driver.ops.DeleteRequest;
Expand Down Expand Up @@ -285,9 +286,9 @@ public Client(Logger logger,
"Must configure AuthorizationProvider to use HttpClient");
}

/* StoreAccessTokenProvider == onprem */
/* StoreAccessTokenProvider/OAuthAccessTokenProvider == onprem */
if (config.getRateLimitingEnabled() &&
!(authProvider instanceof StoreAccessTokenProvider)) {
!isOnPremAuthProvider()) {
logFine(logger, "Starting client with rate limiting enabled");
rateLimiterMap = new RateLimiterMap();
tableLimitUpdateMap = new ConcurrentHashMap<String, AtomicLong>();
Expand Down Expand Up @@ -374,6 +375,11 @@ public int getFreeChannelCount() {
return httpClient.getFreeChannelCount();
}

private boolean isOnPremAuthProvider() {
return authProvider instanceof StoreAccessTokenProvider ||
authProvider instanceof OAuthAccessTokenProvider;
}

/**
* Get the next client-scoped request id. It needs to be combined with the
* client id to obtain a globally unique scope.
Expand Down Expand Up @@ -675,12 +681,10 @@ public Result execute(Request kvRequest) {
kvRequest.setTimeoutInternal(timeoutMs);

/*
* If on-premises the authProvider will always be a
* StoreAccessTokenProvider. If so, check against
* configurable limit. Otherwise check against internal
* hardcoded cloud limit.
* If on-premises, check against configurable limit.
* Otherwise check against internal hardcoded cloud limit.
*/
if (authProvider instanceof StoreAccessTokenProvider) {
if (isOnPremAuthProvider()) {
if (buffer.readableBytes() >
httpClient.getMaxContentLength()) {
throw new RequestSizeLimitException("The request " +
Expand Down Expand Up @@ -844,6 +848,32 @@ public Result execute(Request kvRequest) {
"Client re-auth on AuthenticationException: " +
rae.getMessage());
continue;
} else if (authProvider instanceof OAuthAccessTokenProvider) {
/*
* OAuthAccessTokenProvider obtains a new NoSQL login
* token lazily after the cache is flushed. Retry this
* path only once so repeated RETRY_AUTHENTICATION
* responses are surfaced as authentication failures
* instead of eventually timing out the request.
*/
if (retriedException(kvRequest,
AuthenticationException.class)) {
kvRequest.setRateLimitDelayedMs(rateDelayedMs);
statsControl.observeError(kvRequest);
logFine(logger,
"Client OAuth re-auth failed: " +
rae.getMessage());
throw rae;
}
authProvider.flushCache();
kvRequest.addRetryException(rae.getClass());
kvRequest.incrementRetries();
exception = rae;
logFine(logger,
"Client retrying OAuth re-auth on " +
"AuthenticationException: " +
rae.getMessage());
continue;
}
kvRequest.setRateLimitDelayedMs(rateDelayedMs);
statsControl.observeError(kvRequest);
Expand All @@ -859,7 +889,8 @@ public Result execute(Request kvRequest) {
* failures. This does not include permissions-related errors,
* which would be a UnauthorizedException.
*/
if (retriedInvalidAuthorizationException(kvRequest)) {
if (retriedException(kvRequest,
InvalidAuthorizationException.class)) {
/* same as NoSQLException below */
kvRequest.setRateLimitDelayedMs(rateDelayedMs);
statsControl.observeError(kvRequest);
Expand Down Expand Up @@ -1584,20 +1615,23 @@ private void updateTableLimiters(String tableName, String compartmentId) {
}

/**
* Returns whether an {@link InvalidAuthorizationException} has been
* retried for the given request.
* Returns whether an exception type has been retried for the given
* request.
*
* @param request the request to check
* @return true if an {@link InvalidAuthorizationException} has been
* retried for the request, false otherwise
* @param exceptionClass the exception class to check
* @return true if the exception type has been retried for the request
*/
private boolean retriedInvalidAuthorizationException(Request request) {
private boolean retriedException(
Request request,
Class<? extends Throwable> exceptionClass) {

final RetryStats rs = request.getRetryStats();
if (rs == null || rs.getRetries() <= 0) {
return false;
}

return rs.getNumExceptions(InvalidAuthorizationException.class) > 0;
return rs.getNumExceptions(exceptionClass) > 0;
}

private void throwIfTransportRetryNotAllowed(Request request,
Expand Down
27 changes: 22 additions & 5 deletions driver/src/main/java/oracle/nosql/driver/http/NoSQLHandleImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import oracle.nosql.driver.StatsControl;
import oracle.nosql.driver.UserInfo;
import oracle.nosql.driver.iam.SignatureProvider;
import oracle.nosql.driver.kv.OAuthAccessTokenProvider;
import oracle.nosql.driver.kv.StoreAccessTokenProvider;
import oracle.nosql.driver.ops.AddReplicaRequest;
import oracle.nosql.driver.ops.DeleteRequest;
Expand Down Expand Up @@ -154,15 +155,23 @@ private void configAuthProvider(Logger logger, NoSQLHandleConfig config) {
}
if (stProvider.isSecure() &&
stProvider.getEndpoint() == null) {
String endpoint = config.getServiceURL().toString();
if (endpoint.endsWith("/")) {
endpoint = endpoint.substring(0, endpoint.length() - 1);
}
stProvider.setEndpoint(endpoint)
stProvider.setEndpoint(getAuthEndpoint(config))
.setSslContext(config.getSslContext())
.setSslHandshakeTimeout(
config.getSSLHandshakeTimeout());
}
} else if (ap instanceof OAuthAccessTokenProvider) {
final OAuthAccessTokenProvider oatProvider =
(OAuthAccessTokenProvider) ap;
if (oatProvider.getLogger() == null) {
oatProvider.setLogger(logger);
}
if (oatProvider.getEndpoint() == null) {
oatProvider.setEndpoint(getAuthEndpoint(config))
.setSslContext(config.getSslContext())
.setSslHandshakeTimeout(
config.getSSLHandshakeTimeout());
}
} else if (ap instanceof SignatureProvider) {
SignatureProvider sigProvider = (SignatureProvider) ap;
if (sigProvider.getLogger() == null) {
Expand All @@ -176,6 +185,14 @@ private void configAuthProvider(Logger logger, NoSQLHandleConfig config) {
}
}

private String getAuthEndpoint(NoSQLHandleConfig config) {
String endpoint = config.getServiceURL().toString();
if (endpoint.endsWith("/")) {
endpoint = endpoint.substring(0, endpoint.length() - 1);
}
return endpoint;
}

@Override
public DeleteResult delete(DeleteRequest request) {
checkClient();
Expand Down
Loading