21 | * Authentication: ALGORITHM Credential=CREDENTIAL, SignedHeaders=SIGNED_HEADERS, Signature=SIGNATURE 22 | *23 | * 24 | * Where: 25 | * ALGORITHM := The signing algorithm used for the credential, ex. DTAv1-SHA-256 26 | * CREDENTIAL := KEYID/DATE. 27 | * SIGNED_HEADERS := lower cased header names sorted by byte order joined with semicolons. 28 | * SIGNATURE := The signature calculated by the signing algorithm. 29 | * KEYID := The public id for the sceret key used to calculate the signature. 30 | * DATE := The date the message was signed in YYMMDD format. This is used to generate the daily key. 31 | */ 32 | public class AuthenticationHeader { 33 | private String algorithm; 34 | private String credential; 35 | private String signedHeaders; 36 | private String signature; 37 | 38 | public void setAlgorithm(String algorithm) { 39 | this.algorithm = algorithm; 40 | } 41 | 42 | public void setCredential(String credential) { 43 | this.credential = credential; 44 | } 45 | 46 | public void setSignedHeaders(String signedHeaders) { 47 | this.signedHeaders = signedHeaders; 48 | } 49 | 50 | public void setSignature(String signature) { 51 | this.signature = signature; 52 | } 53 | 54 | public String getAlgorithm() { 55 | return algorithm; 56 | } 57 | 58 | public String getCredential() { 59 | return credential; 60 | } 61 | 62 | public String getSignedHeaders() { 63 | return signedHeaders; 64 | } 65 | 66 | public String getSignature() { 67 | return signature; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/signature/AuthenticationHeaderParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.signature; 16 | 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | /** 21 | * Parses an AuthenticationHeader from a header value string. 22 | * 23 | * Pattern: ALGORITHM SignedHeaders=x;y;z, Credential=XXX, Signature=BIGSHA 24 | * Example: DTA1-HMAC-SHA256 SignedHeaders=aaa;content-type;x-amz-date;zzz, Credential=KEYID/20110909, 25 | * Signature=87729cb3475859a18b5d9cead0bba82f0f56a85c2a13bed3bc229c6c35e06628 26 | */ 27 | public class AuthenticationHeaderParser { 28 | private static final Pattern pattern = Pattern 29 | .compile("(\\S+) SignedHeaders=(\\S+), Credential=(\\S+), Signature=([\\S&&[^,]]+)"); 30 | 31 | public AuthenticationHeader parse(String headerString) { 32 | Matcher match = pattern.matcher(headerString); 33 | AuthenticationHeader header = new AuthenticationHeader(); 34 | 35 | if (!match.find()) { 36 | return null; 37 | } 38 | 39 | header.setAlgorithm(match.group(1)); 40 | header.setSignedHeaders(match.group(2)); 41 | header.setCredential(match.group(3)); 42 | header.setSignature(match.group(4)); 43 | 44 | return header; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/signature/Credential.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.signature; 16 | 17 | /** 18 | * Bean class representing a signing credential 19 | */ 20 | public class Credential { 21 | private String secretKey; 22 | private String publicKey; 23 | 24 | public Credential(String secretkey, String publicKey) { 25 | this.secretKey = secretkey; 26 | this.publicKey = publicKey; 27 | } 28 | 29 | public String getSecretKey() { 30 | return secretKey; 31 | } 32 | 33 | public String getPublicKey() { 34 | return publicKey; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/signature/CredentialNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.signature; 16 | 17 | public class CredentialNotFoundException extends Exception { 18 | public CredentialNotFoundException(String message) { 19 | super(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/signature/CredentialStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.signature; 16 | 17 | import java.io.File; 18 | import java.io.FileInputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.io.StringWriter; 22 | import java.nio.charset.Charset; 23 | import java.util.Collection; 24 | import java.util.HashMap; 25 | 26 | import org.apache.commons.io.IOUtils; 27 | import org.apache.commons.lang.StringUtils; 28 | import org.apache.commons.logging.Log; 29 | import org.apache.commons.logging.LogFactory; 30 | 31 | /** 32 | * Class that is used to manage multiple credentials. 33 | * 34 | * The {@link CredentialStore#load()} method can be called to load keys from a {@link File}, a {@link InputStream} or a 35 | * {@link String}. 36 | * 37 | * Each line of the file/stream/string must contain a secret key and a public key separated by an empty space, for 38 | * example: 39 | * 40 | * 69b2048d-8bf8-4c1c-b49d-e6114897a9a5 dce53190-1f70-4206-ad28-0e1ab3683161 41 | * 42 | * Credentials, then, can be accessed by the public key using {@link CredentialStore#get(String)} 43 | * 44 | */ 45 | public class CredentialStore { 46 | private static final Log log = LogFactory.getLog(CredentialStore.class); 47 | 48 | private HashMap
121 | * This method will encode the given path but not the given baseUri. 122 | *
123 | * 124 | * @param baseUri 125 | * The URI to append to (required, may be relative) 126 | * @param path 127 | * The path to append (may be null or empty) 128 | * @param escapeDoubleSlash 129 | * Whether double-slash in the path should be escaped to "/%2F" 130 | * @return The baseUri with the (encoded) path appended 131 | */ 132 | public static String appendUri(String baseUri, String path, boolean escapeDoubleSlash) { 133 | String resultUri = baseUri; 134 | if (path != null && path.length() > 0) { 135 | if (path.startsWith("/")) { 136 | // trim the trailing slash in baseUri, since the path already starts with a slash 137 | if (resultUri.endsWith("/")) { 138 | resultUri = resultUri.substring(0, resultUri.length() - 1); 139 | } 140 | } else if (!resultUri.endsWith("/")) { 141 | resultUri += "/"; 142 | } 143 | String encodedPath = HttpUtils.urlEncode(path, true); 144 | if (escapeDoubleSlash) { 145 | encodedPath = encodedPath.replace("//", "/%2F"); 146 | } 147 | resultUri += encodedPath; 148 | } else if (!resultUri.endsWith("/")) { 149 | resultUri += "/"; 150 | } 151 | 152 | return resultUri; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v2/serialization/messages/FulfillPurchaseRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v2.serialization.messages; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 18 | import com.amazon.dtasdk.base.InstantAccessRequest; 19 | import org.apache.commons.lang.builder.ToStringBuilder; 20 | import org.apache.commons.lang.builder.ToStringStyle; 21 | 22 | /** 23 | * Serializable FulfillPurchaseRequest object to pass to developer used to fulfill a purchase 24 | */ 25 | 26 | public class FulfillPurchaseRequest extends InstantAccessRequest { 27 | private String purchaseToken; 28 | private String userId; 29 | private String productId; 30 | private String reason; 31 | 32 | @Override 33 | public FulfillPurchaseRequest setOperation(InstantAccessOperationValue operation) { 34 | this.operation = operation; 35 | return this; 36 | } 37 | 38 | public String getPurchaseToken() { 39 | return purchaseToken; 40 | } 41 | 42 | public FulfillPurchaseRequest setPurchaseToken(String purchaseToken) { 43 | this.purchaseToken = purchaseToken; 44 | return this; 45 | } 46 | 47 | public String getUserId() { 48 | return userId; 49 | } 50 | 51 | public FulfillPurchaseRequest setUserId(String userId) { 52 | this.userId = userId; 53 | return this; 54 | } 55 | 56 | public String getProductId() { 57 | return productId; 58 | } 59 | 60 | public FulfillPurchaseRequest setProductId(String productId) { 61 | this.productId = productId; 62 | return this; 63 | } 64 | 65 | public String getReason() { 66 | return reason; 67 | } 68 | 69 | public FulfillPurchaseRequest setReason(String reason) { 70 | this.reason = reason; 71 | return this; 72 | } 73 | 74 | @Override 75 | public int hashCode() { 76 | final int prime = 31; 77 | int result = 1; 78 | result = prime * result + ((purchaseToken == null) ? 0 : purchaseToken.hashCode()); 79 | result = prime * result + ((operation == null) ? 0 : operation.hashCode()); 80 | result = prime * result + ((userId == null) ? 0 : userId.hashCode()); 81 | result = prime * result + ((productId == null) ? 0 : productId.hashCode()); 82 | result = prime * result + ((reason == null) ? 0 : reason.hashCode()); 83 | return result; 84 | } 85 | 86 | @Override 87 | public boolean equals(Object obj) { 88 | if (this == obj) { 89 | return true; 90 | } 91 | if (obj == null) { 92 | return false; 93 | } 94 | if (getClass() != obj.getClass()) { 95 | return false; 96 | } 97 | final FulfillPurchaseRequest other = (FulfillPurchaseRequest) obj; 98 | if (purchaseToken == null) { 99 | if (other.purchaseToken != null) { 100 | return false; 101 | } 102 | } else if (!purchaseToken.equals(other.purchaseToken)) { 103 | return false; 104 | } 105 | 106 | if (operation == null) { 107 | if (other.operation != null) { 108 | return false; 109 | } 110 | } else if (!operation.equals(other.operation)) { 111 | return false; 112 | } 113 | 114 | if (userId == null) { 115 | if (other.userId != null) { 116 | return false; 117 | } 118 | } else if (!userId.equals(other.userId)) { 119 | return false; 120 | } 121 | 122 | if (productId == null) { 123 | if (other.productId != null) { 124 | return false; 125 | } 126 | } else if (!productId.equals(other.productId)) { 127 | return false; 128 | } 129 | 130 | if (reason == null) { 131 | if (other.reason != null) { 132 | return false; 133 | } 134 | } else if (!reason.equals(other.reason)) { 135 | return false; 136 | } 137 | return true; 138 | } 139 | 140 | @Override 141 | public String toString() { 142 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("operation", operation) 143 | .append("reason", reason).append("productId", productId).append("userId", userId) 144 | .append("purchaseToken", purchaseToken).toString(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v2/serialization/messages/FulfillPurchaseResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v2.serialization.messages; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessResponse; 18 | 19 | /** 20 | * Serilizable response from vendor used to fulfill a purchase 21 | */ 22 | 23 | public class FulfillPurchaseResponse extends InstantAccessResponse25 | * This abstract servlet can be extended to implement the V2 Account Linking section of Instant Access API. 26 | *
27 | * 28 | *29 | * When extending this servlet, you must implement the abstract method {@link #getUserId(GetUserIdSerializableRequest)}, 30 | * it is the method for returning a user id based on the parameters in order to link accounts. 31 | *
32 | * 33 | *34 | * You must also implement the abstract method {@link #getCredentialStore()}. This method must provide a valid credential 35 | * store that will be used to verify the message authenticity. 36 | *
37 | * 38 | */ 39 | public abstract class AccountLinkingServlet extends InstantAccessServlet { 40 | 41 | /** 42 | * Process the request and returns the user id 43 | * 44 | * @param request 45 | * the request relative to the get user id operation 46 | * 47 | * @return a GetUserIdSerializableResponse object 48 | */ 49 | public abstract GetUserIdSerializableResponse getUserId(GetUserIdSerializableRequest request); 50 | 51 | @Override 52 | public InstantAccessResponse> processOperation(InstantAccessOperationValue operation, String requestBody) 53 | throws SerializationException { 54 | 55 | GetUserIdSerializableResponse iaResponse; 56 | 57 | // process the request according to the operation 58 | switch (operation) { 59 | case GETUSERID: 60 | iaResponse = getUserId(serializer.decode(requestBody, GetUserIdSerializableRequest.class)); 61 | break; 62 | default: 63 | throw new IllegalArgumentException(String.format("Operation[%s] not supported by %s", operation.name(), 64 | this.getClass().getName())); 65 | } 66 | 67 | return iaResponse; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v2/servlets/InstantAccessServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v2.servlets; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessRequest; 18 | import com.amazon.dtasdk.serializer.JacksonSerializer; 19 | import com.amazon.dtasdk.serializer.SerializationException; 20 | import com.amazon.dtasdk.signature.CredentialStore; 21 | import com.amazon.dtasdk.signature.Request; 22 | import com.amazon.dtasdk.signature.Signer; 23 | import com.amazon.dtasdk.signature.SigningException; 24 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 25 | import com.amazon.dtasdk.base.InstantAccessResponse; 26 | import org.apache.commons.logging.Log; 27 | import org.apache.commons.logging.LogFactory; 28 | 29 | import javax.servlet.http.HttpServlet; 30 | import javax.servlet.http.HttpServletRequest; 31 | import javax.servlet.http.HttpServletResponse; 32 | import java.io.IOException; 33 | import java.nio.charset.Charset; 34 | 35 | /** 36 | *37 | * This abstract servlet is extended by the {@link PurchaseServlet} and {@link AccountLinkingServlet} in order to 38 | * implement the Instant Access API. This class should not be used, use the aforementioned classes instead. 39 | *
40 | * 41 | */ 42 | public abstract class InstantAccessServlet extends HttpServlet { 43 | private static final Log log = LogFactory.getLog(InstantAccessServlet.class); 44 | private static final Charset CHARSET = Charset.forName("UTF-8"); 45 | 46 | private final Signer signer = new Signer(); 47 | 48 | protected final JacksonSerializer serializer = new JacksonSerializer(); 49 | 50 | /** 51 | * Returns the credential store 52 | * 53 | * @return a CredentialStore object with all the credentials 54 | */ 55 | public abstract CredentialStore getCredentialStore(); 56 | 57 | /** 58 | * Processes the request based on the operation 59 | * 60 | * @param operation 61 | * The operation being called 62 | * @param requestBody 63 | * The content of the message 64 | * @return a generic InstantAccessResponse> containing the result of the operation 65 | * 66 | * @throws SerializationException 67 | * @throws IllegalArgumentException 68 | */ 69 | public abstract InstantAccessResponse> processOperation(InstantAccessOperationValue operation, String requestBody) 70 | throws SerializationException; 71 | 72 | @Override 73 | public void doPost(HttpServletRequest request, HttpServletResponse response) { 74 | try { 75 | Request req = new Request(request); 76 | 77 | if (!signer.verify(req, getCredentialStore())) { 78 | throw new SigningException("Request validation failed."); 79 | } 80 | 81 | String requestBody = req.getBody(); 82 | 83 | // deserialize the content to a InstantAccessRequest object so we can check which operation is going 84 | // to be called 85 | InstantAccessRequest iaRequest = serializer.decode(requestBody, InstantAccessRequest.class); 86 | 87 | // process the request according to the operation 88 | InstantAccessResponse> iaResponse = processOperation(iaRequest.getOperation(), requestBody); 89 | 90 | response.setStatus(HttpServletResponse.SC_OK); 91 | response.getOutputStream().write(serializer.encode(iaResponse).getBytes(CHARSET)); 92 | } catch (IOException e) { 93 | log.error("Unable to read the request.", e); 94 | response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 95 | } catch (SigningException e) { 96 | log.error("Unable to verify the request against the credential store.", e); 97 | response.setStatus(HttpServletResponse.SC_FORBIDDEN); 98 | } catch (SerializationException e) { 99 | log.error("Serialization error.", e); 100 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); 101 | } catch (Exception e) { 102 | log.error("Unable to process the request.", e); 103 | response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v2/servlets/PurchaseServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v2.servlets; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 18 | import com.amazon.dtasdk.base.InstantAccessResponse; 19 | import com.amazon.dtasdk.base.SubscriptionResponse; 20 | import com.amazon.dtasdk.v2.serialization.messages.FulfillPurchaseRequest; 21 | import com.amazon.dtasdk.v2.serialization.messages.FulfillPurchaseResponse; 22 | import com.amazon.dtasdk.v2.serialization.messages.RevokePurchaseRequest; 23 | import com.amazon.dtasdk.v2.serialization.messages.RevokePurchaseResponse; 24 | import com.amazon.dtasdk.v2.serialization.messages.SubscriptionActivateRequest; 25 | import com.amazon.dtasdk.v2.serialization.messages.SubscriptionDeactivateRequest; 26 | import com.amazon.dtasdk.serializer.SerializationException; 27 | 28 | /** 29 | *30 | * This abstract servlet can be extended to implement the V2 Purchase/Subscription section of Instant Access API. 31 | *
32 | * 33 | *34 | * When extending this servlet, you must implement the abstract methods relative to the four operations present in the 35 | * API. {@link #fulfillPurchase(FulfillPurchaseRequest)} is the method responsible for fulfilling a purchase, {@link 36 | * #revokePurchase(RevokePurchaseRequest)} is the method responsible for revoking a purchase, {@link 37 | * #processSubscriptionActivate(SubscriptionActivateRequest)} is the method responsible for activating a subscription and 38 | * {@link #processSubscriptionDeactivate(SubscriptionDeactivateRequest)} is the method responsible for deactivating a 39 | * subscription 40 | *
41 | * 42 | *43 | * You must also implement the abstract method {@link #getCredentialStore()}. This method must provide a valid credential 44 | * store that will be used to verify the message authenticity. 45 | *
46 | * 47 | */ 48 | public abstract class PurchaseServlet extends InstantAccessServlet { 49 | 50 | /** 51 | * Process the fulfill purchase request and return the response to whether or not the request succeeded. 52 | * 53 | * @param request 54 | * the request relative to the fulfill purchase 55 | * 56 | * @return a FulfillPurchaseResponse object 57 | */ 58 | public abstract FulfillPurchaseResponse fulfillPurchase(FulfillPurchaseRequest request); 59 | 60 | /** 61 | * Process the revoke purchase request and return the response to whether or not the request succeeded. 62 | * 63 | * @param request 64 | * the request relative to the revoke purchase 65 | * 66 | * @return a RevokePurchaseResponse object 67 | */ 68 | public abstract RevokePurchaseResponse revokePurchase(RevokePurchaseRequest request); 69 | 70 | /** 71 | * Process a subscription activation based on the request and returns the response to whether or not the request 72 | * succeeded. 73 | * 74 | * @param request 75 | * the request object with information about the subscription 76 | * 77 | * @return a SubscriptionResponse object 78 | */ 79 | public abstract SubscriptionResponse processSubscriptionActivate(SubscriptionActivateRequest request); 80 | 81 | /** 82 | * Process a subscription deactivation based on the request and returns the response to whether or not the request 83 | * succeeded. 84 | * 85 | * @param request 86 | * the request object with information about the subscription 87 | * 88 | * @return a SubscriptionResponse object 89 | */ 90 | public abstract SubscriptionResponse processSubscriptionDeactivate(SubscriptionDeactivateRequest request); 91 | 92 | @Override 93 | public InstantAccessResponse> processOperation(InstantAccessOperationValue operation, String requestBody) 94 | throws SerializationException { 95 | 96 | InstantAccessResponse> iaResponse; 97 | 98 | // process the request according to the operation 99 | switch (operation) { 100 | case PURCHASE: 101 | iaResponse = fulfillPurchase(serializer.decode(requestBody, FulfillPurchaseRequest.class)); 102 | break; 103 | case REVOKE: 104 | iaResponse = revokePurchase(serializer.decode(requestBody, RevokePurchaseRequest.class)); 105 | break; 106 | case SUBSCRIPTIONACTIVATE: 107 | iaResponse = processSubscriptionActivate(serializer.decode(requestBody, 108 | SubscriptionActivateRequest.class)); 109 | break; 110 | case SUBSCRIPTIONDEACTIVATE: 111 | iaResponse = processSubscriptionDeactivate(serializer.decode(requestBody, 112 | SubscriptionDeactivateRequest.class)); 113 | break; 114 | default: 115 | throw new IllegalArgumentException(String.format("Operation[%s] not supported by %s", operation.name(), 116 | this.getClass().getName())); 117 | } 118 | 119 | return iaResponse; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/FulfillPurchaseRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | /** 18 | * Serializable FulfillPurchaseRequest object to pass to developer used to fulfill a purchase 19 | */ 20 | public class FulfillPurchaseRequest extends com.amazon.dtasdk.v2.serialization.messages.FulfillPurchaseRequest { 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/FulfillPurchaseResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | /** 18 | * Serilizable response from vendor used to fulfill a purchase 19 | */ 20 | public class FulfillPurchaseResponse extends com.amazon.dtasdk.v2.serialization.messages.FulfillPurchaseResponse { 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/GetUserIdSerializableRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | /** 18 | * Serializable GetUserId object to pass to developer 19 | */ 20 | public class GetUserIdSerializableRequest extends com.amazon.dtasdk.v2.serialization.messages.GetUserIdSerializableRequest { 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/GetUserIdSerializableResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | public class GetUserIdSerializableResponse extends com.amazon.dtasdk.v2.serialization.messages.GetUserIdSerializableResponse { 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/RevokePurchaseRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | /** 18 | * Serializable FulfillPurchaseRequest object to pass to developer used to revoke a purchase 19 | */ 20 | public class RevokePurchaseRequest extends com.amazon.dtasdk.v2.serialization.messages.RevokePurchaseRequest { 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/RevokePurchaseResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | /** 18 | * Serilizable response from vendor used to revoke a purchase 19 | */ 20 | public class RevokePurchaseResponse extends com.amazon.dtasdk.v2.serialization.messages.RevokePurchaseResponse { 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionActivateRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 18 | import com.amazon.dtasdk.base.SubscriptionRequest; 19 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 20 | import org.apache.commons.lang.builder.ToStringBuilder; 21 | import org.apache.commons.lang.builder.ToStringStyle; 22 | 23 | /** 24 | * A request to activate a subscription for a specified user and product 25 | */ 26 | @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) 27 | public class SubscriptionActivateRequest extends SubscriptionRequest { 28 | 29 | private Integer numberOfLicenses; 30 | 31 | @Override 32 | public SubscriptionActivateRequest setOperation(InstantAccessOperationValue operationValue) { 33 | this.operation = operationValue; 34 | return this; 35 | } 36 | 37 | public String getProductId() { 38 | return productId; 39 | } 40 | 41 | @Override 42 | public SubscriptionActivateRequest setSubscriptionId(String subscriptionId) { 43 | this.subscriptionId = subscriptionId; 44 | return this; 45 | } 46 | 47 | public Integer getNumberOfLicenses() { 48 | return numberOfLicenses; 49 | } 50 | 51 | public SubscriptionActivateRequest setNumberOfLicenses(Integer numberOfLicenses) { 52 | this.numberOfLicenses = numberOfLicenses; 53 | return this; 54 | } 55 | 56 | public SubscriptionActivateRequest setProductId(String productId) { 57 | this.productId = productId; 58 | return this; 59 | } 60 | 61 | public String getUserId() { 62 | return userId; 63 | } 64 | 65 | public SubscriptionActivateRequest setUserId(String userId) { 66 | this.userId = userId; 67 | return this; 68 | } 69 | 70 | @Override 71 | public boolean equals(Object o) { 72 | if (this == o) return true; 73 | if (!(o instanceof SubscriptionActivateRequest)) return false; 74 | if (!super.equals(o)) return false; 75 | 76 | final SubscriptionActivateRequest that = (SubscriptionActivateRequest) o; 77 | 78 | if (productId != null ? !productId.equals(that.productId) : that.productId != null) return false; 79 | if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false; 80 | if (numberOfLicenses != null ? !numberOfLicenses.equals(that.numberOfLicenses) : that.numberOfLicenses != null) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | @Override 87 | public int hashCode() { 88 | int result = super.hashCode(); 89 | result = 31 * result + (productId != null ? productId.hashCode() : 0); 90 | result = 31 * result + (userId != null ? userId.hashCode() : 0); 91 | result = 31 * result + (numberOfLicenses != null ? numberOfLicenses.hashCode() : 0); 92 | return result; 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 98 | .append("operation", operation) 99 | .append("subscriptionId", subscriptionId) 100 | .append("productId", productId) 101 | .append("userId", userId) 102 | .append("numberOfLicenses", numberOfLicenses) 103 | .toString(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionActivateResponse.java: -------------------------------------------------------------------------------- 1 | package com.amazon.dtasdk.v3.serialization.messages; 2 | 3 | 4 | import com.amazon.dtasdk.base.SubscriptionResponse; 5 | import org.apache.commons.lang.builder.ToStringBuilder; 6 | import org.apache.commons.lang.builder.ToStringStyle; 7 | 8 | public class SubscriptionActivateResponse extends SubscriptionResponse { 9 | private Integer numberOfUnusedLicenses; 10 | private Integer numberOfUsedLicenses; 11 | private String managementURL; 12 | 13 | public Integer getNumberOfUnusedLicenses() { 14 | return numberOfUnusedLicenses; 15 | } 16 | 17 | public void setNumberOfUnusedLicenses(Integer numberOfUnusedLicenses) { 18 | this.numberOfUnusedLicenses = numberOfUnusedLicenses; 19 | } 20 | 21 | public Integer getNumberOfUsedLicenses() { 22 | return numberOfUsedLicenses; 23 | } 24 | 25 | public void setNumberOfUsedLicenses(Integer numberOfUsedLicenses) { 26 | this.numberOfUsedLicenses = numberOfUsedLicenses; 27 | } 28 | 29 | public String getManagementURL() { 30 | return managementURL; 31 | } 32 | 33 | public void setManagementURL(String managementUrl) { 34 | this.managementURL = managementUrl; 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | final int prime = 31; 40 | int result = 1; 41 | result = prime * result + ((numberOfUnusedLicenses == null) ? 0 : numberOfUnusedLicenses.hashCode()); 42 | result = prime * result + ((numberOfUsedLicenses == null) ? 0 : numberOfUsedLicenses.hashCode()); 43 | result = prime * result + ((managementURL == null) ? 0 : managementURL.hashCode()); 44 | result = prime * result + ((response == null) ? 0 : response.hashCode()); 45 | return result; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | if (this == obj) { 51 | return true; 52 | } 53 | if (obj == null) { 54 | return false; 55 | } 56 | if (getClass() != obj.getClass()) { 57 | return false; 58 | } 59 | final SubscriptionActivateResponse other = (SubscriptionActivateResponse) obj; 60 | if (numberOfUnusedLicenses == null) { 61 | if (other.numberOfUnusedLicenses != null) { 62 | return false; 63 | } 64 | } else if (!numberOfUnusedLicenses.equals(other.numberOfUnusedLicenses)) { 65 | return false; 66 | } 67 | 68 | if (numberOfUsedLicenses == null) { 69 | if (other.numberOfUsedLicenses != null) { 70 | return false; 71 | } 72 | } else if (!numberOfUsedLicenses.equals(other.numberOfUsedLicenses)) { 73 | return false; 74 | } 75 | 76 | if (managementURL == null) { 77 | if (other.managementURL != null) { 78 | return false; 79 | } 80 | } else if (!managementURL.equals(other.managementURL)) { 81 | return false; 82 | } 83 | 84 | if (response == null) { 85 | if (other.response != null) { 86 | return false; 87 | } 88 | } else if (!response.equals(other.response)) { 89 | return false; 90 | } 91 | return true; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 97 | .append("numberOfUnusedLicenses", numberOfUnusedLicenses) 98 | .append("numberOfUsedLicenses", numberOfUsedLicenses) 99 | .append("managementURL", managementURL) 100 | .append("response", response).toString(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionDeactivateRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.serialization.messages; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 18 | import com.amazon.dtasdk.base.SubscriptionPeriodValue; 19 | import com.amazon.dtasdk.base.SubscriptionReasonValue; 20 | import com.amazon.dtasdk.base.SubscriptionRequest; 21 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 22 | import org.apache.commons.lang.builder.ToStringBuilder; 23 | import org.apache.commons.lang.builder.ToStringStyle; 24 | 25 | /** 26 | * A request to deactivate a subscription. 27 | * Includes the reason for deactivation and the period in which it was deactivated. 28 | */ 29 | @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) 30 | public class SubscriptionDeactivateRequest extends SubscriptionRequest { 31 | 32 | protected SubscriptionReasonValue reason; 33 | protected SubscriptionPeriodValue period; 34 | 35 | @Override 36 | public SubscriptionDeactivateRequest setOperation(InstantAccessOperationValue operationValue) { 37 | this.operation = operationValue; 38 | return this; 39 | } 40 | 41 | public SubscriptionReasonValue getReason() { 42 | return reason; 43 | } 44 | 45 | public SubscriptionDeactivateRequest setReason(SubscriptionReasonValue reason) { 46 | this.reason = reason; 47 | return this; 48 | } 49 | 50 | public SubscriptionPeriodValue getPeriod() { 51 | return period; 52 | } 53 | 54 | public SubscriptionDeactivateRequest setPeriod(SubscriptionPeriodValue period) { 55 | this.period = period; 56 | return this; 57 | } 58 | 59 | @Override 60 | public SubscriptionDeactivateRequest setSubscriptionId(String subscriptionId) { 61 | this.subscriptionId = subscriptionId; 62 | return this; 63 | } 64 | 65 | @Override 66 | public boolean equals(Object o) { 67 | if (this == o) return true; 68 | if (o == null || getClass() != o.getClass()) return false; 69 | if (!super.equals(o)) return false; 70 | 71 | final SubscriptionDeactivateRequest that = (SubscriptionDeactivateRequest) o; 72 | 73 | if (period != that.period) return false; 74 | if (reason != that.reason) return false; 75 | 76 | return true; 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | int result = super.hashCode(); 82 | result = 31 * result + (reason != null ? reason.hashCode() : 0); 83 | result = 31 * result + (period != null ? period.hashCode() : 0); 84 | return result; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 90 | .append("operation", operation) 91 | .append("subscriptionId", subscriptionId) 92 | .append("reason", reason) 93 | .append("period", period) 94 | .toString(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionDeactivateResponse.java: -------------------------------------------------------------------------------- 1 | package com.amazon.dtasdk.v3.serialization.messages; 2 | 3 | import com.amazon.dtasdk.base.SubscriptionResponse; 4 | 5 | public class SubscriptionDeactivateResponse extends SubscriptionResponse { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionGetRequest.java: -------------------------------------------------------------------------------- 1 | package com.amazon.dtasdk.v3.serialization.messages; 2 | 3 | import com.amazon.dtasdk.base.SubscriptionRequest; 4 | 5 | public class SubscriptionGetRequest extends SubscriptionRequest { 6 | public SubscriptionGetRequest setProductId(String productId) { 7 | this.productId = productId; 8 | return this; 9 | } 10 | 11 | public SubscriptionGetRequest setUserId(String userId) { 12 | this.userId = userId; 13 | return this; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionGetResponse.java: -------------------------------------------------------------------------------- 1 | package com.amazon.dtasdk.v3.serialization.messages; 2 | 3 | import com.amazon.dtasdk.base.SubscriptionResponse; 4 | import org.apache.commons.lang.builder.ToStringBuilder; 5 | import org.apache.commons.lang.builder.ToStringStyle; 6 | 7 | public class SubscriptionGetResponse extends SubscriptionResponse { 8 | private Integer numberOfUnusedLicenses; 9 | private Integer numberOfUsedLicenses; 10 | private String managementURL; 11 | 12 | public Integer getNumberOfUnusedLicenses() { 13 | return numberOfUnusedLicenses; 14 | } 15 | 16 | public void setNumberOfUnusedLicenses(Integer numberOfUnusedLicenses) { 17 | this.numberOfUnusedLicenses = numberOfUnusedLicenses; 18 | } 19 | 20 | public Integer getNumberOfUsedLicenses() { 21 | return numberOfUsedLicenses; 22 | } 23 | 24 | public void setNumberOfUsedLicenses(Integer numberOfUsedLicenses) { 25 | this.numberOfUsedLicenses = numberOfUsedLicenses; 26 | } 27 | 28 | public String getManagementURL() { 29 | return managementURL; 30 | } 31 | 32 | public void setManagementURL(String managementUrl) { 33 | this.managementURL = managementUrl; 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | final int prime = 31; 39 | int result = 1; 40 | result = prime * result + ((numberOfUnusedLicenses == null) ? 0 : numberOfUnusedLicenses.hashCode()); 41 | result = prime * result + ((numberOfUsedLicenses == null) ? 0 : numberOfUsedLicenses.hashCode()); 42 | result = prime * result + ((managementURL == null) ? 0 : managementURL.hashCode()); 43 | result = prime * result + ((response == null) ? 0 : response.hashCode()); 44 | return result; 45 | } 46 | 47 | @Override 48 | public boolean equals(Object obj) { 49 | if (this == obj) { 50 | return true; 51 | } 52 | if (obj == null) { 53 | return false; 54 | } 55 | if (getClass() != obj.getClass()) { 56 | return false; 57 | } 58 | final SubscriptionGetResponse other = (SubscriptionGetResponse) obj; 59 | if (numberOfUnusedLicenses == null) { 60 | if (other.numberOfUnusedLicenses != null) { 61 | return false; 62 | } 63 | } else if (!numberOfUnusedLicenses.equals(other.numberOfUnusedLicenses)) { 64 | return false; 65 | } 66 | 67 | if (numberOfUsedLicenses == null) { 68 | if (other.numberOfUsedLicenses != null) { 69 | return false; 70 | } 71 | } else if (!numberOfUsedLicenses.equals(other.numberOfUsedLicenses)) { 72 | return false; 73 | } 74 | 75 | if (managementURL == null) { 76 | if (other.managementURL != null) { 77 | return false; 78 | } 79 | } else if (!managementURL.equals(other.managementURL)) { 80 | return false; 81 | } 82 | 83 | if (response == null) { 84 | if (other.response != null) { 85 | return false; 86 | } 87 | } else if (!response.equals(other.response)) { 88 | return false; 89 | } 90 | return true; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 96 | .append("numberOfUnusedLicenses", numberOfUnusedLicenses) 97 | .append("numberOfUsedLicenses", numberOfUsedLicenses) 98 | .append("managementURL", managementURL) 99 | .append("response", response).toString(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.amazon.dtasdk.v3.serialization.messages; 2 | 3 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 4 | import com.amazon.dtasdk.base.SubscriptionRequest; 5 | import org.apache.commons.lang.builder.ToStringBuilder; 6 | import org.apache.commons.lang.builder.ToStringStyle; 7 | 8 | public class SubscriptionUpdateRequest extends SubscriptionRequest { 9 | 10 | private Integer numberOfLicenses; 11 | private Boolean removeAllUnassignedLicenses; 12 | 13 | @Override 14 | public SubscriptionUpdateRequest setOperation(InstantAccessOperationValue operationValue) { 15 | this.operation = operationValue; 16 | return this; 17 | } 18 | 19 | public String getProductId() { 20 | return productId; 21 | } 22 | 23 | @Override 24 | public SubscriptionUpdateRequest setSubscriptionId(String subscriptionId) { 25 | this.subscriptionId = subscriptionId; 26 | return this; 27 | } 28 | 29 | public Integer getNumberOfLicenses() { 30 | return numberOfLicenses; 31 | } 32 | 33 | public SubscriptionUpdateRequest setNumberOfLicenses(Integer numberOfLicenses) { 34 | this.numberOfLicenses = numberOfLicenses; 35 | return this; 36 | } 37 | 38 | public Boolean getRemoveAllUnassignedLicenses() { 39 | return removeAllUnassignedLicenses; 40 | } 41 | 42 | public SubscriptionUpdateRequest setRemoveAllUnassignedLicenses(Boolean removeAllUnassignedLicenses) { 43 | this.removeAllUnassignedLicenses = removeAllUnassignedLicenses; 44 | return this; 45 | } 46 | 47 | public SubscriptionUpdateRequest setProductId(String productId) { 48 | this.productId = productId; 49 | return this; 50 | } 51 | 52 | public String getUserId() { 53 | return userId; 54 | } 55 | 56 | public SubscriptionUpdateRequest setUserId(String userId) { 57 | this.userId = userId; 58 | return this; 59 | } 60 | 61 | @Override 62 | public boolean equals(Object o) { 63 | if (this == o) return true; 64 | if (!(o instanceof SubscriptionUpdateRequest)) return false; 65 | if (!super.equals(o)) return false; 66 | 67 | final SubscriptionUpdateRequest that = (SubscriptionUpdateRequest) o; 68 | 69 | if (productId != null ? !productId.equals(that.productId) : that.productId != null) 70 | return false; 71 | if (userId != null ? !userId.equals(that.userId) : that.userId != null) 72 | return false; 73 | if (numberOfLicenses != null ? !numberOfLicenses.equals(that.numberOfLicenses) : that.numberOfLicenses != null) 74 | return false; 75 | if (removeAllUnassignedLicenses != null ? 76 | !removeAllUnassignedLicenses.equals(that.removeAllUnassignedLicenses) : 77 | that.removeAllUnassignedLicenses != null) 78 | return false; 79 | return true; 80 | } 81 | 82 | @Override 83 | public int hashCode() { 84 | int result = super.hashCode(); 85 | result = 31 * result + (productId != null ? productId.hashCode() : 0); 86 | result = 31 * result + (userId != null ? userId.hashCode() : 0); 87 | result = 31 * result + (numberOfLicenses != null ? numberOfLicenses.hashCode() : 0); 88 | result = 31 * result + (removeAllUnassignedLicenses != null ? removeAllUnassignedLicenses.hashCode() : 0); 89 | return result; 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 95 | .append("operation", operation) 96 | .append("subscriptionId", subscriptionId) 97 | .append("productId", productId) 98 | .append("userId", userId) 99 | .append("numberOfLicenses", numberOfLicenses) 100 | .append("removeAllUnassignedLicenses", removeAllUnassignedLicenses) 101 | .toString(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/serialization/messages/SubscriptionUpdateResponse.java: -------------------------------------------------------------------------------- 1 | package com.amazon.dtasdk.v3.serialization.messages; 2 | 3 | import com.amazon.dtasdk.base.SubscriptionResponse; 4 | import org.apache.commons.lang.builder.ToStringBuilder; 5 | import org.apache.commons.lang.builder.ToStringStyle; 6 | 7 | public class SubscriptionUpdateResponse extends SubscriptionResponse { 8 | private Integer numberOfUnusedLicenses; 9 | private Integer numberOfUsedLicenses; 10 | private String managementURL; 11 | 12 | public Integer getNumberOfUnusedLicenses() { 13 | return numberOfUnusedLicenses; 14 | } 15 | 16 | public void setNumberOfUnusedLicenses(Integer numberOfUnusedLicenses) { 17 | this.numberOfUnusedLicenses = numberOfUnusedLicenses; 18 | } 19 | 20 | public Integer getNumberOfUsedLicenses() { 21 | return numberOfUsedLicenses; 22 | } 23 | 24 | public void setNumberOfUsedLicenses(Integer numberOfUsedLicenses) { 25 | this.numberOfUsedLicenses = numberOfUsedLicenses; 26 | } 27 | 28 | public String getManagementURL() { 29 | return managementURL; 30 | } 31 | 32 | public void setManagementURL(String managementUrl) { 33 | this.managementURL = managementUrl; 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | final int prime = 31; 39 | int result = 1; 40 | result = prime * result + ((numberOfUnusedLicenses == null) ? 0 : numberOfUnusedLicenses.hashCode()); 41 | result = prime * result + ((numberOfUsedLicenses == null) ? 0 : numberOfUsedLicenses.hashCode()); 42 | result = prime * result + ((managementURL == null) ? 0 : managementURL.hashCode()); 43 | result = prime * result + ((response == null) ? 0 : response.hashCode()); 44 | return result; 45 | } 46 | 47 | @Override 48 | public boolean equals(Object obj) { 49 | if (this == obj) { 50 | return true; 51 | } 52 | if (obj == null) { 53 | return false; 54 | } 55 | if (getClass() != obj.getClass()) { 56 | return false; 57 | } 58 | final SubscriptionUpdateResponse other = (SubscriptionUpdateResponse) obj; 59 | if (numberOfUnusedLicenses == null) { 60 | if (other.numberOfUnusedLicenses != null) { 61 | return false; 62 | } 63 | } else if (!numberOfUnusedLicenses.equals(other.numberOfUnusedLicenses)) { 64 | return false; 65 | } 66 | 67 | if (numberOfUsedLicenses == null) { 68 | if (other.numberOfUsedLicenses != null) { 69 | return false; 70 | } 71 | } else if (!numberOfUsedLicenses.equals(other.numberOfUsedLicenses)) { 72 | return false; 73 | } 74 | 75 | if (managementURL == null) { 76 | if (other.managementURL != null) { 77 | return false; 78 | } 79 | } else if (!managementURL.equals(other.managementURL)) { 80 | return false; 81 | } 82 | 83 | if (response == null) { 84 | if (other.response != null) { 85 | return false; 86 | } 87 | } else if (!response.equals(other.response)) { 88 | return false; 89 | } 90 | return true; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 96 | .append("numberOfUnusedLicenses", numberOfUnusedLicenses) 97 | .append("numberOfUsedLicenses", numberOfUsedLicenses) 98 | .append("managementURL", managementURL) 99 | .append("response", response).toString(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/servlets/AccountLinkingServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.servlets; 16 | 17 | import com.amazon.dtasdk.v3.serialization.messages.GetUserIdSerializableRequest; 18 | import com.amazon.dtasdk.v3.serialization.messages.GetUserIdSerializableResponse; 19 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 20 | import com.amazon.dtasdk.base.InstantAccessResponse; 21 | import com.amazon.dtasdk.serializer.SerializationException; 22 | 23 | /** 24 | *25 | * This abstract servlet can be extended to implement the V3 Account Linking section of Instant Access API. 26 | *
27 | * 28 | *29 | * When extending this servlet, you must implement the abstract method {@link #getUserId( GetUserIdSerializableRequest )}, 30 | * it is the method for returning a user id based on the parameters in order to link accounts. 31 | *
32 | * 33 | *34 | * You must also implement the abstract method {@link #getCredentialStore()}. This method must provide a valid credential 35 | * store that will be used to verify the message authenticity. 36 | *
37 | * 38 | */ 39 | public abstract class AccountLinkingServlet extends InstantAccessServlet { 40 | 41 | /** 42 | * Process the request and returns the user id 43 | * 44 | * @param request 45 | * the request relative to the get user id operation 46 | * 47 | * @return a GetUserIdSerializableResponse object 48 | */ 49 | public abstract GetUserIdSerializableResponse getUserId(GetUserIdSerializableRequest request); 50 | 51 | @Override 52 | public InstantAccessResponse> processOperation(InstantAccessOperationValue operation, String requestBody) 53 | throws SerializationException { 54 | 55 | GetUserIdSerializableResponse iaResponse; 56 | 57 | // process the request according to the operation 58 | switch (operation) { 59 | case GETUSERID: 60 | iaResponse = getUserId(serializer.decode(requestBody, GetUserIdSerializableRequest.class)); 61 | break; 62 | default: 63 | throw new IllegalArgumentException(String.format("Operation[%s] not supported by v3 %s", operation.name(), 64 | this.getClass().getName())); 65 | } 66 | 67 | return iaResponse; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/servlets/InstantAccessServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.servlets; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 18 | import com.amazon.dtasdk.base.InstantAccessRequest; 19 | import com.amazon.dtasdk.base.InstantAccessResponse; 20 | import com.amazon.dtasdk.serializer.JacksonSerializer; 21 | import com.amazon.dtasdk.serializer.SerializationException; 22 | import com.amazon.dtasdk.signature.CredentialStore; 23 | import com.amazon.dtasdk.signature.Request; 24 | import com.amazon.dtasdk.signature.Signer; 25 | import com.amazon.dtasdk.signature.SigningException; 26 | import org.apache.commons.logging.Log; 27 | import org.apache.commons.logging.LogFactory; 28 | 29 | import javax.servlet.http.HttpServlet; 30 | import javax.servlet.http.HttpServletRequest; 31 | import javax.servlet.http.HttpServletResponse; 32 | import java.io.IOException; 33 | import java.nio.charset.Charset; 34 | 35 | /** 36 | *37 | * This abstract servlet is extended by the {@link PurchaseServlet} and {@link AccountLinkingServlet} in order to 38 | * implement the Instant Access API. This class should not be used, use the aforementioned classes instead. 39 | *
40 | * 41 | */ 42 | public abstract class InstantAccessServlet extends HttpServlet { 43 | private static final Log log = LogFactory.getLog(InstantAccessServlet.class); 44 | private static final Charset CHARSET = Charset.forName("UTF-8"); 45 | 46 | private final Signer signer = new Signer(); 47 | 48 | protected final JacksonSerializer serializer = new JacksonSerializer(); 49 | 50 | /** 51 | * Returns the credential store 52 | * 53 | * @return a CredentialStore object with all the credentials 54 | */ 55 | public abstract CredentialStore getCredentialStore(); 56 | 57 | /** 58 | * Processes the request based on the operation 59 | * 60 | * @param operation 61 | * The operation being called 62 | * @param requestBody 63 | * The content of the message 64 | * @return a generic InstantAccessResponse> containing the result of the operation 65 | * 66 | * @throws SerializationException 67 | * @throws IllegalArgumentException 68 | */ 69 | public abstract InstantAccessResponse> processOperation(InstantAccessOperationValue operation, String requestBody) 70 | throws SerializationException; 71 | 72 | @Override 73 | public void doPost(HttpServletRequest request, HttpServletResponse response) { 74 | try { 75 | Request req = new Request(request); 76 | 77 | if (!signer.verify(req, getCredentialStore())) { 78 | throw new SigningException("Request validation failed."); 79 | } 80 | 81 | String requestBody = req.getBody(); 82 | 83 | // deserialize the content to a InstantAccessRequest object so we can check which operation is going 84 | // to be called 85 | InstantAccessRequest iaRequest = serializer.decode(requestBody, InstantAccessRequest.class); 86 | 87 | // process the request according to the operation 88 | InstantAccessResponse> iaResponse = processOperation(iaRequest.getOperation(), requestBody); 89 | 90 | response.setStatus(HttpServletResponse.SC_OK); 91 | response.getOutputStream().write(serializer.encode(iaResponse).getBytes(CHARSET)); 92 | } catch (IOException e) { 93 | log.error("Unable to read the v3 request.", e); 94 | response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 95 | } catch (SigningException e) { 96 | log.error("Unable to verify the v3 request against the credential store.", e); 97 | response.setStatus(HttpServletResponse.SC_FORBIDDEN); 98 | } catch (SerializationException e) { 99 | log.error("v3 Serialization error.", e); 100 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); 101 | } catch (Exception e) { 102 | log.error("Unable to process the v3 request.", e); 103 | response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/amazon/dtasdk/v3/servlets/PurchaseServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.v3.servlets; 16 | 17 | import com.amazon.dtasdk.base.InstantAccessOperationValue; 18 | import com.amazon.dtasdk.base.InstantAccessResponse; 19 | import com.amazon.dtasdk.base.SubscriptionResponse; 20 | import com.amazon.dtasdk.serializer.SerializationException; 21 | import com.amazon.dtasdk.v3.serialization.messages.*; 22 | 23 | /** 24 | *25 | * This abstract servlet can be extended to implement the V3 Purchase/Subscription section of Instant Access API. 26 | *
27 | *28 | *
29 | * When extending this servlet, you must implement the abstract methods relative to the four operations present in the 30 | * API. {@link #fulfillPurchase( FulfillPurchaseRequest )} is the method responsible for fulfilling a purchase, {@link 31 | * #revokePurchase( RevokePurchaseRequest )} is the method responsible for revoking a purchase, {@link 32 | * #processSubscriptionActivate( SubscriptionActivateRequest )} is the method responsible for activating a subscription, 33 | * {@link #processSubscriptionDeactivate( SubscriptionDeactivateRequest )} is the method responsible for deactivating a 34 | * subscription, {@link #processSubscriptionUpdate( SubscriptionUpdateRequest )} is the method responsible for updating a 35 | * subscription and {@link #processSubscriptionGet( SubscriptionGetRequest )} is the method responsible for getting a 36 | * subscription 37 | *
38 | *39 | *
40 | * You must also implement the abstract method {@link #getCredentialStore()}. This method must provide a valid credential 41 | * store that will be used to verify the message authenticity. 42 | *
43 | */ 44 | public abstract class PurchaseServlet extends InstantAccessServlet { 45 | 46 | /** 47 | * Process the fulfill purchase request and return the response to whether or not the request succeeded. 48 | * 49 | * @param request the request relative to the fulfill purchase 50 | * @return a FulfillPurchaseResponse object 51 | */ 52 | public abstract FulfillPurchaseResponse fulfillPurchase(FulfillPurchaseRequest request); 53 | 54 | /** 55 | * Process the revoke purchase request and return the response to whether or not the request succeeded. 56 | * 57 | * @param request the request relative to the revoke purchase 58 | * @return a RevokePurchaseResponse object 59 | */ 60 | public abstract RevokePurchaseResponse revokePurchase(RevokePurchaseRequest request); 61 | 62 | /** 63 | * Process a subscription activation based on the request and returns the response to whether or not the request 64 | * succeeded. 65 | * 66 | * @param request the request object with information about the subscription 67 | * @return a SubscriptionResponse object 68 | */ 69 | public abstract SubscriptionResponse processSubscriptionActivate(SubscriptionActivateRequest request); 70 | 71 | /** 72 | * Process a subscription deactivation based on the request and returns the response to whether or not the request 73 | * succeeded. 74 | * 75 | * @param request the request object with information about the subscription 76 | * @return a SubscriptionResponse object 77 | */ 78 | public abstract SubscriptionResponse processSubscriptionDeactivate(SubscriptionDeactivateRequest request); 79 | 80 | 81 | /** 82 | * Process a subscription get based on the request and returns the response to whether or not the request 83 | * succeeded. 84 | * 85 | * @param request the request object with information about the subscription 86 | * @return a SubscriptionGetResponse object 87 | */ 88 | public abstract SubscriptionGetResponse processSubscriptionGet(SubscriptionGetRequest request); 89 | 90 | /** 91 | * Process a subscription update based on the request and returns the response to whether or not the request 92 | * succeeded. 93 | * 94 | * @param request the request object with information about the subscription 95 | * @return a SubscriptionResponse object 96 | */ 97 | public abstract SubscriptionResponse processSubscriptionUpdate(SubscriptionUpdateRequest request); 98 | 99 | @Override 100 | public InstantAccessResponse> processOperation(InstantAccessOperationValue operation, String requestBody) 101 | throws SerializationException { 102 | 103 | InstantAccessResponse> iaResponse; 104 | 105 | // process the request according to the operation 106 | switch (operation) { 107 | case PURCHASE: 108 | iaResponse = fulfillPurchase(serializer.decode(requestBody, FulfillPurchaseRequest.class)); 109 | break; 110 | case REVOKE: 111 | iaResponse = revokePurchase(serializer.decode(requestBody, RevokePurchaseRequest.class)); 112 | break; 113 | case SUBSCRIPTIONGET: 114 | iaResponse = processSubscriptionGet(serializer.decode(requestBody, SubscriptionGetRequest.class)); 115 | break; 116 | case SUBSCRIPTIONACTIVATE: 117 | iaResponse = processSubscriptionActivate(serializer.decode(requestBody, 118 | SubscriptionActivateRequest.class)); 119 | break; 120 | case SUBSCRIPTIONDEACTIVATE: 121 | iaResponse = processSubscriptionDeactivate(serializer.decode(requestBody, 122 | SubscriptionDeactivateRequest.class)); 123 | break; 124 | case SUBSCRIPTIONUPDATE: 125 | iaResponse = processSubscriptionUpdate(serializer.decode(requestBody, SubscriptionUpdateRequest.class)); 126 | break; 127 | default: 128 | throw new IllegalArgumentException(String.format("Operation[%s] not supported by v3 %s", operation.name(), 129 | this.getClass().getName())); 130 | } 131 | 132 | return iaResponse; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/examples/servlet/AccountLinkingServletImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package examples.servlet; 17 | 18 | import com.amazon.dtasdk.signature.CredentialStore; 19 | import com.amazon.dtasdk.v2.serialization.messages.GetUserIdSerializableResponseValue; 20 | import com.amazon.dtasdk.v3.serialization.messages.GetUserIdSerializableRequest; 21 | import com.amazon.dtasdk.v3.serialization.messages.GetUserIdSerializableResponse; 22 | import com.amazon.dtasdk.v3.servlets.AccountLinkingServlet; 23 | import org.apache.commons.logging.Log; 24 | import org.apache.commons.logging.LogFactory; 25 | 26 | /** 27 | * Servlet class that listens to the account linking requests 28 | */ 29 | public class AccountLinkingServletImpl extends AccountLinkingServlet { 30 | 31 | private static final Log log = LogFactory.getLog(AccountLinkingServletImpl.class); 32 | 33 | @Override 34 | public CredentialStore getCredentialStore() { 35 | CredentialStore store = new CredentialStore(); 36 | 37 | /** 38 | * Add your public and private keys to the CredentialStore 39 | */ 40 | 41 | return store; 42 | } 43 | 44 | @Override 45 | public GetUserIdSerializableResponse getUserId(GetUserIdSerializableRequest request) { 46 | log.info(String.format("Started getUserId with request[%s]", request)); 47 | 48 | GetUserIdSerializableResponse response = new GetUserIdSerializableResponse(); 49 | 50 | try { 51 | /** 52 | * Retrieve userId and set it in the response object 53 | * response.setUserId(service.getUserId(request)); 54 | */ 55 | 56 | response.setResponse(GetUserIdSerializableResponseValue.OK); 57 | } catch (Exception e) { 58 | log.error(String.format("Error while processing getUserId[%s]", request), e); 59 | response.setResponse(GetUserIdSerializableResponseValue.FAIL_ACCOUNT_INVALID); 60 | } 61 | 62 | log.info(String.format("Finished getUserId with response[%s]", response)); 63 | 64 | return response; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/examples/servlet/PurchaseServletImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package examples.servlet; 17 | 18 | import com.amazon.dtasdk.base.SubscriptionResponse; 19 | import com.amazon.dtasdk.base.SubscriptionResponseValue; 20 | import com.amazon.dtasdk.signature.CredentialStore; 21 | import com.amazon.dtasdk.v2.serialization.messages.FulfillPurchaseResponseValue; 22 | import com.amazon.dtasdk.v2.serialization.messages.RevokePurchaseResponseValue; 23 | import com.amazon.dtasdk.v3.serialization.messages.FulfillPurchaseRequest; 24 | import com.amazon.dtasdk.v3.serialization.messages.FulfillPurchaseResponse; 25 | import com.amazon.dtasdk.v3.serialization.messages.RevokePurchaseRequest; 26 | import com.amazon.dtasdk.v3.serialization.messages.RevokePurchaseResponse; 27 | import com.amazon.dtasdk.v3.serialization.messages.SubscriptionActivateRequest; 28 | import com.amazon.dtasdk.v3.serialization.messages.SubscriptionDeactivateRequest; 29 | import com.amazon.dtasdk.v3.serialization.messages.SubscriptionGetRequest; 30 | import com.amazon.dtasdk.v3.serialization.messages.SubscriptionGetResponse; 31 | import com.amazon.dtasdk.v3.serialization.messages.SubscriptionUpdateRequest; 32 | import com.amazon.dtasdk.v3.servlets.PurchaseServlet; 33 | import org.apache.commons.logging.Log; 34 | import org.apache.commons.logging.LogFactory; 35 | 36 | 37 | /** 38 | * Servlet class that listens to the purchases/subscriptions requests 39 | */ 40 | public class PurchaseServletImpl extends PurchaseServlet { 41 | private static final Log log = LogFactory.getLog(PurchaseServletImpl.class); 42 | 43 | @Override 44 | public CredentialStore getCredentialStore() { 45 | CredentialStore store = new CredentialStore(); 46 | 47 | /** 48 | * Add your public and private keys to the CredentialStore 49 | */ 50 | 51 | return store; 52 | } 53 | 54 | @Override 55 | public FulfillPurchaseResponse fulfillPurchase(FulfillPurchaseRequest request) { 56 | log.info(String.format("Started fulfillPurchase with request[%s]", request)); 57 | 58 | FulfillPurchaseResponse response = new FulfillPurchaseResponse(); 59 | 60 | try { 61 | /** 62 | * Add logic to fulfill a purchase 63 | */ 64 | response.setResponse(FulfillPurchaseResponseValue.OK); 65 | } catch (Exception e) { 66 | log.error(String.format("Error while processing fulfillPurchase[%s]", request), e); 67 | response.setResponse(FulfillPurchaseResponseValue.FAIL_OTHER); 68 | } 69 | 70 | log.info(String.format("Finished fulfillPurchase with response[%s]", response)); 71 | 72 | return response; 73 | } 74 | 75 | @Override 76 | public RevokePurchaseResponse revokePurchase(RevokePurchaseRequest request) { 77 | log.info(String.format("Started revokePurchase with request[%s]", request)); 78 | 79 | RevokePurchaseResponse response = new RevokePurchaseResponse(); 80 | 81 | try { 82 | /** 83 | * Add logic to revoke a purchase 84 | */ 85 | response.setResponse(RevokePurchaseResponseValue.OK); 86 | } catch (Exception e) { 87 | log.error(String.format("Error while processing revokePurchase[%s]", request), e); 88 | response.setResponse(RevokePurchaseResponseValue.FAIL_OTHER); 89 | } 90 | 91 | log.info(String.format("Finished revokePurchase with response[%s]", response)); 92 | 93 | return response; 94 | } 95 | 96 | @Override 97 | public SubscriptionResponse processSubscriptionActivate(SubscriptionActivateRequest request) { 98 | log.info(String.format("Started processSubscriptionActivate with request[%s]", request)); 99 | 100 | SubscriptionResponse response = new SubscriptionResponse(); 101 | 102 | try { 103 | /** 104 | * Add logic to activate a subscription 105 | */ 106 | response.setResponse(SubscriptionResponseValue.OK); 107 | } catch (Exception e) { 108 | log.error(String.format("Error while processing processSubscriptionActivate[%s]", request), e); 109 | response.setResponse(SubscriptionResponseValue.FAIL_OTHER); 110 | } 111 | 112 | log.info(String.format("Finished processSubscriptionActivate with response[%s]", response)); 113 | 114 | return response; 115 | } 116 | 117 | @Override 118 | public SubscriptionResponse processSubscriptionDeactivate(SubscriptionDeactivateRequest request) { 119 | log.info(String.format("Started processSubscriptionDeactivate with request[%s]", request)); 120 | 121 | SubscriptionResponse response = new SubscriptionResponse(); 122 | 123 | try { 124 | /** 125 | * Add logic to deactivate a subscription 126 | */ 127 | response.setResponse(SubscriptionResponseValue.OK); 128 | } catch (Exception e) { 129 | log.error(String.format("Error while processing processSubscriptionDeactivate[%s]", request), e); 130 | response.setResponse(SubscriptionResponseValue.FAIL_OTHER); 131 | } 132 | 133 | log.info(String.format("Finished processSubscriptionDeactivate with response[%s]", response)); 134 | 135 | return response; 136 | } 137 | 138 | @Override 139 | public SubscriptionGetResponse processSubscriptionGet(SubscriptionGetRequest request) { 140 | log.info(String.format("Started processSubscriptionGet with request[%s]", request)); 141 | 142 | SubscriptionGetResponse response = new SubscriptionGetResponse(); 143 | 144 | try { 145 | /** 146 | * Add logic to get a subscription 147 | */ 148 | response.setResponse(SubscriptionResponseValue.OK); 149 | } catch (Exception e) { 150 | log.error(String.format("Error while processing processSubscriptionGet[%s]", request), e); 151 | response.setResponse(SubscriptionResponseValue.FAIL_OTHER); 152 | } 153 | 154 | log.info(String.format("Finished processSubscriptionGet with response[%s]", response)); 155 | 156 | return response; 157 | } 158 | 159 | @Override 160 | public SubscriptionResponse processSubscriptionUpdate(SubscriptionUpdateRequest request) { 161 | log.info(String.format("Started processSubscriptionUpdate with request[%s]", request)); 162 | 163 | SubscriptionResponse response = new SubscriptionResponse(); 164 | 165 | try { 166 | /** 167 | * Add logic to update a subscription 168 | */ 169 | response.setResponse(SubscriptionResponseValue.OK); 170 | } catch (Exception e) { 171 | log.error(String.format("Error while processing processSubscriptionUpdate[%s]", request), e); 172 | response.setResponse(SubscriptionResponseValue.FAIL_OTHER); 173 | } 174 | 175 | log.info(String.format("Finished processSubscriptionUpdate with response[%s]", response)); 176 | 177 | return response; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/test/java/com/amazon/dtasdk/connection/SignatureVerificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.connection; 16 | 17 | import com.amazon.dtasdk.signature.Credential; 18 | import com.amazon.dtasdk.signature.Request; 19 | import com.amazon.dtasdk.signature.Signer; 20 | import com.amazon.dtasdk.signature.SigningException; 21 | import org.apache.commons.httpclient.HttpClient; 22 | import org.apache.commons.httpclient.HttpMethod; 23 | import org.apache.commons.httpclient.methods.GetMethod; 24 | import org.apache.commons.httpclient.methods.PostMethod; 25 | import org.eclipse.jetty.server.handler.AbstractHandler; 26 | import org.junit.AfterClass; 27 | import org.junit.Before; 28 | import org.junit.BeforeClass; 29 | import org.junit.Test; 30 | 31 | import javax.servlet.ServletException; 32 | import javax.servlet.http.HttpServletRequest; 33 | import javax.servlet.http.HttpServletResponse; 34 | import java.io.IOException; 35 | import java.security.KeyManagementException; 36 | import java.security.NoSuchAlgorithmException; 37 | 38 | import static org.junit.Assert.assertEquals; 39 | 40 | @Deprecated 41 | public class SignatureVerificationTest { 42 | 43 | private static MockHandler handler; 44 | private static TestServer server; 45 | private static HttpClient httpClient; 46 | private HttpClient client; 47 | private Signer signer; 48 | 49 | static class MockHandler extends AbstractHandler { 50 | 51 | private Credential credential; 52 | private Signer signer = new Signer(); 53 | private Exception exception; 54 | 55 | @Override 56 | public void handle(String s, org.eclipse.jetty.server.Request jettyRequest, 57 | HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, 58 | ServletException { 59 | Request request = new Request(httpServletRequest); 60 | 61 | try { 62 | if (!signer.verify(request, this.credential)) { 63 | httpServletResponse.setStatus(403); 64 | jettyRequest.setHandled(true); 65 | return; 66 | } 67 | } catch (SigningException e) { 68 | this.exception = e; 69 | throw new IOException(e); 70 | } 71 | 72 | httpServletResponse.setStatus(200); 73 | httpServletResponse.getWriter().write("success"); 74 | jettyRequest.setHandled(true); 75 | } 76 | 77 | public void setCredential(Credential credential) { 78 | this.credential = credential; 79 | } 80 | 81 | public void clear() { 82 | exception = null; 83 | } 84 | 85 | public Exception getException() { 86 | return exception; 87 | } 88 | } 89 | 90 | @BeforeClass 91 | public static void startServer() throws Exception { 92 | handler = new MockHandler(); 93 | server = new TestServer(handler).start(); 94 | } 95 | 96 | @AfterClass 97 | public static void stopServer() throws Exception { 98 | server.stop(); 99 | } 100 | 101 | private String serverUrl() { 102 | return "http://localhost:" + server.getPort(); 103 | } 104 | 105 | private void setDefaultHeaders(Request request) { 106 | request.setHeader("x-amz-request-id", "0A49CE4060975EAC"); 107 | request.setHeader("x-amz-customer-id", "ABCDCUSTID"); 108 | request.setHeader("x-amz-dta-version", "1"); 109 | } 110 | 111 | private void copyHeaders(Request request, HttpMethod method) { 112 | for (String headerName : request.getHeaderNames()) { 113 | method.setRequestHeader(headerName, request.getHeader(headerName)); 114 | } 115 | } 116 | 117 | @Before 118 | public void before() throws KeyManagementException, NoSuchAlgorithmException { 119 | client = new HttpClient(); 120 | signer = new Signer(); 121 | } 122 | 123 | @Test 124 | public void roundTripServer_withBareUrl() throws Exception { 125 | Credential credential = new Credential("SECRETKEY", "KEYID"); 126 | handler.setCredential(credential); 127 | 128 | Request request = new Request(serverUrl(), Request.Method.GET, ""); 129 | setDefaultHeaders(request); 130 | signer.sign(request, credential); 131 | 132 | HttpMethod method = new GetMethod(request.getUrl()); 133 | copyHeaders(request, method); 134 | 135 | assertEquals(200, client.executeMethod(method)); 136 | } 137 | 138 | @Test 139 | public void roundTrip_withPath() throws Exception { 140 | Credential credential = new Credential("SECRETKEY", "KEYID"); 141 | handler.setCredential(credential); 142 | 143 | Request request = new Request(serverUrl() + "/path/to/servlet", Request.Method.POST, ""); 144 | setDefaultHeaders(request); 145 | request.setBody("{\"json\": \"value\"}"); 146 | signer.sign(request, credential); 147 | 148 | PostMethod method = new PostMethod(request.getUrl()); 149 | copyHeaders(request, method); 150 | method.setRequestBody(request.getBody()); 151 | 152 | assertEquals(200, client.executeMethod(method)); 153 | } 154 | 155 | @Test 156 | public void roundTrip_NoAuth() throws Exception { 157 | Credential credential = new Credential("SECRETKEY", "KEYID"); 158 | handler.setCredential(credential); 159 | 160 | PostMethod method = new PostMethod(serverUrl() + "/path/to/servlet"); 161 | method.setRequestBody("{\"json\": \"value\"}"); 162 | 163 | assertEquals(403, client.executeMethod(method)); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/test/java/com/amazon/dtasdk/connection/TestServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.connection; 16 | 17 | import org.eclipse.jetty.server.Server; 18 | import org.eclipse.jetty.server.handler.AbstractHandler; 19 | import org.junit.Ignore; 20 | 21 | /** 22 | * This is a wrapper for unit tests that brings up a real Jetty HTTP server with a handler. 23 | */ 24 | @Deprecated 25 | @Ignore 26 | public class TestServer { 27 | private final Server server; 28 | private final int port; 29 | 30 | public TestServer(AbstractHandler handler) { 31 | port = 58901 + (int) (Math.random() * 6000); 32 | server = new Server(port); 33 | server.setHandler(handler); 34 | } 35 | 36 | public int getPort() { 37 | return port; 38 | } 39 | 40 | public TestServer start() throws Exception { 41 | server.start(); 42 | return this; 43 | } 44 | 45 | public void stop() throws Exception { 46 | server.stop(); 47 | server.join(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/amazon/dtasdk/serializer/JacksonSerializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | package com.amazon.dtasdk.serializer; 16 | 17 | import com.amazon.dtasdk.serializer.TestJson.Name; 18 | import com.fasterxml.jackson.databind.JsonNode; 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import junit.framework.Assert; 21 | import org.junit.Test; 22 | 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | 26 | public class JacksonSerializerTest { 27 | private static final String jsonString = "{\"value\":\"theValue\"," 28 | + "\"names\":[{\"first\":\"Joe\",\"last\":\"Sixpack\"}," + "{\"first\":\"Bill\",\"last\":\"Fourpack\"}]}"; 29 | 30 | private static final JacksonSerializer serializer = new JacksonSerializer(); 31 | 32 | @Test 33 | public void testDecode() throws Exception { 34 | TestJson dtgObject = serializer.decode(jsonString, TestJson.class); 35 | 36 | Assert.assertEquals(TestJson.class, dtgObject.getClass()); 37 | TestJson testJson = dtgObject; 38 | Assert.assertEquals("Joe", testJson.getNames().get(0).getFirst()); 39 | Assert.assertEquals("Sixpack", testJson.getNames().get(0).getLast()); 40 | Assert.assertEquals("Bill", testJson.getNames().get(1).getFirst()); 41 | Assert.assertEquals("Fourpack", testJson.getNames().get(1).getLast()); 42 | Assert.assertEquals("theValue", testJson.getValue()); 43 | } 44 | 45 | @Test 46 | public void testEncode() throws Exception { 47 | String encodedJson = encodeObject(getTestObject()); 48 | 49 | ObjectMapper mapper = new ObjectMapper(); 50 | JsonNode expected = mapper.readTree(jsonString); 51 | JsonNode actual = mapper.readTree(encodedJson); 52 | 53 | Assert.assertEquals(expected, actual); 54 | } 55 | 56 | private TestJson getTestObject() throws Exception { 57 | TestJson testJson = new TestJson(); 58 | Name name = new Name(); 59 | name.setFirst("Joe"); 60 | name.setLast("Sixpack"); 61 | 62 | Name name2 = new Name(); 63 | name2.setFirst("Bill"); 64 | name2.setLast("Fourpack"); 65 | 66 | List