Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit da489d7

Browse files
committedMar 13, 2025·
cognito-idp integration test
1 parent 2b534e6 commit da489d7

File tree

3 files changed

+270
-78
lines changed

3 files changed

+270
-78
lines changed
 

‎src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4aSigner.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ namespace smithy {
290290
const bool m_includeSha256HashHeader{true};
291291
const bool m_urlEscape{true};
292292
const Aws::Set<Aws::String> m_unsignedHeaders{USER_AGENT,X_AMZN_TRACE_ID};
293-
const Aws::Crt::Auth::SignatureType m_signatureType{Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders};
293+
const Aws::Crt::Auth::SignatureType m_signatureType{Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams};
294294
std::condition_variable m_cv;
295295
std::mutex m_mutex;
296296
};

‎tests/aws-cpp-sdk-cognitoidentityprovider-integration-tests/CMakeLists.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ find_package(OpenSSL REQUIRED)
3737
# Include directories for OpenSSL headers
3838
include_directories(${OPENSSL_INCLUDE_DIR})
3939

40-
target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS})
40+
target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS} OpenSSL::Crypto)
4141

4242

4343

‎tests/aws-cpp-sdk-cognitoidentityprovider-integration-tests/OperationTest.cpp‎

Lines changed: 268 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,32 @@
1414
#include <aws/cognito-idp/model/AuthFlowType.h>
1515
#include <aws/cognito-idp/model/ExplicitAuthFlowsType.h>
1616
#include <aws/cognito-idp/model/InitiateAuthRequest.h>
17-
#include <aws/cognito-idp/model/CreateUserPoolClientRequest.h>
1817
#include <aws/cognito-idp/model/SignUpRequest.h>
18+
#include <aws/cognito-idp/model/CreateUserPoolClientRequest.h>
1919
#include <aws/cognito-idp/model/DeleteUserPoolClientRequest.h>
20+
#include <aws/cognito-idp/model/CreateUserPoolRequest.h>
21+
#include <aws/cognito-idp/model/DeleteUserPoolRequest.h>
22+
#include <aws/cognito-idp/model/AdminCreateUserRequest.h>
23+
#include <aws/cognito-idp/model/AdminDeleteUserRequest.h>
24+
#include <aws/cognito-idp/model/MessageActionType.h>
25+
#include <aws/cognito-idp/CognitoIdentityProviderServiceClientModel.h>
2026

2127
#include <aws/core/client/CoreErrors.h>
2228
#include <aws/core/utils/json/JsonSerializer.h>
2329
#include <aws/core/utils/Outcome.h>
2430
#include <aws/testing/TestingEnvironment.h>
2531
#include <aws/core/platform/Environment.h>
26-
#include <openssl/srp.h>
32+
#include <openssl/sha.h>
33+
#include <openssl/evp.h>
34+
#include <openssl/hmac.h>
35+
#include <openssl/bn.h>
36+
37+
2738
using namespace Aws::CognitoIdentityProvider;
2839
using namespace Aws::CognitoIdentityProvider::Model;
2940
using namespace Aws::Client;
3041
using namespace Aws::Region;
3142

