Skip to content
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

Add flexible checksum support for non-streaming cases #4376

Conversation

haydenbaker
Copy link
Contributor

@haydenbaker haydenbaker commented Aug 31, 2023

Motivation and Context

  • Flexible checksum support is needed for a few specific cases where a custom checksum can be added to a request
  • This PR addresses the non-streaming cases for unsigned and signed payload
  • A follow-up PR will be sent to address the streaming (aws-chunked) case, but there is no plan to support flexible checksums for event-streaming case or non-streaming CRT-V4a

Modifications

  • Copies SdkChecksum and related code from sdk-core to use internally without importing sdk-core
  • Add new internal classes to handle flexible checksum cases, and remove the old digest-related stream and subscriber code
  • Cleans up a couple of APIs that should be internal, not protected

Testing

  • Run new and existing tests, make sure no failures
  • Run subscriber TCK test, make sure the implementation is compliant

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • [x]I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@haydenbaker haydenbaker requested a review from a team as a code owner August 31, 2023 16:51
@haydenbaker haydenbaker force-pushed the haydenbaker/sra-ia-awssigners-flexible-checksums branch from 9de4aef to eb70caa Compare August 31, 2023 23:12
import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha256Checksum;

@SdkInternalApi
public final class ChecksumUtil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add unit tests for this class?

*/
String checksum(ContentStreamProvider payload);
void checksum(ContentStreamProvider payload, SdkHttpRequest.Builder request);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we make this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before flexible checksums, the checksummer only ever returned the checksum as a value. Now, the checksummer has to be able to do multiple things (i.e. compute a checksum, add it to the request, compute another checksum, add it to the request somewhere else).

@haydenbaker haydenbaker force-pushed the haydenbaker/sra-ia-awssigners-flexible-checksums branch from eb70caa to 3124558 Compare September 1, 2023 16:20
* Implementation of {@link SdkChecksum} to provide a constant checksum.
*/
@SdkInternalApi
public class ConstantChecksum implements SdkChecksum {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use-case for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Touched upon here: #4376 (comment)


private final Collection<Checksum> checksums = new ArrayList<>();

public ChecksumInputStream(InputStream stream, Collection<? extends Checksum> checksums) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason this takes a list of checksums? From the checksum spec, only one checksum algorithm is allowed on the request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! It takes multiple because multiple "checksums" are computed when a flexible checksum is specified in the signing request - the "flexible"checksum and the sha-256 content hash (or one of the pre-defined constant values, which is why we need the ConstantChecksum)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any use cases defined in tests for these variants?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. The ChecksumInputStreamTest and FlexibleChecksummerTest should test multiple checksums being configured.

private static boolean hasTrailer(SignRequest<?, ? extends AwsCredentialsIdentity> request) {
// Flexible checksums dictates adding a trailer when signing, but there may be existing trailers on
// the request (in the future)
return request.hasProperty(CHECKSUM_ALGORITHM) || request.request().firstMatchingHeader(X_AMZ_TRAILER).isPresent();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why request.hasProperty(CHECKSUM_ALGORITHM) means it has trailer? Nit: can we move the comment to the javadoc? Comments sometimes clutter the code imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see how this would be confusing. Changing.

public class ChecksumInputStreamTest {

@Test
public void test_computesCorrectSha256() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, we don't really use "test" as part of test name since it's unnecessary. The patterns we've established are methodToTest_when_expectedBehavior or given_when_then

* The default implementation of a checksummer. By default, this will calculate the SHA256 checksum of a payload and add it as the
* value for the 'x-amz-content-sha256' header on the request.
*/
@SdkInternalApi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this class? Since technically, this is covered in FlexibleChecksummer by passing just SHA256

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, you're right, it can be removed.

* the cases where the checksum is a pre-defined value that dictates specific behavior by the signer, and flexible checksums is
* not enabled for the request (such as aws-chunked payload signing without trailers, unsigned streaming without trailers, etc.).
*/
@SdkInternalApi
public final class PrecomputedChecksummer implements Checksummer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this class? It seems like we can use FlexibleChecksummer and pass ConstantChecksumAlgorithm right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an optimization, using this class means it doesn't need to read the stream like it does with Flexible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename it to PrecomputedSha256Checksummer to make it more clear?

/**
* Gets the SdkChecksum object based on the given ChecksumAlgorithm.
*/
public static SdkChecksum fromChecksumAlgorithm(ChecksumAlgorithm checksumAlgorithm) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to create a map for this to make it easier to maintain and may be a micro performance improvement Map<ChecksumAlgorithm, Supplier<SdkChecksum>>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do this for the most, we can't for ConstantChecksum, since it takes a value as part of construction. Updating for this case.

* the cases where the checksum is a pre-defined value that dictates specific behavior by the signer, and flexible checksums is
* not enabled for the request (such as aws-chunked payload signing without trailers, unsigned streaming without trailers, etc.).
*/
@SdkInternalApi
public final class PrecomputedChecksummer implements Checksummer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename it to PrecomputedSha256Checksummer to make it more clear?

* Get a flexible checksummer that performs two checksums: the given checksum-algorithm and a precomputed checksum from the
* given checksum string.
*/
static Checksummer create(String checksum, ChecksumAlgorithm checksumAlgorithm) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting static Checksummer forFlexibleChecksum(String preComputedSha256, ChecksumAlgorithm checksumAlgorithm)

*/
@SdkInternalApi
public final class FlexibleChecksummer implements Checksummer {
private final Map<String, SdkChecksum> checksumMap;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Map<SdkChecksum, String> seems to be more intuitive. Can we rename it to checksumToHeader or headerToChecksum if you want to keep it as is.

* given checksum string.
*/
static Checksummer create(String checksum, ChecksumAlgorithm checksumAlgorithm) {
if (checksumAlgorithm != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we require chekcsumAlgorithm to be not null

/**
* Get a precomputed checksummer that results the given checksum string.
*/
static Checksummer create(String checksum) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting static Checksummer forPrecomputed256Checksum(String preComputedSha256)

* Given a payload, calculate a checksum and return it as a string.
* Get a flexible checksummer that performs two checksums: the given checksum-algorithm and the default (sha256).
*/
static Checksummer create(ChecksumAlgorithm checksumAlgorithm) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting static Checksummer forFlexibleChecksum(ChecksumAlgorithm checksumAlgorithm) and requiring checksumAlgorithims to be not null.

Copy link
Contributor

@zoewangg zoewangg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to merge once require chekcsumAlgorithm thing is fixed.

@haydenbaker haydenbaker merged commit 53c7b3b into feature/master/sra-identity-auth Sep 6, 2023
10 of 12 checks passed
@haydenbaker haydenbaker deleted the haydenbaker/sra-ia-awssigners-flexible-checksums branch September 6, 2023 16:34
@sonarcloud
Copy link

sonarcloud bot commented Sep 6, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 3 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot E 2 Security Hotspots
Code Smell A 352 Code Smells

0.0% 0.0% Coverage
6.2% 6.2% Duplication

idea Catch issues before they fail your Quality Gate with our IDE extension sonarlint SonarLint

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants