Skip to content

Commit

Permalink
core: update errors retryable condition.
Browse files Browse the repository at this point in the history
Retry request in case of auth store revision old error from server

Fixes #1344.

Signed-off-by: rmarian <marianradu12@gmail.com>
  • Loading branch information
Rmarian committed Mar 23, 2024
1 parent 9130dcd commit 194c57f
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 1 deletion.
2 changes: 1 addition & 1 deletion jetcd-core/src/main/java/io/etcd/jetcd/support/Errors.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private Errors() {
}

public static boolean isRetryable(Status status) {
return Status.UNAVAILABLE.getCode().equals(status.getCode()) || isInvalidTokenError(status);
return Status.UNAVAILABLE.getCode().equals(status.getCode()) || isInvalidTokenError(status) || isAuthStoreExpired(status);
}

public static boolean isInvalidTokenError(Throwable e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package io.etcd.jetcd.impl.auth;

import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.Client;
import io.etcd.jetcd.KV;
import io.etcd.jetcd.auth.Permission;
import io.etcd.jetcd.impl.TestUtil;
import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.test.EtcdClusterExtension;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.io.File;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Timeout(value = 30)
public class AuthTokenRefreshTest {

@RegisterExtension
public static final EtcdClusterExtension cluster = EtcdClusterExtension.builder()
.withNodes(1)
.withSsl(true)
.withAdditionalArgs(
List.of(
"--auth-token",
"jwt,pub-key=/etc/ssl/etcd/server.pem,priv-key=/etc/ssl/etcd/server-key.pem,sign-method=RS256,ttl=300s"))
.build();

private static final ByteSequence key = TestUtil.bytesOf("key");
private static final ByteSequence keyEnd = TestUtil.bytesOf("key1");
private static final ByteSequence user = TestUtil.bytesOf("root");
private static final ByteSequence password = TestUtil.randomByteSequence();


@Test
public void testTokenIsRefreshedWhenRevisionsIsOld() throws Exception {
setUpEnvironment();

Client authClient = createAuthClient();
KV kvClient = authClient.getKVClient();

ByteSequence value = TestUtil.randomByteSequence();
kvClient.put(key, value).get(1, TimeUnit.SECONDS);

//read the created key to generate a new jwt token
GetResponse getResponse = kvClient.get(key).get(1, TimeUnit.SECONDS);
Assertions.assertEquals(1, getResponse.getKvs().size());
Assertions.assertEquals(key, getResponse.getKvs().get(0).getKey());
Assertions.assertEquals(value, getResponse.getKvs().get(0).getValue());

//update auth database revision by adding a new role thus invalidating existing token of the kv client
authClient.getAuthClient().roleAdd(TestUtil.bytesOf("newRole")).get(1, TimeUnit.SECONDS);

//kv client should automatically refresh the old token and read the key
getResponse = kvClient.get(key).get(1, TimeUnit.SECONDS);

Assertions.assertEquals(1, getResponse.getKvs().size());
Assertions.assertEquals(key, getResponse.getKvs().get(0).getKey());
Assertions.assertEquals(value, getResponse.getKvs().get(0).getValue());
}


private void setUpEnvironment() throws Exception {
final File caFile = new File(Objects.requireNonNull(getClass().getResource("/ssl/cert/ca.pem")).toURI());

Client client = TestUtil.client(cluster)
.authority("etcd0")
.sslContext(b -> b.trustManager(caFile))
.build();

// enable authentication to enforce usage of access token
ByteSequence role = TestUtil.bytesOf("root");
client.getAuthClient().roleAdd(role).get();
client.getAuthClient().userAdd(user, password).get();
// grant access only to given key
client.getAuthClient().roleGrantPermission(role, key, keyEnd, Permission.Type.READWRITE).get();
client.getAuthClient().userGrantRole(user, role).get();
client.getAuthClient().authEnable().get();

client.close();
}

private Client createAuthClient() throws Exception {
final File caFile = new File(Objects.requireNonNull(getClass().getResource("/ssl/cert/ca.pem")).toURI());

return TestUtil.client(cluster)
.user(user)
.password(password)
.authority("etcd0")
.sslContext(b -> b.trustManager(caFile))
.build();
}

}

0 comments on commit 194c57f

Please sign in to comment.