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:
parent
43d5bd248c
commit
d56bc2f731
5 changed files with 88 additions and 3 deletions
10
.changeset/thirty-cups-joke.md
Normal file
10
.changeset/thirty-cups-joke.md
Normal 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.
|
|
@ -99,7 +99,7 @@ describe('encryptUserPassword()', () => {
|
|||
describe('verifyUserPassword()', () => {
|
||||
const { verifyUserPassword } = createUserLibrary(queries);
|
||||
|
||||
describe('Argon2', () => {
|
||||
describe('Argon2i', () => {
|
||||
it('resolves when password is correct', async () => {
|
||||
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', () => {
|
||||
const user = {
|
||||
...mockUser,
|
||||
|
|
|
@ -178,7 +178,10 @@ export const createUserLibrary = (queries: Queries) => {
|
|||
);
|
||||
|
||||
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 });
|
||||
assertThat(result, new RequestError({ code: 'session.invalid_credentials', status: 422 }));
|
||||
break;
|
||||
|
|
|
@ -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;
|
|
@ -1,6 +1,6 @@
|
|||
/* 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 (
|
||||
tenant_id varchar(21) not null
|
||||
|
|
Loading…
Reference in a new issue