-
Notifications
You must be signed in to change notification settings - Fork 6
[ENG-3808] Add aws auth login #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
7c024a3
Add aws auth login stuff
e7707be
Implement aws auth provider
126656a
Add tests
762e398
Add more test cases````
5b63505
Fix broken tests
54cf472
imports
359a36f
Make base64 values instead
cb1c340
Use v2 aws sdk instead
3a08a58
Clean up a bit
5ba8249
Flatten header
984bc71
Fixed tests
ba1f98b
Add session token
5819ecd
Add fromInstanceProfile
c4b2f44
Make aws auth focus on providing params only
4cfafd2
Make deps optional, revert unwanted changes
b404069
Revert api client
9af6271
Try to fix tests
39398e6
Fix IDE complain
33c8017
Fix broken tests
7be77af
More test cases
5eca544
Add a bit doc
4c10ae7
Rename
df1db68
Add non null
ee12f13
Bring AwsAuthLogin changes back
0b39380
Remove unused deps
999a17a
Add to builder arg
ca8fdf1
Remove duplicate log deps
59e3ea4
Add default provider
e1d973f
Be a bit more careful with the region value
63bb17c
Add overload method with just the identity id to make it more userfri…
87ff9ab
Remove not needed region regex check
f0be8e4
Remove unused import
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
src/main/java/com/infisical/sdk/auth/AwsAuthProvider.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package com.infisical.sdk.auth; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.infisical.sdk.models.AwsAuthParameters; | ||
import java.net.URI; | ||
import java.net.URLEncoder; | ||
import java.nio.charset.StandardCharsets; | ||
import java.time.Clock; | ||
import java.time.Instant; | ||
import java.time.ZoneOffset; | ||
import java.util.Base64; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NonNull; | ||
import software.amazon.awssdk.auth.credentials.AwsCredentials; | ||
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; | ||
import software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider; | ||
import software.amazon.awssdk.http.ContentStreamProvider; | ||
import software.amazon.awssdk.http.SdkHttpFullRequest; | ||
import software.amazon.awssdk.http.SdkHttpMethod; | ||
import software.amazon.awssdk.http.SdkHttpRequest; | ||
import software.amazon.awssdk.http.auth.aws.signer.AwsV4FamilyHttpSigner; | ||
import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner; | ||
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner; | ||
import software.amazon.awssdk.regions.Region; | ||
import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; | ||
|
||
@Data | ||
@Builder | ||
public class AwsAuthProvider { | ||
private static final ObjectMapper objectMapper = new ObjectMapper(); | ||
|
||
@NonNull @Builder.Default private final String serviceName = "sts"; | ||
@NonNull @Builder.Default private final SdkHttpMethod httpMethod = SdkHttpMethod.POST; | ||
@NonNull @Builder.Default private final String endpointTemplate = "https://sts.%s.amazonaws.com"; | ||
|
||
@NonNull @Builder.Default | ||
private final String contentType = "application/x-www-form-urlencoded; charset=utf-8"; | ||
|
||
@NonNull @Builder.Default | ||
private final Map<String, List<String>> params = | ||
Map.ofEntries( | ||
Map.entry("Action", List.of("GetCallerIdentity")), | ||
Map.entry("Version", List.of("2011-06-15"))); | ||
|
||
private final Instant overrideInstant; | ||
|
||
/** | ||
* Create AwsAuthLoginInput from given AWS credentials. | ||
* | ||
* @param region region of AWS identity | ||
* @param credentials AWS credentials for creating the login input | ||
* @param sessionToken Session token for creating the login input | ||
* @return the AwsAuthLoginInput created from the given credentials for exchanging access token | ||
*/ | ||
public AwsAuthParameters fromCredentials( | ||
String region, AwsCredentials credentials, String sessionToken) { | ||
final AwsV4HttpSigner signer = AwsV4HttpSigner.create(); | ||
final String iamRequestURL = endpointTemplate.formatted(region); | ||
fangpenlin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
final String iamRequestBody = encodeParameters(params); | ||
final SdkHttpFullRequest.Builder requestBuilder = | ||
SdkHttpFullRequest.builder() | ||
.uri(URI.create(iamRequestURL)) | ||
.method(httpMethod) | ||
.appendHeader("Content-Type", contentType); | ||
if (sessionToken != null) { | ||
requestBuilder.appendHeader("X-Amz-Security-Token", sessionToken); | ||
} | ||
final SdkHttpFullRequest request = requestBuilder.build(); | ||
final SdkHttpRequest signedRequest = | ||
signer | ||
.sign( | ||
signingRequest -> { | ||
var req = | ||
signingRequest | ||
.request(request) | ||
.identity(credentials) | ||
.payload( | ||
ContentStreamProvider.fromByteArray( | ||
iamRequestBody.getBytes(StandardCharsets.UTF_8))) | ||
.putProperty(AwsV4FamilyHttpSigner.SERVICE_SIGNING_NAME, serviceName) | ||
.putProperty(AwsV4HttpSigner.REGION_NAME, region); | ||
if (overrideInstant != null) { | ||
req.putProperty( | ||
HttpSigner.SIGNING_CLOCK, Clock.fixed(overrideInstant, ZoneOffset.UTC)); | ||
} | ||
}) | ||
.request(); | ||
final Map<String, String> requestHeaders = | ||
signedRequest.headers().entrySet().stream() | ||
.map(entry -> Map.entry(entry.getKey(), entry.getValue().getFirst())) | ||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); | ||
requestHeaders.put("Content-Length", String.valueOf(iamRequestBody.length())); | ||
final String encodedHeader; | ||
try { | ||
encodedHeader = | ||
Base64.getEncoder() | ||
.encodeToString( | ||
objectMapper.writeValueAsString(requestHeaders).getBytes(StandardCharsets.UTF_8)); | ||
} catch (JsonProcessingException e) { | ||
throw new RuntimeException(e); | ||
} | ||
final String encodedBody = | ||
Base64.getEncoder().encodeToString(iamRequestBody.getBytes(StandardCharsets.UTF_8)); | ||
return AwsAuthParameters.builder() | ||
.iamHttpRequestMethod(httpMethod.name()) | ||
.iamRequestHeaders(encodedHeader) | ||
.iamRequestBody(encodedBody) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Create AwsAuthLoginInput from the instance profile in the current environment. | ||
* | ||
* @return the AwsAuthLoginInput created from the current instance profile for exchanging access | ||
* token | ||
*/ | ||
public AwsAuthParameters fromInstanceProfile() { | ||
try (InstanceProfileCredentialsProvider provider = | ||
InstanceProfileCredentialsProvider.create()) { | ||
final AwsSessionCredentials credentials = | ||
(AwsSessionCredentials) provider.resolveCredentials(); | ||
fangpenlin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
final DefaultAwsRegionProviderChain regionProvider = | ||
DefaultAwsRegionProviderChain.builder().build(); | ||
final Region region = regionProvider.getRegion(); | ||
final String sessionToken = credentials.sessionToken(); | ||
return fromCredentials(region.id(), credentials, sessionToken); | ||
} | ||
} | ||
|
||
/** | ||
* Encode given parameters with URL encoding for the body of form posting request. | ||
* | ||
* @param params parameters mapping key to values to encode | ||
* @return URL-encoded string of the parameters | ||
*/ | ||
public static String encodeParameters(Map<String, List<String>> params) { | ||
return params.entrySet().stream() | ||
.flatMap(entry -> entry.getValue().stream().map(item -> Map.entry(entry.getKey(), item))) | ||
// Notice: this is not really needed for real world usage, but it makes the | ||
// body encoded in a deterministic order, so that unit test is much easier | ||
.sorted(Map.Entry.comparingByKey()) | ||
.map( | ||
entry -> | ||
String.format( | ||
"%s=%s", | ||
URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8), | ||
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))) | ||
.collect(Collectors.joining("&")); | ||
} | ||
|
||
public static AwsAuthProvider defaultProvider() { | ||
return builder().build(); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
src/main/java/com/infisical/sdk/models/AwsAuthLoginInput.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.infisical.sdk.models; | ||
|
||
import com.infisical.sdk.util.Helper; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NonNull; | ||
|
||
@Data | ||
@Builder(toBuilder = true) | ||
public class AwsAuthLoginInput { | ||
@NonNull private final String identityId; | ||
@NonNull private final String iamHttpRequestMethod; | ||
@NonNull private final String iamRequestHeaders; | ||
@NonNull private final String iamRequestBody; | ||
|
||
public String validate() { | ||
if (Helper.isNullOrEmpty(identityId)) { | ||
return "Identity ID is required"; | ||
} | ||
|
||
if (Helper.isNullOrEmpty(iamHttpRequestMethod)) { | ||
return "IamHttpRequestMethod is required"; | ||
} | ||
|
||
if (Helper.isNullOrEmpty(iamRequestHeaders)) { | ||
return "IamRequestHeaders is required"; | ||
} | ||
|
||
if (Helper.isNullOrEmpty(iamRequestBody)) { | ||
return "IamRequestBody is required"; | ||
} | ||
return null; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/infisical/sdk/models/AwsAuthParameters.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.infisical.sdk.models; | ||
|
||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NonNull; | ||
|
||
@Data | ||
@Builder(toBuilder = true) | ||
public class AwsAuthParameters { | ||
@NonNull private final String iamHttpRequestMethod; | ||
@NonNull private final String iamRequestHeaders; | ||
@NonNull private final String iamRequestBody; | ||
|
||
public AwsAuthLoginInput toLoginInput(String identityId) { | ||
return AwsAuthLoginInput.builder() | ||
.identityId(identityId) | ||
.iamRequestHeaders(iamRequestHeaders) | ||
.iamHttpRequestMethod(iamHttpRequestMethod) | ||
.iamRequestBody(iamRequestBody) | ||
.build(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.