I'm trying to migrate users from an old Drupal 6 CMS to Keycloak. I'd like to migrate the users with their old passwords and then assigning an "Update Password" required action to their profile.
However migrating the passwords seems problematic as I can only access them in their hashed form.
The passwords are hashed with an MD5 algorithm using no salt.
I've tried migrating them according to this page:
https://lists.jboss.org/pipermail/keycloak-user/2015-December/004212.html
Here's the JSON I'm sending to the Keycloak REST API:
{
"hashedSaltedValue" : "password-hash",
"algorithm" : "restcomm-md5",
"type" : "password",
}
Here's a list of things I've tried
Included a NULL hash value
Included a 0 hashIteration value
Base64 encoded the hash
Converted the hash to binary and then Base64 encoding it
Has anyone ever had any luck getting this feature working?
The following curl command worked for me to migrate a old hashed password. Replace {hashedSaltedValue} with your hashed password and {salt} with you salt.
token="..."
curl 'http://keycloak-http/auth/admin/realms/testrealm/users/f:60f0ff50-2cc5-492d-8222-04ac0a9964e1:217b93e8-2830-4392-83e3-9feceea94575' \
-X PUT \
-H "Authorization: $token" \
-H "Content-Type: application/json" \
--data '{"credentials": [ { "algorithm": "pbkdf2-sha512", "hashedSaltedValue": "{hashedpassword}", "hashIterations": 30000, "type": "password", "salt":"{salt}"}]}'
The parameters hashedSaltedValue etc. are deprecated and keycloak 10 and newer will log a deprecation warning.
There is a new CredentialRepresentation defined where you put JSON into the strings for attributes secretData and credentialData.
I'm so late, but my answer may be useful for someone. I have the same problem, we don't want to notify our users to reset password. We are creating users by Keycloak Admin REST API java client. Our user's password are hashed by MD5 algorithm. By default KK don't support MD5, that's why firstly we import custom MD5 password hash provider. Below piece of code that help us.
#Test
public void createUser() {
UserDTO user = UserDTO.builder()
.email("dake#mail.ru")
.username("dake#mail.ru")
.emailVerified(true)
.build();
String rawPassword = "barcelona";
String md5Password = "dea56e47f1c62c30b83b70eb281a6c39";
UserRepresentation userRepresentation = convertToUserRepresentation(user);
//setUserRepresentationPassword(userRepresentation, rawPassword, true);
setUserRepresentationPassword(userRepresentation, md5Password, false);
createUser(userRepresentation);
}
public static UserRepresentation convertToUserRepresentation(UserDTO userDTO) {
UserRepresentation userRepresentation = new UserRepresentation();
userRepresentation.setId(userDTO.getId());
userRepresentation.setEnabled(true);
userRepresentation.setUsername(userDTO.getUsername());
userRepresentation.setFirstName(userDTO.getFirstName());
userRepresentation.setLastName(userDTO.getLastName());
userRepresentation.setEmail(userDTO.getEmail());
userRepresentation.setEmailVerified(userDTO.isEmailVerified());
userRepresentation.singleAttribute("cityId", userDTO.getCityId() != null ? "" + userDTO.getCityId() : null);
userRepresentation.singleAttribute("phone", userDTO.getPhone());
userRepresentation.singleAttribute("phoneVerified", "" + userDTO.isPhoneVerified());
userRepresentation.singleAttribute("notificationsEnabled", "" + userDTO.isNotificationsEnabled());
return userRepresentation;
}
/**
* #return User uuid
*/
public String createUser(UserRepresentation userRepresentation) {
if (CollectionUtils.isEmpty(userRepresentation.getGroups())) {
userRepresentation.setGroups(Arrays.asList(GROUP_USERS));
}
RealmResource realm = keycloak.realm(realmName);
Response response = realm.users().create(userRepresentation);
if (response.getStatus() < 200 || response.getStatus() > 299) {
String error = "User create error: " + response.readEntity(String.class);
log.error(error);
throw new RuntimeException(error);
}
// Extract the uuid of the user we just created.
String location = response.getMetadata().get("Location").get(0).toString();
String uuid = location.substring(location.lastIndexOf("/") + 1);
log.info("User created: " + uuid);
return uuid;
}
/**
* Set password for user
*
* #param userRepresentation user
* #param password raw(plaintext) password or hashed password(this way is deprecated)
* #param isRawPassword password is plaintext
*/
#SneakyThrows
public static void setUserRepresentationPassword(UserRepresentation userRepresentation, String password, boolean isRawPassword) {
CredentialRepresentation credential = new CredentialRepresentation();
credential.setType(CredentialRepresentation.PASSWORD);
credential.setTemporary(false);
if (isRawPassword) {
credential.setValue(password);
} else {
Field algorithm = credential.getClass().getDeclaredField("algorithm");
algorithm.setAccessible(true);
algorithm.set(credential, "MD5");
Field hashIterations = credential.getClass().getDeclaredField("hashIterations");
hashIterations.setAccessible(true);
hashIterations.set(credential, 0);
Field hashedSaltedValue = credential.getClass().getDeclaredField("hashedSaltedValue");
hashedSaltedValue.setAccessible(true);
hashedSaltedValue.set(credential, password);
}
userRepresentation.setCredentials(Arrays.asList(credential));
}
After that everything is good. I noticed, after I logged in my MD5 password are automatically converted to pbkdf2-sha256.
Keycloak reset-password api is, what you're trying to use?
Using "reset-password" api, I believe it only accepts plain text password, which means, you can't reset-password with already hashed password value.
If you use create user api, then you can add hashed value as password.
I am using Aerobase with Keycloak and try to update password using reset-password api, it's not working with hashed password, it only works with plain text password and then store hashed password instead.
If there's anyone who's successfully reset-password with hashed password, please leave comment here!
Related
I am working on prestashop web services for my android app, i searched a lot in google, but i did not find proper document/proper explanation. Can any one please guide me how to do user login/authentication using prestashop web services?.
You can make a call to the customer endpoint filtering by the customer's email. The result would have a "passwd" field, which is a hashed password which could either be md5 or bcrypt since Prestashop supports both. You can then hash the customer's password input and compare with the "passwd" field in the response. If the length of the "passwd" field is 32 (md5), you'll need parameter _COOKIE_KEY_ set in /app/config/parameters.php as a salt to generate your hash;
Make the call like this https://yourprestashopurl.com/api/customers?filter[email]=email#email.com&display=full
For md5 (if passwd is 32 characters long):
$hash = md5(_COOKIE_KEY_ . $input_password);
You can then compare $hash with passwd
For bcrypt (if passwd is 60 characters long):
Option 1:
$verify = password_verify($input_password, passwd);
You can accept $input_password when this returns true, otherwise $input_password is invalid
Option 2:
$hash = password_hash($input_password, PASSWORD_BCRYPT);
You can then compare $hash with passwd
Note: password_hash and password_verify are both built-in php functions since PHP 5.5.0
Use the PrestaShop webservices and filter with email and password like below:
http://localhost/api/customers/?filter[email]=test#prestashop.com&filter[password]=19910794b7c0b413e80f58298a8d8300
For those who are still searching for this answer:
<?php
if (isset($_GET["email"]) && isset($_GET["password"]))
{
$email = $_GET["email"];
$password = $_GET["password"];
$COOKIE_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$jsonurl = "https://XXXXXXXXXXXXXXXXXXXX#example.com/api/customers?filter[email]=".$email."&display=[passwd]&output_format=JSON";
$json = file_get_contents($jsonurl);
$json_a = json_decode($json, true);
$loopone = $json_a['customers'];
$looptwo = $loopone[0];
$loopthree = $looptwo['passwd'];
$ZCpassword = md5($COOKIE_KEY . $password);
if (strcmp($loopthree, $ZCpassword) == 0) {
echo "sucess";
} else {
echo "fail";
}
}
else
{
echo "Error";
}
?>
I have to modify the password of an account on a vtiger crm. The problem is that I don't know the location of the database.
Anyone know the path of the database containing the credential of the users?
If your username starts with 'ad' like 'admin'. use the following mysql query
UPDATE vtiger_users SET user_password = '$1$ad000000$mnnPAFfqzJOuoYY7aB.mR0' WHERE user_name='admin';
This query will reset the password for user with admin username. The password will be set to password.
Vtiger use encrypt_password function in Users.php on line 264 to encrypt user password.
modules/Users/Users.php
It use crypt_type and username for encrypt new passwords. so Mysql query only work if your username starts with ad for example 'admin' , 'adam' and etc.
function encrypt_password($user_password, $crypt_type='') {
// encrypt the password.
$salt = substr($this->column_fields["user_name"], 0, 2);
// Fix for: http://trac.vtiger.com/cgi-bin/trac.cgi/ticket/4923
if($crypt_type == '') {
// Try to get the crypt_type which is in database for the user
$crypt_type = $this->get_user_crypt_type();
}
// For more details on salt format look at: http://in.php.net/crypt
if($crypt_type == 'MD5') {
$salt = '$1$' . $salt . '$';
} elseif($crypt_type == 'BLOWFISH') {
$salt = '$2$' . $salt . '$';
} elseif($crypt_type == 'PHP5.3MD5') {
//only change salt for php 5.3 or higher version for backward
//compactibility.
//crypt API is lot stricter in taking the value for salt.
$salt = '$1$' . str_pad($salt, 9, '0');
}
$encrypted_password = crypt($user_password, $salt);
return $encrypted_password;
}
You can use the following tools on Github. it can change all users password without login into crm and phpmyadmin and update vtiger user privileges file.
https://github.com/spadana2004/Vtiger-CRM-Reset-Password-Tools
Go to My preferences(right top of the browser). There you can change the password of the user.
In database you can't change bcoz there it will be converted to MD5. Then also for your kind information in database check the table vtiger_users for user detail.
update vtiger_users set user_password = 'adpexzg3FUZAk', crypt_type = '' where id = '1';
Login: admin
Password:admin
To make this really easy for admins I created a simple gist that will generate the sql query you need to run to reset a password with any username. Just put in the username and temp password, then run the script and use the SQL it provides. After that just login with that username and password. It is tested with and working on VTiger 7.2.
https://gist.github.com/mav2287/59d5587c7efabdbb105b739c4bc27cb5
<?php
// Put in your username as found in the "vtiger_users" table under the "username" column
$user_name = "";
// Set your TEMPORARY password. You NEED to reset your password after using this to reset it.
$user_password = "password";
// return the approiate stamtent
echo "Run the following SQL query to reset your password: \n";
echo "\"UPDATE vtiger_users SET user_password='".crypt($user_password, substr($user_name, 0, 2))."',crypt_type=''WHERE user_name='".$user_name."'\"";
I used the following code to hash the password:
$password = $_POST['user_pass'];
$hash = wp_hash_password('$password');
What am I missing? The error I get is
ERROR: The password you entered for the username willshatner is incorrect.
This code will not input the password you have sent, because of the single quotes:
$hash = wp_hash_password('$password'); // here the password is set to the string $password
use this code instead:
$hash = wp_hash_password($password); // here the password is set to the value of the variable $password
Since the password is MD5 encrypted, you'd prob have to encrypt the POST to match the db
$password = MD5($_POST['user_pass']);
I am using SOAP Partner API and I have a Developer edition. I am creating users by using API. And upon creation of users I want to email these users temporary password which they can use to login to SalesForce.
This is my code:
SaveResult[] results = connection.create(new SObject[] { user });
if (results[0].isSuccess())
{
out.println("Created user: " + results[0].getId());
//connection.setPassword(results[0].getId(), "password");
ResetPasswordResult rpr = connection.resetPassword(results[0].getId());
String result = rpr.getPassword();
System.out.println("The temporary password for user ID " + results[0].getId()
+ " is " + result);
}
else
{
out.println("Error: " + results[0].getErrors()[0].getStatusCode() +
":" + results[0].getErrors()[0].getMessage());
}
This is the output I am getting in console:
The temporary password for user ID 005E0000000MwkZIAS is ucQD2PADs
However, the user is NOT receiving any password. :-(
Thanks,
Wap Rau
If you build & pass an EmailHeader in your soap request you can control what types of emails will get sent from your request.
It looks like you're using WSC, so you can add this call before calling resetPassword, which will enabled emails being sent to users. This should then send the standard reset password email.
connection.setEmailHeader(false, false, true);
use this class to send out an email. include the pwd variable in the string you want to send the user. there's an example that spells everything out
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_email_outbound.htm
I want to move to Symfony2, because I am totally impressed by its modernity and good programming.
Now I am taking a users table from my old system, with 10,000 users, and I don't want to anger them by making them set a new password....so I want them to be able to login with their old password
Here is pseudo-code of how my users table looks like with 3 major fields concerning login/signup:
id, int(10) unsigned NOT NULL
username varchar(40) NOT NULL
passhash varchar(32) NOT NULL
secret varchar(20) NOT NULL
on signup, the data gets generated this way:
$secret = mksecret ();
$passhash = md5 ($secret . $password_formfield . $secret);
on login, the data gets checked the following way:
if ($row['passhash'] != md5 ($row['secret'] . $password_formfield . $row['secret']))
{
//show login error
}
So how do I handle it best in FOSUserBundle, without having to edit too many files?
You need to create a custom password encoder:
<?php
use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
class MyPasswordEncoder extends BasePasswordEncoder
{
public function encodePassword($raw, $salt)
{
return md5($salt.$raw.$salt);
}
public function isPasswordValid($encoded, $raw, $salt)
{
return $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
}
}
And configure it in security.yml:
services:
my_password_encoder:
class: MyPasswordEncoder
security:
encoders:
FOS\UserBundle\Model\UserInterface: { id: my_password_encoder }
As long as User::getSalt() returns secret and User::getPassword() returns passhash you should be good to go.
It is very easy to do with FOSUserBundle. This is the code for it:
$userManager = $this->get('fos_user.user_manager');
foreach ($items as $item) {
$newItem = $userManager->createUser();
//$newItem->setId($item->getObjId());
// FOSUserBundle required fields
$newItem->setUsername($item->getUsername());
$newItem->setEmail($item->getEmail());
$newItem->setPlainPassword($item->getPassword()); // get original password
$newItem->setEnabled(true);
$userManager->updateUser($newItem, true);
}