32-
#define TEST_POOL_PREFIX "IntegrationTest_"
33-
3443
namespace
3544
{
3645
static const char* ALLOCATION_TAG = "IdentityProviderOperationTest";
@@ -49,19 +58,64 @@ class IdentityProviderOperationTest : public ::testing::Test
4958
protected:
5059

5160
const Aws::String m_clientName{"testClient"};
61+
Aws::String m_userPoolId;
62+
Aws::String m_clientId;
63+
const Aws::String m_username{"testUser"};
64+
Aws::String m_clientSecret;
5265

5366
void SetUp()
5467
{
5568
Aws::Client::ClientConfiguration config;
5669
config.region = AWS_TEST_REGION;
5770

58-
//TODO: move this over to profile config file.
5971
client = Aws::MakeShared<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient>(ALLOCATION_TAG, config);
72+
73+
//make user pool
74+
m_userPoolId = createUserPool("TestPool");
75+
76+
ASSERT_TRUE(!m_userPoolId.empty());
77+
78+
//make client
79+
if(!m_userPoolId.empty())
80+
{
81+
auto ret = createPoolClient(m_userPoolId, m_clientName);
82+
m_clientId = ret.first;
83+
m_clientSecret = ret.second;
84+
}
85+
86+
ASSERT_TRUE(!m_clientId.empty());
87+
ASSERT_TRUE(!m_clientSecret.empty());
88+
89+
//create user
90+
if(!m_userPoolId.empty() && !m_clientId.empty())
91+
{
92+
ASSERT_TRUE(createUser(m_username, "Password123!", m_userPoolId));
93+
}
94+
6095
}
6196

6297
void TearDown()
6398
{
64-
client = nullptr;
99+
100+
//delete user
101+
if(!m_userPoolId.empty())
102+
{
103+
ASSERT_TRUE(deleteUser(m_username, m_userPoolId));
104+
}
105+
106+
// delete client
107+
if(!m_userPoolId.empty() && !m_clientId.empty())
108+
{
109+
ASSERT_TRUE(deletePoolClient(m_userPoolId, m_clientId));
110+
}
111+
112+
// delete user pool
113+
if(!m_userPoolId.empty())
114+
{
115+
ASSERT_TRUE(deleteUserPool(m_userPoolId));
116+
}
117+
118+
65119
if (::testing::Test::HasFailure())
66120
{
67121
std::cout << "Test traces: " << testTrace << "\n";
@@ -70,125 +124,263 @@ class IdentityProviderOperationTest : public ::testing::Test
70124
}
71125

72126

73-
void registerUser(const Aws::String& username, const Aws::String& password)
74-
{
75-
// Set up the request for creating a new User Pool Client
76-
Aws::CognitoIdentityProvider::Model::SignUpRequest request;
77-
request.SetClientId(m_clientName);
78-
request.SetUsername(username);
79-
request.SetPassword(password);
127+
Aws::String createUserPool(Aws::String poolName)
128+
{
129+
if(poolName.empty())
130+
{
131+
return {};
132+
}
133+
Aws::CognitoIdentityProvider::Model::CreateUserPoolRequest userPoolRequest;
134+
userPoolRequest.SetPoolName(poolName);
135+
136+
CreateUserPoolOutcome userPoolOutcome = client->CreateUserPool(userPoolRequest);
137+
//ASSERT_TRUE(userPoolOutcome.IsSuccess());
138+
if (!userPoolOutcome.IsSuccess()) {
139+
return {};
140+
}
141+
142+
auto poolId = userPoolOutcome.GetResult().GetUserPool().GetId();
143+
std::cout << "Created User Pool with ID: " << poolId << " for pool name="<<poolName<<std::endl;
144+
return poolId;
145+
}
80146

81-
auto outcome = client->SignUp(request);
82-
ASSERT_TRUE(outcome.IsSuccess());
83-
if (outcome.IsSuccess())
147+
bool deleteUserPool(const Aws::String& poolId)
148+
{
149+
if (poolId.empty())
84150
{
85-
std::cout << "User registered successfully." << std::endl;
86-
std::cout << "User confirmed: " << (outcome.GetResult().GetUserConfirmed() ? "Yes" : "No") << std::endl;
87-
std::cout << "User sub: " << outcome.GetResult().GetUserSub() << std::endl;
151+
return false;
152+
}
153+
Aws::CognitoIdentityProvider::Model::DeleteUserPoolRequest deletePoolRequest;
154+
deletePoolRequest.SetUserPoolId(poolId);
155+
156+
auto deletePoolOutcome = client->DeleteUserPool(deletePoolRequest);
157+
//ASSERT_TRUE(deletePoolOutcome.IsSuccess());
158+
if (!deletePoolOutcome.IsSuccess()) {
159+
std::cerr << "Failed to delete User Pool: " << deletePoolOutcome.GetError().GetMessage() << std::endl;
160+
}
161+
else
162+
{
163+
std::cout << "Deleted User Pool with ID: " << poolId << std::endl;
164+
}
165+
return deletePoolOutcome.IsSuccess();
166+
}
167+
168+
bool createUser(const Aws::String& username, const Aws::String& password, const Aws::String& userPoolId)
169+
{
170+
if (userPoolId.empty() || username.empty() || password.empty())
171+
{
172+
return false;
173+
}
174+
175+
Aws::CognitoIdentityProvider::Model::AdminCreateUserRequest createUserRequest;
176+
createUserRequest.SetUserPoolId(userPoolId);
177+
createUserRequest.SetUsername(username);
178+
179+
Aws::CognitoIdentityProvider::Model::AttributeType emailAttribute;
180+
emailAttribute.SetName("email");
181+
emailAttribute.SetValue("testuser@example.com");
182+
createUserRequest.AddUserAttributes(emailAttribute);
183+
184+
// Set a temporary password
185+
createUserRequest.SetTemporaryPassword(password);
186+
187+
// Suppress sending an email to the user
188+
createUserRequest.SetMessageAction(Aws::CognitoIdentityProvider::Model::MessageActionType::SUPPRESS);
189+
190+
auto outcome = client->AdminCreateUser(createUserRequest);
191+
//ASSERT_TRUE(outcome.IsSuccess());
192+
if (outcome.IsSuccess()) {
193+
std::cout << "User created successfully: " << outcome.GetResult().GetUser().GetUsername() << std::endl;
194+
} else {
195+
std::cerr << "Failed to create user: " << outcome.GetError().GetMessage() << std::endl;
196+
}
88197

198+
return outcome.IsSuccess();
199+
}
89200

201+
bool deleteUser(const Aws::String& username, const Aws::String& userPoolId)
202+
{
203+
if (username.empty() || userPoolId.empty())
204+
{
205+
return false;
206+
}
207+
208+
Aws::CognitoIdentityProvider::Model::AdminDeleteUserRequest deleteUserRequest;
209+
deleteUserRequest.SetUserPoolId(userPoolId);
210+
deleteUserRequest.SetUsername(username);
211+
auto deleteUserOutcome = client->AdminDeleteUser(deleteUserRequest);
212+
//ASSERT_TRUE(deleteUserOutcome.IsSuccess());
213+
if (!deleteUserOutcome.IsSuccess()) {
214+
std::cerr << "Failed to delete user: " << deleteUserOutcome.GetError().GetMessage() << std::endl;
90215
}
216+
else
217+
{
218+
std::cout << "Deleted test user: " << username << std::endl;
219+
}
220+
return deleteUserOutcome.IsSuccess();
91221
}
92222

93-
CreateUserPoolClientOutcome createPoolClient()
223+
224+
std::pair<Aws::String, Aws::String> createPoolClient(const Aws::String& userPoolId, const Aws::String& clientName)
94225
{
95-
// Set up the request for creating a new User Pool Client
226+
if(userPoolId.empty() || clientName.empty())
227+
{
228+
return {};
229+
}
230+
96231
Aws::CognitoIdentityProvider::Model::CreateUserPoolClientRequest request;
97-
request.SetUserPoolId("test-pool-id");
98-
request.SetClientName("testClient");
232+
request.SetUserPoolId(userPoolId);
233+
request.SetClientName(clientName);
99234

100-
request.SetGenerateSecret(true); // If you need a secret for your client
101-
Aws::Vector<Aws::CognitoIdentityProvider::Model::ExplicitAuthFlowsType> authFlows{Aws::CognitoIdentityProvider::Model::ExplicitAuthFlowsType::ALLOW_USER_SRP_AUTH};
235+
request.SetGenerateSecret(true);
236+
Aws::Vector<Aws::CognitoIdentityProvider::Model::ExplicitAuthFlowsType> authFlows{Aws::CognitoIdentityProvider::Model::ExplicitAuthFlowsType::ALLOW_USER_SRP_AUTH, Aws::CognitoIdentityProvider::Model::ExplicitAuthFlowsType::ALLOW_REFRESH_TOKEN_AUTH};
102237
request.SetExplicitAuthFlows(authFlows);
103238

104-
// Make the call to create the user pool client
105-
auto outcome = client->CreateUserPoolClient(request);
106-
ASSERT_TRUE(outcome.IsSuccess());
239+
Aws::CognitoIdentityProvider::Model::CreateUserPoolClientOutcome outcome = client->CreateUserPoolClient(request);
240+
//ASSERT_TRUE(outcome.IsSuccess());
241+
Aws::String clientId, clientSecret;
107242
if (outcome.IsSuccess())
108243
{
244+
clientId = outcome.GetResult().GetUserPoolClient().GetClientId();
245+
clientSecret = outcome.GetResult().GetUserPoolClient().GetClientSecret();
109246
std::cout << "User Pool Client created successfully." << std::endl;
110-
std::cout << "Client ID: " << outcome.GetResult().GetUserPoolClient().GetClientId() << std::endl;
111-
if (request.GetGenerateSecret())
112-
{
113-
std::cout << "Client Secret: " << outcome.GetResult().GetUserPoolClient().GetClientSecret() << std::endl;
114-
}
247+
std::cout << "Client ID: " << clientId << std::endl;
115248
}
116-
return outcome;
249+
return {clientId,clientSecret};
117250
}
118251

119-
void deletePoolClient()
252+
bool deletePoolClient(const Aws::String& userPoolId, const Aws::String& clientId)
120253
{
121254
// Set up the request for deleting the User Pool Client
122255
Aws::CognitoIdentityProvider::Model::DeleteUserPoolClientRequest request;
123-
request.SetUserPoolId("test-pool-id");
124-
request.SetClientId("testClient");
256+
request.SetUserPoolId(userPoolId);
257+
request.SetClientId(clientId);
125258

126259
// Make the call to delete the user pool client
127260
auto outcome = client->DeleteUserPoolClient(request);
128-
ASSERT_TRUE(outcome.IsSuccess());
129261
if (outcome.IsSuccess())
130262
{
131263
std::cout << "User Pool Client deleted successfully." << std::endl;
132264
}
265+
//ASSERT_TRUE(outcome.IsSuccess());
266+
return outcome.IsSuccess();
133267
}
134268

135-
136269
};
137270

138271

139-
140-
141-
142-
143-
TEST_F(IdentityProviderOperationTest, testSecret)
272+
Aws::String ComputeSecretHash(const Aws::String &userPoolClientId, const Aws::String &clientSecret, const Aws::String &userName)
144273
{
145-
auto outcome = createPoolClient();
274+
const auto message = userName + userPoolClientId;
275+
unsigned char hash[EVP_MAX_MD_SIZE];
276+
unsigned int len = 0;
277+
278+
HMAC(EVP_sha256(),
279+
clientSecret.c_str(), clientSecret.length(),
280+
(unsigned char*)message.c_str(), message.length(),
281+
hash, &len);
282+
283+
// Base64 encode the hash
284+
char encoded[128];
285+
EVP_EncodeBlock((unsigned char*)encoded, hash, len);
146286

287+
return std::string(encoded);
288+
}
289+
// https://github.com/aws/amazon-cognito-identity-js/blob/master/src/AuthenticationHelper.js#L22
290+
const char* initN =
291+
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
292+
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
293+
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
294+
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
295+
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
296+
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
297+
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
298+
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
299+
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
300+
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
301+
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
302+
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
303+
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
304+
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
305+
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
306+
"43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
307+
// https://github.com/aws/amazon-cognito-identity-js/blob/master/src/AuthenticationHelper.js#
308+
const char* generator = "2";
309+
310+
311+
class SRPClient {
312+
public:
313+
SRPClient(const std::string& N_hex, const std::string& g):N(BN_new()), g(BN_new()), a(nullptr), A(BN_new()), ctx(BN_CTX_new())
314+
{
315+
if (!BN_hex2bn(&N, N_hex.c_str())) {
316+
std::cout<<"Failed to load N"<<std::endl;
317+
}
318+
319+
if (!BN_dec2bn(&this->g, g.c_str())) {
320+
std::cout<<"Failed to load g"<<std::endl;
321+
}
147322

148-
Aws::String ComputeSecretHash(const Aws::String &userPoolClientId, const Aws::String &userPoolClientSecret, const Aws::String &userName)
323+
generatePrivateKey(256);
324+
}
325+
~SRPClient()
149326
{
150-
const auto secret = userPoolClientSecret;
151-
const auto message = userName + userPoolClientId;
152-
153-
unsigned char * digest = HMAC(EVP_sha256(),
154-
secret.c_str(), static_cast<int>(secret.length()),
155-
reinterpret_cast<const unsigned char*>(message.c_str()),
156-
static_cast<int>(message.length()),
157-
NULL, NULL);
158-
159-
char mdString[SHA256_DIGEST_LENGTH * 2 + 1];
160-
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
161-
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
327+
BN_free(N);
328+
BN_free(g);
329+
BN_free(a);
330+
BN_free(A);
331+
BN_CTX_free(ctx);
332+
}
162333

163-
mdString[64] = '\0'; // null-terminate the string
164-
165-
return Aws::String(mdString);
334+
335+
private:
336+
BIGNUM* N{nullptr};
337+
BIGNUM* g{nullptr};
338+
BIGNUM* a{nullptr};
339+
BIGNUM* A{nullptr};
340+
BN_CTX* ctx;
341+
342+
void generatePrivateKey(int bits)
343+
{
344+
a = BN_new();
345+
if (!BN_rand(a, bits, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY)) {
346+
std::cout<<"Failed to generate private key"<<std::endl;
347+
}
166348
}
167349

350+
public:
351+
std::string calculateA() const
352+
{
353+
if (!BN_mod_exp(A, g, a, N, ctx)) {
354+
std::cout<<"Failed to compute A = g^a % N"<<std::endl;
355+
return {};
356+
}
357+
358+
char* A_hex = BN_bn2hex(A);
359+
std::string A_str(A_hex);
360+
OPENSSL_free(A_hex);
361+
362+
return A_str;
363+
}
364+
};
168365

169-
Aws::Map<Aws::String, Aws::String> authParameters;
170-
authParameters["USERNAME"] = "dummyuser"; // Replace with actual username
171366

172-
// Compute SECRET_HASH if the client has a secret
173-
const Aws::String clientId = outcome.GetResult().GetUserPoolClient().GetClientId(); // Client ID from previous step
174-
const Aws::String clientSecret = outcome.GetResult().GetUserPoolClient().GetClientSecret(); // Client Secret if generated
175-
authParameters["SECRET_HASH"] = ComputeSecretHash(clientId, clientSecret, "dummyuser");
176367

177-
// Note: SRP_A is part of the SRP protocol, you need to implement or use a library for SRP
178-
// This is a placeholder for a correct SRP implementation:
179-
authParameters["SRP_A"] = "dummy"; // Replace with actual SRP_A value
368+
TEST_F(IdentityProviderOperationTest, testSecret)
369+
{
370+
SRPClient srpclient(initN, generator);
371+
Aws::Map<Aws::String, Aws::String> authParameters;
372+
authParameters["USERNAME"] = m_username;
373+
authParameters["SECRET_HASH"] = ComputeSecretHash(m_clientId, m_clientSecret, m_username);
374+
auto srpa = srpclient.calculateA();
375+
ASSERT_TRUE(!srpa.empty());
376+
authParameters["SRP_A"] = srpa;
180377

181378
Aws::CognitoIdentityProvider::Model::InitiateAuthRequest authRequest;
182-
authRequest.SetClientId(clientId); // Client ID from when you created the client
379+
authRequest.SetClientId(m_clientId);
183380
authRequest.SetAuthFlow(Aws::CognitoIdentityProvider::Model::AuthFlowType::USER_SRP_AUTH);
184381
authRequest.SetAuthParameters(authParameters);
185-
186382
Aws::CognitoIdentityProvider::Model::InitiateAuthOutcome authResult = client->InitiateAuth( authRequest );
187-
188383
EXPECT_TRUE(authResult.IsSuccess());
189-
190-
191-
deletePoolClient();
192384
}
193385

194386
}

0 commit comments

Comments
 (0)
Please sign in to comment.