mirror of
https://github.com/logto-io/logto.git
synced 2025-03-31 22:51:25 -05:00
feat(core): register with admin role (#1140)
* feat(core): register with admin role register user with admin role * fix(core): cr fix cr fix
This commit is contained in:
parent
ac99c26181
commit
4f32ad3a51
2 changed files with 55 additions and 2 deletions
|
@ -1,4 +1,5 @@
|
|||
import { User } from '@logto/schemas';
|
||||
import { adminConsoleApplicationId } from '@logto/schemas/lib/seeds';
|
||||
import { Provider } from 'oidc-provider';
|
||||
|
||||
import { mockUser } from '@/__mocks__';
|
||||
|
@ -29,6 +30,8 @@ jest.mock('@/lib/user', () => ({
|
|||
const insertUser = jest.fn(async (..._args: unknown[]) => ({ id: 'id' }));
|
||||
const findUserById = jest.fn(async (): Promise<User> => mockUser);
|
||||
const updateUserById = jest.fn(async (..._args: unknown[]) => ({ id: 'id' }));
|
||||
const hasActiveUsers = jest.fn(async () => true);
|
||||
|
||||
jest.mock('@/queries/user', () => ({
|
||||
findUserById: async () => findUserById(),
|
||||
findUserByIdentity: async () => ({ id: 'id', identities: {} }),
|
||||
|
@ -41,6 +44,7 @@ jest.mock('@/queries/user', () => ({
|
|||
connectorId === 'connectorId' && userId === 'id',
|
||||
hasUserWithPhone: async (phone: string) => phone === '13000000000',
|
||||
hasUserWithEmail: async (email: string) => email === 'a@a.com',
|
||||
hasActiveUsers: async () => hasActiveUsers(),
|
||||
}));
|
||||
|
||||
const grantSave = jest.fn(async () => 'finalGrantId');
|
||||
|
@ -149,6 +153,8 @@ describe('sessionRoutes', () => {
|
|||
|
||||
describe('POST /session/register/username-password', () => {
|
||||
it('assign result and redirect', async () => {
|
||||
interactionDetails.mockResolvedValueOnce({ params: {} });
|
||||
|
||||
const response = await sessionRequest
|
||||
.post('/session/register/username-password')
|
||||
.send({ username: 'username', password: 'password' });
|
||||
|
@ -158,6 +164,7 @@ describe('sessionRoutes', () => {
|
|||
username: 'username',
|
||||
passwordEncrypted: 'password_user1',
|
||||
passwordEncryptionMethod: 'Argon2i',
|
||||
roleNames: [],
|
||||
})
|
||||
);
|
||||
expect(response.body).toHaveProperty('redirectTo');
|
||||
|
@ -169,6 +176,40 @@ describe('sessionRoutes', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('register user with admin role for admin console if no active user found', async () => {
|
||||
interactionDetails.mockResolvedValueOnce({
|
||||
params: { client_id: adminConsoleApplicationId },
|
||||
});
|
||||
|
||||
hasActiveUsers.mockResolvedValueOnce(false);
|
||||
|
||||
await sessionRequest
|
||||
.post('/session/register/username-password')
|
||||
.send({ username: 'username', password: 'password' });
|
||||
|
||||
expect(insertUser).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
roleNames: ['admin'],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should not register user with admin role for admin console if any active user found', async () => {
|
||||
interactionDetails.mockResolvedValueOnce({
|
||||
params: { client_id: adminConsoleApplicationId },
|
||||
});
|
||||
|
||||
await sessionRequest
|
||||
.post('/session/register/username-password')
|
||||
.send({ username: 'username', password: 'password' });
|
||||
|
||||
expect(insertUser).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
roleNames: [],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('throw error if username not valid', async () => {
|
||||
const usernameStartedWithNumber = '1username';
|
||||
const response = await sessionRequest
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import path from 'path';
|
||||
|
||||
import { LogtoErrorCode } from '@logto/phrases';
|
||||
import { UserRole } from '@logto/schemas';
|
||||
import { adminConsoleApplicationId } from '@logto/schemas/lib/seeds';
|
||||
import { passwordRegEx, usernameRegEx } from '@logto/shared';
|
||||
import { conditional } from '@silverhand/essentials';
|
||||
import { Provider } from 'oidc-provider';
|
||||
|
@ -15,7 +17,7 @@ import {
|
|||
updateLastSignInAt,
|
||||
} from '@/lib/user';
|
||||
import koaGuard from '@/middleware/koa-guard';
|
||||
import { hasUser, insertUser } from '@/queries/user';
|
||||
import { hasUser, insertUser, hasActiveUsers } from '@/queries/user';
|
||||
import assertThat from '@/utils/assert-that';
|
||||
|
||||
import { AnonymousRouter } from '../types';
|
||||
|
@ -120,8 +122,17 @@ export default function sessionRoutes<T extends AnonymousRouter>(router: T, prov
|
|||
})
|
||||
);
|
||||
|
||||
const {
|
||||
params: { client_id },
|
||||
} = await provider.interactionDetails(ctx.req, ctx.res);
|
||||
|
||||
const createAdminUser =
|
||||
String(client_id) === adminConsoleApplicationId && !(await hasActiveUsers());
|
||||
const roleNames = createAdminUser ? [UserRole.Admin] : [];
|
||||
|
||||
const id = await generateUserId();
|
||||
ctx.log(type, { userId: id });
|
||||
|
||||
ctx.log(type, { userId: id, roleNames });
|
||||
|
||||
const { passwordEncrypted, passwordEncryptionMethod } = await encryptUserPassword(password);
|
||||
|
||||
|
@ -130,6 +141,7 @@ export default function sessionRoutes<T extends AnonymousRouter>(router: T, prov
|
|||
username,
|
||||
passwordEncrypted,
|
||||
passwordEncryptionMethod,
|
||||
roleNames,
|
||||
});
|
||||
await updateLastSignInAt(id);
|
||||
await assignInteractionResults(ctx, provider, { login: { accountId: id } });
|
||||
|
|
Loading…
Add table
Reference in a new issue