@loopback/authentication 4.2.9 → 6.0.1
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/CHANGELOG.md +56 -0
- package/README.md +13 -9
- package/dist/authentication.component.d.ts +5 -3
- package/dist/authentication.component.js +3 -2
- package/dist/authentication.component.js.map +1 -1
- package/dist/decorators/authenticate.decorator.d.ts +4 -5
- package/dist/decorators/authenticate.decorator.js +16 -13
- package/dist/decorators/authenticate.decorator.js.map +1 -1
- package/dist/keys.d.ts +11 -7
- package/dist/keys.js +8 -5
- package/dist/keys.js.map +1 -1
- package/dist/providers/auth-action.provider.d.ts +8 -3
- package/dist/providers/auth-action.provider.js +75 -24
- package/dist/providers/auth-action.provider.js.map +1 -1
- package/dist/providers/auth-metadata.provider.d.ts +2 -2
- package/dist/providers/auth-metadata.provider.js +2 -1
- package/dist/providers/auth-metadata.provider.js.map +1 -1
- package/dist/providers/auth-strategy.provider.d.ts +5 -5
- package/dist/providers/auth-strategy.provider.js +23 -17
- package/dist/providers/auth-strategy.provider.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.js +11 -1
- package/dist/types.js.map +1 -1
- package/package.json +14 -15
- package/src/authentication.component.ts +9 -10
- package/src/decorators/authenticate.decorator.ts +24 -22
- package/src/keys.ts +18 -11
- package/src/providers/auth-action.provider.ts +88 -26
- package/src/providers/auth-metadata.provider.ts +4 -4
- package/src/providers/auth-strategy.provider.ts +32 -21
- package/src/types.ts +15 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,62 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [6.0.1](https://github.com/strongloop/loopback-next/compare/@loopback/authentication@6.0.0...@loopback/authentication@6.0.1) (2020-08-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @loopback/authentication
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [6.0.0](https://github.com/strongloop/loopback-next/compare/@loopback/authentication@5.0.0...@loopback/authentication@6.0.0) (2020-08-19)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **authentication:** add support for multiple strategies on same method ([f2f1580](https://github.com/strongloop/loopback-next/commit/f2f15806189d568d0a2c6d6198de74e6801f094c)), closes [#5310](https://github.com/strongloop/loopback-next/issues/5310)
|
|
20
|
+
* **authentication:** update signature of authenticate decorator ([ae6c0e6](https://github.com/strongloop/loopback-next/commit/ae6c0e68a58a2b574fd534242e599aa2a96fc855))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### BREAKING CHANGES
|
|
24
|
+
|
|
25
|
+
* **authentication:** The `@authenticate` signature changed, options are no longer
|
|
26
|
+
a separate input parameter but instead have to be provided in the metadata object.
|
|
27
|
+
The metadata value is now `AuthenticationMetadata[]`.
|
|
28
|
+
|
|
29
|
+
Signed-off-by: nflaig <nflaig@protonmail.com>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# [5.0.0](https://github.com/strongloop/loopback-next/compare/@loopback/authentication@4.2.10...@loopback/authentication@5.0.0) (2020-08-05)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
* **authentication:** add a middleware for authentication ([de6f96c](https://github.com/strongloop/loopback-next/commit/de6f96c7af946486ded0425e643ff22c92d6f04f))
|
|
41
|
+
* **authentication:** authentication action is no longer needed ([041fa21](https://github.com/strongloop/loopback-next/commit/041fa213482bcfe723dd075518fa890dce3936e0))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### BREAKING CHANGES
|
|
45
|
+
|
|
46
|
+
* **authentication:** with the newly introduced middleware-based sequence for
|
|
47
|
+
'@loopback/rest', it is no longer needed to explicitly add the authentication
|
|
48
|
+
action for middleware-based sequence.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## [4.2.10](https://github.com/strongloop/loopback-next/compare/@loopback/authentication@4.2.9...@loopback/authentication@4.2.10) (2020-07-20)
|
|
55
|
+
|
|
56
|
+
**Note:** Version bump only for package @loopback/authentication
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
6
62
|
## [4.2.9](https://github.com/strongloop/loopback-next/compare/@loopback/authentication@4.2.8...@loopback/authentication@4.2.9) (2020-06-30)
|
|
7
63
|
|
|
8
64
|
**Note:** Version bump only for package @loopback/authentication
|
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @loopback/authentication
|
|
2
2
|
|
|
3
|
-
A LoopBack 4 component for authentication support.
|
|
3
|
+
A LoopBack 4 component for authentication support. Its corresponding
|
|
4
|
+
documentation is in
|
|
5
|
+
[LoopBack component authentication](https://loopback.io/doc/en/lb4/Loopback-component-authentication.html)
|
|
4
6
|
|
|
5
7
|
## Overview
|
|
6
8
|
|
|
@@ -13,7 +15,8 @@ It contains:
|
|
|
13
15
|
|
|
14
16
|
- A decorator to express an authentication requirement on controller methods
|
|
15
17
|
- A provider to access method-level authentication metadata
|
|
16
|
-
- An action in the REST sequence to enforce authentication
|
|
18
|
+
- An action in the REST sequence to enforce authentication (**No longer needed
|
|
19
|
+
for middleware based sequence**)
|
|
17
20
|
- An extension point to discover all authentication strategies and handle the
|
|
18
21
|
delegation
|
|
19
22
|
|
|
@@ -25,22 +28,23 @@ npm install --save @loopback/authentication
|
|
|
25
28
|
|
|
26
29
|
## Basic Use
|
|
27
30
|
|
|
28
|
-
[Load the AuthenticationComponent](https://loopback.io/doc/en/lb4/Loopback-component-authentication.html#authentication-component)
|
|
31
|
+
[Load the AuthenticationComponent](https://loopback.io/doc/en/lb4/Loopback-component-authentication.html#mounting-authentication-component)
|
|
29
32
|
into your application.
|
|
30
33
|
|
|
31
34
|
**Extension developers** need to:
|
|
32
35
|
|
|
33
|
-
- [create custom authentication strategies](https://loopback.io/doc/en/lb4/
|
|
36
|
+
- [create custom authentication strategies](https://loopback.io/doc/en/lb4/Implement-your-own-strategy.html)
|
|
34
37
|
|
|
35
38
|
**Application Developers** need to:
|
|
36
39
|
|
|
37
|
-
- [decorate controller functions with the authentication decorator](https://loopback.io/doc/en/lb4/
|
|
38
|
-
- [add the authentication action to a custom sequence](https://loopback.io/doc/en/lb4/
|
|
40
|
+
- [decorate controller functions with the authentication decorator](https://loopback.io/doc/en/lb4/Authentication-component-decorator.html)
|
|
41
|
+
- [add the authentication action to a custom sequence](https://loopback.io/doc/en/lb4/Authentication-component-action.html#adding-an-authentication-action-to-a-custom-sequence)
|
|
39
42
|
and
|
|
40
|
-
[bind the custom sequence to the application](https://loopback.io/doc/en/lb4/
|
|
41
|
-
|
|
43
|
+
[bind the custom sequence to the application](https://loopback.io/doc/en/lb4/Authentication-component-action.html#binding-the-authenticating-sequence-to-the-application)
|
|
44
|
+
(**No longer needed for middleware based sequence**)
|
|
45
|
+
- [register the authentication strategies](https://loopback.io/doc/en/lb4/Authentication-component-strategy.html)
|
|
42
46
|
|
|
43
|
-
[Create and register a passport based strategy](https://
|
|
47
|
+
[Create and register a passport based strategy](https://loopback.io/doc/en/lb4/Authentication-passport.html)
|
|
44
48
|
|
|
45
49
|
## Related resources
|
|
46
50
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Component
|
|
1
|
+
import { Component } from '@loopback/core';
|
|
2
|
+
import { AuthenticateActionProvider, AuthenticationMiddlewareProvider, AuthenticationStrategyProvider, AuthMetadataProvider } from './providers';
|
|
2
3
|
export declare class AuthenticationComponent implements Component {
|
|
3
|
-
providers
|
|
4
|
-
|
|
4
|
+
providers: {
|
|
5
|
+
[x: string]: typeof AuthenticateActionProvider | typeof AuthenticationMiddlewareProvider | typeof AuthMetadataProvider | typeof AuthenticationStrategyProvider;
|
|
6
|
+
};
|
|
5
7
|
}
|
|
@@ -15,12 +15,13 @@ let AuthenticationComponent = class AuthenticationComponent {
|
|
|
15
15
|
[keys_1.AuthenticationBindings.AUTH_ACTION.key]: providers_1.AuthenticateActionProvider,
|
|
16
16
|
[keys_1.AuthenticationBindings.STRATEGY.key]: providers_1.AuthenticationStrategyProvider,
|
|
17
17
|
[keys_1.AuthenticationBindings.METADATA.key]: providers_1.AuthMetadataProvider,
|
|
18
|
+
[keys_1.AuthenticationBindings.AUTHENTICATION_MIDDLEWARE
|
|
19
|
+
.key]: providers_1.AuthenticationMiddlewareProvider,
|
|
18
20
|
};
|
|
19
21
|
}
|
|
20
22
|
};
|
|
21
23
|
AuthenticationComponent = tslib_1.__decorate([
|
|
22
|
-
core_1.bind({ tags: { [core_1.ContextTags.KEY]: keys_1.AuthenticationBindings.COMPONENT } })
|
|
23
|
-
tslib_1.__metadata("design:paramtypes", [])
|
|
24
|
+
core_1.bind({ tags: { [core_1.ContextTags.KEY]: keys_1.AuthenticationBindings.COMPONENT } })
|
|
24
25
|
], AuthenticationComponent);
|
|
25
26
|
exports.AuthenticationComponent = AuthenticationComponent;
|
|
26
27
|
//# sourceMappingURL=authentication.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authentication.component.js","sourceRoot":"","sources":["../src/authentication.component.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,
|
|
1
|
+
{"version":3,"file":"authentication.component.js","sourceRoot":"","sources":["../src/authentication.component.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAA4D;AAC5D,iCAA8C;AAC9C,2CAKqB;AAGrB,IAAa,uBAAuB,GAApC,MAAa,uBAAuB;IAApC;QACE,cAAS,GAAG;YACV,CAAC,6BAAsB,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,sCAA0B;YACpE,CAAC,6BAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,0CAA8B;YACrE,CAAC,6BAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,gCAAoB;YAC3D,CAAC,6BAAsB,CAAC,yBAAyB;iBAC9C,GAAG,CAAC,EAAE,4CAAgC;SAC1C,CAAC;IACJ,CAAC;CAAA,CAAA;AARY,uBAAuB;IADnC,WAAI,CAAC,EAAC,IAAI,EAAE,EAAC,CAAC,kBAAW,CAAC,GAAG,CAAC,EAAE,6BAAsB,CAAC,SAAS,EAAC,EAAC,CAAC;GACvD,uBAAuB,CAQnC;AARY,0DAAuB"}
|
|
@@ -3,11 +3,10 @@ import { AuthenticationMetadata } from '../types';
|
|
|
3
3
|
/**
|
|
4
4
|
* Mark a controller method as requiring authenticated user.
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
7
|
-
* or
|
|
8
|
-
* @param options - Additional options to configure the authentication.
|
|
6
|
+
* @param strategies - The names of the authentication strategies to use
|
|
7
|
+
* or authentication metadata objects.
|
|
9
8
|
*/
|
|
10
|
-
export declare function authenticate(
|
|
9
|
+
export declare function authenticate(...strategies: (string | AuthenticationMetadata)[]): (target: any, method?: string | undefined, methodDescriptor?: TypedPropertyDescriptor<any> | undefined) => any;
|
|
11
10
|
export declare namespace authenticate {
|
|
12
11
|
/**
|
|
13
12
|
* `@authenticate.skip()` - a sugar decorator to skip authentication
|
|
@@ -20,4 +19,4 @@ export declare namespace authenticate {
|
|
|
20
19
|
* @param targetClass - Target controller
|
|
21
20
|
* @param methodName - Target method
|
|
22
21
|
*/
|
|
23
|
-
export declare function getAuthenticateMetadata(targetClass: Constructor<{}>, methodName: string): AuthenticationMetadata | undefined;
|
|
22
|
+
export declare function getAuthenticateMetadata(targetClass: Constructor<{}>, methodName: string): AuthenticationMetadata[] | undefined;
|
|
@@ -12,11 +12,10 @@ class AuthenticateClassDecoratorFactory extends core_1.ClassDecoratorFactory {
|
|
|
12
12
|
/**
|
|
13
13
|
* Mark a controller method as requiring authenticated user.
|
|
14
14
|
*
|
|
15
|
-
* @param
|
|
16
|
-
* or
|
|
17
|
-
* @param options - Additional options to configure the authentication.
|
|
15
|
+
* @param strategies - The names of the authentication strategies to use
|
|
16
|
+
* or authentication metadata objects.
|
|
18
17
|
*/
|
|
19
|
-
function authenticate(
|
|
18
|
+
function authenticate(...strategies) {
|
|
20
19
|
return function authenticateDecoratorForClassOrMethod(
|
|
21
20
|
// Class or a prototype
|
|
22
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -25,23 +24,27 @@ function authenticate(strategyNameOrMetadata, options) {
|
|
|
25
24
|
// See https://github.com/strongloop/loopback-next/pull/2704
|
|
26
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
26
|
methodDescriptor) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const specs = [];
|
|
28
|
+
for (const strategy of strategies) {
|
|
29
|
+
if (typeof strategy === 'object') {
|
|
30
|
+
specs.push(strategy);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
specs.push({ strategy: strategy });
|
|
34
|
+
}
|
|
34
35
|
}
|
|
35
36
|
if (method && methodDescriptor) {
|
|
36
37
|
// Method
|
|
37
|
-
return core_1.MethodDecoratorFactory.createDecorator(keys_1.AUTHENTICATION_METADATA_KEY,
|
|
38
|
+
return core_1.MethodDecoratorFactory.createDecorator(keys_1.AUTHENTICATION_METADATA_KEY, specs, { decoratorName: '@authenticate' })(target, method, methodDescriptor);
|
|
38
39
|
}
|
|
39
40
|
if (typeof target === 'function' && !method && !methodDescriptor) {
|
|
40
41
|
// Class
|
|
41
|
-
return AuthenticateClassDecoratorFactory.createDecorator(keys_1.AUTHENTICATION_METADATA_CLASS_KEY,
|
|
42
|
+
return AuthenticateClassDecoratorFactory.createDecorator(keys_1.AUTHENTICATION_METADATA_CLASS_KEY, specs, {
|
|
43
|
+
decoratorName: '@authenticate',
|
|
44
|
+
})(target);
|
|
42
45
|
}
|
|
43
46
|
// Not on a class or method
|
|
44
|
-
throw new Error('@
|
|
47
|
+
throw new Error('@authenticate cannot be used on a property: ' +
|
|
45
48
|
core_1.DecoratorFactory.getTargetName(target, method, methodDescriptor));
|
|
46
49
|
};
|
|
47
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.decorator.js","sourceRoot":"","sources":["../../src/decorators/authenticate.decorator.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAMwB;AACxB,kCAIiB;AAGjB,MAAM,iCAAkC,SAAQ,4BAE/C;CAAG;AAEJ
|
|
1
|
+
{"version":3,"file":"authenticate.decorator.js","sourceRoot":"","sources":["../../src/decorators/authenticate.decorator.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAMwB;AACxB,kCAIiB;AAGjB,MAAM,iCAAkC,SAAQ,4BAE/C;CAAG;AAEJ;;;;;GAKG;AACH,SAAgB,YAAY,CAC1B,GAAG,UAA+C;IAElD,OAAO,SAAS,qCAAqC;IACnD,uBAAuB;IACvB,8DAA8D;IAC9D,MAAW,EACX,MAAe;IACf,6CAA6C;IAC7C,4DAA4D;IAC5D,8DAA8D;IAC9D,gBAA+C;QAE/C,MAAM,KAAK,GAA6B,EAAE,CAAC;QAE3C,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE;YACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE;gBAChC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aACtB;iBAAM;gBACL,KAAK,CAAC,IAAI,CAAC,EAAC,QAAQ,EAAE,QAAQ,EAAC,CAAC,CAAC;aAClC;SACF;QAED,IAAI,MAAM,IAAI,gBAAgB,EAAE;YAC9B,SAAS;YACT,OAAO,6BAAsB,CAAC,eAAe,CAC3C,kCAA2B,EAC3B,KAAK,EACL,EAAC,aAAa,EAAE,eAAe,EAAC,CACjC,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;SACrC;QACD,IAAI,OAAO,MAAM,KAAK,UAAU,IAAI,CAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE;YAChE,QAAQ;YACR,OAAO,iCAAiC,CAAC,eAAe,CAEtD,wCAAiC,EAAE,KAAK,EAAE;gBAC1C,aAAa,EAAE,eAAe;aAC/B,CAAC,CAAC,MAAM,CAAC,CAAC;SACZ;QACD,2BAA2B;QAC3B,MAAM,IAAI,KAAK,CACb,8CAA8C;YAC5C,uBAAgB,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,CAAC,CACnE,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AA7CD,oCA6CC;AAED,WAAiB,YAAY;IAC3B;;OAEG;IACU,iBAAI,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,EAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;AACrE,CAAC,EALgB,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAK5B;AAED;;;;;GAKG;AACH,SAAgB,uBAAuB,CACrC,WAA4B,EAC5B,UAAkB;IAElB,2BAA2B;IAC3B,IAAI,QAAQ,GAAG,wBAAiB,CAAC,iBAAiB,CAChD,yCAAkC,EAClC,WAAW,CAAC,SAAS,EACrB,UAAU,CACX,CAAC;IACF,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,GAAG,wBAAiB,CAAC,gBAAgB,CAC3C,wCAAiC,EACjC,WAAW,CACZ,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAjBD,0DAiBC"}
|
package/dist/keys.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BindingKey, MetadataAccessor } from '@loopback/core';
|
|
2
2
|
import { UserProfile } from '@loopback/security';
|
|
3
|
+
import { Middleware } from '@loopback/rest';
|
|
3
4
|
import { AuthenticationComponent } from './authentication.component';
|
|
4
5
|
import { AuthenticateFn, AuthenticationMetadata, AuthenticationStrategy, UserProfileFactory } from './types';
|
|
5
6
|
/**
|
|
@@ -21,8 +22,8 @@ export declare namespace AuthenticationBindings {
|
|
|
21
22
|
*/
|
|
22
23
|
const USER_PROFILE_FACTORY: BindingKey<UserProfileFactory<any>>;
|
|
23
24
|
/**
|
|
24
|
-
* Key used to bind an authentication strategy
|
|
25
|
-
* authentication function to use.
|
|
25
|
+
* Key used to bind an authentication strategy or multiple strategies
|
|
26
|
+
* to the context for the authentication function to use.
|
|
26
27
|
*
|
|
27
28
|
* @example
|
|
28
29
|
* ```ts
|
|
@@ -31,7 +32,7 @@ export declare namespace AuthenticationBindings {
|
|
|
31
32
|
* .toProvider(MyAuthenticationStrategy);
|
|
32
33
|
* ```
|
|
33
34
|
*/
|
|
34
|
-
const STRATEGY: BindingKey<AuthenticationStrategy | undefined>;
|
|
35
|
+
const STRATEGY: BindingKey<AuthenticationStrategy | AuthenticationStrategy[] | undefined>;
|
|
35
36
|
/**
|
|
36
37
|
* Key used to inject the authentication function into the sequence.
|
|
37
38
|
*
|
|
@@ -64,6 +65,10 @@ export declare namespace AuthenticationBindings {
|
|
|
64
65
|
* ```
|
|
65
66
|
*/
|
|
66
67
|
const AUTH_ACTION: BindingKey<AuthenticateFn>;
|
|
68
|
+
/**
|
|
69
|
+
* Binding key for AUTHENTICATION_MIDDLEWARE
|
|
70
|
+
*/
|
|
71
|
+
const AUTHENTICATION_MIDDLEWARE: BindingKey<Middleware>;
|
|
67
72
|
/**
|
|
68
73
|
* Key used to inject authentication metadata, which is used to determine
|
|
69
74
|
* whether a request requires authentication or not.
|
|
@@ -73,18 +78,17 @@ export declare namespace AuthenticationBindings {
|
|
|
73
78
|
* class MyPassportStrategyProvider implements Provider<Strategy | undefined> {
|
|
74
79
|
* constructor(
|
|
75
80
|
* @inject(AuthenticationBindings.METADATA)
|
|
76
|
-
* private metadata
|
|
81
|
+
* private metadata?: AuthenticationMetadata[],
|
|
77
82
|
* ) {}
|
|
78
83
|
* value(): ValueOrPromise<Strategy | undefined> {
|
|
79
|
-
* if (this.metadata) {
|
|
80
|
-
* const name = this.metadata.strategy;
|
|
84
|
+
* if (this.metadata?.length) {
|
|
81
85
|
* // logic to determine which authentication strategy to return
|
|
82
86
|
* }
|
|
83
87
|
* }
|
|
84
88
|
* }
|
|
85
89
|
* ```
|
|
86
90
|
*/
|
|
87
|
-
const METADATA: BindingKey<AuthenticationMetadata | undefined>;
|
|
91
|
+
const METADATA: BindingKey<AuthenticationMetadata[] | undefined>;
|
|
88
92
|
const AUTHENTICATION_STRATEGY_EXTENSION_POINT_NAME = "authentication.strategies";
|
|
89
93
|
const CURRENT_USER: BindingKey<UserProfile>;
|
|
90
94
|
const AUTHENTICATION_REDIRECT_URL: BindingKey<string>;
|
package/dist/keys.js
CHANGED
|
@@ -28,8 +28,8 @@ var AuthenticationBindings;
|
|
|
28
28
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
29
29
|
AuthenticationBindings.USER_PROFILE_FACTORY = core_1.BindingKey.create('authentication.userProfileFactory');
|
|
30
30
|
/**
|
|
31
|
-
* Key used to bind an authentication strategy
|
|
32
|
-
* authentication function to use.
|
|
31
|
+
* Key used to bind an authentication strategy or multiple strategies
|
|
32
|
+
* to the context for the authentication function to use.
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```ts
|
|
@@ -71,6 +71,10 @@ var AuthenticationBindings;
|
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
73
|
AuthenticationBindings.AUTH_ACTION = core_1.BindingKey.create('authentication.actions.authenticate');
|
|
74
|
+
/**
|
|
75
|
+
* Binding key for AUTHENTICATION_MIDDLEWARE
|
|
76
|
+
*/
|
|
77
|
+
AuthenticationBindings.AUTHENTICATION_MIDDLEWARE = core_1.BindingKey.create('middleware.authentication');
|
|
74
78
|
/**
|
|
75
79
|
* Key used to inject authentication metadata, which is used to determine
|
|
76
80
|
* whether a request requires authentication or not.
|
|
@@ -80,11 +84,10 @@ var AuthenticationBindings;
|
|
|
80
84
|
* class MyPassportStrategyProvider implements Provider<Strategy | undefined> {
|
|
81
85
|
* constructor(
|
|
82
86
|
* @inject(AuthenticationBindings.METADATA)
|
|
83
|
-
* private metadata
|
|
87
|
+
* private metadata?: AuthenticationMetadata[],
|
|
84
88
|
* ) {}
|
|
85
89
|
* value(): ValueOrPromise<Strategy | undefined> {
|
|
86
|
-
* if (this.metadata) {
|
|
87
|
-
* const name = this.metadata.strategy;
|
|
90
|
+
* if (this.metadata?.length) {
|
|
88
91
|
* // logic to determine which authentication strategy to return
|
|
89
92
|
* }
|
|
90
93
|
* }
|
package/dist/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAA4D;AAC5D,iDAAiE;
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAA4D;AAC5D,iDAAiE;AAUjE;;GAEG;AACH,IAAiB,sBAAsB,CAqHtC;AArHD,WAAiB,sBAAsB;IACxB,gCAAS,GAAG,iBAAU,CAAC,MAAM,CACxC,oCAAoC,CACrC,CAAC;IAEF;;;;;;;;;;;OAWG;IACH,uDAAuD;IAC1C,2CAAoB,GAAG,iBAAU,CAAC,MAAM,CAEnD,mCAAmC,CAAC,CAAC;IAEvC;;;;;;;;;;OAUG;IACU,+BAAQ,GAAG,iBAAU,CAAC,MAAM,CAEvC,yBAAyB,CAAC,CAAC;IAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACU,kCAAW,GAAG,iBAAU,CAAC,MAAM,CAC1C,qCAAqC,CACtC,CAAC;IAEF;;OAEG;IACU,gDAAyB,GAAG,iBAAU,CAAC,MAAM,CACxD,2BAA2B,CAC5B,CAAC;IAEF;;;;;;;;;;;;;;;;;;OAkBG;IACU,+BAAQ,GAAG,iBAAU,CAAC,MAAM,CAEvC,kCAAkC,CAAC,CAAC;IAEzB,mEAA4C,GACvD,2BAA2B,CAAC;IAE9B,oFAAoF;IACvE,mCAAY,GAA4B,2BAAgB,CAAC,IAAI,CAAC;IAE3E,+CAA+C;IAClC,kDAA2B,GAAG,iBAAU,CAAC,MAAM,CAC1D,6BAA6B,CAC9B,CAAC;IAEF,2FAA2F;IAC9E,qDAA8B,GAAG,iBAAU,CAAC,MAAM,CAC7D,gCAAgC,CACjC,CAAC;AACJ,CAAC,EArHgB,sBAAsB,GAAtB,8BAAsB,KAAtB,8BAAsB,QAqHtC;AAED;;GAEG;AACU,QAAA,kCAAkC,GAAG,uBAAgB,CAAC,MAAM,CAGvE,uBAAuB,CAAC,CAAC;AAE3B;;GAEG;AACU,QAAA,2BAA2B,GAAG,0CAAkC,CAAC;AAE9E;;GAEG;AACU,QAAA,iCAAiC,GAAG,uBAAgB,CAAC,MAAM,CAGtE,sBAAsB,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Getter, Provider, Setter } from '@loopback/core';
|
|
2
|
-
import { Request } from '@loopback/rest';
|
|
2
|
+
import { Middleware, Request } from '@loopback/rest';
|
|
3
3
|
import { UserProfile } from '@loopback/security';
|
|
4
4
|
import { AuthenticateFn, AuthenticationStrategy } from '../types';
|
|
5
5
|
/**
|
|
@@ -7,11 +7,11 @@ import { AuthenticateFn, AuthenticationStrategy } from '../types';
|
|
|
7
7
|
* @example `context.bind('authentication.actions.authenticate').toProvider(AuthenticateActionProvider)`
|
|
8
8
|
*/
|
|
9
9
|
export declare class AuthenticateActionProvider implements Provider<AuthenticateFn> {
|
|
10
|
-
readonly
|
|
10
|
+
readonly getStrategies: Getter<AuthenticationStrategy | AuthenticationStrategy[] | undefined>;
|
|
11
11
|
readonly setCurrentUser: Setter<UserProfile>;
|
|
12
12
|
readonly setRedirectUrl: Setter<string>;
|
|
13
13
|
readonly setRedirectStatus: Setter<number>;
|
|
14
|
-
constructor(
|
|
14
|
+
constructor(getStrategies: Getter<AuthenticationStrategy | AuthenticationStrategy[] | undefined>, setCurrentUser: Setter<UserProfile>, setRedirectUrl: Setter<string>, setRedirectStatus: Setter<number>);
|
|
15
15
|
/**
|
|
16
16
|
* @returns authenticateFn
|
|
17
17
|
*/
|
|
@@ -22,3 +22,8 @@ export declare class AuthenticateActionProvider implements Provider<Authenticate
|
|
|
22
22
|
*/
|
|
23
23
|
action(request: Request): Promise<UserProfile | undefined>;
|
|
24
24
|
}
|
|
25
|
+
export declare class AuthenticationMiddlewareProvider implements Provider<Middleware> {
|
|
26
|
+
private authenticate;
|
|
27
|
+
constructor(authenticate: AuthenticateFn);
|
|
28
|
+
value(): Middleware;
|
|
29
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// This file is licensed under the MIT License.
|
|
5
5
|
// License text available at https://opensource.org/licenses/MIT
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.AuthenticateActionProvider = void 0;
|
|
7
|
+
exports.AuthenticationMiddlewareProvider = exports.AuthenticateActionProvider = void 0;
|
|
8
8
|
const tslib_1 = require("tslib");
|
|
9
9
|
const core_1 = require("@loopback/core");
|
|
10
10
|
const rest_1 = require("@loopback/rest");
|
|
@@ -24,8 +24,8 @@ let AuthenticateActionProvider = class AuthenticateActionProvider {
|
|
|
24
24
|
// To solve this, we are injecting a getter function that will
|
|
25
25
|
// defer resolution of the strategy until authenticate() action
|
|
26
26
|
// is executed.
|
|
27
|
-
|
|
28
|
-
this.
|
|
27
|
+
getStrategies, setCurrentUser, setRedirectUrl, setRedirectStatus) {
|
|
28
|
+
this.getStrategies = getStrategies;
|
|
29
29
|
this.setCurrentUser = setCurrentUser;
|
|
30
30
|
this.setRedirectUrl = setRedirectUrl;
|
|
31
31
|
this.setRedirectStatus = setRedirectStatus;
|
|
@@ -41,35 +41,57 @@ let AuthenticateActionProvider = class AuthenticateActionProvider {
|
|
|
41
41
|
* @param request - The incoming request provided by the REST layer
|
|
42
42
|
*/
|
|
43
43
|
async action(request) {
|
|
44
|
-
|
|
45
|
-
if (!
|
|
44
|
+
let strategies = await this.getStrategies();
|
|
45
|
+
if (!strategies) {
|
|
46
46
|
// The invoked operation does not require authentication.
|
|
47
47
|
return undefined;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
// convert to array if required
|
|
50
|
+
strategies = Array.isArray(strategies) ? strategies : [strategies];
|
|
51
|
+
let authenticated = false;
|
|
52
|
+
let redirected = false;
|
|
53
|
+
let authError;
|
|
54
|
+
let authResponse;
|
|
50
55
|
let userProfile;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
for (const strategy of strategies) {
|
|
57
|
+
// the first strategy to succeed or redirect will halt the execution chain
|
|
58
|
+
if (authenticated || redirected)
|
|
59
|
+
break;
|
|
60
|
+
try {
|
|
61
|
+
authResponse = await strategy.authenticate(request);
|
|
62
|
+
// response from `strategy.authenticate()` could return an object of type UserProfile or RedirectRoute
|
|
63
|
+
if (rest_1.RedirectRoute.isRedirectRoute(authResponse)) {
|
|
64
|
+
redirected = true;
|
|
65
|
+
const redirectOptions = authResponse;
|
|
66
|
+
// bind redirection url and status to the context
|
|
67
|
+
// controller should handle actual redirection
|
|
68
|
+
this.setRedirectUrl(redirectOptions.targetLocation);
|
|
69
|
+
this.setRedirectStatus(redirectOptions.statusCode);
|
|
70
|
+
}
|
|
71
|
+
else if (authResponse) {
|
|
72
|
+
authenticated = true;
|
|
73
|
+
// if `strategy.authenticate()` returns an object of type UserProfile, set it as current user
|
|
74
|
+
userProfile = authResponse;
|
|
75
|
+
}
|
|
76
|
+
else if (!authResponse) {
|
|
77
|
+
// important to throw a non-protocol-specific error here
|
|
78
|
+
const error = new Error(`User profile not returned from strategy's authenticate function`);
|
|
79
|
+
Object.assign(error, {
|
|
80
|
+
code: types_1.USER_PROFILE_NOT_FOUND,
|
|
81
|
+
});
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
authError = authError !== null && authError !== void 0 ? authError : error;
|
|
87
|
+
}
|
|
58
88
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
89
|
+
if (!authenticated && !redirected)
|
|
90
|
+
throw authError;
|
|
91
|
+
if (userProfile) {
|
|
62
92
|
this.setCurrentUser(userProfile);
|
|
63
93
|
return userProfile;
|
|
64
94
|
}
|
|
65
|
-
else if (!authResponse) {
|
|
66
|
-
// important to throw a non-protocol-specific error here
|
|
67
|
-
const error = new Error(`User profile not returned from strategy's authenticate function`);
|
|
68
|
-
Object.assign(error, {
|
|
69
|
-
code: types_1.USER_PROFILE_NOT_FOUND,
|
|
70
|
-
});
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
95
|
}
|
|
74
96
|
};
|
|
75
97
|
AuthenticateActionProvider = tslib_1.__decorate([
|
|
@@ -80,4 +102,33 @@ AuthenticateActionProvider = tslib_1.__decorate([
|
|
|
80
102
|
tslib_1.__metadata("design:paramtypes", [Function, Function, Function, Function])
|
|
81
103
|
], AuthenticateActionProvider);
|
|
82
104
|
exports.AuthenticateActionProvider = AuthenticateActionProvider;
|
|
105
|
+
let AuthenticationMiddlewareProvider = class AuthenticationMiddlewareProvider {
|
|
106
|
+
constructor(authenticate) {
|
|
107
|
+
this.authenticate = authenticate;
|
|
108
|
+
}
|
|
109
|
+
value() {
|
|
110
|
+
return async (ctx, next) => {
|
|
111
|
+
try {
|
|
112
|
+
await this.authenticate(ctx.request);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (error.code === types_1.AUTHENTICATION_STRATEGY_NOT_FOUND ||
|
|
116
|
+
error.code === types_1.USER_PROFILE_NOT_FOUND) {
|
|
117
|
+
error.statusCode = 401;
|
|
118
|
+
}
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
return next();
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
AuthenticationMiddlewareProvider = tslib_1.__decorate([
|
|
126
|
+
core_1.bind(rest_1.asMiddleware({
|
|
127
|
+
group: rest_1.RestMiddlewareGroups.AUTHENTICATION,
|
|
128
|
+
upstreamGroups: [rest_1.RestMiddlewareGroups.FIND_ROUTE],
|
|
129
|
+
})),
|
|
130
|
+
tslib_1.__param(0, core_1.inject(keys_1.AuthenticationBindings.AUTH_ACTION)),
|
|
131
|
+
tslib_1.__metadata("design:paramtypes", [Function])
|
|
132
|
+
], AuthenticationMiddlewareProvider);
|
|
133
|
+
exports.AuthenticationMiddlewareProvider = AuthenticationMiddlewareProvider;
|
|
83
134
|
//# sourceMappingURL=auth-action.provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-action.provider.js","sourceRoot":"","sources":["../../src/providers/auth-action.provider.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,
|
|
1
|
+
{"version":3,"file":"auth-action.provider.js","sourceRoot":"","sources":["../../src/providers/auth-action.provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { AuthenticationMetadata, AuthenticationOptions } from '../types';
|
|
|
4
4
|
* Provides authentication metadata of a controller method
|
|
5
5
|
* @example `context.bind('authentication.operationMetadata').toProvider(AuthMetadataProvider)`
|
|
6
6
|
*/
|
|
7
|
-
export declare class AuthMetadataProvider implements Provider<AuthenticationMetadata | undefined> {
|
|
7
|
+
export declare class AuthMetadataProvider implements Provider<AuthenticationMetadata[] | undefined> {
|
|
8
8
|
private readonly controllerClass;
|
|
9
9
|
private readonly methodName;
|
|
10
10
|
private readonly options;
|
|
@@ -12,5 +12,5 @@ export declare class AuthMetadataProvider implements Provider<AuthenticationMeta
|
|
|
12
12
|
/**
|
|
13
13
|
* @returns AuthenticationMetadata
|
|
14
14
|
*/
|
|
15
|
-
value(): AuthenticationMetadata | undefined;
|
|
15
|
+
value(): AuthenticationMetadata[] | undefined;
|
|
16
16
|
}
|
|
@@ -23,11 +23,12 @@ let AuthMetadataProvider = class AuthMetadataProvider {
|
|
|
23
23
|
* @returns AuthenticationMetadata
|
|
24
24
|
*/
|
|
25
25
|
value() {
|
|
26
|
+
var _a;
|
|
26
27
|
if (!this.controllerClass || !this.methodName)
|
|
27
28
|
return;
|
|
28
29
|
const metadata = decorators_1.getAuthenticateMetadata(this.controllerClass, this.methodName);
|
|
29
30
|
// Skip authentication if `skip` is `true`
|
|
30
|
-
if (metadata === null || metadata === void 0 ? void 0 : metadata.skip)
|
|
31
|
+
if ((_a = metadata === null || metadata === void 0 ? void 0 : metadata[0]) === null || _a === void 0 ? void 0 : _a.skip)
|
|
31
32
|
return undefined;
|
|
32
33
|
if (metadata)
|
|
33
34
|
return metadata;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-metadata.provider.js","sourceRoot":"","sources":["../../src/providers/auth-metadata.provider.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAMwB;AACxB,8CAAsD;AACtD,kCAA+C;AAG/C;;;GAGG;AACH,IAAa,oBAAoB,GAAjC,MAAa,oBAAoB;IAE/B,YAEmB,eAAgC,EAEhC,UAAkB,EAElB,UAAiC,EAAE;QAJnC,oBAAe,GAAf,eAAe,CAAiB;QAEhC,eAAU,GAAV,UAAU,CAAQ;QAElB,YAAO,GAAP,OAAO,CAA4B;IACnD,CAAC;IAEJ;;OAEG;IACH,KAAK
|
|
1
|
+
{"version":3,"file":"auth-metadata.provider.js","sourceRoot":"","sources":["../../src/providers/auth-metadata.provider.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAMwB;AACxB,8CAAsD;AACtD,kCAA+C;AAG/C;;;GAGG;AACH,IAAa,oBAAoB,GAAjC,MAAa,oBAAoB;IAE/B,YAEmB,eAAgC,EAEhC,UAAkB,EAElB,UAAiC,EAAE;QAJnC,oBAAe,GAAf,eAAe,CAAiB;QAEhC,eAAU,GAAV,UAAU,CAAQ;QAElB,YAAO,GAAP,OAAO,CAA4B;IACnD,CAAC;IAEJ;;OAEG;IACH,KAAK;;QACH,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QACtD,MAAM,QAAQ,GAAG,oCAAuB,CACtC,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,UAAU,CAChB,CAAC;QACF,0CAA0C;QAC1C,UAAI,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,CAAC,2CAAG,IAAI;YAAE,OAAO,SAAS,CAAC;QAC1C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,gCAAgC;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;IACtC,CAAC;CACF,CAAA;AA1BY,oBAAoB;IAG5B,mBAAA,aAAM,CAAC,mBAAY,CAAC,gBAAgB,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAA;IAEvD,mBAAA,aAAM,CAAC,mBAAY,CAAC,sBAAsB,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAA;IAE7D,mBAAA,aAAM,CAAC,EAAC,WAAW,EAAE,6BAAsB,CAAC,SAAS,EAAC,CAAC,CAAA;;GAP/C,oBAAoB,CA0BhC;AA1BY,oDAAoB"}
|
|
@@ -9,10 +9,10 @@ import { AuthenticationMetadata, AuthenticationStrategy } from '../types';
|
|
|
9
9
|
*
|
|
10
10
|
* @example `context.bind('authentication.strategy').toProvider(AuthenticationStrategyProvider)`
|
|
11
11
|
*/
|
|
12
|
-
export declare class AuthenticationStrategyProvider implements Provider<AuthenticationStrategy | undefined> {
|
|
12
|
+
export declare class AuthenticationStrategyProvider implements Provider<AuthenticationStrategy[] | undefined> {
|
|
13
13
|
protected authenticationStrategies: Getter<AuthenticationStrategy[]>;
|
|
14
|
-
protected metadata?: AuthenticationMetadata | undefined;
|
|
15
|
-
constructor(authenticationStrategies: Getter<AuthenticationStrategy[]>, metadata?: AuthenticationMetadata | undefined);
|
|
16
|
-
value(): Promise<AuthenticationStrategy | undefined>;
|
|
17
|
-
|
|
14
|
+
protected metadata?: AuthenticationMetadata[] | undefined;
|
|
15
|
+
constructor(authenticationStrategies: Getter<AuthenticationStrategy[]>, metadata?: AuthenticationMetadata[] | undefined);
|
|
16
|
+
value(): Promise<AuthenticationStrategy[] | undefined>;
|
|
17
|
+
private findAuthenticationStrategies;
|
|
18
18
|
}
|
|
@@ -24,25 +24,31 @@ let AuthenticationStrategyProvider = class AuthenticationStrategyProvider {
|
|
|
24
24
|
this.metadata = metadata;
|
|
25
25
|
}
|
|
26
26
|
async value() {
|
|
27
|
-
|
|
27
|
+
var _a;
|
|
28
|
+
if (!((_a = this.metadata) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
28
29
|
return undefined;
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
const strategy = await this.findAuthenticationStrategy(name);
|
|
32
|
-
if (!strategy) {
|
|
33
|
-
// important to throw a non-protocol-specific error here
|
|
34
|
-
const error = new Error(`The strategy '${name}' is not available.`);
|
|
35
|
-
Object.assign(error, {
|
|
36
|
-
code: types_1.AUTHENTICATION_STRATEGY_NOT_FOUND,
|
|
37
|
-
});
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
return strategy;
|
|
31
|
+
return this.findAuthenticationStrategies(this.metadata);
|
|
41
32
|
}
|
|
42
|
-
async
|
|
43
|
-
const strategies =
|
|
44
|
-
const
|
|
45
|
-
|
|
33
|
+
async findAuthenticationStrategies(metadata) {
|
|
34
|
+
const strategies = [];
|
|
35
|
+
const existingStrategies = await this.authenticationStrategies();
|
|
36
|
+
const findStrategy = (name) => {
|
|
37
|
+
const strategy = existingStrategies.find(a => a.name === name);
|
|
38
|
+
if (!strategy) {
|
|
39
|
+
const error = new Error(`The strategy '${name}' is not available.`);
|
|
40
|
+
Object.assign(error, {
|
|
41
|
+
code: types_1.AUTHENTICATION_STRATEGY_NOT_FOUND,
|
|
42
|
+
});
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
return strategy;
|
|
46
|
+
};
|
|
47
|
+
for (const data of metadata) {
|
|
48
|
+
const strategy = findStrategy(data.strategy);
|
|
49
|
+
strategies.push(strategy);
|
|
50
|
+
}
|
|
51
|
+
return strategies;
|
|
46
52
|
}
|
|
47
53
|
};
|
|
48
54
|
AuthenticationStrategyProvider = tslib_1.__decorate([
|
|
@@ -50,7 +56,7 @@ AuthenticationStrategyProvider = tslib_1.__decorate([
|
|
|
50
56
|
,
|
|
51
57
|
tslib_1.__param(0, core_1.extensions()),
|
|
52
58
|
tslib_1.__param(1, core_1.inject(keys_1.AuthenticationBindings.METADATA)),
|
|
53
|
-
tslib_1.__metadata("design:paramtypes", [Function,
|
|
59
|
+
tslib_1.__metadata("design:paramtypes", [Function, Array])
|
|
54
60
|
], AuthenticationStrategyProvider);
|
|
55
61
|
exports.AuthenticationStrategyProvider = AuthenticationStrategyProvider;
|
|
56
62
|
//# sourceMappingURL=auth-strategy.provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-strategy.provider.js","sourceRoot":"","sources":["../../src/providers/auth-strategy.provider.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAOwB;AACxB,kCAA+C;AAC/C,oCAIkB;AAElB;;;;;;;;GAQG;AAKH,IAAa,8BAA8B,GAA3C,MAAa,8BAA8B;IAEzC,YAEY,wBAA0D,EAE1D,
|
|
1
|
+
{"version":3,"file":"auth-strategy.provider.js","sourceRoot":"","sources":["../../src/providers/auth-strategy.provider.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCAOwB;AACxB,kCAA+C;AAC/C,oCAIkB;AAElB;;;;;;;;GAQG;AAKH,IAAa,8BAA8B,GAA3C,MAAa,8BAA8B;IAEzC,YAEY,wBAA0D,EAE1D,QAAmC;QAFnC,6BAAwB,GAAxB,wBAAwB,CAAkC;QAE1D,aAAQ,GAAR,QAAQ,CAA2B;IAC5C,CAAC;IACJ,KAAK,CAAC,KAAK;;QACT,IAAI,QAAC,IAAI,CAAC,QAAQ,0CAAE,MAAM,CAAA,EAAE;YAC1B,OAAO,SAAS,CAAC;SAClB;QACD,OAAO,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAEO,KAAK,CAAC,4BAA4B,CACxC,QAAkC;QAElC,MAAM,UAAU,GAA6B,EAAE,CAAC;QAEhD,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAEjE,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE;YACpC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAC/D,IAAI,CAAC,QAAQ,EAAE;gBACb,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iBAAiB,IAAI,qBAAqB,CAAC,CAAC;gBACpE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;oBACnB,IAAI,EAAE,yCAAiC;iBACxC,CAAC,CAAC;gBACH,MAAM,KAAK,CAAC;aACb;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE;YAC3B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7C,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;SAC3B;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAA;AAzCY,8BAA8B;IAJ1C,qBAAc,CACb,6BAAsB,CAAC,4CAA4C,EACnE,EAAC,KAAK,EAAE,mBAAY,CAAC,SAAS,EAAC,CAChC,CAAC,6DAA6D;;IAI1D,mBAAA,iBAAU,EAAE,CAAA;IAEZ,mBAAA,aAAM,CAAC,6BAAsB,CAAC,QAAQ,CAAC,CAAA;;GAL/B,8BAA8B,CAyC1C;AAzCY,wEAA8B"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Binding, BindingTemplate, Constructor, Context } from '@loopback/core';
|
|
2
|
-
import {
|
|
2
|
+
import { RedirectRoute, Request } from '@loopback/rest';
|
|
3
3
|
import { UserProfile } from '@loopback/security';
|
|
4
4
|
/**
|
|
5
5
|
* Authentication metadata stored via Reflection API
|
|
@@ -43,7 +43,7 @@ export interface AuthenticationOptions {
|
|
|
43
43
|
* `@authenticate`. If not set, no default authentication will be enforced for
|
|
44
44
|
* those methods without authentication metadata.
|
|
45
45
|
*/
|
|
46
|
-
defaultMetadata?: AuthenticationMetadata;
|
|
46
|
+
defaultMetadata?: AuthenticationMetadata[];
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
49
|
* An interface that describes the common authentication strategy.
|
|
@@ -87,3 +87,10 @@ export declare function registerAuthenticationStrategy(context: Context, strateg
|
|
|
87
87
|
* A binding template for auth strategy contributor extensions
|
|
88
88
|
*/
|
|
89
89
|
export declare const asAuthStrategy: BindingTemplate;
|
|
90
|
+
/**
|
|
91
|
+
* Get the authentication metadata object for the specified strategy.
|
|
92
|
+
*
|
|
93
|
+
* @param metadata - Array of authentication metadata objects
|
|
94
|
+
* @param strategyName - Name of the authentication strategy
|
|
95
|
+
*/
|
|
96
|
+
export declare function getAuthenticationMetadataForStrategy(metadata: AuthenticationMetadata[], strategyName: string): AuthenticationMetadata | undefined;
|
package/dist/types.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// This file is licensed under the MIT License.
|
|
5
5
|
// License text available at https://opensource.org/licenses/MIT
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.asAuthStrategy = exports.registerAuthenticationStrategy = exports.USER_PROFILE_NOT_FOUND = exports.AUTHENTICATION_STRATEGY_NOT_FOUND = void 0;
|
|
7
|
+
exports.getAuthenticationMetadataForStrategy = exports.asAuthStrategy = exports.registerAuthenticationStrategy = exports.USER_PROFILE_NOT_FOUND = exports.AUTHENTICATION_STRATEGY_NOT_FOUND = void 0;
|
|
8
8
|
const core_1 = require("@loopback/core");
|
|
9
9
|
const keys_1 = require("./keys");
|
|
10
10
|
exports.AUTHENTICATION_STRATEGY_NOT_FOUND = 'AUTHENTICATION_STRATEGY_NOT_FOUND';
|
|
@@ -32,4 +32,14 @@ exports.asAuthStrategy = binding => {
|
|
|
32
32
|
namespace: keys_1.AuthenticationBindings.AUTHENTICATION_STRATEGY_EXTENSION_POINT_NAME,
|
|
33
33
|
});
|
|
34
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Get the authentication metadata object for the specified strategy.
|
|
37
|
+
*
|
|
38
|
+
* @param metadata - Array of authentication metadata objects
|
|
39
|
+
* @param strategyName - Name of the authentication strategy
|
|
40
|
+
*/
|
|
41
|
+
function getAuthenticationMetadataForStrategy(metadata, strategyName) {
|
|
42
|
+
return metadata.find(data => data.strategy === strategyName);
|
|
43
|
+
}
|
|
44
|
+
exports.getAuthenticationMetadataForStrategy = getAuthenticationMetadataForStrategy;
|
|
35
45
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAOwB;AAGxB,iCAA8C;AAgFjC,QAAA,iCAAiC,GAC5C,mCAAmC,CAAC;AAEzB,QAAA,sBAAsB,GAAG,wBAAwB,CAAC;AAE/D;;;;;;;GAOG;AACH,SAAgB,8BAA8B,CAC5C,OAAgB,EAChB,aAAkD;IAElD,OAAO,mBAAY,CACjB,OAAO,EACP,6BAAsB,CAAC,4CAA4C,EACnE,aAAa,EACb;QACE,SAAS,EACP,6BAAsB,CAAC,4CAA4C;KACtE,CACF,CAAC;AACJ,CAAC;AAbD,wEAaC;AAED;;GAEG;AACU,QAAA,cAAc,GAAoB,OAAO,CAAC,EAAE;IACvD,mBAAY,CACV,6BAAsB,CAAC,4CAA4C,CACpE,CAAC,OAAO,CAAC,CAAC;IACX,OAAO,CAAC,GAAG,CAAC;QACV,SAAS,EACP,6BAAsB,CAAC,4CAA4C;KACtE,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,wCAAwC;AACxC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAOwB;AAGxB,iCAA8C;AAgFjC,QAAA,iCAAiC,GAC5C,mCAAmC,CAAC;AAEzB,QAAA,sBAAsB,GAAG,wBAAwB,CAAC;AAE/D;;;;;;;GAOG;AACH,SAAgB,8BAA8B,CAC5C,OAAgB,EAChB,aAAkD;IAElD,OAAO,mBAAY,CACjB,OAAO,EACP,6BAAsB,CAAC,4CAA4C,EACnE,aAAa,EACb;QACE,SAAS,EACP,6BAAsB,CAAC,4CAA4C;KACtE,CACF,CAAC;AACJ,CAAC;AAbD,wEAaC;AAED;;GAEG;AACU,QAAA,cAAc,GAAoB,OAAO,CAAC,EAAE;IACvD,mBAAY,CACV,6BAAsB,CAAC,4CAA4C,CACpE,CAAC,OAAO,CAAC,CAAC;IACX,OAAO,CAAC,GAAG,CAAC;QACV,SAAS,EACP,6BAAsB,CAAC,4CAA4C;KACtE,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;;;;GAKG;AACH,SAAgB,oCAAoC,CAClD,QAAkC,EAClC,YAAoB;IAEpB,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC;AAC/D,CAAC;AALD,oFAKC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopback/authentication",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "A LoopBack component for authentication support.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,21 +24,20 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@loopback/core": "^2.9.
|
|
28
|
-
"@loopback/
|
|
29
|
-
"@loopback/
|
|
30
|
-
"@
|
|
31
|
-
"@types/
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"tslib": "^2.0.0"
|
|
27
|
+
"@loopback/core": "^2.9.5",
|
|
28
|
+
"@loopback/rest": "^6.2.0",
|
|
29
|
+
"@loopback/security": "^0.2.18",
|
|
30
|
+
"@types/express": "^4.17.7",
|
|
31
|
+
"@types/lodash": "^4.14.160",
|
|
32
|
+
"lodash": "^4.17.20",
|
|
33
|
+
"tslib": "^2.0.1"
|
|
35
34
|
},
|
|
36
35
|
"devDependencies": {
|
|
37
|
-
"@loopback/build": "^6.
|
|
38
|
-
"@loopback/eslint-config": "^
|
|
39
|
-
"@loopback/openapi-spec-builder": "^2.1.
|
|
40
|
-
"@loopback/testlab": "^3.2.
|
|
41
|
-
"@types/node": "^10.17.
|
|
36
|
+
"@loopback/build": "^6.2.2",
|
|
37
|
+
"@loopback/eslint-config": "^9.0.2",
|
|
38
|
+
"@loopback/openapi-spec-builder": "^2.1.13",
|
|
39
|
+
"@loopback/testlab": "^3.2.4",
|
|
40
|
+
"@types/node": "^10.17.28",
|
|
42
41
|
"jsonwebtoken": "^8.5.1"
|
|
43
42
|
},
|
|
44
43
|
"keywords": [
|
|
@@ -56,5 +55,5 @@
|
|
|
56
55
|
"url": "https://github.com/strongloop/loopback-next.git",
|
|
57
56
|
"directory": "packages/authentication"
|
|
58
57
|
},
|
|
59
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "a3f54273814de63819e0d8bc86509f8a737800bb"
|
|
60
59
|
}
|
|
@@ -3,23 +3,22 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {bind, Component, ContextTags
|
|
6
|
+
import {bind, Component, ContextTags} from '@loopback/core';
|
|
7
7
|
import {AuthenticationBindings} from './keys';
|
|
8
8
|
import {
|
|
9
9
|
AuthenticateActionProvider,
|
|
10
|
+
AuthenticationMiddlewareProvider,
|
|
10
11
|
AuthenticationStrategyProvider,
|
|
11
12
|
AuthMetadataProvider,
|
|
12
13
|
} from './providers';
|
|
13
14
|
|
|
14
15
|
@bind({tags: {[ContextTags.KEY]: AuthenticationBindings.COMPONENT}})
|
|
15
16
|
export class AuthenticationComponent implements Component {
|
|
16
|
-
providers
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
}
|
|
17
|
+
providers = {
|
|
18
|
+
[AuthenticationBindings.AUTH_ACTION.key]: AuthenticateActionProvider,
|
|
19
|
+
[AuthenticationBindings.STRATEGY.key]: AuthenticationStrategyProvider,
|
|
20
|
+
[AuthenticationBindings.METADATA.key]: AuthMetadataProvider,
|
|
21
|
+
[AuthenticationBindings.AUTHENTICATION_MIDDLEWARE
|
|
22
|
+
.key]: AuthenticationMiddlewareProvider,
|
|
23
|
+
};
|
|
25
24
|
}
|
|
@@ -18,19 +18,17 @@ import {
|
|
|
18
18
|
import {AuthenticationMetadata} from '../types';
|
|
19
19
|
|
|
20
20
|
class AuthenticateClassDecoratorFactory extends ClassDecoratorFactory<
|
|
21
|
-
AuthenticationMetadata
|
|
21
|
+
AuthenticationMetadata[]
|
|
22
22
|
> {}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Mark a controller method as requiring authenticated user.
|
|
26
26
|
*
|
|
27
|
-
* @param
|
|
28
|
-
* or
|
|
29
|
-
* @param options - Additional options to configure the authentication.
|
|
27
|
+
* @param strategies - The names of the authentication strategies to use
|
|
28
|
+
* or authentication metadata objects.
|
|
30
29
|
*/
|
|
31
30
|
export function authenticate(
|
|
32
|
-
|
|
33
|
-
options?: object,
|
|
31
|
+
...strategies: (string | AuthenticationMetadata)[]
|
|
34
32
|
) {
|
|
35
33
|
return function authenticateDecoratorForClassOrMethod(
|
|
36
34
|
// Class or a prototype
|
|
@@ -42,31 +40,35 @@ export function authenticate(
|
|
|
42
40
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
41
|
methodDescriptor?: TypedPropertyDescriptor<any>,
|
|
44
42
|
) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
const specs: AuthenticationMetadata[] = [];
|
|
44
|
+
|
|
45
|
+
for (const strategy of strategies) {
|
|
46
|
+
if (typeof strategy === 'object') {
|
|
47
|
+
specs.push(strategy);
|
|
48
|
+
} else {
|
|
49
|
+
specs.push({strategy: strategy});
|
|
50
|
+
}
|
|
50
51
|
}
|
|
52
|
+
|
|
51
53
|
if (method && methodDescriptor) {
|
|
52
54
|
// Method
|
|
53
|
-
return MethodDecoratorFactory.createDecorator<AuthenticationMetadata>(
|
|
55
|
+
return MethodDecoratorFactory.createDecorator<AuthenticationMetadata[]>(
|
|
54
56
|
AUTHENTICATION_METADATA_KEY,
|
|
55
|
-
|
|
57
|
+
specs,
|
|
56
58
|
{decoratorName: '@authenticate'},
|
|
57
59
|
)(target, method, methodDescriptor);
|
|
58
60
|
}
|
|
59
61
|
if (typeof target === 'function' && !method && !methodDescriptor) {
|
|
60
62
|
// Class
|
|
61
|
-
return AuthenticateClassDecoratorFactory.createDecorator
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
)(target);
|
|
63
|
+
return AuthenticateClassDecoratorFactory.createDecorator<
|
|
64
|
+
AuthenticationMetadata[]
|
|
65
|
+
>(AUTHENTICATION_METADATA_CLASS_KEY, specs, {
|
|
66
|
+
decoratorName: '@authenticate',
|
|
67
|
+
})(target);
|
|
66
68
|
}
|
|
67
69
|
// Not on a class or method
|
|
68
70
|
throw new Error(
|
|
69
|
-
'@
|
|
71
|
+
'@authenticate cannot be used on a property: ' +
|
|
70
72
|
DecoratorFactory.getTargetName(target, method, methodDescriptor),
|
|
71
73
|
);
|
|
72
74
|
};
|
|
@@ -88,16 +90,16 @@ export namespace authenticate {
|
|
|
88
90
|
export function getAuthenticateMetadata(
|
|
89
91
|
targetClass: Constructor<{}>,
|
|
90
92
|
methodName: string,
|
|
91
|
-
): AuthenticationMetadata | undefined {
|
|
93
|
+
): AuthenticationMetadata[] | undefined {
|
|
92
94
|
// First check method level
|
|
93
|
-
let metadata = MetadataInspector.getMethodMetadata<AuthenticationMetadata>(
|
|
95
|
+
let metadata = MetadataInspector.getMethodMetadata<AuthenticationMetadata[]>(
|
|
94
96
|
AUTHENTICATION_METADATA_METHOD_KEY,
|
|
95
97
|
targetClass.prototype,
|
|
96
98
|
methodName,
|
|
97
99
|
);
|
|
98
100
|
if (metadata) return metadata;
|
|
99
101
|
// Check if the class level has `@authenticate`
|
|
100
|
-
metadata = MetadataInspector.getClassMetadata<AuthenticationMetadata>(
|
|
102
|
+
metadata = MetadataInspector.getClassMetadata<AuthenticationMetadata[]>(
|
|
101
103
|
AUTHENTICATION_METADATA_CLASS_KEY,
|
|
102
104
|
targetClass,
|
|
103
105
|
);
|
package/src/keys.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import {BindingKey, MetadataAccessor} from '@loopback/core';
|
|
7
7
|
import {SecurityBindings, UserProfile} from '@loopback/security';
|
|
8
|
+
import {Middleware} from '@loopback/rest';
|
|
8
9
|
import {AuthenticationComponent} from './authentication.component';
|
|
9
10
|
import {
|
|
10
11
|
AuthenticateFn,
|
|
@@ -39,8 +40,8 @@ export namespace AuthenticationBindings {
|
|
|
39
40
|
>('authentication.userProfileFactory');
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
|
-
* Key used to bind an authentication strategy
|
|
43
|
-
* authentication function to use.
|
|
43
|
+
* Key used to bind an authentication strategy or multiple strategies
|
|
44
|
+
* to the context for the authentication function to use.
|
|
44
45
|
*
|
|
45
46
|
* @example
|
|
46
47
|
* ```ts
|
|
@@ -49,9 +50,9 @@ export namespace AuthenticationBindings {
|
|
|
49
50
|
* .toProvider(MyAuthenticationStrategy);
|
|
50
51
|
* ```
|
|
51
52
|
*/
|
|
52
|
-
export const STRATEGY = BindingKey.create<
|
|
53
|
-
|
|
54
|
-
);
|
|
53
|
+
export const STRATEGY = BindingKey.create<
|
|
54
|
+
AuthenticationStrategy | AuthenticationStrategy[] | undefined
|
|
55
|
+
>('authentication.strategy');
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* Key used to inject the authentication function into the sequence.
|
|
@@ -88,6 +89,13 @@ export namespace AuthenticationBindings {
|
|
|
88
89
|
'authentication.actions.authenticate',
|
|
89
90
|
);
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Binding key for AUTHENTICATION_MIDDLEWARE
|
|
94
|
+
*/
|
|
95
|
+
export const AUTHENTICATION_MIDDLEWARE = BindingKey.create<Middleware>(
|
|
96
|
+
'middleware.authentication',
|
|
97
|
+
);
|
|
98
|
+
|
|
91
99
|
/**
|
|
92
100
|
* Key used to inject authentication metadata, which is used to determine
|
|
93
101
|
* whether a request requires authentication or not.
|
|
@@ -97,20 +105,19 @@ export namespace AuthenticationBindings {
|
|
|
97
105
|
* class MyPassportStrategyProvider implements Provider<Strategy | undefined> {
|
|
98
106
|
* constructor(
|
|
99
107
|
* @inject(AuthenticationBindings.METADATA)
|
|
100
|
-
* private metadata
|
|
108
|
+
* private metadata?: AuthenticationMetadata[],
|
|
101
109
|
* ) {}
|
|
102
110
|
* value(): ValueOrPromise<Strategy | undefined> {
|
|
103
|
-
* if (this.metadata) {
|
|
104
|
-
* const name = this.metadata.strategy;
|
|
111
|
+
* if (this.metadata?.length) {
|
|
105
112
|
* // logic to determine which authentication strategy to return
|
|
106
113
|
* }
|
|
107
114
|
* }
|
|
108
115
|
* }
|
|
109
116
|
* ```
|
|
110
117
|
*/
|
|
111
|
-
export const METADATA = BindingKey.create<
|
|
112
|
-
|
|
113
|
-
);
|
|
118
|
+
export const METADATA = BindingKey.create<
|
|
119
|
+
AuthenticationMetadata[] | undefined
|
|
120
|
+
>('authentication.operationMetadata');
|
|
114
121
|
|
|
115
122
|
export const AUTHENTICATION_STRATEGY_EXTENSION_POINT_NAME =
|
|
116
123
|
'authentication.strategies';
|
|
@@ -3,13 +3,20 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {Getter, inject, Provider, Setter} from '@loopback/core';
|
|
7
|
-
import {
|
|
6
|
+
import {bind, Getter, inject, Provider, Setter} from '@loopback/core';
|
|
7
|
+
import {
|
|
8
|
+
asMiddleware,
|
|
9
|
+
Middleware,
|
|
10
|
+
RedirectRoute,
|
|
11
|
+
Request,
|
|
12
|
+
RestMiddlewareGroups,
|
|
13
|
+
} from '@loopback/rest';
|
|
8
14
|
import {SecurityBindings, UserProfile} from '@loopback/security';
|
|
9
15
|
import {AuthenticationBindings} from '../keys';
|
|
10
16
|
import {
|
|
11
17
|
AuthenticateFn,
|
|
12
18
|
AuthenticationStrategy,
|
|
19
|
+
AUTHENTICATION_STRATEGY_NOT_FOUND,
|
|
13
20
|
USER_PROFILE_NOT_FOUND,
|
|
14
21
|
} from '../types';
|
|
15
22
|
/**
|
|
@@ -26,7 +33,9 @@ export class AuthenticateActionProvider implements Provider<AuthenticateFn> {
|
|
|
26
33
|
// defer resolution of the strategy until authenticate() action
|
|
27
34
|
// is executed.
|
|
28
35
|
@inject.getter(AuthenticationBindings.STRATEGY)
|
|
29
|
-
readonly
|
|
36
|
+
readonly getStrategies: Getter<
|
|
37
|
+
AuthenticationStrategy | AuthenticationStrategy[] | undefined
|
|
38
|
+
>,
|
|
30
39
|
@inject.setter(SecurityBindings.USER)
|
|
31
40
|
readonly setCurrentUser: Setter<UserProfile>,
|
|
32
41
|
@inject.setter(AuthenticationBindings.AUTHENTICATION_REDIRECT_URL)
|
|
@@ -47,36 +56,89 @@ export class AuthenticateActionProvider implements Provider<AuthenticateFn> {
|
|
|
47
56
|
* @param request - The incoming request provided by the REST layer
|
|
48
57
|
*/
|
|
49
58
|
async action(request: Request): Promise<UserProfile | undefined> {
|
|
50
|
-
|
|
51
|
-
if (!
|
|
59
|
+
let strategies = await this.getStrategies();
|
|
60
|
+
if (!strategies) {
|
|
52
61
|
// The invoked operation does not require authentication.
|
|
53
62
|
return undefined;
|
|
54
63
|
}
|
|
64
|
+
// convert to array if required
|
|
65
|
+
strategies = Array.isArray(strategies) ? strategies : [strategies];
|
|
66
|
+
|
|
67
|
+
let authenticated = false;
|
|
68
|
+
let redirected = false;
|
|
69
|
+
let authError: Error | undefined;
|
|
70
|
+
let authResponse: UserProfile | RedirectRoute | undefined;
|
|
71
|
+
let userProfile: UserProfile | undefined;
|
|
72
|
+
|
|
73
|
+
for (const strategy of strategies) {
|
|
74
|
+
// the first strategy to succeed or redirect will halt the execution chain
|
|
75
|
+
if (authenticated || redirected) break;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
authResponse = await strategy.authenticate(request);
|
|
79
|
+
|
|
80
|
+
// response from `strategy.authenticate()` could return an object of type UserProfile or RedirectRoute
|
|
81
|
+
if (RedirectRoute.isRedirectRoute(authResponse)) {
|
|
82
|
+
redirected = true;
|
|
83
|
+
const redirectOptions = authResponse;
|
|
84
|
+
// bind redirection url and status to the context
|
|
85
|
+
// controller should handle actual redirection
|
|
86
|
+
this.setRedirectUrl(redirectOptions.targetLocation);
|
|
87
|
+
this.setRedirectStatus(redirectOptions.statusCode);
|
|
88
|
+
} else if (authResponse) {
|
|
89
|
+
authenticated = true;
|
|
90
|
+
// if `strategy.authenticate()` returns an object of type UserProfile, set it as current user
|
|
91
|
+
userProfile = authResponse as UserProfile;
|
|
92
|
+
} else if (!authResponse) {
|
|
93
|
+
// important to throw a non-protocol-specific error here
|
|
94
|
+
const error = new Error(
|
|
95
|
+
`User profile not returned from strategy's authenticate function`,
|
|
96
|
+
);
|
|
97
|
+
Object.assign(error, {
|
|
98
|
+
code: USER_PROFILE_NOT_FOUND,
|
|
99
|
+
});
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
authError = authError ?? error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
55
106
|
|
|
56
|
-
|
|
57
|
-
let userProfile: UserProfile;
|
|
107
|
+
if (!authenticated && !redirected) throw authError;
|
|
58
108
|
|
|
59
|
-
|
|
60
|
-
if (RedirectRoute.isRedirectRoute(authResponse)) {
|
|
61
|
-
const redirectOptions = authResponse;
|
|
62
|
-
// bind redirection url and status to the context
|
|
63
|
-
// controller should handle actual redirection
|
|
64
|
-
this.setRedirectUrl(redirectOptions.targetLocation);
|
|
65
|
-
this.setRedirectStatus(redirectOptions.statusCode);
|
|
66
|
-
} else if (authResponse) {
|
|
67
|
-
// if `strategy.authenticate()` returns an object of type UserProfile, set it as current user
|
|
68
|
-
userProfile = authResponse as UserProfile;
|
|
109
|
+
if (userProfile) {
|
|
69
110
|
this.setCurrentUser(userProfile);
|
|
70
111
|
return userProfile;
|
|
71
|
-
} else if (!authResponse) {
|
|
72
|
-
// important to throw a non-protocol-specific error here
|
|
73
|
-
const error = new Error(
|
|
74
|
-
`User profile not returned from strategy's authenticate function`,
|
|
75
|
-
);
|
|
76
|
-
Object.assign(error, {
|
|
77
|
-
code: USER_PROFILE_NOT_FOUND,
|
|
78
|
-
});
|
|
79
|
-
throw error;
|
|
80
112
|
}
|
|
81
113
|
}
|
|
82
114
|
}
|
|
115
|
+
|
|
116
|
+
@bind(
|
|
117
|
+
asMiddleware({
|
|
118
|
+
group: RestMiddlewareGroups.AUTHENTICATION,
|
|
119
|
+
upstreamGroups: [RestMiddlewareGroups.FIND_ROUTE],
|
|
120
|
+
}),
|
|
121
|
+
)
|
|
122
|
+
export class AuthenticationMiddlewareProvider implements Provider<Middleware> {
|
|
123
|
+
constructor(
|
|
124
|
+
@inject(AuthenticationBindings.AUTH_ACTION)
|
|
125
|
+
private authenticate: AuthenticateFn,
|
|
126
|
+
) {}
|
|
127
|
+
|
|
128
|
+
value(): Middleware {
|
|
129
|
+
return async (ctx, next) => {
|
|
130
|
+
try {
|
|
131
|
+
await this.authenticate(ctx.request);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (
|
|
134
|
+
error.code === AUTHENTICATION_STRATEGY_NOT_FOUND ||
|
|
135
|
+
error.code === USER_PROFILE_NOT_FOUND
|
|
136
|
+
) {
|
|
137
|
+
error.statusCode = 401;
|
|
138
|
+
}
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
return next();
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
import {
|
|
7
7
|
config,
|
|
8
8
|
Constructor,
|
|
9
|
+
CoreBindings,
|
|
9
10
|
inject,
|
|
10
11
|
Provider,
|
|
11
|
-
CoreBindings,
|
|
12
12
|
} from '@loopback/core';
|
|
13
13
|
import {getAuthenticateMetadata} from '../decorators';
|
|
14
14
|
import {AuthenticationBindings} from '../keys';
|
|
@@ -19,7 +19,7 @@ import {AuthenticationMetadata, AuthenticationOptions} from '../types';
|
|
|
19
19
|
* @example `context.bind('authentication.operationMetadata').toProvider(AuthMetadataProvider)`
|
|
20
20
|
*/
|
|
21
21
|
export class AuthMetadataProvider
|
|
22
|
-
implements Provider<AuthenticationMetadata | undefined> {
|
|
22
|
+
implements Provider<AuthenticationMetadata[] | undefined> {
|
|
23
23
|
constructor(
|
|
24
24
|
@inject(CoreBindings.CONTROLLER_CLASS, {optional: true})
|
|
25
25
|
private readonly controllerClass: Constructor<{}>,
|
|
@@ -32,14 +32,14 @@ export class AuthMetadataProvider
|
|
|
32
32
|
/**
|
|
33
33
|
* @returns AuthenticationMetadata
|
|
34
34
|
*/
|
|
35
|
-
value(): AuthenticationMetadata | undefined {
|
|
35
|
+
value(): AuthenticationMetadata[] | undefined {
|
|
36
36
|
if (!this.controllerClass || !this.methodName) return;
|
|
37
37
|
const metadata = getAuthenticateMetadata(
|
|
38
38
|
this.controllerClass,
|
|
39
39
|
this.methodName,
|
|
40
40
|
);
|
|
41
41
|
// Skip authentication if `skip` is `true`
|
|
42
|
-
if (metadata?.skip) return undefined;
|
|
42
|
+
if (metadata?.[0]?.skip) return undefined;
|
|
43
43
|
if (metadata) return metadata;
|
|
44
44
|
// Fall back to default metadata
|
|
45
45
|
return this.options.defaultMetadata;
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
BindingScope,
|
|
8
|
-
Getter,
|
|
9
|
-
inject,
|
|
10
8
|
extensionPoint,
|
|
11
9
|
extensions,
|
|
10
|
+
Getter,
|
|
11
|
+
inject,
|
|
12
12
|
Provider,
|
|
13
13
|
} from '@loopback/core';
|
|
14
14
|
import {AuthenticationBindings} from '../keys';
|
|
@@ -32,33 +32,44 @@ import {
|
|
|
32
32
|
{scope: BindingScope.TRANSIENT},
|
|
33
33
|
) //this needs to be transient, e.g. for request level context.
|
|
34
34
|
export class AuthenticationStrategyProvider
|
|
35
|
-
implements Provider<AuthenticationStrategy | undefined> {
|
|
35
|
+
implements Provider<AuthenticationStrategy[] | undefined> {
|
|
36
36
|
constructor(
|
|
37
37
|
@extensions()
|
|
38
38
|
protected authenticationStrategies: Getter<AuthenticationStrategy[]>,
|
|
39
39
|
@inject(AuthenticationBindings.METADATA)
|
|
40
|
-
protected metadata?: AuthenticationMetadata,
|
|
40
|
+
protected metadata?: AuthenticationMetadata[],
|
|
41
41
|
) {}
|
|
42
|
-
async value(): Promise<AuthenticationStrategy | undefined> {
|
|
43
|
-
if (!this.metadata) {
|
|
42
|
+
async value(): Promise<AuthenticationStrategy[] | undefined> {
|
|
43
|
+
if (!this.metadata?.length) {
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
const strategy = await this.findAuthenticationStrategy(name);
|
|
48
|
-
if (!strategy) {
|
|
49
|
-
// important to throw a non-protocol-specific error here
|
|
50
|
-
const error = new Error(`The strategy '${name}' is not available.`);
|
|
51
|
-
Object.assign(error, {
|
|
52
|
-
code: AUTHENTICATION_STRATEGY_NOT_FOUND,
|
|
53
|
-
});
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
return strategy;
|
|
46
|
+
return this.findAuthenticationStrategies(this.metadata);
|
|
57
47
|
}
|
|
58
48
|
|
|
59
|
-
async
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
private async findAuthenticationStrategies(
|
|
50
|
+
metadata: AuthenticationMetadata[],
|
|
51
|
+
): Promise<AuthenticationStrategy[]> {
|
|
52
|
+
const strategies: AuthenticationStrategy[] = [];
|
|
53
|
+
|
|
54
|
+
const existingStrategies = await this.authenticationStrategies();
|
|
55
|
+
|
|
56
|
+
const findStrategy = (name: string) => {
|
|
57
|
+
const strategy = existingStrategies.find(a => a.name === name);
|
|
58
|
+
if (!strategy) {
|
|
59
|
+
const error = new Error(`The strategy '${name}' is not available.`);
|
|
60
|
+
Object.assign(error, {
|
|
61
|
+
code: AUTHENTICATION_STRATEGY_NOT_FOUND,
|
|
62
|
+
});
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
return strategy;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
for (const data of metadata) {
|
|
69
|
+
const strategy = findStrategy(data.strategy);
|
|
70
|
+
strategies.push(strategy);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return strategies;
|
|
63
74
|
}
|
|
64
75
|
}
|
package/src/types.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
Context,
|
|
12
12
|
extensionFor,
|
|
13
13
|
} from '@loopback/core';
|
|
14
|
-
import {
|
|
14
|
+
import {RedirectRoute, Request} from '@loopback/rest';
|
|
15
15
|
import {UserProfile} from '@loopback/security';
|
|
16
16
|
import {AuthenticationBindings} from './keys';
|
|
17
17
|
|
|
@@ -59,7 +59,7 @@ export interface AuthenticationOptions {
|
|
|
59
59
|
* `@authenticate`. If not set, no default authentication will be enforced for
|
|
60
60
|
* those methods without authentication metadata.
|
|
61
61
|
*/
|
|
62
|
-
defaultMetadata?: AuthenticationMetadata;
|
|
62
|
+
defaultMetadata?: AuthenticationMetadata[];
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
@@ -133,3 +133,16 @@ export const asAuthStrategy: BindingTemplate = binding => {
|
|
|
133
133
|
AuthenticationBindings.AUTHENTICATION_STRATEGY_EXTENSION_POINT_NAME,
|
|
134
134
|
});
|
|
135
135
|
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get the authentication metadata object for the specified strategy.
|
|
139
|
+
*
|
|
140
|
+
* @param metadata - Array of authentication metadata objects
|
|
141
|
+
* @param strategyName - Name of the authentication strategy
|
|
142
|
+
*/
|
|
143
|
+
export function getAuthenticationMetadataForStrategy(
|
|
144
|
+
metadata: AuthenticationMetadata[],
|
|
145
|
+
strategyName: string,
|
|
146
|
+
): AuthenticationMetadata | undefined {
|
|
147
|
+
return metadata.find(data => data.strategy === strategyName);
|
|
148
|
+
}
|