0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

feat(core): add admin guard to signin (#1523)

* feat(core): add admin guard to signin

add admin guard to signin

* fix(core): cr update

cr update

* fix(core): naming update

naming update
This commit is contained in:
simeng-li 2022-07-12 21:58:02 +08:00 committed by GitHub
parent fc19c00cb2
commit 3e76de0ac9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 5 deletions

View file

@ -1,4 +1,4 @@
import { User } from '@logto/schemas';
import { User, UserRole } from '@logto/schemas';
import { adminConsoleApplicationId } from '@logto/schemas/lib/seeds';
import { Provider } from 'oidc-provider';
@ -10,7 +10,7 @@ import sessionRoutes from './session';
jest.mock('@/lib/user', () => ({
async findUserByUsernameAndPassword(username: string, password: string) {
if (username !== 'username') {
if (username !== 'username' && username !== 'admin') {
throw new RequestError('session.invalid_credentials');
}
@ -18,7 +18,9 @@ jest.mock('@/lib/user', () => ({
throw new RequestError('session.invalid_credentials');
}
return { id: 'user1' };
const roleNames = username === 'admin' ? [UserRole.Admin] : [];
return { id: 'user1', roleNames };
},
generateUserId: () => 'user1',
encryptUserPassword: (password: string) => ({
@ -120,6 +122,7 @@ describe('sessionRoutes', () => {
describe('POST /session/sign-in/username-password', () => {
it('assign result and redirect', async () => {
interactionDetails.mockResolvedValueOnce({ params: {} });
const response = await sessionRequest.post('/session/sign-in/username-password').send({
username: 'username',
password: 'password',
@ -135,6 +138,7 @@ describe('sessionRoutes', () => {
});
it('throw if user not found', async () => {
interactionDetails.mockResolvedValueOnce({ params: {} });
const response = await sessionRequest.post('/session/sign-in/username-password').send({
username: 'notexistuser',
password: 'password',
@ -143,12 +147,38 @@ describe('sessionRoutes', () => {
});
it('throw if user found but wrong password', async () => {
interactionDetails.mockResolvedValueOnce({ params: {} });
const response = await sessionRequest.post('/session/sign-in/username-password').send({
username: 'username',
password: '_password',
});
expect(response.statusCode).toEqual(400);
});
it('throw if non-admin user sign in to AC', async () => {
interactionDetails.mockResolvedValueOnce({
params: { client_id: adminConsoleApplicationId },
});
const response = await sessionRequest.post('/session/sign-in/username-password').send({
username: 'username',
password: 'password',
});
expect(response.statusCode).toEqual(403);
console.log(response);
});
it('should throw if admin user sign in to AC', async () => {
interactionDetails.mockResolvedValueOnce({
params: { client_id: adminConsoleApplicationId },
});
const response = await sessionRequest.post('/session/sign-in/username-password').send({
username: 'admin',
password: 'password',
});
expect(response.statusCode).toEqual(200);
});
});
describe('POST /session/register/username-password', () => {

View file

@ -46,12 +46,23 @@ export default function sessionRoutes<T extends AnonymousRouter>(router: T, prov
}),
}),
async (ctx, next) => {
await provider.interactionDetails(ctx.req, ctx.res);
const {
params: { client_id },
} = await provider.interactionDetails(ctx.req, ctx.res);
const { username, password } = ctx.guard.body;
const type = 'SignInUsernamePassword';
ctx.log(type, { username });
const { id } = await findUserByUsernameAndPassword(username, password);
const { id, roleNames } = await findUserByUsernameAndPassword(username, password);
// Temp solution before migrating to RBAC. As AC sign-in exp currently hardcoded to username password only.
if (String(client_id) === adminConsoleApplicationId) {
assertThat(
roleNames.includes(UserRole.Admin),
new RequestError({ code: 'auth.forbidden', status: 403 })
);
}
ctx.log(type, { userId: id });
await updateLastSignInAt(id);
await assignInteractionResults(ctx, provider, { login: { accountId: id } }, true);