0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

feat(core,schemas): add support for argon2d and argon2id (#6404)

This commit is contained in:
wangsijie 2024-08-06 15:12:47 +08:00 committed by GitHub
parent 43d5bd248c
commit d56bc2f731
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 88 additions and 3 deletions

View file

@ -0,0 +1,10 @@
---
"@logto/schemas": minor
"@logto/core": minor
---
add support for new password digest algorithm argon2d and argon2id
In `POST /users`, the `passwordAlgorithm` field now accepts `Argon2d` and `Argon2id`.
Users with those algorithms will be migrated to `Argon2i` upon succussful sign in.

View file

@ -99,7 +99,7 @@ describe('encryptUserPassword()', () => {
describe('verifyUserPassword()', () => { describe('verifyUserPassword()', () => {
const { verifyUserPassword } = createUserLibrary(queries); const { verifyUserPassword } = createUserLibrary(queries);
describe('Argon2', () => { describe('Argon2i', () => {
it('resolves when password is correct', async () => { it('resolves when password is correct', async () => {
await expect(verifyUserPassword(mockUser, 'password')).resolves.not.toThrowError(); await expect(verifyUserPassword(mockUser, 'password')).resolves.not.toThrowError();
}); });
@ -111,6 +111,43 @@ describe('verifyUserPassword()', () => {
}); });
}); });
describe('Argon2d', () => {
const user = {
...mockUser,
passwordEncrypted: '$argon2d$v=19$m=16,t=2,p=1$VW1JcEJrMjN1Vnp3Tm5JUA$Ddl/I6Zem7vbZ4r5jPCb/g',
passwordEncryptionMethod: UsersPasswordEncryptionMethod.Argon2d,
};
it('resolves when password is correct', async () => {
await expect(verifyUserPassword(user, 'password')).resolves.not.toThrowError();
});
it('rejects when password is incorrect', async () => {
await expect(verifyUserPassword(user, 'wrong')).rejects.toThrowError(
new RequestError({ code: 'session.invalid_credentials', status: 422 })
);
});
});
describe('Argon2id', () => {
const user = {
...mockUser,
passwordEncrypted:
'$argon2id$v=19$m=16,t=2,p=1$VW1JcEJrMjN1Vnp3Tm5JUA$0uzNwxbjs/f/1e5r4uX7JQ',
passwordEncryptionMethod: UsersPasswordEncryptionMethod.Argon2id,
};
it('resolves when password is correct', async () => {
await expect(verifyUserPassword(user, 'password')).resolves.not.toThrowError();
});
it('rejects when password is incorrect', async () => {
await expect(verifyUserPassword(user, 'wrong')).rejects.toThrowError(
new RequestError({ code: 'session.invalid_credentials', status: 422 })
);
});
});
describe('MD5', () => { describe('MD5', () => {
const user = { const user = {
...mockUser, ...mockUser,

View file

@ -178,7 +178,10 @@ export const createUserLibrary = (queries: Queries) => {
); );
switch (passwordEncryptionMethod) { switch (passwordEncryptionMethod) {
case UsersPasswordEncryptionMethod.Argon2i: { // Argon2i, Argon2id, Argon2d shares the same verify function
case UsersPasswordEncryptionMethod.Argon2i:
case UsersPasswordEncryptionMethod.Argon2id:
case UsersPasswordEncryptionMethod.Argon2d: {
const result = await argon2Verify({ password, hash: passwordEncrypted }); const result = await argon2Verify({ password, hash: passwordEncrypted });
assertThat(result, new RequestError({ code: 'session.invalid_credentials', status: 422 })); assertThat(result, new RequestError({ code: 'session.invalid_credentials', status: 422 }));
break; break;

View file

@ -0,0 +1,35 @@
import { sql } from '@silverhand/slonik';
import type { AlterationScript } from '../lib/types/alteration.js';
const alteration: AlterationScript = {
up: async (pool) => {
await pool.query(sql`
alter type users_password_encryption_method add value 'Argon2id';
alter type users_password_encryption_method add value 'Argon2d';
`);
},
down: async (pool) => {
const { rows } = await pool.query(sql`
select id from users
where password_encryption_method = ${'Argon2id'}
or password_encryption_method = ${'Argon2d'}
`);
if (rows.length > 0) {
throw new Error('There are users with password encryption methods Argon2id or Argon2d.');
}
await pool.query(sql`
create type users_password_encryption_method_revised as enum ('Argon2i', 'SHA1', 'SHA256', 'MD5', 'Bcrypt');
alter table users
alter column password_encryption_method type users_password_encryption_method_revised
using password_encryption_method::text::users_password_encryption_method_revised;
drop type users_password_encryption_method;
alter type users_password_encryption_method_revised rename to users_password_encryption_method;
`);
},
};
export default alteration;

View file

@ -1,6 +1,6 @@
/* init_order = 1 */ /* init_order = 1 */
create type users_password_encryption_method as enum ('Argon2i', 'SHA1', 'SHA256', 'MD5', 'Bcrypt'); create type users_password_encryption_method as enum ('Argon2i', 'Argon2id', 'Argon2d', 'SHA1', 'SHA256', 'MD5', 'Bcrypt');
create table users ( create table users (
tenant_id varchar(21) not null tenant_id varchar(21) not null