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+
2738using namespace Aws ::CognitoIdentityProvider;
2839using namespace Aws ::CognitoIdentityProvider::Model;
2940using namespace Aws ::Client;
3041using namespace Aws ::Region;
3142
32- #define TEST_POOL_PREFIX " IntegrationTest_"
33-
3443namespace
3544{
3645static const char * ALLOCATION_TAG = " IdentityProviderOperationTest" ;
@@ -49,19 +58,64 @@ class IdentityProviderOperationTest : public ::testing::Test
4958protected:
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