When I use the below code:
$result = $this->client->adminInitiateAuth([
'AuthFlow' => 'ADMIN_NO_SRP_AUTH',
'ClientId' => $this->client_id,
'UserPoolId' => $this->userpool_id,
'AuthParameters' => [
'USERNAME' => $username,
'PASSWORD' => $password,
],
]);
I am getting a response with session and challengeName :NEW_PASSWORD_REQUIRED. From this how to generate the AccessToken in AWS-cognito?
You can use the respondToAuthChallenge method to set the user's new password and log them in. It should also return the accessToken for you.
You could do something like this:
$result = $this->client->respondToAuthChallenge([
'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
'ClientId' => $this->client_id,
'ChallengeResponses' => [
'USERNAME' => $username,
'NEW_PASSWORD' => $password,
],
'Session' => $session,
]);
You need to respond this challenge (respondToAuthChallenge) using the session returned by adminInitiateAuth method. This session is a key to respond because the user at this time not is logged yet and is valid for 3 minutes. After that, you will reveive (if the session is valid) the RefreshToken, AccessToken and IdToken.
Related
I'm trying to use respondToAuthChallenge with NEW_PASSWORD_REQUIRED to change the user's password. I keep getting "Invalid attributes given, given_name is missing" errors. I've tried adding the user's attributes to the call, but I can't seem to find any documentation on how that data should be formatted within the call.
Here is the original code...
$QUERY = $COG_CLIENT->respondToAuthChallenge([
'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
'ClientId' => $COG_CLIENT_ID,
'ChallengeResponses' => [
'USERNAME' => $USER_EMAIL,
'NEW_PASSWORD' => $USER_NEW_PASS,
'SECRET_HASH' => $SEC_HASH,
],
'Session' => $COG_USER_SESSION,
]);
Then I tried adding the user attributes like so...
$QUERY = $COG_CLIENT->respondToAuthChallenge([
'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
'ClientId' => $COG_CLIENT_ID,
'ChallengeResponses' => [
'USERNAME' => $USER_EMAIL,
'NEW_PASSWORD' => $USER_NEW_PASS,
'SECRET_HASH' => $SEC_HASH,
'UserAttributes' => '{"given_name":"Bob"}',
],
'Session' => $COG_USER_SESSION,
]);
But I'm still getting the same error. If I format the UserAttributes value as an array, I get an error saying that a string is expected.
Does anyone know how I should be passing the user attributes? I'm super lost on this one.
Ah, I think I figured it out after hours of trying many different variations... this is what finally ended up working.
$QUERY = $COG_CLIENT->respondToAuthChallenge([
'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
'ClientId' => $COG_CLIENT_ID,
'ChallengeResponses' => [
'USERNAME' => $USER_EMAIL,
'NEW_PASSWORD' => $USER_NEW_PASS,
'SECRET_HASH' => $SEC_HASH,
'userAttributes.given_name' => 'Bob',
],
'Session' => $COG_USER_SESSION,
]);
I can't believe this isn't documented somewhere.
I would like to change the password of a user in AD since there are no attribute for password in AD.
Currently running laravel framework with Adldap2-laravel package in order to manage ADLDAP operations.
Here's my ldap_auth.php
<?php
return [
'connection' => env('LDAP_CONNECTION', 'default'),
'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class,
'model' => App\User::class,
'rules' => [
Adldap\Laravel\Validation\Rules\DenyTrashed::class,
],
'scopes' => [
Adldap\Laravel\Scopes\UidScope::class
],
'identifiers' => [
'ldap' => [
'locate_users_by' => 'uid',
'bind_users_by' => 'dn',
],
'database' => [
'guid_column' => 'objectguid',
'username_column' => 'username',
],
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
],
'passwords' => [
'sync' => env('LDAP_PASSWORD_SYNC', false),
'column' => 'password',
],
'login_fallback' => env('LDAP_LOGIN_FALLBACK', false),
'sync_attributes' => [
'username' => 'uid',
'password' => 'userPassword',
'name' => 'cn',
'role' => 'l',
'category' => 'businessCategory',
'telephone_number' => 'telephoneNumber',
'email' => 'mail'
],
'logging' => [
'enabled' => env('LDAP_LOGGING', true),
'events' => [
\Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
\Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
\Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
\Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
\Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
\Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
\Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
\Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
\Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
\Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
\Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,
],
],
];
Here is my LdapController.php where I include function to reset password
public function resetPassword(Request $req)
{
$req->validate([
'userid' => 'required',
'password' => 'required|min:6|confirmed'
]);
$userLdap = Adldap::search()->where('uid', $req->userid)->firstOrFail();
$newPassword = "{SHA}" . base64_encode(pack("H*", sha1($req->password)));
$res = $userLdap->update([
'userpassword' => $newPassword
]);
//Force change AD Password
// $adPassword = str_replace("\n", "", shell_exec("echo -n '\"" . $req->password . "\"' | recode latin1..utf-16le/base64"));
// $provider = Adldap\Models\User::connect('ad');
// $dn = $provider->search()->where('cn', $req->userid)->get();
// $res = $dn->setPassword($adPassword);
if ($res) {
return back()->withSuccess('<strong>Success!</strong> Your password has been changed');
} else {
return back()->withErrors('<strong>Failed!</strong> Your password was unable to changed');
}
}
Unfortunately $res = $dn->setPassword($adPassword); returns error 'Method Adldap\Query\Collection::setPassword does not exist.'
I found an example here when I searched Google for "Adldap2-laravel change password".
$user = Adldap::users()->find('jdoe');
if ($user instanceof Adldap\Models\User) {
$oldPassword = 'password123';
$newPassword = 'correcthorsebatterystaple';
$user->changePassword($oldPassword, $newPassword);
}
If you want to reset the password, then it seems like this should work:
$user->setPassword("correcthorsebatterystaple");
$user->save();
If you want to know what's going on underneath, or how it can be done without Adldap2-laravel:
The attribute is unicodePwd. You can either "change" the password, or "reset" it.
Changing the password requires knowing the old password. This is what a user would do themselves.
Resetting a password requires the "Reset password" permission on the account, which is usually given to administrative accounts.
The documentation for unicodePwd tells you how to do both. For a "change", you send a delete instruction with the old password and an add instruction with the new one, all in the same request.
For a reset, you send a single replace instruction.
In both cases, the passwords have to be sent in a specific format.
The PHP documentation for 'ldap_modify_batch` shows an example of how to change a password.
On the documentation page for ldap_mod_replace, there is a comment that shows you how to reset a password.
When calling the following code it returns an exception
$this->client->adminSetUserPassword([
'Password' => $password,
'Permanent' => true,
'UserPoolId' => $this->poolId,
'Username' => $email,
]);
-errorCode: "UserNotFoundException"
-errorMessage: "User does not exist."
I'm using similar admin level requests elsewhere as follows...
$result = $this->client->adminDeleteUser([
'UserPoolId' => $this->poolId,
'Username' => $email,
]);
$result = $this->client->adminDisableUser([
'UserPoolId' => $this->poolId,
'Username' => $email,
]);
$response = $this->client->adminInitiateAuth([
'AuthFlow' => 'ADMIN_NO_SRP_AUTH',
'AuthParameters' => [
'USERNAME' => $email,
'PASSWORD' => $password,
'SECRET_HASH' => $this->cognitoSecretHash($email),
],
'ClientId' => $this->clientId,
'UserPoolId' => $this->poolId,
]);
All these methods and others work correctly with the user, but the new adminSetUserPassword method seems to fail, despite the user definitely being in my user pool.
I am trying to log in the user to the AWS Cognito user pool using PHP SDK. I am following this tutorial, https://sanderknape.com/2017/02/getting-started-with-aws-cognito/. But I am getting the error.
Here is my code:
$credentials = array(
'key' => env('AWS_IAM_KEY', ''),
'secret' => env('AWS_IAM_SECRET', '')
);
//2014-06-30
$client = CognitoIdentityClient::factory(array('region' => env('AWS_REGION',''), 'version' => 'latest', $credentials));
$result = $client->adminInitiateAuth([
'AuthFlow' => 'ADMIN_NO_SRP_AUTH',
'ClientId' => COGNITO_APP_CLIENT_ID,
'UserPoolId' => COGNITO_USER_POOL_ID,
'AuthParameters' => [
'USERNAME' => "name",
'PASSWORD' => 'password',
],
]);
$accessToken = $result->get('AuthenticationResult')['AccessToken'];
When I run the code, I got this error:
InvalidArgumentException
Operation not found: AdminInitiateAuth
It is saying the AdminInitiiateAuth does not exist. But I am correctly following the tutorial. What is missing in my code?
The problem here is that CognitoIdentityClient does not contain the adminInitiateAuth functionality.
You will need to use the CognitoIdentityProviderClient
I am testing in laravel and saw yesterday that you can't have followingRedirects before assertSessionHas. So I wanted to know if it is possible to have it after the assertSessionHas without repeating the whole test code. I have now this a temporary solution:
$response = $this->post('/signup', [
'username' => 'Testing',
'email' => 'testing#test.com',
'password' => 'secret',
'password_confirmation' => 'secret',
]);
$this->assertDatabaseHas('users', ['username' => 'Testing', 'email' => 'testing#test.com']);
$response->assertSessionHas('success', 'Your account has been created!');
$code = $this->followRedirects($response)->getStatusCode();
$this->assertEquals(200, $code);
But I want to know if you are able to change the response later on with the followingRedirects instead of using it this way.
When sending a post request in Laravel using PHPUnit, you don't need to pass the csrf_token(), it is included automatically.
I would refactor your code like this:
$this->post('/signup', [
'username' => 'Testing',
'email' => 'testing#test.com',
'password' => 'secret',
'password_confirmation' => 'secret',
])->assertStatus(200)
->assertSessionHas('success', 'Your account has been created!');
$user = User::latest()->first();
$this->assertEquals('Testing', $user->name);
$this->assertEquals('testing#test.com', $user->email);