Skip to content

Commit

Permalink
javafmt + fixes after rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
radeusgd committed Jan 16, 2024
1 parent c254200 commit 01f1443
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 60 deletions.
2 changes: 2 additions & 0 deletions std-bits/aws/src/main/java/org/enso/aws/AwsCredential.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

public sealed interface AwsCredential {
record Key(HideableValue accessKeyId, HideableValue secretAccessKey) implements AwsCredential {}

record Profile(String name) implements AwsCredential {}

record Default() implements AwsCredential {}
}
10 changes: 5 additions & 5 deletions std-bits/aws/src/main/java/org/enso/aws/ClientBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ public ClientBuilder(AwsCredential credential) {
}

public S3Client buildS3Client() {
return S3Client.builder()
.credentialsProvider(unsafeBuildCredentialProvider())
.build();
return S3Client.builder().credentialsProvider(unsafeBuildCredentialProvider()).build();
}

/**
* The {@code AwsCredentialsProviders} may leak secrets, so it should never be returned to user code.
* The {@code AwsCredentialsProviders} may leak secrets, so it should never be returned to user
* code.
*/
private AwsCredentialsProvider unsafeBuildCredentialProvider() {
return switch (this.awsCredential) {
Expand All @@ -36,7 +35,8 @@ private AwsCredentialsProvider unsafeBuildCredentialProvider() {
}

/**
* This function is allowed access to secrets. Extra care should be taken to ensure its result is not leaked.
* This function is allowed access to secrets. Extra care should be taken to ensure its result is
* not leaked.
*/
private String unsafeResolveSecrets(HideableValue value) {
return ExternalLibrarySecretHelper.resolveValue(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,6 @@

/** Makes HTTP requests with secrets in either header or query string. */
public final class EnsoSecretHelper extends SecretValueResolver {
/**
* Gets the value of an HideableValue resolving secrets.
*
* @param value The value to resolve.
* @return The pair's value. Should not be returned to Enso.
*/
private static String resolveValue(HideableValue value) {
return switch (value) {
case HideableValue.PlainValue plainValue -> plainValue.value();
case HideableValue.SecretValue secretValue -> {
yield EnsoSecretReader.readSecret(secretValue.secretId());
}
case HideableValue.ConcatValues concatValues -> {
String left = resolveValue(concatValues.left());
String right = resolveValue(concatValues.right());
yield left + right;
}
case HideableValue.Base64EncodeValue base64EncodeValue -> HideableValue.Base64EncodeValue
.encode(resolveValue(base64EncodeValue.value()));
};
}

/** Gets a JDBC connection resolving EnsoKeyValuePair into the properties. */
public static Connection getJDBCConnection(String url, Pair<String, HideableValue>[] properties)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import java.util.List;
import java.util.Optional;

/** An entry point allowing external libraries to access Enso secrets.
* <p>
* It will only allow access from trusted code locations.
/**
* An entry point allowing external libraries to access Enso secrets.
*
* <p>It will only allow access from trusted code locations.
*/
public final class ExternalLibrarySecretHelper extends SecretValueResolver {
public static String resolveValue(HideableValue hideableValue) throws EnsoSecretAccessDenied {
Expand All @@ -14,40 +15,43 @@ public static String resolveValue(HideableValue hideableValue) throws EnsoSecret
}

/**
* Checks the current stack trace to find the caller and checks if it is one of the allowed locations.
* <p>
* This is a very rudimentary approach to the access control, and it is not very extensible, as it requires updating
* std-base whenever a new library that needs access to secrets is added. However, it seems like the best simple
* solution for now.
* <p>
* Later we may want to replace it with some other solution, e.g. a key that trusted libraries will use to 'sign'
* their class name, proving that they can be trusted, without the need to update std-base whenever a new library is
* added.
* Checks the current stack trace to find the caller and checks if it is one of the allowed
* locations.
*
* <p>This is a very rudimentary approach to the access control, and it is not very extensible, as
* it requires updating std-base whenever a new library that needs access to secrets is added.
* However, it seems like the best simple solution for now.
*
* <p>Later we may want to replace it with some other solution, e.g. a key that trusted libraries
* will use to 'sign' their class name, proving that they can be trusted, without the need to
* update std-base whenever a new library is added.
*/
private static void checkAccess() throws EnsoSecretAccessDenied {
var accessLocation = StackWalker.getInstance().walk((stackFrameStream -> {
String myClassName = ExternalLibrarySecretHelper.class.getName();
Optional<StackWalker.StackFrame> firstClientFrame = stackFrameStream
.filter((frame) -> !frame.getClassName().equals(myClassName))
.findFirst();
if (firstClientFrame.isEmpty()) {
throw new IllegalStateException("Unable to find client frame.");
}
var accessLocation =
StackWalker.getInstance()
.walk(
(stackFrameStream -> {
String myClassName = ExternalLibrarySecretHelper.class.getName();
Optional<StackWalker.StackFrame> firstClientFrame =
stackFrameStream
.filter((frame) -> !frame.getClassName().equals(myClassName))
.findFirst();
if (firstClientFrame.isEmpty()) {
throw new IllegalStateException("Unable to find client frame.");
}

var frame = firstClientFrame.get();
return new AccessLocation(frame.getClassName(), frame.getMethodName());
}));
var frame = firstClientFrame.get();
return new AccessLocation(frame.getClassName(), frame.getMethodName());
}));

boolean isAllowed = allowedAccessLocations.contains(accessLocation);
if (!isAllowed) {
throw new EnsoSecretAccessDenied();
}
}

private record AccessLocation(String className, String method) {
}
private record AccessLocation(String className, String method) {}

private static final List<AccessLocation> allowedAccessLocations = List.of(
new AccessLocation("org.enso.aws.ClientBuilder", "unsafeResolveSecrets")
);
private static final List<AccessLocation> allowedAccessLocations =
List.of(new AccessLocation("org.enso.aws.ClientBuilder", "unsafeResolveSecrets"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ sealed class SecretValueResolver permits EnsoSecretHelper, ExternalLibrarySecret
protected static String resolveValue(HideableValue value) {
return switch (value) {
case HideableValue.PlainValue plainValue -> plainValue.value();
case HideableValue.SecretValue secretValue -> EnsoSecretReader.readSecret(
secretValue.secretId());
case HideableValue.ConcatValues concatValues ->
resolveValue(concatValues.left()) + resolveValue(concatValues.right());
case HideableValue.Base64EncodeValue base64EncodeValue ->
HideableValue.Base64EncodeValue.encode(resolveValue(base64EncodeValue.value()));
case HideableValue.SecretValue secretValue -> {
yield EnsoSecretReader.readSecret(secretValue.secretId());
}
case HideableValue.ConcatValues concatValues -> {
String left = resolveValue(concatValues.left());
String right = resolveValue(concatValues.right());
yield left + right;
}
case HideableValue.Base64EncodeValue base64EncodeValue -> HideableValue.Base64EncodeValue
.encode(resolveValue(base64EncodeValue.value()));
};
}
}

0 comments on commit 01f1443

Please sign in to comment.