Skip to content

Commit

Permalink
feat: allow admin login when using demo auth type
Browse files Browse the repository at this point in the history
  • Loading branch information
00Chaotic committed Apr 9, 2024
1 parent 2b3516d commit fcbaa9f
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 10 deletions.
2 changes: 1 addition & 1 deletion frontend/src/component/user/DemoAuth/DemoAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const DemoAuth: VFC<IDemoAuthProps> = ({ authDetails, redirect }) => {
id='email'
data-testid={LOGIN_EMAIL_ID}
required
type='email'
type={email === 'admin' ? 'text' : 'email'}
/>

<Button
Expand Down
1 change: 1 addition & 0 deletions src/lib/__snapshots__/create-config.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ exports[`should create default config 1`] = `
"styleSrc": [],
},
"authentication": {
"authDemoAllowAdminLogin": false,
"createAdminUser": true,
"customAuthHandler": [Function],
"enableApiToken": true,
Expand Down
14 changes: 14 additions & 0 deletions src/lib/create-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,20 @@ test('should handle cases where no env var specified for tokens', async () => {
expect(config.authentication.initApiTokens).toHaveLength(1);
});

test('should load demo admin login flag from env var', async () => {
process.env.AUTH_DEMO_ALLOW_ADMIN_LOGIN = 'true';

const config = createConfig({});

expect(config.authentication.authDemoAllowAdminLogin).toBeTruthy();
delete process.env.AUTH_DEMO_ALLOW_ADMIN_LOGIN;
});

test('should default demo admin login to false', async () => {
const config = createConfig({});
expect(config.authentication.authDemoAllowAdminLogin).toBeFalsy();
});

test('should load environment overrides from env var', async () => {
process.env.ENABLED_ENVIRONMENTS = 'default,production';

Expand Down
1 change: 1 addition & 0 deletions src/lib/create-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ const defaultVersionOption: IVersionOption = {
};

const defaultAuthentication: IAuthOption = {
authDemoAllowAdminLogin: parseEnvVarBoolean(process.env.AUTH_DEMO_ALLOW_ADMIN_LOGIN, false),
enableApiToken: parseEnvVarBoolean(process.env.AUTH_ENABLE_API_TOKEN, true),
type: authTypeFromString(process.env.AUTH_TYPE),
customAuthHandler: defaultCustomAuthDenyAll,
Expand Down
57 changes: 57 additions & 0 deletions src/lib/middleware/demo-authentication.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { IAuthType } from '../server-impl';
import dbInit, { ITestDb } from '../../test/e2e/helpers/database-init';
import { IUnleashStores } from '../types';
import { setupAppWithCustomAuth } from '../../test/e2e/helpers/test-helper';

let db: ITestDb;
let stores: IUnleashStores;

beforeAll(async () => {
db = await dbInit('demo_auth_serial');
stores = db.stores;
});

afterAll(async () => {
await db?.destroy();
});

const getApp = (adminLoginEnabled: boolean) =>
setupAppWithCustomAuth(stores, () => {}, {
authentication: {
authDemoAllowAdminLogin: adminLoginEnabled,
type: IAuthType.DEMO,
createAdminUser: true,
},
});

test('should create regular user with flag enabled', async () => {
const app = await getApp(true);
return app.request
.post(`/auth/demo/login`)
.send({ email: '[email protected]' })
.expect(200)
.expect((res) => {
expect(res.body.email).toBe('[email protected]');
expect(res.body.id).not.toBe(1);
});
});

test('should return 403 for admin user if flag disabled', async () => {
const app = await getApp(false);
return app.request
.post(`/auth/demo/login`)
.send({ email: 'admin' })
.expect(403);
});

test('should allow login with admin user if flag enabled', async () => {
const app = await getApp(true);
return app.request
.post(`/auth/demo/login`)
.send({ email: 'admin' })
.expect(200)
.expect((res) => {
expect(res.body.id).toBe(1);
expect(res.body.username).toBe('admin');
});
});
30 changes: 21 additions & 9 deletions src/lib/middleware/demo-authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { IUnleashServices } from '../types/services';
import type { IUnleashConfig } from '../types/option';
import ApiUser from '../types/api-user';
import { ApiTokenType } from '../types/models/api-token';
import type { IAuthRequest } from '../server-impl';
import type { IAuthRequest, IUser } from '../server-impl';
import type { IApiRequest } from '../routes/unleash-types';
import { encrypt } from '../util';

Expand All @@ -19,14 +19,26 @@ function demoAuthentication(
): void {
app.post(`${basePath}/auth/demo/login`, async (req: IAuthRequest, res) => {
let { email } = req.body;
email = flagResolver.isEnabled('encryptEmails', { email })
? encrypt(email)
: email;
let user: IUser;

try {
const user = await userService.loginUserWithoutPassword(
email,
true,
);
if (!authentication.authDemoAllowAdminLogin && email === 'admin') {
return res.status(403)
.json({ error: `Admin login not enabled for demo auth type`})
.end;
} else if (authentication.authDemoAllowAdminLogin && email === 'admin') {
user = await userService.loginDemoAuthDefaultAdmin();
} else {
email = flagResolver.isEnabled('encryptEmails', { email })
? encrypt(email)
: email;

user = await userService.loginUserWithoutPassword(
email,
true,
);
}

req.session.user = user;
return res.status(200).json(user);
} catch (e) {
Expand All @@ -37,7 +49,7 @@ function demoAuthentication(
});

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.

app.use(`${basePath}/api/admin/`, (req: IAuthRequest, res, next) => {
if (req.session.user?.email) {
if (req.session.user?.email || req.session.user?.username === 'admin') {
req.user = req.session.user;
}
next();
Expand Down
10 changes: 10 additions & 0 deletions src/lib/services/user-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,16 @@ class UserService {
return user;
}

async loginDemoAuthDefaultAdmin(): Promise<IUser> {
let user: IUser;

// Queries default admin user
user = await this.store.getByQuery({ id: 1 });

await this.store.successfullyLogin(user);
return user;
}

async changePassword(userId: number, password: string): Promise<void> {
this.validatePassword(password);
const passwordHash = await bcrypt.hash(password, saltRounds);
Expand Down
1 change: 1 addition & 0 deletions src/lib/types/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export type CustomAuthHandler = (
) => void;

export interface IAuthOption {
authDemoAllowAdminLogin?: boolean;
enableApiToken: boolean;
type: IAuthType;
customAuthHandler?: CustomAuthHandler;
Expand Down

0 comments on commit fcbaa9f

Please sign in to comment.