1 /** 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * SPDX-License-Identifier: Apache-2.0. 4 */ 5 6 package software.amazon.awssdk.crt.auth.credentials; 7 8 import java.lang.IllegalArgumentException; 9 import java.nio.ByteBuffer; 10 import java.nio.charset.Charset; 11 import java.util.ArrayList; 12 13 import software.amazon.awssdk.crt.http.HttpHeader; 14 import software.amazon.awssdk.crt.http.HttpProxyOptions; 15 import software.amazon.awssdk.crt.io.ClientBootstrap; 16 import software.amazon.awssdk.crt.io.TlsContext; 17 18 19 /** 20 * A class that wraps a credentials provider that sources session credentials from the AWS Cognito Identity service. 21 */ 22 public class CognitoCredentialsProvider extends CredentialsProvider { 23 24 private final static Charset UTF8 = java.nio.charset.StandardCharsets.UTF_8; 25 private final static int BUFFER_INT_SIZE = 4; 26 27 /** 28 * Pair of strings specifying an identity provider name and an associated login token. 29 */ 30 static public class CognitoLoginTokenPair { 31 32 public final byte[] identityProviderName; 33 public final byte[] identityProviderToken; 34 CognitoLoginTokenPair(String identityProviderName, String identityProviderToken)35 public CognitoLoginTokenPair(String identityProviderName, String identityProviderToken) { 36 this.identityProviderName = identityProviderName.getBytes(UTF8); 37 this.identityProviderToken = identityProviderToken.getBytes(UTF8); 38 } 39 }; 40 41 /** 42 * A builder class for the Cognito provider and its options 43 */ 44 static public class CognitoCredentialsProviderBuilder { 45 46 private String endpoint; 47 private String identity; 48 private String customRoleArn; 49 private ArrayList<CognitoLoginTokenPair> logins = new ArrayList<CognitoLoginTokenPair>(); 50 51 private TlsContext tlsContext; 52 private ClientBootstrap clientBootstrap; 53 private HttpProxyOptions httpProxyOptions; 54 55 /** 56 * Default constructor 57 */ CognitoCredentialsProviderBuilder()58 public CognitoCredentialsProviderBuilder() {} 59 60 /** 61 * Sets the Cognito service endpoint to use when sourcing credentials via HTTP 62 * @param endpoint cognito service endpoint to use 63 * @return The current builder 64 */ withEndpoint(String endpoint)65 public CognitoCredentialsProviderBuilder withEndpoint(String endpoint) { 66 this.endpoint = endpoint; 67 return this; 68 } 69 getEndpoint()70 public String getEndpoint() { return endpoint; } 71 72 /** 73 * Sets the Cognito identity to source credentials for 74 * @param identity the cognito identity to source credentials for 75 * @return The current builder 76 */ withIdentity(String identity)77 public CognitoCredentialsProviderBuilder withIdentity(String identity) { 78 this.identity = identity; 79 return this; 80 } 81 getIdentity()82 public String getIdentity() { return identity; } 83 84 /** 85 * (optional) Sets the ARN of the role to be assumed when multiple roles were received in the token from the 86 * identity provider. 87 * @param customRoleArn ARN of the role to be assumed when multiple roles were received in the token from the 88 * identity provider 89 * @return The current builder 90 */ withCustomRoleArn(String customRoleArn)91 public CognitoCredentialsProviderBuilder withCustomRoleArn(String customRoleArn) { 92 this.customRoleArn = customRoleArn; 93 return this; 94 } 95 getCustomRoleArn()96 public String getCustomRoleArn() { return customRoleArn; } 97 98 /** 99 * Adds an identity provider token pair to allow for authenticated identity access. 100 * @param login identity provider token pair 101 * @return The current builder 102 */ withLogin(CognitoLoginTokenPair login)103 public CognitoCredentialsProviderBuilder withLogin(CognitoLoginTokenPair login) { 104 this.logins.add(login); 105 return this; 106 } 107 getLogins()108 public ArrayList<CognitoLoginTokenPair> getLogins() { return logins; } 109 110 /** 111 * (Optional) Sets the client bootstrap (host resolver and event loop group) to use when making the connections 112 * required by this provider. 113 * @param clientBootstrap client bootstrap to use 114 * @return The current builder 115 */ withClientBootstrap(ClientBootstrap clientBootstrap)116 public CognitoCredentialsProviderBuilder withClientBootstrap(ClientBootstrap clientBootstrap) { 117 this.clientBootstrap = clientBootstrap; 118 119 return this; 120 } 121 getClientBootstrap()122 ClientBootstrap getClientBootstrap() { return clientBootstrap; } 123 124 /** 125 * Sets the tls context to use when making HTTP requests to the Cognito Identity service 126 * @param tlsContext the tls context to use when making HTTP requests 127 * @return The current builder 128 */ withTlsContext(TlsContext tlsContext)129 public CognitoCredentialsProviderBuilder withTlsContext(TlsContext tlsContext) { 130 this.tlsContext = tlsContext; 131 132 return this; 133 } 134 getTlsContext()135 TlsContext getTlsContext() { return tlsContext; } 136 137 /** 138 * Sets the proxy configuration to use when making the http request that fetches session 139 * credentials from the AWS Cognito Identity service 140 * @param httpProxyOptions proxy configuration for the credentials fetching http request 141 * @return The current builder 142 */ withHttpProxyOptions(HttpProxyOptions httpProxyOptions)143 public CognitoCredentialsProviderBuilder withHttpProxyOptions(HttpProxyOptions httpProxyOptions) { 144 this.httpProxyOptions = httpProxyOptions; 145 146 return this; 147 } 148 getHttpProxyOptions()149 HttpProxyOptions getHttpProxyOptions() { return httpProxyOptions; } 150 151 152 /** 153 * Creates a new Cognito credentials provider, based on this builder's configuration 154 * @return a new Cognito credentials provider 155 */ build()156 public CognitoCredentialsProvider build() { 157 return new CognitoCredentialsProvider(this); 158 } 159 } 160 CognitoCredentialsProvider(CognitoCredentialsProviderBuilder builder)161 private CognitoCredentialsProvider(CognitoCredentialsProviderBuilder builder) { 162 super(); 163 164 String endpoint = builder.getEndpoint(); 165 String identity = builder.getIdentity(); 166 if (endpoint == null || identity == null) { 167 throw new IllegalArgumentException("CognitoCredentialsProvider - endpoint and identity must not be null"); 168 } 169 170 ClientBootstrap clientBootstrap = builder.getClientBootstrap(); 171 if (clientBootstrap == null) { 172 clientBootstrap = ClientBootstrap.getOrCreateStaticDefault(); 173 } 174 175 TlsContext tlsContext = builder.getTlsContext(); 176 if (clientBootstrap == null || tlsContext == null) { 177 throw new IllegalArgumentException("CognitoCredentialsProvider - clientBootstrap and tlsContext must not be null"); 178 } 179 180 int proxyConnectionType = 0; 181 long proxyTlsContextHandle = 0; 182 String proxyHost = null; 183 int proxyPort = 0; 184 int proxyAuthorizationType = 0; 185 String proxyAuthorizationUsername = null; 186 String proxyAuthorizationPassword = null; 187 HttpProxyOptions proxyOptions = builder.getHttpProxyOptions(); 188 if (proxyOptions != null) { 189 proxyConnectionType = proxyOptions.getConnectionType().getValue(); 190 TlsContext proxyTlsContext = proxyOptions.getTlsContext(); 191 if (proxyTlsContext != null) { 192 proxyTlsContextHandle = proxyTlsContext.getNativeHandle(); 193 } 194 195 proxyHost = proxyOptions.getHost(); 196 proxyPort = proxyOptions.getPort(); 197 proxyAuthorizationType = proxyOptions.getAuthorizationType().getValue(); 198 proxyAuthorizationUsername = proxyOptions.getAuthorizationUsername(); 199 proxyAuthorizationPassword = proxyOptions.getAuthorizationPassword(); 200 } 201 202 long nativeHandle = cognitoCredentialsProviderNew( 203 this, 204 clientBootstrap.getNativeHandle(), 205 tlsContext.getNativeHandle(), 206 endpoint, 207 identity, 208 builder.getCustomRoleArn(), 209 marshalLoginsForJni(builder.getLogins()), 210 proxyConnectionType, 211 proxyHost != null ? proxyHost.getBytes(UTF8) : null, 212 proxyPort, 213 proxyTlsContextHandle, 214 proxyAuthorizationType, 215 proxyAuthorizationUsername != null ? proxyAuthorizationUsername.getBytes(UTF8) : null, 216 proxyAuthorizationPassword != null ? proxyAuthorizationPassword.getBytes(UTF8) : null); 217 218 acquireNativeHandle(nativeHandle); 219 addReferenceTo(clientBootstrap); 220 addReferenceTo(tlsContext); 221 } 222 writeLengthPrefixedBytesSafe(ByteBuffer buffer, byte[] bytes)223 private void writeLengthPrefixedBytesSafe(ByteBuffer buffer, byte[] bytes) { 224 if (bytes != null) { 225 buffer.putInt(bytes.length); 226 buffer.put(bytes); 227 } else { 228 buffer.putInt(0); 229 } 230 } 231 marshalLoginsForJni(ArrayList<CognitoLoginTokenPair> logins)232 private byte[] marshalLoginsForJni(ArrayList<CognitoLoginTokenPair> logins) { 233 int size = 0; 234 235 for (CognitoLoginTokenPair login : logins) { 236 size += BUFFER_INT_SIZE * 2; 237 if (login.identityProviderName != null) { 238 size += login.identityProviderName.length; 239 } 240 241 if (login.identityProviderToken != null) { 242 size += login.identityProviderToken.length; 243 } 244 } 245 246 if (size == 0) { 247 return null; 248 } 249 250 ByteBuffer buffer = ByteBuffer.allocate(size); 251 for (CognitoLoginTokenPair login : logins) { 252 writeLengthPrefixedBytesSafe(buffer, login.identityProviderName); 253 writeLengthPrefixedBytesSafe(buffer, login.identityProviderToken); 254 } 255 256 return buffer.array(); 257 } 258 259 /******************************************************************************* 260 * Native methods 261 ******************************************************************************/ 262 cognitoCredentialsProviderNew(CognitoCredentialsProvider thisObj, long bootstrapHandle, long tlsContextHandle, String endpoint, String identity, String customRoleArn, byte[] marshalledLogins, int proxyConnectionType, byte[] proxyHost, int proxyPort, long proxyTlsContext, int proxyAuthorizationType, byte[] proxyAuthorizationUsername, byte[] proxyAuthorizationPassword)263 private static native long cognitoCredentialsProviderNew(CognitoCredentialsProvider thisObj, 264 long bootstrapHandle, 265 long tlsContextHandle, 266 String endpoint, 267 String identity, 268 String customRoleArn, 269 byte[] marshalledLogins, 270 int proxyConnectionType, 271 byte[] proxyHost, 272 int proxyPort, 273 long proxyTlsContext, 274 int proxyAuthorizationType, 275 byte[] proxyAuthorizationUsername, 276 byte[] proxyAuthorizationPassword); 277 } 278