diff --git a/core/http-auth-spi/pom.xml b/core/http-auth-spi/pom.xml index c366580aa013..1cc8f8771d11 100644 --- a/core/http-auth-spi/pom.xml +++ b/core/http-auth-spi/pom.xml @@ -70,6 +70,11 @@ equalsverifier test + + org.mockito + mockito-core + test + diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/AsyncHttpSignRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/AsyncHttpSignRequest.java new file mode 100644 index 000000000000..58c14d445161 --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/AsyncHttpSignRequest.java @@ -0,0 +1,50 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi; + +import java.nio.ByteBuffer; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.annotations.Immutable; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.http.auth.spi.internal.DefaultAsyncHttpSignRequest; +import software.amazon.awssdk.identity.spi.Identity; +import software.amazon.awssdk.utils.builder.SdkBuilder; + +/** + * Input parameters to sign a request with async payload, using {@link HttpSigner}. + * + * @param The type of the identity. + */ +@SdkPublicApi +@Immutable +@ThreadSafe +public interface AsyncHttpSignRequest extends HttpSignRequest, IdentityT> { + /** + * Get a new builder for creating a {@link AsyncHttpSignRequest}. + */ + static Builder builder(IdentityT identity) { + return new DefaultAsyncHttpSignRequest.BuilderImpl<>(identity); + } + + /** + * A builder for a {@link AsyncHttpSignRequest}. + */ + interface Builder + extends HttpSignRequest.Builder, Publisher, IdentityT>, + SdkBuilder, AsyncHttpSignRequest> { + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/AsyncSignedHttpRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/AsyncSignedHttpRequest.java new file mode 100644 index 000000000000..ed66105313be --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/AsyncSignedHttpRequest.java @@ -0,0 +1,47 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi; + +import java.nio.ByteBuffer; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.annotations.Immutable; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.http.auth.spi.internal.DefaultAsyncSignedHttpRequest; +import software.amazon.awssdk.utils.builder.SdkBuilder; + +/** + * Represents a request with async payload that has been signed by {@link HttpSigner}. + */ +@SdkPublicApi +@Immutable +@ThreadSafe +public interface AsyncSignedHttpRequest extends SignedHttpRequest> { + + /** + * Get a new builder for creating a {@link AsyncSignedHttpRequest}. + */ + static Builder builder() { + return new DefaultAsyncSignedHttpRequest.BuilderImpl(); + } + + /** + * A builder for a {@link AsyncSignedHttpRequest}. + */ + interface Builder extends SignedHttpRequest.Builder>, + SdkBuilder { + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthOption.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthOption.java index f7f3ddc29ba2..481421b6f5d9 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthOption.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthOption.java @@ -81,7 +81,7 @@ interface SignerPropertyConsumer { } interface Builder extends SdkBuilder { - Builder schemeId(String schemeId); + Builder schemeId(String schemeId); Builder putIdentityProperty(IdentityProperty key, T value); diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthScheme.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthScheme.java index 69b5d863bfdc..155a7c605e11 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthScheme.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpAuthScheme.java @@ -58,5 +58,5 @@ public interface HttpAuthScheme { * Retrieve the signer associated with this authentication scheme. This signer is guaranteed to support the identity * generated by the identity provider in this authentication scheme. */ - HttpSigner signer(); + HttpSigner signer(); } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSignRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSignRequest.java index c67b0c4a5bf7..261a28c00cc4 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSignRequest.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSignRequest.java @@ -20,30 +20,18 @@ import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.annotations.ThreadSafe; import software.amazon.awssdk.http.SdkHttpRequest; -import software.amazon.awssdk.http.auth.spi.internal.DefaultHttpSignRequest; -import software.amazon.awssdk.utils.builder.SdkBuilder; +import software.amazon.awssdk.identity.spi.Identity; /** - * Represents a request to be signed by {@link HttpSigner}. + * Input parameters to sign a request using {@link HttpSigner}. * - * @param The type of payload of this request. + * @param The type of payload of the request. + * @param The type of the identity. */ @SdkPublicApi @Immutable @ThreadSafe -public interface HttpSignRequest { - - /** - * Get a new builder for creating a {@link HttpSignRequest}. - */ - static Builder builder(Class payloadType) { - return new DefaultHttpSignRequest.BuilderImpl(payloadType); - } - - /** - * Returns the type of the payload. - */ - Class payloadType(); +public interface HttpSignRequest { /** * Returns the HTTP request object, without the request body payload. @@ -56,28 +44,38 @@ static Builder builder(Class payloadType) { Optional payload(); /** - * Returns the property that the {@link HttpSigner} can use during signing. + * Returns the identity. + */ + IdentityT identity(); + + /** + * Returns the value of a property that the {@link HttpSigner} can use during signing. */ T property(SignerProperty property); /** * A builder for a {@link HttpSignRequest}. */ - interface Builder extends SdkBuilder, HttpSignRequest> { + interface Builder, PayloadT, IdentityT extends Identity> { /** * Set the HTTP request object, without the request body payload. */ - Builder request(SdkHttpRequest request); + B request(SdkHttpRequest request); /** * Set the body payload of the request. A payload is optional. By default, the payload will be empty. */ - Builder payload(PayloadT payload); + B payload(PayloadT payload); + + /** + * Set the identity of the request. + */ + B identity(IdentityT identity); /** * Set a property that the {@link HttpSigner} can use during signing. */ - Builder putProperty(SignerProperty key, T value); + B putProperty(SignerProperty key, T value); } } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSigner.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSigner.java index 60596518403f..7cc8ac5d4784 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSigner.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/HttpSigner.java @@ -15,31 +15,62 @@ package software.amazon.awssdk.http.auth.spi; -import java.nio.ByteBuffer; -import org.reactivestreams.Publisher; +import java.util.function.Consumer; import software.amazon.awssdk.annotations.SdkPublicApi; -import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.auth.spi.internal.DefaultAsyncHttpSignRequest; +import software.amazon.awssdk.http.auth.spi.internal.DefaultSyncHttpSignRequest; +import software.amazon.awssdk.identity.spi.Identity; /** * Interface for the process of modifying a request destined for a service so that the service can authenticate the SDK - * customer’s identity + * customer’s identity. + * + * @param The type of the identity. */ @SdkPublicApi -public interface HttpSigner { +public interface HttpSigner { + + /** + * Method that takes in inputs to sign a request with sync payload and returns a signed version of the request. + * + * @param request The inputs to sign a request. + * @return A signed version of the request. + */ + SyncSignedHttpRequest sign(SyncHttpSignRequest request); + + /** + * Method that takes in inputs to sign a request with sync payload and returns a signed version of the request. + *

+ * Similar to {@link #sign(SyncHttpSignRequest)}, but takes a lambda to configure a new {@link SyncHttpSignRequest.Builder}. + * This removes the need to call {@link SyncHttpSignRequest#builder(IdentityT)}} and + * {@link SyncHttpSignRequest.Builder#build()}. + * + * @param consumer A {@link Consumer} to which an empty {@link SyncHttpSignRequest.Builder} will be given. + * @return A signed version of the request. + */ + default SyncSignedHttpRequest sign(Consumer> consumer) { + return sign(new DefaultSyncHttpSignRequest.BuilderImpl().applyMutation(consumer).build()); + } /** - * Method that takes in a request and returns a signed version of the request. + * Method that takes in inputs to sign a request with async payload and returns a signed version of the request. * - * @param request The request to sign, with sync payload - * @return A signed version of the input request + * @param request The inputs to sign a request. + * @return A signed version of the request. */ - SignedHttpRequest sign(HttpSignRequest request); + AsyncSignedHttpRequest signAsync(AsyncHttpSignRequest request); /** - * Method that takes in a request and returns a signed version of the request. + * Method that takes in inputs to sign a request with async payload and returns a signed version of the request. + *

+ * Similar to {@link #signAsync(AsyncHttpSignRequest)}, but takes a lambda to configure a new + * {@link AsyncHttpSignRequest.Builder}. This removes the need to call {@link AsyncHttpSignRequest#builder(IdentityT)}} and + * {@link AsyncHttpSignRequest.Builder#build()}. * - * @param request The request to sign, with async payload - * @return A signed version of the input request + * @param consumer A {@link Consumer} to which an empty {@link HttpSignRequest.Builder} will be given. + * @return A signed version of the request. */ - SignedHttpRequest> signAsync(HttpSignRequest> request); + default AsyncSignedHttpRequest signAsync(Consumer> consumer) { + return signAsync(new DefaultAsyncHttpSignRequest.BuilderImpl().applyMutation(consumer).build()); + } } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignedHttpRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignedHttpRequest.java index 380fdff00f46..87ecdf5cff49 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignedHttpRequest.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignedHttpRequest.java @@ -20,31 +20,17 @@ import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.annotations.ThreadSafe; import software.amazon.awssdk.http.SdkHttpRequest; -import software.amazon.awssdk.http.auth.spi.internal.DefaultSignedHttpRequest; -import software.amazon.awssdk.utils.builder.SdkBuilder; /** * Represents a request that has been signed by {@link HttpSigner}. * - * @param The type of payload of this request. + * @param The type of payload of the request. */ @SdkPublicApi @Immutable @ThreadSafe public interface SignedHttpRequest { - /** - * Get a new builder for creating a {@link SignedHttpRequest}. - */ - static Builder builder(Class payloadType) { - return new DefaultSignedHttpRequest.BuilderImpl(payloadType); - } - - /** - * Returns the type of the payload. - */ - Class payloadType(); - /** * Returns the HTTP request object, without the request body payload. */ @@ -58,16 +44,16 @@ static Builder builder(Class payloadType) { /** * A builder for a {@link SignedHttpRequest}. */ - interface Builder extends SdkBuilder, SignedHttpRequest> { + interface Builder, PayloadT> { /** * Set the HTTP request object, without the request body payload. */ - Builder request(SdkHttpRequest request); + B request(SdkHttpRequest request); /** * Set the body payload of the request. A payload is optional. By default, the payload will be empty. */ - Builder payload(PayloadT payload); + B payload(PayloadT payload); } } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignerProperty.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignerProperty.java index 7a424a71bdb8..299421a829e1 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignerProperty.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SignerProperty.java @@ -24,7 +24,7 @@ /** * A strongly-typed property for input to an {@link HttpSigner}. - * @param The type of the attribute. + * @param The type of the property. */ @SdkPublicApi @Immutable diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SyncHttpSignRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SyncHttpSignRequest.java new file mode 100644 index 000000000000..f220a5a7e89d --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SyncHttpSignRequest.java @@ -0,0 +1,49 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi; + +import software.amazon.awssdk.annotations.Immutable; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.auth.spi.internal.DefaultSyncHttpSignRequest; +import software.amazon.awssdk.identity.spi.Identity; +import software.amazon.awssdk.utils.builder.SdkBuilder; + +/** + * Input parameters to sign a request with sync payload, using {@link HttpSigner}. + * + * @param The type of the identity. + */ +@SdkPublicApi +@Immutable +@ThreadSafe +public interface SyncHttpSignRequest extends HttpSignRequest { + /** + * Get a new builder for creating a {@link SyncHttpSignRequest}. + */ + static Builder builder(IdentityT identity) { + return new DefaultSyncHttpSignRequest.BuilderImpl<>(identity); + } + + /** + * A builder for a {@link SyncHttpSignRequest}. + */ + interface Builder + extends HttpSignRequest.Builder, ContentStreamProvider, IdentityT>, + SdkBuilder, SyncHttpSignRequest> { + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SyncSignedHttpRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SyncSignedHttpRequest.java new file mode 100644 index 000000000000..b0cedff2429e --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/SyncSignedHttpRequest.java @@ -0,0 +1,46 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi; + +import software.amazon.awssdk.annotations.Immutable; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.auth.spi.internal.DefaultSyncSignedHttpRequest; +import software.amazon.awssdk.utils.builder.SdkBuilder; + +/** + * Represents a request with sync payload that has been signed by {@link HttpSigner}. + */ +@SdkPublicApi +@Immutable +@ThreadSafe +public interface SyncSignedHttpRequest extends SignedHttpRequest { + + /** + * Get a new builder for creating a {@link SyncSignedHttpRequest}. + */ + static Builder builder() { + return new DefaultSyncSignedHttpRequest.BuilderImpl(); + } + + /** + * A builder for a {@link SyncSignedHttpRequest}. + */ + interface Builder extends SignedHttpRequest.Builder, + SdkBuilder { + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultAsyncHttpSignRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultAsyncHttpSignRequest.java new file mode 100644 index 000000000000..8edbcadbac4b --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultAsyncHttpSignRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi.internal; + +import java.nio.ByteBuffer; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.auth.spi.AsyncHttpSignRequest; +import software.amazon.awssdk.identity.spi.Identity; +import software.amazon.awssdk.utils.ToString; + +@SdkInternalApi +public final class DefaultAsyncHttpSignRequest + extends DefaultHttpSignRequest, IdentityT> implements AsyncHttpSignRequest { + + private DefaultAsyncHttpSignRequest(BuilderImpl builder) { + super(builder); + } + + @Override + public String toString() { + return ToString.builder("AsyncHttpSignRequest") + .add("request", request) + .add("identity", identity) + .add("properties", properties) + .build(); + } + + @SdkInternalApi + public static final class BuilderImpl + extends DefaultHttpSignRequest.BuilderImpl, Publisher, IdentityT> + implements AsyncHttpSignRequest.Builder { + + // Used to enable consumer builder pattern in HttpSigner.signAsync() + public BuilderImpl() { + } + + // Used by AsyncHttpSignRequest#builder() where identity is passed as parameter, to avoid having to pass Class. + public BuilderImpl(IdentityT identity) { + super(identity); + } + + @Override + public AsyncHttpSignRequest build() { + return new DefaultAsyncHttpSignRequest<>(this); + } + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultAsyncSignedHttpRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultAsyncSignedHttpRequest.java new file mode 100644 index 000000000000..bcec4ff9066d --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultAsyncSignedHttpRequest.java @@ -0,0 +1,49 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi.internal; + +import java.nio.ByteBuffer; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.auth.spi.AsyncSignedHttpRequest; +import software.amazon.awssdk.utils.ToString; + +@SdkInternalApi +public final class DefaultAsyncSignedHttpRequest + extends DefaultSignedHttpRequest> implements AsyncSignedHttpRequest { + + private DefaultAsyncSignedHttpRequest(BuilderImpl builder) { + super(builder); + } + + @Override + public String toString() { + return ToString.builder("AsyncSignedHttpRequest") + .add("request", request) + .build(); + } + + @SdkInternalApi + public static final class BuilderImpl + extends DefaultSignedHttpRequest.BuilderImpl> + implements AsyncSignedHttpRequest.Builder { + + @Override + public AsyncSignedHttpRequest build() { + return new DefaultAsyncSignedHttpRequest(this); + } + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpAuthOption.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpAuthOption.java index 36acc96df21a..3d375f6a642c 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpAuthOption.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpAuthOption.java @@ -83,7 +83,7 @@ public static final class BuilderImpl implements Builder { private final Map, Object> signerProperties = new HashMap<>(); @Override - public Builder schemeId(String schemeId) { + public Builder schemeId(String schemeId) { this.schemeId = schemeId; return this; } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpSignRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpSignRequest.java index 544620400482..fd7f18676f71 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpSignRequest.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultHttpSignRequest.java @@ -15,6 +15,7 @@ package software.amazon.awssdk.http.auth.spi.internal; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -22,27 +23,22 @@ import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.auth.spi.HttpSignRequest; import software.amazon.awssdk.http.auth.spi.SignerProperty; -import software.amazon.awssdk.utils.ToString; +import software.amazon.awssdk.identity.spi.Identity; import software.amazon.awssdk.utils.Validate; @SdkInternalApi -public final class DefaultHttpSignRequest implements HttpSignRequest { +abstract class DefaultHttpSignRequest implements HttpSignRequest { - private final Class payloadType; - private final SdkHttpRequest request; - private final PayloadT payload; - private final Map, Object> properties; + protected final SdkHttpRequest request; + protected final PayloadT payload; + protected final IdentityT identity; + protected final Map, Object> properties; - DefaultHttpSignRequest(BuilderImpl builder) { - this.payloadType = Validate.paramNotNull(builder.payloadType, "payloadType"); + protected DefaultHttpSignRequest(BuilderImpl builder) { this.request = Validate.paramNotNull(builder.request, "request"); this.payload = builder.payload; - this.properties = new HashMap<>(builder.properties); - } - - @Override - public Class payloadType() { - return payloadType; + this.identity = Validate.paramNotNull(builder.identity, "identity"); + this.properties = Collections.unmodifiableMap(builder.properties); } @Override @@ -51,56 +47,61 @@ public SdkHttpRequest request() { } @Override - public Optional payload() { + public Optional payload() { return payload == null ? Optional.empty() : Optional.of(payload); } @Override - public T property(SignerProperty property) { - return (T) properties.get(property); + public IdentityT identity() { + return identity; } @Override - public String toString() { - return ToString.builder("HttpSignRequest") - .add("payloadType", payloadType) - .add("request", request) - .add("properties", properties) - .build(); + public T property(SignerProperty property) { + return (T) properties.get(property); } - - public static final class BuilderImpl implements Builder { - private final Class payloadType; + @SdkInternalApi + protected abstract static class BuilderImpl, PayloadT, + IdentityT extends Identity> implements Builder { private SdkHttpRequest request; private PayloadT payload; + private IdentityT identity; private final Map, Object> properties = new HashMap<>(); - public BuilderImpl(Class payloadType) { - this.payloadType = payloadType; + protected BuilderImpl() { + } + + protected BuilderImpl(IdentityT identity) { + this.identity = identity; } @Override - public Builder request(SdkHttpRequest request) { + public B request(SdkHttpRequest request) { this.request = request; - return this; + return thisBuilder(); } @Override - public Builder payload(PayloadT payload) { + public B payload(PayloadT payload) { this.payload = payload; - return this; + return thisBuilder(); } @Override - public Builder putProperty(SignerProperty key, T value) { - this.properties.put(key, value); - return this; + public B identity(IdentityT identity) { + this.identity = identity; + return thisBuilder(); } @Override - public HttpSignRequest build() { - return new DefaultHttpSignRequest(this); + public B putProperty(SignerProperty key, T value) { + this.properties.put(key, value); + return thisBuilder(); + } + + private B thisBuilder() { + return (B) this; } } } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSignedHttpRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSignedHttpRequest.java index 3e2b70ecd764..0465ec4a5d8c 100644 --- a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSignedHttpRequest.java +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSignedHttpRequest.java @@ -19,69 +19,50 @@ import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.auth.spi.SignedHttpRequest; -import software.amazon.awssdk.utils.ToString; import software.amazon.awssdk.utils.Validate; @SdkInternalApi -public final class DefaultSignedHttpRequest implements SignedHttpRequest { +abstract class DefaultSignedHttpRequest implements SignedHttpRequest { - private final Class payloadType; - private final SdkHttpRequest request; - private final PayloadT payload; + protected final SdkHttpRequest request; + protected final PayloadT payload; - DefaultSignedHttpRequest(BuilderImpl builder) { - this.payloadType = Validate.paramNotNull(builder.payloadType, "payloadType"); + protected DefaultSignedHttpRequest(BuilderImpl builder) { this.request = Validate.paramNotNull(builder.request, "request"); this.payload = builder.payload; } - @Override - public Class payloadType() { - return payloadType; - } - @Override public SdkHttpRequest request() { return request; } @Override - public Optional payload() { + public Optional payload() { return payload == null ? Optional.empty() : Optional.of(payload); } - @Override - public String toString() { - return ToString.builder("SignedHttpRequest") - .add("payloadType", payloadType) - .add("request", request) - .build(); - } - - public static final class BuilderImpl implements Builder { - private final Class payloadType; + protected abstract static class BuilderImpl, PayloadT> implements Builder { private SdkHttpRequest request; private PayloadT payload; - public BuilderImpl(Class payloadType) { - this.payloadType = payloadType; + protected BuilderImpl() { } @Override - public Builder request(SdkHttpRequest request) { + public B request(SdkHttpRequest request) { this.request = request; - return this; + return thisBuilder(); } @Override - public Builder payload(PayloadT payload) { + public B payload(PayloadT payload) { this.payload = payload; - return this; + return thisBuilder(); } - @Override - public SignedHttpRequest build() { - return new DefaultSignedHttpRequest(this); + private B thisBuilder() { + return (B) this; } } } diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSyncHttpSignRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSyncHttpSignRequest.java new file mode 100644 index 000000000000..3d6a952e93e5 --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSyncHttpSignRequest.java @@ -0,0 +1,60 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi.internal; + +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.auth.spi.SyncHttpSignRequest; +import software.amazon.awssdk.identity.spi.Identity; +import software.amazon.awssdk.utils.ToString; + +@SdkInternalApi +public final class DefaultSyncHttpSignRequest + extends DefaultHttpSignRequest implements SyncHttpSignRequest { + + private DefaultSyncHttpSignRequest(BuilderImpl builder) { + super(builder); + } + + @Override + public String toString() { + return ToString.builder("SyncHttpSignRequest") + .add("request", request) + .add("identity", identity) + .add("properties", properties) + .build(); + } + + @SdkInternalApi + public static final class BuilderImpl + extends DefaultHttpSignRequest.BuilderImpl, ContentStreamProvider, IdentityT> + implements SyncHttpSignRequest.Builder { + + // Used to enable consumer builder pattern in HttpSigner.sign() + public BuilderImpl() { + } + + // Used by SyncHttpSignRequest#builder() where identity is passed as parameter, to avoid having to pass Class. + public BuilderImpl(IdentityT identity) { + super(identity); + } + + @Override + public SyncHttpSignRequest build() { + return new DefaultSyncHttpSignRequest<>(this); + } + } +} diff --git a/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSyncSignedHttpRequest.java b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSyncSignedHttpRequest.java new file mode 100644 index 000000000000..f08a562ea7a3 --- /dev/null +++ b/core/http-auth-spi/src/main/java/software/amazon/awssdk/http/auth/spi/internal/DefaultSyncSignedHttpRequest.java @@ -0,0 +1,48 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi.internal; + +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.ContentStreamProvider; +import software.amazon.awssdk.http.auth.spi.SyncSignedHttpRequest; +import software.amazon.awssdk.utils.ToString; + +@SdkInternalApi +public final class DefaultSyncSignedHttpRequest + extends DefaultSignedHttpRequest implements SyncSignedHttpRequest { + + private DefaultSyncSignedHttpRequest(BuilderImpl builder) { + super(builder); + } + + @Override + public String toString() { + return ToString.builder("SyncSignedHttpRequest") + .add("request", request) + .build(); + } + + @SdkInternalApi + public static final class BuilderImpl + extends DefaultSignedHttpRequest.BuilderImpl + implements SyncSignedHttpRequest.Builder { + + @Override + public SyncSignedHttpRequest build() { + return new DefaultSyncSignedHttpRequest(this); + } + } +} diff --git a/core/http-auth-spi/src/test/java/software/amazon/awssdk/http/auth/spi/HttpSignerTest.java b/core/http-auth-spi/src/test/java/software/amazon/awssdk/http/auth/spi/HttpSignerTest.java new file mode 100644 index 000000000000..1df17a72f011 --- /dev/null +++ b/core/http-auth-spi/src/test/java/software/amazon/awssdk/http/auth/spi/HttpSignerTest.java @@ -0,0 +1,111 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.auth.spi; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; + +import java.nio.ByteBuffer; +import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.identity.spi.TokenIdentity; + +public class HttpSignerTest { + + private static final SignerProperty KEY = SignerProperty.create(String.class, "key"); + private static final String VALUE = "value"; + private static final TokenIdentity IDENTITY = TokenIdentity.create("token"); + + final HttpSigner signer = new TestSigner(); + + @Test + public void sign_usingConsumerBuilder_works() { + SyncSignedHttpRequest signedRequest = signer.sign(r -> r.request(mock(SdkHttpRequest.class)) + .identity(IDENTITY) + .putProperty(KEY, VALUE)); + assertNotNull(signedRequest); + } + + @Test + public void sign_usingRequest_works() { + SyncSignedHttpRequest signedRequest = + signer.sign(SyncHttpSignRequest.builder(IDENTITY) + .request(mock(SdkHttpRequest.class)) + .identity(IDENTITY) // Note, this is doable + .putProperty(KEY, VALUE) + .build()); + assertNotNull(signedRequest); + } + + @Test + public void signAsync_usingConsumerBuilder_works() { + Publisher payload = subscriber -> {}; + AsyncSignedHttpRequest signedRequest = signer.signAsync(r -> r.request(mock(SdkHttpRequest.class)) + .payload(payload) + .identity(IDENTITY) + .putProperty(KEY, VALUE)); + assertNotNull(signedRequest); + } + + @Test + public void signAsync_usingRequest_works() { + Publisher payload = subscriber -> {}; + AsyncSignedHttpRequest signedRequest = + signer.signAsync(AsyncHttpSignRequest.builder(IDENTITY) + .request(mock(SdkHttpRequest.class)) + .payload(payload) + .identity(IDENTITY) // Note, this is doable + .putProperty(KEY, VALUE) + .build()); + assertNotNull(signedRequest); + } + + /** + * NoOp Signer that asserts that the input created via builder or Consumer builder pattern are set up correctly. + * This is similar to what a bearerTokenSigner would look like - which would insert the identity in a Header. + + */ + private static class TestSigner implements HttpSigner { + @Override + public SyncSignedHttpRequest sign(SyncHttpSignRequest request) { + assertEquals(VALUE, request.property(KEY)); + assertEquals(IDENTITY, request.identity()); + + return SyncSignedHttpRequest.builder() + .request(addTokenHeader(request)) + .payload(request.payload().orElse(null)) + .build(); + } + + @Override + public AsyncSignedHttpRequest signAsync(AsyncHttpSignRequest request) { + assertEquals(VALUE, request.property(KEY)); + assertEquals(IDENTITY, request.identity()); + + return AsyncSignedHttpRequest.builder() + .request(addTokenHeader(request)) + .payload(request.payload().orElse(null)) + .build(); + } + + private SdkHttpRequest addTokenHeader(HttpSignRequest input) { + // return input.request().copy(b -> b.putHeader("Token-Header", input.identity().token())); + return input.request(); + } + } +}