@adonisjs/auth 9.0.0-6 → 9.0.0-8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/factories/basic_auth_guard_factory.d.ts +12 -0
- package/build/factories/basic_auth_guard_factory.js +22 -0
- package/build/src/auth/define_config.d.ts +0 -2
- package/build/src/auth/define_config.js +0 -1
- package/build/src/auth/errors.d.ts +5 -0
- package/build/src/auth/errors.js +17 -0
- package/build/src/auth/plugins/japa/api_client.d.ts +2 -1
- package/build/src/auth/plugins/japa/api_client.js +48 -41
- package/build/src/auth/plugins/japa/browser_client.d.ts +25 -0
- package/build/src/auth/plugins/japa/browser_client.js +42 -0
- package/build/src/guards/basic_auth/define_config.d.ts +16 -0
- package/build/src/guards/basic_auth/define_config.js +38 -0
- package/build/src/guards/basic_auth/guard.d.ts +70 -0
- package/build/src/guards/basic_auth/guard.js +190 -0
- package/build/src/guards/basic_auth/main.d.ts +2 -0
- package/build/src/guards/basic_auth/main.js +10 -0
- package/build/src/guards/basic_auth/types.d.ts +35 -0
- package/build/src/guards/basic_auth/types.js +9 -0
- package/build/src/guards/session/guard.js +2 -0
- package/package.json +18 -3
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
import { FactoryUser, TestLucidUserProvider } from './lucid_user_provider.js';
|
|
3
|
+
import { BasicAuthGuard } from '../src/guards/basic_auth/guard.js';
|
|
4
|
+
import type { UserProviderContract } from '../src/core/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Exposes the API to create a basic auth guard for testing. Under
|
|
7
|
+
* the hood configures Lucid models for looking up users
|
|
8
|
+
*/
|
|
9
|
+
export declare class BasicAuthGuardFactory {
|
|
10
|
+
merge(): this;
|
|
11
|
+
create<UserProvider extends UserProviderContract<unknown> = TestLucidUserProvider<typeof FactoryUser>>(ctx: HttpContext, provider?: UserProvider): BasicAuthGuard<TestLucidUserProvider<typeof FactoryUser> | UserProvider>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/auth
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { LucidUserProviderFactory, } from './lucid_user_provider.js';
|
|
10
|
+
import { BasicAuthGuard } from '../src/guards/basic_auth/guard.js';
|
|
11
|
+
/**
|
|
12
|
+
* Exposes the API to create a basic auth guard for testing. Under
|
|
13
|
+
* the hood configures Lucid models for looking up users
|
|
14
|
+
*/
|
|
15
|
+
export class BasicAuthGuardFactory {
|
|
16
|
+
merge() {
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
create(ctx, provider) {
|
|
20
|
+
return new BasicAuthGuard('basic', ctx, provider || new LucidUserProviderFactory().create());
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -7,7 +7,6 @@ import type { LucidAuthenticatable, LucidUserProviderOptions, DatabaseUserProvid
|
|
|
7
7
|
*/
|
|
8
8
|
export type ResolvedAuthConfig<KnownGuards extends Record<string, GuardFactory | GuardConfigProvider<GuardFactory>>> = {
|
|
9
9
|
default: keyof KnownGuards;
|
|
10
|
-
loginRoute: string;
|
|
11
10
|
guards: {
|
|
12
11
|
[K in keyof KnownGuards]: KnownGuards[K] extends GuardConfigProvider<infer A> ? A : KnownGuards[K];
|
|
13
12
|
};
|
|
@@ -19,7 +18,6 @@ export type ResolvedAuthConfig<KnownGuards extends Record<string, GuardFactory |
|
|
|
19
18
|
*/
|
|
20
19
|
export declare function defineConfig<KnownGuards extends Record<string, GuardFactory | GuardConfigProvider<GuardFactory>>>(config: {
|
|
21
20
|
default: keyof KnownGuards;
|
|
22
|
-
loginRoute: string;
|
|
23
21
|
guards: KnownGuards;
|
|
24
22
|
}): ConfigProvider<ResolvedAuthConfig<KnownGuards>>;
|
|
25
23
|
/**
|
|
@@ -12,6 +12,11 @@ export declare class AuthenticationException extends Exception {
|
|
|
12
12
|
* is unable to authenticate the request
|
|
13
13
|
*/
|
|
14
14
|
static E_INVALID_AUTH_SESSION(): AuthenticationException;
|
|
15
|
+
/**
|
|
16
|
+
* Raises authentication exception when session guard
|
|
17
|
+
* is unable to authenticate the request
|
|
18
|
+
*/
|
|
19
|
+
static E_INVALID_BASIC_AUTH_CREDENTIALS(): AuthenticationException;
|
|
15
20
|
guardDriverName: string;
|
|
16
21
|
redirectTo?: string;
|
|
17
22
|
identifier: string;
|
package/build/src/auth/errors.js
CHANGED
|
@@ -25,6 +25,17 @@ export class AuthenticationException extends Exception {
|
|
|
25
25
|
guardDriverName: 'session',
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Raises authentication exception when session guard
|
|
30
|
+
* is unable to authenticate the request
|
|
31
|
+
*/
|
|
32
|
+
static E_INVALID_BASIC_AUTH_CREDENTIALS() {
|
|
33
|
+
return new AuthenticationException('Invalid basic auth credentials', {
|
|
34
|
+
code: 'E_INVALID_BASIC_AUTH_CREDENTIALS',
|
|
35
|
+
status: 401,
|
|
36
|
+
guardDriverName: 'basic_auth',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
28
39
|
guardDriverName;
|
|
29
40
|
redirectTo;
|
|
30
41
|
identifier = 'auth.authenticate';
|
|
@@ -84,6 +95,12 @@ export class AuthenticationException extends Exception {
|
|
|
84
95
|
break;
|
|
85
96
|
}
|
|
86
97
|
},
|
|
98
|
+
basic_auth: (message, _, ctx) => {
|
|
99
|
+
ctx.response
|
|
100
|
+
.status(this.status)
|
|
101
|
+
.header('WWW-Authenticate', `Basic realm="Authenticate", charset="UTF-8"`)
|
|
102
|
+
.send(message);
|
|
103
|
+
},
|
|
87
104
|
};
|
|
88
105
|
/**
|
|
89
106
|
* Self handles the auth exception and converts it to an
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluginFn } from '@japa/runner/types';
|
|
1
2
|
import type { ApplicationService } from '@adonisjs/core/types';
|
|
2
3
|
import type { Authenticators, GuardContract, GuardFactory } from '../../types.js';
|
|
3
4
|
declare module '@japa/api-client' {
|
|
@@ -28,4 +29,4 @@ declare module '@japa/api-client' {
|
|
|
28
29
|
* Auth API client to authenticate users when making
|
|
29
30
|
* HTTP requests using the Japa API client
|
|
30
31
|
*/
|
|
31
|
-
export declare const authApiClient: (app: ApplicationService) =>
|
|
32
|
+
export declare const authApiClient: (app: ApplicationService) => PluginFn;
|
|
@@ -6,51 +6,58 @@
|
|
|
6
6
|
* For the full copyright and license information, please view the LICENSE
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
|
-
/// <reference types="@adonisjs/session/plugins/api_client" />
|
|
10
9
|
import { ApiClient, ApiRequest } from '@japa/api-client';
|
|
10
|
+
import debug from '../../debug.js';
|
|
11
11
|
/**
|
|
12
12
|
* Auth API client to authenticate users when making
|
|
13
13
|
* HTTP requests using the Japa API client
|
|
14
14
|
*/
|
|
15
15
|
export const authApiClient = (app) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
16
|
+
const pluginFn = function () {
|
|
17
|
+
debug('installing auth api client plugin');
|
|
18
|
+
ApiRequest.macro('loginAs', function (user) {
|
|
19
|
+
this.authData = {
|
|
20
|
+
guard: '__default__',
|
|
21
|
+
user: user,
|
|
22
|
+
};
|
|
23
|
+
return this;
|
|
24
|
+
});
|
|
25
|
+
ApiRequest.macro('withGuard', function (guard) {
|
|
26
|
+
return {
|
|
27
|
+
loginAs: (user) => {
|
|
28
|
+
this.authData = {
|
|
29
|
+
guard,
|
|
30
|
+
user: user,
|
|
31
|
+
};
|
|
32
|
+
return this;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Hook into the request and login the user
|
|
38
|
+
*/
|
|
39
|
+
ApiClient.setup(async (request) => {
|
|
40
|
+
const auth = await app.container.make('auth.manager');
|
|
41
|
+
const authData = request['authData'];
|
|
42
|
+
if (!authData) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const client = auth.createAuthenticatorClient();
|
|
46
|
+
const guard = authData.guard === '__default__' ? client.use() : client.use(authData.guard);
|
|
47
|
+
const requestData = await guard.authenticateAsClient(authData.user);
|
|
48
|
+
if (requestData.headers) {
|
|
49
|
+
debug('defining headers with api client request %O', requestData.headers);
|
|
50
|
+
request.headers(requestData.headers);
|
|
51
|
+
}
|
|
52
|
+
if (requestData.session) {
|
|
53
|
+
debug('defining session with api client request %O', requestData.session);
|
|
54
|
+
request.withSession(requestData.session);
|
|
55
|
+
}
|
|
56
|
+
if (requestData.cookies) {
|
|
57
|
+
debug('defining session with api client request %O', requestData.session);
|
|
58
|
+
request.cookies(requestData.cookies);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
return pluginFn;
|
|
56
63
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PluginFn } from '@japa/runner/types';
|
|
2
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
3
|
+
import type { Authenticators, GuardContract, GuardFactory } from '../../types.js';
|
|
4
|
+
declare module 'playwright' {
|
|
5
|
+
interface BrowserContext {
|
|
6
|
+
/**
|
|
7
|
+
* Login a user using the default authentication
|
|
8
|
+
* guard when using the browser context to
|
|
9
|
+
* make page visits
|
|
10
|
+
*/
|
|
11
|
+
loginAs(user: {
|
|
12
|
+
[K in keyof Authenticators]: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Define the authentication guard for login
|
|
16
|
+
*/
|
|
17
|
+
withGuard<K extends keyof Authenticators>(guard: K): {
|
|
18
|
+
/**
|
|
19
|
+
* Login a user using a specific auth guard
|
|
20
|
+
*/
|
|
21
|
+
loginAs(user: Authenticators[K] extends GuardFactory ? ReturnType<Authenticators[K]> extends GuardContract<infer A> ? A : never : never): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export declare const authBrowserClient: (app: ApplicationService) => PluginFn;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adoniss/auth
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/// <reference types="@japa/plugin-adonisjs" />
|
|
10
|
+
/// <reference types="@adonisjs/session/plugins/browser_client" />
|
|
11
|
+
import { RuntimeException } from '@poppinss/utils';
|
|
12
|
+
import { decoratorsCollection } from '@japa/browser-client';
|
|
13
|
+
import debug from '../../debug.js';
|
|
14
|
+
export const authBrowserClient = (app) => {
|
|
15
|
+
const pluginFn = async function () {
|
|
16
|
+
debug('installing auth browser client plugin');
|
|
17
|
+
const auth = await app.container.make('auth.manager');
|
|
18
|
+
decoratorsCollection.register({
|
|
19
|
+
context(context) {
|
|
20
|
+
context.loginAs = async function (user) {
|
|
21
|
+
const client = auth.createAuthenticatorClient();
|
|
22
|
+
const guard = client.use();
|
|
23
|
+
const requestData = await guard.authenticateAsClient(user);
|
|
24
|
+
if (requestData.headers) {
|
|
25
|
+
throw new RuntimeException(`Cannot use "${guard.driverName}" guard with browser client`);
|
|
26
|
+
}
|
|
27
|
+
if (requestData.cookies) {
|
|
28
|
+
debug('defining cookies with browser context %O', requestData.cookies);
|
|
29
|
+
Object.keys(requestData.cookies).forEach((cookie) => {
|
|
30
|
+
context.setCookie(cookie, requestData.cookies[cookie]);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (requestData.session) {
|
|
34
|
+
debug('defining session with browser context %O', requestData.session);
|
|
35
|
+
context.setSession(requestData.session);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
return pluginFn;
|
|
42
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
import type { ConfigProvider } from '@adonisjs/core/types';
|
|
3
|
+
import type { GuardConfigProvider } from '../../auth/types.js';
|
|
4
|
+
import type { UserProviderContract } from '../../core/types.js';
|
|
5
|
+
import { BasicAuthGuard } from './guard.js';
|
|
6
|
+
/**
|
|
7
|
+
* Helper function to configure the basic auth guard for
|
|
8
|
+
* authentication.
|
|
9
|
+
*
|
|
10
|
+
* This method returns a config builder, which internally
|
|
11
|
+
* returns a factory function to construct a guard
|
|
12
|
+
* during HTTP requests.
|
|
13
|
+
*/
|
|
14
|
+
export declare function basicAuthGuard<UserProvider extends UserProviderContract<unknown>>(config: {
|
|
15
|
+
provider: ConfigProvider<UserProvider>;
|
|
16
|
+
}): GuardConfigProvider<(ctx: HttpContext) => BasicAuthGuard<UserProvider>>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/auth
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { configProvider } from '@adonisjs/core';
|
|
10
|
+
import { RuntimeException } from '@poppinss/utils';
|
|
11
|
+
import { BasicAuthGuard } from './guard.js';
|
|
12
|
+
/**
|
|
13
|
+
* Helper function to configure the basic auth guard for
|
|
14
|
+
* authentication.
|
|
15
|
+
*
|
|
16
|
+
* This method returns a config builder, which internally
|
|
17
|
+
* returns a factory function to construct a guard
|
|
18
|
+
* during HTTP requests.
|
|
19
|
+
*/
|
|
20
|
+
export function basicAuthGuard(config) {
|
|
21
|
+
return {
|
|
22
|
+
async resolver(guardName, app) {
|
|
23
|
+
const provider = await configProvider.resolve(app, config.provider);
|
|
24
|
+
if (!provider) {
|
|
25
|
+
throw new RuntimeException(`Invalid user provider defined on "${guardName}" guard`);
|
|
26
|
+
}
|
|
27
|
+
const emitter = await app.container.make('emitter');
|
|
28
|
+
/**
|
|
29
|
+
* Factory function needed by Authenticator to switch
|
|
30
|
+
* between guards and perform authentication
|
|
31
|
+
*/
|
|
32
|
+
return (ctx) => {
|
|
33
|
+
const guard = new BasicAuthGuard(guardName, ctx, provider);
|
|
34
|
+
return guard.withEmitter(emitter);
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Emitter } from '@adonisjs/core/events';
|
|
2
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
|
+
import type { BasicAuthGuardEvents } from './types.js';
|
|
4
|
+
import type { GuardContract } from '../../auth/types.js';
|
|
5
|
+
import type { UserProviderContract } from '../../core/types.js';
|
|
6
|
+
import { PROVIDER_REAL_USER, GUARD_KNOWN_EVENTS } from '../../auth/symbols.js';
|
|
7
|
+
/**
|
|
8
|
+
* Implementation of basic auth as an authentication guard
|
|
9
|
+
*/
|
|
10
|
+
export declare class BasicAuthGuard<UserProvider extends UserProviderContract<unknown>> implements GuardContract<UserProvider[typeof PROVIDER_REAL_USER]> {
|
|
11
|
+
#private;
|
|
12
|
+
[GUARD_KNOWN_EVENTS]: BasicAuthGuardEvents<UserProvider[typeof PROVIDER_REAL_USER]>;
|
|
13
|
+
/**
|
|
14
|
+
* Driver name of the guard
|
|
15
|
+
*/
|
|
16
|
+
driverName: 'basic_auth';
|
|
17
|
+
/**
|
|
18
|
+
* Whether or not the authentication has been attempted
|
|
19
|
+
* during the current request
|
|
20
|
+
*/
|
|
21
|
+
authenticationAttempted: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* A boolean to know if the current request has
|
|
24
|
+
* been authenticated
|
|
25
|
+
*/
|
|
26
|
+
isAuthenticated: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Reference to an instance of the authenticated or logged-in
|
|
29
|
+
* user. The value only exists after calling one of the
|
|
30
|
+
* following methods.
|
|
31
|
+
*
|
|
32
|
+
* - authenticate
|
|
33
|
+
*
|
|
34
|
+
* You can use the "getUserOrFail" method to throw an exception if
|
|
35
|
+
* the request is not authenticated.
|
|
36
|
+
*/
|
|
37
|
+
user?: UserProvider[typeof PROVIDER_REAL_USER];
|
|
38
|
+
constructor(name: string, ctx: HttpContext, userProvider: UserProvider);
|
|
39
|
+
/**
|
|
40
|
+
* Register an event emitter to listen for global events for
|
|
41
|
+
* authentication lifecycle.
|
|
42
|
+
*/
|
|
43
|
+
withEmitter(emitter: Emitter<any>): this;
|
|
44
|
+
/**
|
|
45
|
+
* Returns an instance of the authenticated user. Or throws
|
|
46
|
+
* an exception if the request is not authenticated.
|
|
47
|
+
*/
|
|
48
|
+
getUserOrFail(): UserProvider[typeof PROVIDER_REAL_USER];
|
|
49
|
+
/**
|
|
50
|
+
* Verifies user credentials and returns an instance of
|
|
51
|
+
* the user or throws "E_INVALID_BASIC_AUTH_CREDENTIALS" exception.
|
|
52
|
+
*/
|
|
53
|
+
verifyCredentials(uid: string, password: string): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
|
|
54
|
+
/**
|
|
55
|
+
* Authenticates the current HTTP request for basic
|
|
56
|
+
* auth credentials
|
|
57
|
+
*/
|
|
58
|
+
authenticate(): Promise<UserProvider[typeof PROVIDER_REAL_USER]>;
|
|
59
|
+
/**
|
|
60
|
+
* Silently attempt to authenticate the user.
|
|
61
|
+
*
|
|
62
|
+
* The method returns a boolean indicating if the authentication
|
|
63
|
+
* succeeded or failed.
|
|
64
|
+
*/
|
|
65
|
+
check(): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Not support
|
|
68
|
+
*/
|
|
69
|
+
authenticateAsClient(_: UserProvider[typeof PROVIDER_REAL_USER]): Promise<never>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/auth
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import auth from 'basic-auth';
|
|
10
|
+
import { RuntimeException } from '@poppinss/utils';
|
|
11
|
+
import debug from '../../auth/debug.js';
|
|
12
|
+
import { AuthenticationException } from '../../auth/errors.js';
|
|
13
|
+
import { GUARD_KNOWN_EVENTS } from '../../auth/symbols.js';
|
|
14
|
+
/**
|
|
15
|
+
* Implementation of basic auth as an authentication guard
|
|
16
|
+
*/
|
|
17
|
+
export class BasicAuthGuard {
|
|
18
|
+
/**
|
|
19
|
+
* A unique name for the guard. It is used while
|
|
20
|
+
* emitting events
|
|
21
|
+
*/
|
|
22
|
+
#name;
|
|
23
|
+
/**
|
|
24
|
+
* Reference to the current HTTP context
|
|
25
|
+
*/
|
|
26
|
+
#ctx;
|
|
27
|
+
/**
|
|
28
|
+
* Provider to lookup user details
|
|
29
|
+
*/
|
|
30
|
+
#userProvider;
|
|
31
|
+
/**
|
|
32
|
+
* Emitter to emit events
|
|
33
|
+
*/
|
|
34
|
+
#emitter;
|
|
35
|
+
/**
|
|
36
|
+
* Driver name of the guard
|
|
37
|
+
*/
|
|
38
|
+
driverName = 'basic_auth';
|
|
39
|
+
/**
|
|
40
|
+
* Whether or not the authentication has been attempted
|
|
41
|
+
* during the current request
|
|
42
|
+
*/
|
|
43
|
+
authenticationAttempted = false;
|
|
44
|
+
/**
|
|
45
|
+
* A boolean to know if the current request has
|
|
46
|
+
* been authenticated
|
|
47
|
+
*/
|
|
48
|
+
isAuthenticated = false;
|
|
49
|
+
/**
|
|
50
|
+
* Reference to an instance of the authenticated or logged-in
|
|
51
|
+
* user. The value only exists after calling one of the
|
|
52
|
+
* following methods.
|
|
53
|
+
*
|
|
54
|
+
* - authenticate
|
|
55
|
+
*
|
|
56
|
+
* You can use the "getUserOrFail" method to throw an exception if
|
|
57
|
+
* the request is not authenticated.
|
|
58
|
+
*/
|
|
59
|
+
user;
|
|
60
|
+
constructor(name, ctx, userProvider) {
|
|
61
|
+
this.#ctx = ctx;
|
|
62
|
+
this.#name = name;
|
|
63
|
+
this.#userProvider = userProvider;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Notifies about authentication failure and throws the exception
|
|
67
|
+
*/
|
|
68
|
+
#authenticationFailed(error) {
|
|
69
|
+
if (this.#emitter) {
|
|
70
|
+
this.#emitter.emit('basic_auth:authentication_failed', {
|
|
71
|
+
guardName: this.#name,
|
|
72
|
+
error,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Register an event emitter to listen for global events for
|
|
79
|
+
* authentication lifecycle.
|
|
80
|
+
*/
|
|
81
|
+
withEmitter(emitter) {
|
|
82
|
+
this.#emitter = emitter;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns an instance of the authenticated user. Or throws
|
|
87
|
+
* an exception if the request is not authenticated.
|
|
88
|
+
*/
|
|
89
|
+
getUserOrFail() {
|
|
90
|
+
if (!this.user) {
|
|
91
|
+
throw AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS();
|
|
92
|
+
}
|
|
93
|
+
return this.user;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Verifies user credentials and returns an instance of
|
|
97
|
+
* the user or throws "E_INVALID_BASIC_AUTH_CREDENTIALS" exception.
|
|
98
|
+
*/
|
|
99
|
+
async verifyCredentials(uid, password) {
|
|
100
|
+
debug('basic_auth_guard: attempting to verify credentials for uid "%s"', uid);
|
|
101
|
+
/**
|
|
102
|
+
* Attempt to find a user by the uid and raise
|
|
103
|
+
* error when unable to find one
|
|
104
|
+
*/
|
|
105
|
+
const providerUser = await this.#userProvider.findByUid(uid);
|
|
106
|
+
if (!providerUser) {
|
|
107
|
+
this.#authenticationFailed(AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS());
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Raise error when unable to verify password
|
|
111
|
+
*/
|
|
112
|
+
const user = providerUser.getOriginal();
|
|
113
|
+
/**
|
|
114
|
+
* Raise error when unable to verify password
|
|
115
|
+
*/
|
|
116
|
+
if (!(await providerUser.verifyPassword(password))) {
|
|
117
|
+
this.#authenticationFailed(AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS());
|
|
118
|
+
}
|
|
119
|
+
return user;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Authenticates the current HTTP request for basic
|
|
123
|
+
* auth credentials
|
|
124
|
+
*/
|
|
125
|
+
async authenticate() {
|
|
126
|
+
/**
|
|
127
|
+
* Avoid re-authenticating when already authenticated
|
|
128
|
+
*/
|
|
129
|
+
if (this.authenticationAttempted) {
|
|
130
|
+
return this.getUserOrFail();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Beginning authentication attempt
|
|
134
|
+
*/
|
|
135
|
+
this.authenticationAttempted = true;
|
|
136
|
+
if (this.#emitter) {
|
|
137
|
+
this.#emitter.emit('basic_auth:authentication_attempted', {
|
|
138
|
+
guardName: this.#name,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Fetch credentials from the header
|
|
143
|
+
*/
|
|
144
|
+
const credentials = auth(this.#ctx.request.request);
|
|
145
|
+
if (!credentials) {
|
|
146
|
+
this.#authenticationFailed(AuthenticationException.E_INVALID_BASIC_AUTH_CREDENTIALS());
|
|
147
|
+
}
|
|
148
|
+
debug('basic_auth_guard: authenticating user using credentials');
|
|
149
|
+
/**
|
|
150
|
+
* Verifying user credentials
|
|
151
|
+
*/
|
|
152
|
+
this.user = await this.verifyCredentials(credentials.name, credentials.pass);
|
|
153
|
+
this.isAuthenticated = true;
|
|
154
|
+
debug('basic_auth_guard: marking user as authenticated');
|
|
155
|
+
if (this.#emitter) {
|
|
156
|
+
this.#emitter.emit('basic_auth:authentication_succeeded', {
|
|
157
|
+
guardName: this.#name,
|
|
158
|
+
user: this.user,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Return user
|
|
163
|
+
*/
|
|
164
|
+
return this.getUserOrFail();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Silently attempt to authenticate the user.
|
|
168
|
+
*
|
|
169
|
+
* The method returns a boolean indicating if the authentication
|
|
170
|
+
* succeeded or failed.
|
|
171
|
+
*/
|
|
172
|
+
async check() {
|
|
173
|
+
try {
|
|
174
|
+
await this.authenticate();
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
if (error instanceof AuthenticationException) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Not support
|
|
186
|
+
*/
|
|
187
|
+
async authenticateAsClient(_) {
|
|
188
|
+
throw new RuntimeException('Cannot authenticate as a client when using basic auth');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/auth
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
export { BasicAuthGuard } from './guard.js';
|
|
10
|
+
export { basicAuthGuard } from './define_config.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Exception } from '@poppinss/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Events emitted by the basic auth guard
|
|
4
|
+
*/
|
|
5
|
+
export type BasicAuthGuardEvents<User> = {
|
|
6
|
+
/**
|
|
7
|
+
* The event is emitted when the user credentials
|
|
8
|
+
* have been verified successfully.
|
|
9
|
+
*/
|
|
10
|
+
'basic_auth:credentials_verified': {
|
|
11
|
+
guardName: string;
|
|
12
|
+
uid: string;
|
|
13
|
+
user: User;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Attempting to authenticate the user
|
|
17
|
+
*/
|
|
18
|
+
'basic_auth:authentication_attempted': {
|
|
19
|
+
guardName: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Authentication was successful
|
|
23
|
+
*/
|
|
24
|
+
'basic_auth:authentication_succeeded': {
|
|
25
|
+
guardName: string;
|
|
26
|
+
user: User;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Authentication failed
|
|
30
|
+
*/
|
|
31
|
+
'basic_auth:authentication_failed': {
|
|
32
|
+
guardName: string;
|
|
33
|
+
error: Exception;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -327,6 +327,7 @@ export class SessionGuard {
|
|
|
327
327
|
if (!providerUser) {
|
|
328
328
|
this.#authenticationFailed(AuthenticationException.E_INVALID_AUTH_SESSION(), session.sessionId);
|
|
329
329
|
}
|
|
330
|
+
debug('session_guard: marking user with id "%s" as authenticated', providerUser.getId());
|
|
330
331
|
this.user = providerUser.getOriginal();
|
|
331
332
|
this.isAuthenticated = true;
|
|
332
333
|
this.isLoggedOut = false;
|
|
@@ -390,6 +391,7 @@ export class SessionGuard {
|
|
|
390
391
|
debug('session_guard: marking user with id "%s" as logged in from remember me cookie', userId);
|
|
391
392
|
session.put(this.sessionKeyName, userId);
|
|
392
393
|
session.regenerate();
|
|
394
|
+
debug('session_guard: marking user with id "%s" as authenticated', userId);
|
|
393
395
|
this.user = providerUser.getOriginal();
|
|
394
396
|
this.isAuthenticated = true;
|
|
395
397
|
this.isLoggedOut = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonisjs/auth",
|
|
3
|
-
"version": "9.0.0-
|
|
3
|
+
"version": "9.0.0-8",
|
|
4
4
|
"description": "Official authentication provider for Adonis framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"./types": "./build/src/auth/types.js",
|
|
24
24
|
"./auth_provider": "./build/providers/auth_provider.js",
|
|
25
25
|
"./plugins/api_client": "./build/src/auth/plugins/japa/api_client.js",
|
|
26
|
+
"./plugins/browser_client": "./build/src/auth/plugins/japa/browser_client.js",
|
|
26
27
|
"./services/main": "./build/services/auth.js",
|
|
27
28
|
"./core/token": "./build/src/core/token.js",
|
|
28
29
|
"./core/guard_user": "./build/src/core/guard_user.js",
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
"./core/token_providers/*": "./build/src/core/token_providers/*.js",
|
|
31
32
|
"./types/core": "./build/src/core/types.js",
|
|
32
33
|
"./session": "./build/src/guards/session/main.js",
|
|
34
|
+
"./basic_auth": "./build/src/guards/basic_auth/main.js",
|
|
33
35
|
"./initialize_auth_middleware": "./build/src/auth/middleware/initialize_auth_middleware.js",
|
|
34
36
|
"./types/session": "./build/src/guards/session/types.js"
|
|
35
37
|
},
|
|
@@ -77,11 +79,14 @@
|
|
|
77
79
|
"@commitlint/config-conventional": "^18.0.0",
|
|
78
80
|
"@japa/api-client": "^2.0.0",
|
|
79
81
|
"@japa/assert": "^2.0.0",
|
|
82
|
+
"@japa/browser-client": "^2.0.0",
|
|
80
83
|
"@japa/expect-type": "^2.0.0",
|
|
81
84
|
"@japa/file-system": "^2.0.0",
|
|
85
|
+
"@japa/plugin-adonisjs": "^2.0.0",
|
|
82
86
|
"@japa/runner": "^3.0.4",
|
|
83
87
|
"@japa/snapshot": "^2.0.0",
|
|
84
88
|
"@swc/core": "1.3.82",
|
|
89
|
+
"@types/basic-auth": "^1.1.5",
|
|
85
90
|
"@types/luxon": "^3.3.3",
|
|
86
91
|
"@types/node": "^20.8.7",
|
|
87
92
|
"@types/set-cookie-parser": "^2.4.5",
|
|
@@ -94,6 +99,7 @@
|
|
|
94
99
|
"husky": "^8.0.3",
|
|
95
100
|
"luxon": "^3.4.3",
|
|
96
101
|
"np": "^8.0.4",
|
|
102
|
+
"playwright": "^1.39.0",
|
|
97
103
|
"prettier": "^3.0.3",
|
|
98
104
|
"set-cookie-parser": "^2.6.0",
|
|
99
105
|
"sqlite3": "^5.1.6",
|
|
@@ -131,13 +137,16 @@
|
|
|
131
137
|
]
|
|
132
138
|
},
|
|
133
139
|
"dependencies": {
|
|
134
|
-
"@poppinss/utils": "^6.5.0"
|
|
140
|
+
"@poppinss/utils": "^6.5.0",
|
|
141
|
+
"basic-auth": "^2.0.1"
|
|
135
142
|
},
|
|
136
143
|
"peerDependencies": {
|
|
137
144
|
"@adonisjs/core": "^6.1.5-31",
|
|
138
145
|
"@adonisjs/lucid": "^19.0.0-3",
|
|
139
146
|
"@adonisjs/session": "^7.0.0-13",
|
|
140
|
-
"@japa/api-client": "^2.0.0"
|
|
147
|
+
"@japa/api-client": "^2.0.0",
|
|
148
|
+
"@japa/browser-client": "^2.0.0",
|
|
149
|
+
"@japa/plugin-adonisjs": "^2.0.0"
|
|
141
150
|
},
|
|
142
151
|
"peerDependenciesMeta": {
|
|
143
152
|
"@adonisjs/lucid": {
|
|
@@ -148,6 +157,12 @@
|
|
|
148
157
|
},
|
|
149
158
|
"@japa/api-client": {
|
|
150
159
|
"optional": true
|
|
160
|
+
},
|
|
161
|
+
"@japa/browser-client": {
|
|
162
|
+
"optional": true
|
|
163
|
+
},
|
|
164
|
+
"@japa/plugin-adonisjs": {
|
|
165
|
+
"optional": true
|
|
151
166
|
}
|
|
152
167
|
}
|
|
153
168
|
}
|