My Symfony application loads its user entities from the database. Here's the entry in security.yml:
security:
encoders:
MyProject\MyBundle\Entity\UserEntity:
algorithm: bcrypt
providers:
main:
entity:
class: MyBundle:UserEntity
property: username
When I implemented this I followed Symfony’s recommendation to store a unique salt for each user, using it whenever the password is encoded:
$encoder = $this->get('security.encoder_factory')->getEncoder($user);
$encodedPassword = $encoder->encodePassword($form->getData()->getPassword(), $user->getSalt());
if ($encodedPassword === $user->getPassword()) {
// Success
}
Symfony 3.0 no longer allows you to pass a salt, so I’ve updated my logic:
$encoder = $this->get('security.password_encoder');
$encodedPassword = $encoder->encodePassword($user, $form->getData()->getPassword());
if ($encodedPassword === $user->getPassword()) {
// Success
}
But encoding without the salt obviously doesn't work. Is there any way I can get my users password working on 3.0, short of asking every one of them to reset their credentials?
The issue was that I wasn't using the isPasswordValid function. This recognises the salt that is now stored within the bcrypt encrypted password:
$encoder = $this->get('security.encoder_factory')->getEncoder($user);
$passwordValid = $encoder->isPasswordValid(
$user->getPassword(),
$form->getData()->getPassword(),
null
);
Related
By default, Strapi has a welcome email template and password reset template. For the custom function we are writing, we want to create users without a password (or random password the user doesn't know). Then, when our function is finished, we want to send the user a welcome email (overwriting/disabling the default), with a password reset link. Therefore, we need to call the function/service to reset the password for the user, and receive the URL to send this in the welcome email.
However, currently I cannot find any information regarding the function/service to reset the user password. The only method I now see is to call http://localhost/auth/reset-password with the username or email, but would like to use a service such as strapi.services.user.resetPassword(userID) to get the URL back.
Does this function exists and/or is this possible?
Using Strapi 3.1.2
I have move my original answer here since it was more relevant to the question.
To reset a user password, we have to provide an identifier which is in this case the username. The possible steps are:
Query the user based on the identifier
Generate new hash password based on provided randomly generated value
Update the user password with the newly generated hash-password.
The implementation at a controller can be like this:
module.exports = {
resetPassword: async ctx => {
....
// Provide identifier and newPassword
const params = ctx.request.body;
const identifier = params.identifier
const newPassword = params.newPassword
// Get User based on identifier
const user = await strapi.query('user', 'users permissions').findOne({username: identifier});
// Generate new hash password
const password = await strapi.plugins['users-permissions'].services.user.hashPassword({password: newPassword});
// Update user password
await strapi
.query('user', 'users-permissions')
.update({ id: user.id }, { resetPasswordToken: null, password });
...
}
}
Don't forget to implement isOwner policy, or if the old password can be provided, we can validate the process using isValidPassword
// Validate given old password against user query result password
const isValidPassword = await strapi.plugins['users-permissions'].services.user.validatePassword(old.password, user.password);
I have a running application that uses client-side Sha256 hashing.
I would like to use Laravels serverside bcrypt hashing instead.
My strategy is to wrap all passwords with bcrypt, so I have bcrypt(sha256('password')), and then rehash the password when the user attempts to log in, so I simply have bcrypt('password').
My problem is authenticating the user when they try to log in with a Sha256 password.
I try to authenticate them by running
if (hash('sha256', 'password' . 'salt') == $stored_pw)
But with no luck. I'm only fairly certain that the client-side hashing simply appends the salt, and I'm unsure if Laravels hash function adds a salt of its own.
Here's a hash created by the client from the password 1234567: $5$a0FpUG9JUgkj1d6H$eSSzXebYU87wPAWSTRJGyWw/kOMgDvPqcri4CI1QCV0
I am trying to recreate the same hash using the salt, the password, and Laravels hashing functions.
How do I specify that the Sha256 function should use a specific salt?
Try.
use phpseclib\Crypt\Hash;
or
use Hash
\Hash::make($request->password);
or
$hash = Hash::make('secret');
$input = 'secret';
if(Hash::check($input, $hash)){
// the input matches the secret
}
I use a helper
if (!function_exists('genSSH512')) {
function genSSH512($value)
{
$salt = Str::random(8);
return base64_encode(hash('sha512', $value.$salt, true).$salt);
}
}
Laravel has dedicated Facade Support for this:
use Illuminate\Support\Facades\Hash;
$hash = Hash::make($string);
if (Hash::check($stringYouWantToCompare, $hash)) {
return true; // Valid
}else {
return false; // Invalid
}
by default the password reset token emailed to email is different from one being saved to database. I have used the Hasher::make() and hash_hmac('sha256', $token, env('APP_KEY')) to hash that and then compare that token to database but invain. what should i do to transform emailed token to database token or compare them?
I also tried
public function convertToken($token)
{
if (Str::startsWith($key = env('APP_KEY'), 'base64:')) {
$key = base64_decode(substr($key, 7));
}
return hash_hmac('sha256', $token, $key);
}
The Hasher used by the Laravel default implementation can be retrieved with
$hasher = Password::broker()->getRepository()->getHasher();
You can then hash your token to add them to your database like this :
$hasher->make($token);
And you can check a token against the value stored in your database with this code :
$hasher->check($token, $databaseToken);
But why do you want to implement yourself what Laravel team has already done ? You'd better use Laravel default authentication, unless you do this for fun.
When I sign in, my login should be saved, I don't want to enter the userName Password each and every login time.
below my code :
login() {
this.userService.login(this.user)
.subscribe(
(response: any) => {
this.router.navigate(["/dashboard"]);
},
(error) => alert(error)
);
}
userService.ts
return this.http.post(
url,
JSON.stringify({
name: user.email,
password: user.password
}),
{
headers: new HttpHeaders().set('Content-Type', 'application/json'),
responseType: 'text'
}
)
.map((response: any) => {
for (var x in response) {
if (response.hasOwnProperty(x)) {
}
}
console.log("_body: " + response._body);
return response._body;
})
.catch(this.handleErrors)
}
It's good to keep in mind that any keys and values written to the UserDefaults and SharedPreferences, so the native APIs that are used by the application settings module and the getString and setString methods are simply stored on the disk, for anyone with access to the phone to see. This API is not meant for storing sensitive data, and is meant solely for persisting user settings, so 'defaults' and 'preferences'.
If you want a way to securely store email addresses and passwords on the device, take a look at this library: Nativescript-secure-storage. It does a very similar job to the aforementioned APIs but everything is encrypted so people can't just read the contents from the disk.
NativeScript has exposed the application-settings module. The Application Settings module is used to store strings, booleans, and numbers in a built-in key/value store. Uses SharedPreferences on Android and NSUserDefaults on iOS.
So for example, you could store the login information and use it to check if the user has already been logged in (just as you would do in native Android & iOS projects) - demo POC here
Just like #Nick suggested, you can use application-settings module to store your access token that you can use for underground check later when the user returns.
After successful initial login attempt, get your JWT token from the login process ( or whatever authentication mode you chosse ) and to store it for re-authentication later or just check if the key/[value] is set previously and can be used for simple offline login as well.
use JWT, also you can use offline data.
look at this link for example:
https://medium.com/#njwest/building-a-react-native-jwt-client-api-requests-and-asyncstorage-d1a20ab60cf4
you can use local storage.
You may have
<TextField hint="{{ 'user_name' | L }}" autocorrect="false" required autocapitalizationType="none" [(ngModel)]="model.email"
#emailModel="ngModel" name="email" keyboardType="email"></TextField>
While logging in the component, save it in localstorage
localStorage.setString("username", this.model.email);
in ngOnInit(), you can fetch it back
localStorage.getString("username");
I'm using the this tutorial to secure my Web-API calls with basic auth. Basically it checks if there is a auth header on the request and then proves this header against a database:
public static bool CheckPassword(string user, string password)
{
//Do a Database checkup
if(CheckDB(user,password)) {
//if true, set the principal
var identity = new GenericIdentity(user);
SetPrincipal(new GenericPrincipal(identity,null));
}
else {
//return 401...
}
}
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
This is working fine. But it queries the database for every request I do. Even when I just request a JavaScript file.
I like to optimize this process and just call CheckDB() on the first request. All following request should not need another database request. Is it possible to save the Principal? I tried to check Thread.CurrentPrincipal but it seams to reinitialize on every request.
You have a couple of options:
If you have a simple topology with only a single machine handling requests for a relatively small number of users you could implement an in memory cache of usernames and passwords that you can use to efficiently validate subsequent calls. You could implement this using something like ConcurrentDictionary that keys off the username and gives the password, although there are security considerations to such an approach (do you really want passwords to be in memory all the time?).
Set a cookie after a username/password pair has been validated. The cookie could contain something like the timestamp after which the username/password should be revalidated, along with some kind of hash that's generated by a means that only the server knows (and that it can use to validate that it set the timestamp).
With either of these approaches the "CheckPassword" method would either compare the password with the one from the cache, or checking the cookie, and if the result is satisfactory directly create a new principal without calling the database.