Skip to content

Commit

Permalink
feat: upgrade the credential refresh mechanism and add fallbacks for …
Browse files Browse the repository at this point in the history
…error scenarios
  • Loading branch information
yndu13 committed Dec 3, 2024
1 parent e1c991c commit 9ad6c7b
Show file tree
Hide file tree
Showing 22 changed files with 491 additions and 180 deletions.
78 changes: 32 additions & 46 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.aliyun</groupId>
<artifactId>credentials-java</artifactId>
<version>1.0.0</version>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>credentials-java</name>
Expand All @@ -21,14 +21,23 @@
https://www.aliyun.com
</description>

<!-- <distributionManagement>-->
<!-- <snapshotRepository>-->
<!-- <id>sonatype-nexus-snapshots</id>-->
<!-- <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>-->
<!-- </snapshotRepository>-->
<!-- <repository>-->
<!-- <id>sonatype-nexus-staging</id>-->
<!-- <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>-->
<!-- </repository>-->
<!-- </distributionManagement>-->

<distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
<id>snapshots</id>
<name>alibaba Repositories Group</name>
<url>http://mvnrepo.alibaba-inc.com/mvn/snapshots</url>
<layout>default</layout>
</repository>
</distributionManagement>

Expand Down Expand Up @@ -56,8 +65,7 @@
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<powermock.version>2.0.2</powermock.version>
<mockito.version>3.0.0</mockito.version>
<mockito.version>4.11.0</mockito.version>
</properties>

<dependencies>
Expand All @@ -69,7 +77,7 @@
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
<version>[1.1.14, 2.0.0)</version>
<version>[1.2.0, 2.0.0)</version>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand All @@ -94,38 +102,16 @@
<version>0.8.8</version>
<classifier>runtime</classifier>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.17.1</version>
</dependency>
</dependencies>

Expand Down Expand Up @@ -164,17 +150,17 @@
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>sonatype-nexus-staging</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<!-- <plugin>-->
<!-- <groupId>org.sonatype.plugins</groupId>-->
<!-- <artifactId>nexus-staging-maven-plugin</artifactId>-->
<!-- <version>1.6.8</version>-->
<!-- <extensions>true</extensions>-->
<!-- <configuration>-->
<!-- <serverId>sonatype-nexus-staging</serverId>-->
<!-- <nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>-->
<!-- <autoReleaseAfterClose>true</autoReleaseAfterClose>-->
<!-- </configuration>-->
<!-- </plugin>-->

<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public String getProviderName() {
return providerName;
}

@Override
public String toString() {
return String.format("Credential(accessKeyId=%s, accessKeySecret=%s, securityToken=%s, providerName=%s, expiration=%s)", accessKeyId, accessKeySecret, securityToken, providerName, expiration);
}

public static final class Builder {
private String accessKeyId;
private String accessKeySecret;
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/com/aliyun/credentials/policy/NonBlocking.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.aliyun.credentials.policy;

import com.aliyun.tea.logging.ClientLogger;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.util.concurrent.TimeUnit.SECONDS;

public class NonBlocking implements PrefetchStrategy {
private static final ClientLogger logger = new ClientLogger(NonBlocking.class);
private final AtomicBoolean currentlyRefreshing = new AtomicBoolean(false);

private final ExecutorService executor;

public NonBlocking() {
this.executor = new ThreadPoolExecutor(0, 1, 5, SECONDS,
new LinkedBlockingQueue<>(1),
Executors.defaultThreadFactory());
}

@Override
public void prefetch(Runnable valueUpdater) {
if (currentlyRefreshing.compareAndSet(false, true)) {
try {
executor.submit(() -> {
try {
valueUpdater.run();
} finally {
currentlyRefreshing.set(false);
}
});
} catch (RuntimeException e) {
currentlyRefreshing.set(false);
throw e;
}
}
}

@Override
public void close() {
executor.shutdown();
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/aliyun/credentials/policy/OneCallerBlocks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.aliyun.credentials.policy;

import java.util.concurrent.atomic.AtomicBoolean;

public class OneCallerBlocks implements PrefetchStrategy {
private final AtomicBoolean currentlyRefreshing = new AtomicBoolean(false);

@Override
public void prefetch(Runnable valueUpdater) {
if (currentlyRefreshing.compareAndSet(false, true)) {
try {
valueUpdater.run();
} finally {
currentlyRefreshing.set(false);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.aliyun.credentials.policy;

@FunctionalInterface
public interface PrefetchStrategy extends AutoCloseable {
void prefetch(Runnable valueUpdater);

default void close() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private CLIProfileCredentialsProvider(Builder builder) {
this.currentProfileName = builder.profileName == null ? System.getenv("ALIBABA_CLOUD_PROFILE") : builder.profileName;
}

static Builder builder() {
public static Builder builder() {
return new Builder();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@ private void createDefaultChain() {
defaultProviders.add(new SystemPropertiesCredentialsProvider());
defaultProviders.add(new EnvironmentVariableCredentialsProvider());
if (AuthUtils.environmentEnableOIDC()) {
defaultProviders.add(OIDCRoleArnCredentialProvider.builder()
.roleArn(AuthUtils.getEnvironmentRoleArn())
.oidcProviderArn(AuthUtils.getEnvironmentOIDCProviderArn())
.oidcTokenFilePath(AuthUtils.getEnvironmentOIDCTokenFilePath())
.build());
defaultProviders.add(OIDCRoleArnCredentialProvider.builder().build());
}
defaultProviders.add(CLIProfileCredentialsProvider.builder().build());
defaultProviders.add(new ProfileCredentialsProvider());
Expand Down Expand Up @@ -99,7 +95,7 @@ public CredentialModel getCredentials() {
errorMessages.add(provider.getClass().getSimpleName() + ": " + e.getMessage());
}
}
throw new CredentialException("Unable to load credentials from any of the providers in the chain: ." + errorMessages);
throw new CredentialException("Unable to load credentials from any of the providers in the chain: " + errorMessages);
}

@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.Map;

public class ECSMetadataServiceCredentialsFetcher {
Expand Down Expand Up @@ -115,6 +116,9 @@ public RefreshResult<CredentialModel> fetch(CompatibleUrlConnClient client) {
if (!"Success".equals(result.get("Code"))) {
throw new CredentialException(ECS_METADAT_FETCH_ERROR_MSG);
}
if (!result.containsKey("AccessKeyId") || !result.containsKey("AccessKeySecret") || !result.containsKey("SecurityToken")) {
throw new CredentialException(String.format("Error retrieving credentials from IMDS result: %s.", jsonContent));
}
long expiration = ParameterHelper.getUTCDate(result.get("Expiration")).getTime();
CredentialModel credential = CredentialModel.builder()
.accessKeyId(result.get("AccessKeyId"))
Expand All @@ -125,11 +129,24 @@ public RefreshResult<CredentialModel> fetch(CompatibleUrlConnClient client) {
.expiration(expiration)
.build();
return RefreshResult.builder(credential)
.staleTime(expiration - 3 * 60 * 1000)
.staleTime(getStaleTime(expiration))
.prefetchTime(getPrefetchTime(expiration))
.build();

}

private long getStaleTime(long expiration) {
return expiration <= 0 ?
new Date().getTime() + 60 * 60 * 1000
: expiration - 15 * 60 * 1000;
}

private long getPrefetchTime(long expiration) {
return expiration <= 0 ?
new Date().getTime() + 5 * 60 * 1000
: new Date().getTime() + 60 * 60 * 1000;
}

public URL getCredentialUrl() {
return credentialUrl;
}
Expand Down
Loading

0 comments on commit 9ad6c7b

Please sign in to comment.