@soapjs/soap-auth 0.1.1 → 0.3.0
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/README.md +120 -169
- package/build/factories/http-auth-strategy.factory.js +1 -1
- package/build/factories/index.d.ts +3 -0
- package/build/factories/index.js +19 -0
- package/build/index.d.ts +4 -25
- package/build/index.js +4 -25
- package/build/session/index.d.ts +3 -0
- package/build/session/index.js +19 -0
- package/build/soap-auth.d.ts +9 -9
- package/build/soap-auth.js +64 -34
- package/build/strategies/api-key/api-key.strategy.d.ts +4 -3
- package/build/strategies/api-key/api-key.strategy.js +9 -6
- package/build/strategies/api-key/api-key.types.d.ts +2 -4
- package/build/strategies/base-auth.strategy.d.ts +4 -3
- package/build/strategies/base-auth.strategy.js +18 -2
- package/build/strategies/basic/basic.strategy.d.ts +5 -11
- package/build/strategies/basic/basic.strategy.js +14 -19
- package/build/strategies/basic/basic.types.d.ts +2 -2
- package/build/strategies/{credential-based-auth.strategy.d.ts → credential-auth.strategy.d.ts} +15 -12
- package/build/strategies/{credential-based-auth.strategy.js → credential-auth.strategy.js} +95 -46
- package/build/strategies/index.d.ts +16 -0
- package/build/strategies/index.js +32 -0
- package/build/strategies/jwt/jwt.strategy.d.ts +17 -2
- package/build/strategies/jwt/jwt.strategy.js +118 -57
- package/build/strategies/jwt/jwt.tools.d.ts +7 -3
- package/build/strategies/jwt/jwt.tools.js +80 -41
- package/build/strategies/jwt/jwt.types.d.ts +3 -27
- package/build/strategies/local/local.strategy.d.ts +3 -9
- package/build/strategies/local/local.strategy.js +7 -58
- package/build/strategies/local/local.types.d.ts +2 -2
- package/build/strategies/oauth2/oauth2.strategy.d.ts +21 -7
- package/build/strategies/oauth2/oauth2.strategy.js +158 -49
- package/build/strategies/oauth2/oauth2.types.d.ts +8 -16
- package/build/strategies/token-auth.strategy.d.ts +25 -0
- package/build/strategies/token-auth.strategy.js +78 -0
- package/build/tools/index.d.ts +3 -0
- package/build/tools/index.js +19 -0
- package/build/types.d.ts +87 -57
- package/package.json +2 -1
- package/build/strategies/token-based-auth.strategy.d.ts +0 -25
- package/build/strategies/token-based-auth.strategy.js +0 -130
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as Soap from "@soapjs/soap";
|
|
2
2
|
import { AuthResult, AuthStrategy } from "../../types";
|
|
3
3
|
import { ApiKeyStrategyConfig } from "./api-key.types";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { BaseAuthStrategy } from "../base-auth.strategy";
|
|
5
|
+
export declare class ApiKeyStrategy<TContext = unknown, TUser = unknown> extends BaseAuthStrategy<TContext, TUser> implements AuthStrategy<TContext, TUser> {
|
|
6
|
+
protected config: ApiKeyStrategyConfig<TContext, TUser>;
|
|
7
7
|
constructor(config: ApiKeyStrategyConfig<TContext, TUser>, logger: Soap.Logger);
|
|
8
8
|
init(): Promise<void>;
|
|
9
9
|
authenticate(context?: TContext): Promise<AuthResult<TUser>>;
|
|
@@ -11,4 +11,5 @@ export declare class ApiKeyStrategy<TContext = unknown, TUser = unknown> impleme
|
|
|
11
11
|
revoke(apiKey: string): Promise<void>;
|
|
12
12
|
private trackApiKeyUsage;
|
|
13
13
|
private incrementRequestCount;
|
|
14
|
+
logout(context: TContext): Promise<void>;
|
|
14
15
|
}
|
|
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ApiKeyStrategy = void 0;
|
|
4
4
|
const api_key_errors_1 = require("./api-key.errors");
|
|
5
5
|
const errors_1 = require("../../errors");
|
|
6
|
-
|
|
6
|
+
const base_auth_strategy_1 = require("../base-auth.strategy");
|
|
7
|
+
class ApiKeyStrategy extends base_auth_strategy_1.BaseAuthStrategy {
|
|
7
8
|
config;
|
|
8
|
-
logger;
|
|
9
9
|
constructor(config, logger) {
|
|
10
|
+
super(config, null, logger);
|
|
10
11
|
this.config = config;
|
|
11
|
-
this.logger = logger;
|
|
12
12
|
if (!this.config.extractApiKey || !this.config.retrieveUserByApiKey) {
|
|
13
13
|
throw new Error("ApiKeyStrategy requires extractApiKey and retrieveUserByApiKey functions.");
|
|
14
14
|
}
|
|
@@ -45,13 +45,13 @@ class ApiKeyStrategy {
|
|
|
45
45
|
}
|
|
46
46
|
await this.trackApiKeyUsage(apiKey);
|
|
47
47
|
await this.incrementRequestCount(apiKey);
|
|
48
|
-
await this.
|
|
48
|
+
await this.onSuccess("authenticate", { user, context });
|
|
49
49
|
return { user };
|
|
50
50
|
}
|
|
51
51
|
catch (error) {
|
|
52
52
|
this.logger.error("API Key authentication error:", error);
|
|
53
53
|
try {
|
|
54
|
-
await this.
|
|
54
|
+
await this.onFailure("authenticate", { error, context });
|
|
55
55
|
}
|
|
56
56
|
catch (callbackError) {
|
|
57
57
|
this.logger.error("onFailure callback error during authentication:", callbackError);
|
|
@@ -63,7 +63,7 @@ class ApiKeyStrategy {
|
|
|
63
63
|
if (this.config.authorize) {
|
|
64
64
|
return this.config.authorize(user, action, resource);
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
return true;
|
|
67
67
|
}
|
|
68
68
|
async revoke(apiKey) {
|
|
69
69
|
if (this.config.revokeApiKey) {
|
|
@@ -91,5 +91,8 @@ class ApiKeyStrategy {
|
|
|
91
91
|
this.logger.warn("Failed to increment request count:", error);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
+
logout(context) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
94
97
|
}
|
|
95
98
|
exports.ApiKeyStrategy = ApiKeyStrategy;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { RateLimitConfig, RoleAuthorizationConfig,
|
|
2
|
-
export interface ApiKeyStrategyConfig<TContext = unknown, TUser = unknown> extends ApiKeyTrackingConfig, RateLimitConfig, RoleAuthorizationConfig<TUser>, AccountLockConfig<TContext> {
|
|
1
|
+
import { RateLimitConfig, RoleAuthorizationConfig, AccountLockConfig, AuthResultConfig } from "../../types";
|
|
2
|
+
export interface ApiKeyStrategyConfig<TContext = unknown, TUser = unknown> extends AuthResultConfig<TContext, TUser>, ApiKeyTrackingConfig, RateLimitConfig, RoleAuthorizationConfig<TUser>, AccountLockConfig<TContext> {
|
|
3
3
|
extractApiKey: (context: TContext) => string | null;
|
|
4
4
|
retrieveUserByApiKey: (apiKey: string) => Promise<TUser | null>;
|
|
5
5
|
authorize?: (user: TUser, action: string, resource?: string) => Promise<boolean>;
|
|
6
6
|
revokeApiKey?: (apiKey: string) => Promise<void>;
|
|
7
|
-
onSuccess?: (context: AuthSuccessContext<TUser, TContext>) => Promise<void> | void;
|
|
8
|
-
onFailure?: (context: AuthFailureContext<TContext>) => Promise<void> | void;
|
|
9
7
|
}
|
|
10
8
|
export interface ApiKeyTrackingConfig {
|
|
11
9
|
trackApiKeyUsage?: (apiKey: string) => Promise<void>;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as Soap from "@soapjs/soap";
|
|
2
|
-
import { AuthResult, AuthStrategy, BaseAuthStrategyConfig } from "../types";
|
|
2
|
+
import { AuthFailureContext, AuthResult, AuthStrategy, AuthSuccessContext, BaseAuthStrategyConfig } from "../types";
|
|
3
3
|
import { SessionHandler } from "../session/session-handler";
|
|
4
4
|
export declare abstract class BaseAuthStrategy<TContext = unknown, TUser = unknown> implements AuthStrategy<TContext, TUser> {
|
|
5
5
|
protected config: BaseAuthStrategyConfig<TContext, TUser>;
|
|
6
6
|
protected session?: SessionHandler;
|
|
7
7
|
protected logger?: Soap.Logger;
|
|
8
8
|
abstract authenticate(context?: TContext): Promise<AuthResult<TUser>>;
|
|
9
|
-
protected abstract retrieveUser(context: TContext): Promise<TUser | null>;
|
|
10
9
|
abstract logout(context: TContext): Promise<void>;
|
|
11
10
|
constructor(config: BaseAuthStrategyConfig<TContext, TUser>, session?: SessionHandler, logger?: Soap.Logger);
|
|
12
11
|
init(): Promise<void>;
|
|
13
|
-
protected isAccountLocked(account: any
|
|
12
|
+
protected isAccountLocked(account: any): Promise<boolean>;
|
|
14
13
|
protected isAuthorized(user: TUser): Promise<boolean>;
|
|
15
14
|
protected checkRateLimit(data: unknown): Promise<void>;
|
|
16
15
|
protected checkMfa(user: TUser, context: TContext): Promise<void>;
|
|
16
|
+
protected onSuccess(action: string, context: AuthSuccessContext<TUser, TContext>): Promise<void>;
|
|
17
|
+
protected onFailure(action: string, context: AuthFailureContext<TContext>): Promise<void>;
|
|
17
18
|
}
|
|
@@ -14,8 +14,8 @@ class BaseAuthStrategy {
|
|
|
14
14
|
async init() {
|
|
15
15
|
return Promise.resolve();
|
|
16
16
|
}
|
|
17
|
-
async isAccountLocked(account
|
|
18
|
-
if (await this.config.lock.isAccountLocked?.(account
|
|
17
|
+
async isAccountLocked(account) {
|
|
18
|
+
if (await this.config.lock.isAccountLocked?.(account)) {
|
|
19
19
|
throw new errors_1.AccountLockedError();
|
|
20
20
|
}
|
|
21
21
|
return false;
|
|
@@ -65,5 +65,21 @@ class BaseAuthStrategy {
|
|
|
65
65
|
throw error;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
async onSuccess(action, context) {
|
|
69
|
+
try {
|
|
70
|
+
await this.config.onSuccess?.(action, context);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
this.logger?.error(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async onFailure(action, context) {
|
|
77
|
+
try {
|
|
78
|
+
await this.config.onFailure?.(action, context);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
this.logger?.error(error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
68
84
|
}
|
|
69
85
|
exports.BaseAuthStrategy = BaseAuthStrategy;
|
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import * as Soap from "@soapjs/soap";
|
|
2
|
-
import {
|
|
2
|
+
import { CredentialAuthStrategy } from "../credential-auth.strategy";
|
|
3
3
|
import { BasicContext, BasicStrategyConfig } from "./basic.types";
|
|
4
4
|
import { SessionHandler } from "../../session/session-handler";
|
|
5
|
-
export declare class BasicStrategy<TContext extends BasicContext = BasicContext, TUser = unknown> extends
|
|
5
|
+
export declare class BasicStrategy<TContext extends BasicContext = BasicContext, TUser = unknown> extends CredentialAuthStrategy<TContext, TUser> {
|
|
6
6
|
protected config: BasicStrategyConfig<TContext, TUser>;
|
|
7
7
|
protected session?: SessionHandler;
|
|
8
8
|
protected logger?: Soap.Logger;
|
|
9
9
|
constructor(config: BasicStrategyConfig<TContext, TUser>, session?: SessionHandler, logger?: Soap.Logger);
|
|
10
|
-
protected extractCredentials(context?: TContext):
|
|
10
|
+
protected extractCredentials(context?: TContext): {
|
|
11
11
|
identifier: string;
|
|
12
12
|
password: string;
|
|
13
|
-
}
|
|
14
|
-
protected verifyCredentials(
|
|
15
|
-
identifier: string;
|
|
16
|
-
password: string;
|
|
17
|
-
}): Promise<boolean>;
|
|
13
|
+
};
|
|
14
|
+
protected verifyCredentials(identifier: string, password: string): Promise<boolean>;
|
|
18
15
|
protected retrieveUser(credentials: {
|
|
19
16
|
identifier: string;
|
|
20
17
|
password: string;
|
|
21
18
|
}): Promise<TUser | null>;
|
|
22
|
-
requestPasswordReset(email: string): Promise<void>;
|
|
23
|
-
resetPassword(email: string, token: string, newPassword: string): Promise<void>;
|
|
24
|
-
changePassword(email: string, oldPassword: string, newPassword: string): Promise<void>;
|
|
25
19
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BasicStrategy = void 0;
|
|
4
|
-
const
|
|
4
|
+
const credential_auth_strategy_1 = require("../credential-auth.strategy");
|
|
5
5
|
const errors_1 = require("../../errors");
|
|
6
|
-
class BasicStrategy extends
|
|
6
|
+
class BasicStrategy extends credential_auth_strategy_1.CredentialAuthStrategy {
|
|
7
7
|
config;
|
|
8
8
|
session;
|
|
9
9
|
logger;
|
|
@@ -13,17 +13,21 @@ class BasicStrategy extends credential_based_auth_strategy_1.CredentialBasedAuth
|
|
|
13
13
|
this.session = session;
|
|
14
14
|
this.logger = logger;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
const authHeader =
|
|
16
|
+
extractCredentials(context) {
|
|
17
|
+
const authHeader = this.config.credentials.extractCredentials
|
|
18
|
+
? this.config.credentials.extractCredentials(context)
|
|
19
|
+
: context?.headers?.authorization ||
|
|
20
|
+
context?.headers?.["x-custom-auth"] ||
|
|
21
|
+
context?.headers?.["proxy-authorization"];
|
|
18
22
|
if (!authHeader) {
|
|
19
23
|
throw new errors_1.MissingCredentialsError();
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
if (parts.length !== 2 || parts[0] !== "Basic") {
|
|
25
|
+
if (!authHeader || !authHeader.toLowerCase().startsWith("basic ")) {
|
|
23
26
|
throw new errors_1.InvalidCredentialsError();
|
|
24
27
|
}
|
|
28
|
+
const encoded = authHeader.substring(6);
|
|
25
29
|
try {
|
|
26
|
-
const decoded = Buffer.from(
|
|
30
|
+
const decoded = Buffer.from(encoded, "base64").toString("utf-8");
|
|
27
31
|
const [username, password] = decoded.split(":");
|
|
28
32
|
if (!username || !password) {
|
|
29
33
|
throw new errors_1.InvalidCredentialsError();
|
|
@@ -34,20 +38,11 @@ class BasicStrategy extends credential_based_auth_strategy_1.CredentialBasedAuth
|
|
|
34
38
|
throw new errors_1.InvalidCredentialsError();
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
async verifyCredentials(
|
|
38
|
-
return this.config.
|
|
41
|
+
async verifyCredentials(identifier, password) {
|
|
42
|
+
return this.config.credentials.verifyCredentials(identifier, password);
|
|
39
43
|
}
|
|
40
44
|
async retrieveUser(credentials) {
|
|
41
|
-
return this.config.
|
|
42
|
-
}
|
|
43
|
-
async requestPasswordReset(email) {
|
|
44
|
-
await super.requestPasswordReset(email);
|
|
45
|
-
}
|
|
46
|
-
async resetPassword(email, token, newPassword) {
|
|
47
|
-
await super.resetPassword(email, token, newPassword);
|
|
48
|
-
}
|
|
49
|
-
async changePassword(email, oldPassword, newPassword) {
|
|
50
|
-
await super.changePassword(email, oldPassword, newPassword);
|
|
45
|
+
return this.config.user.getUserData(credentials.identifier);
|
|
51
46
|
}
|
|
52
47
|
}
|
|
53
48
|
exports.BasicStrategy = BasicStrategy;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export interface BasicStrategyConfig<TContext = unknown, TUser = unknown> extends
|
|
1
|
+
import { CredentialAuthStrategyConfig } from "../../types";
|
|
2
|
+
export interface BasicStrategyConfig<TContext = unknown, TUser = unknown> extends CredentialAuthStrategyConfig<TContext, TUser> {
|
|
3
3
|
}
|
|
4
4
|
export type BasicContext = {
|
|
5
5
|
headers: {
|
package/build/strategies/{credential-based-auth.strategy.d.ts → credential-auth.strategy.d.ts}
RENAMED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import * as Soap from "@soapjs/soap";
|
|
2
|
-
import { AuthResult,
|
|
2
|
+
import { AuthResult, CredentialAuthStrategyConfig } from "../types";
|
|
3
3
|
import { BaseAuthStrategy } from "./base-auth.strategy";
|
|
4
4
|
import { SessionHandler } from "../session/session-handler";
|
|
5
|
-
export declare abstract class
|
|
6
|
-
protected config:
|
|
5
|
+
export declare abstract class CredentialAuthStrategy<TContext = unknown, TUser = unknown> extends BaseAuthStrategy<TContext, TUser> {
|
|
6
|
+
protected config: CredentialAuthStrategyConfig<TContext, TUser>;
|
|
7
7
|
protected session?: SessionHandler;
|
|
8
8
|
protected logger?: Soap.Logger;
|
|
9
|
-
protected abstract
|
|
10
|
-
|
|
11
|
-
password: string;
|
|
12
|
-
}>;
|
|
13
|
-
protected abstract verifyCredentials(credentials: any): Promise<boolean>;
|
|
9
|
+
protected abstract verifyCredentials(identifier: string, password: string): Promise<boolean>;
|
|
10
|
+
protected abstract extractCredentials(context: TContext): any;
|
|
14
11
|
protected abstract retrieveUser(credentials: any): Promise<TUser | null>;
|
|
15
|
-
constructor(config:
|
|
16
|
-
|
|
12
|
+
constructor(config: CredentialAuthStrategyConfig<TContext, TUser>, session?: SessionHandler, logger?: Soap.Logger);
|
|
13
|
+
protected storeUserSession(user: TUser, context: TContext): Promise<void>;
|
|
14
|
+
protected handleAuthenticationError(error: Error, context: TContext): Promise<never>;
|
|
15
|
+
protected preAuthChecks(identifier: string): Promise<void>;
|
|
16
|
+
protected handleFailedLogin(identifier: string): Promise<void>;
|
|
17
|
+
protected handleSuccessfulLogin(identifier: string): Promise<void>;
|
|
18
|
+
protected finalizeAuthentication(user: TUser, context: TContext): Promise<void>;
|
|
19
|
+
authenticate(context: TContext): Promise<AuthResult<TUser>>;
|
|
17
20
|
protected handleSession(user: TUser, context?: TContext): Promise<void>;
|
|
18
|
-
logout(context
|
|
21
|
+
logout(context: TContext): Promise<void>;
|
|
19
22
|
requestPasswordReset(identifier: string, email?: string): Promise<void>;
|
|
20
23
|
resetPassword(identifier: string, token: string, newPassword: string): Promise<void>;
|
|
21
24
|
changePassword(identifier: string, oldPassword: string, newPassword: string): Promise<void>;
|
|
@@ -23,7 +26,7 @@ export declare abstract class CredentialBasedAuthStrategy<TContext = unknown, TU
|
|
|
23
26
|
protected auditPasswordChange(identifier: string, context?: TContext): Promise<void>;
|
|
24
27
|
protected validatePasswordPolicy(password: string): boolean;
|
|
25
28
|
protected checkFailedAttempts(identifier: string): Promise<void>;
|
|
26
|
-
protected isAccountLocked(account: any
|
|
29
|
+
protected isAccountLocked(account: any): Promise<boolean>;
|
|
27
30
|
protected incrementFailedAttempts(account: any): Promise<void>;
|
|
28
31
|
protected notifyAccountLocked(identifier: string): Promise<void>;
|
|
29
32
|
protected checkPasswordExpiry(identifier: string): Promise<void>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CredentialAuthStrategy = void 0;
|
|
4
4
|
const errors_1 = require("../errors");
|
|
5
5
|
const base_auth_strategy_1 = require("./base-auth.strategy");
|
|
6
|
-
class
|
|
6
|
+
class CredentialAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy {
|
|
7
7
|
config;
|
|
8
8
|
session;
|
|
9
9
|
logger;
|
|
@@ -13,34 +13,73 @@ class CredentialBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy
|
|
|
13
13
|
this.session = session;
|
|
14
14
|
this.logger = logger;
|
|
15
15
|
}
|
|
16
|
+
async storeUserSession(user, context) {
|
|
17
|
+
if (!this.session || !this.config.session) {
|
|
18
|
+
this.logger?.info("Session management is not configured. Skipping session storage.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let sessionId = this.config.session.getSessionId?.(context);
|
|
22
|
+
if (!sessionId) {
|
|
23
|
+
sessionId = this.config.session.generateSessionId
|
|
24
|
+
? this.config.session.generateSessionId(user, context)
|
|
25
|
+
: `sid-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
26
|
+
}
|
|
27
|
+
const sessionData = this.config.session.createSessionData
|
|
28
|
+
? this.config.session.createSessionData(user, context)
|
|
29
|
+
: { user };
|
|
30
|
+
if (this.config.session.store) {
|
|
31
|
+
await this.config.session.store.setSession(sessionId, sessionData);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
await this.session.set(sessionId, sessionData);
|
|
35
|
+
}
|
|
36
|
+
this.config.session.embedSessionId?.(context, sessionId);
|
|
37
|
+
this.logger?.info(`Stored user session with ID: ${sessionId}`);
|
|
38
|
+
}
|
|
39
|
+
async handleAuthenticationError(error, context) {
|
|
40
|
+
this.logger?.error("Authentication failed:", error);
|
|
41
|
+
await this.onFailure("login", { context, error });
|
|
42
|
+
throw new errors_1.AuthError(error, "Authentication failed.");
|
|
43
|
+
}
|
|
44
|
+
async preAuthChecks(identifier) {
|
|
45
|
+
await this.isAccountLocked(identifier);
|
|
46
|
+
await this.checkFailedAttempts(identifier);
|
|
47
|
+
await this.checkRateLimit(identifier);
|
|
48
|
+
await this.checkPasswordExpiry(identifier);
|
|
49
|
+
}
|
|
50
|
+
async handleFailedLogin(identifier) {
|
|
51
|
+
await this.config.failedAttempts.incrementFailedAttempts?.(identifier);
|
|
52
|
+
}
|
|
53
|
+
async handleSuccessfulLogin(identifier) {
|
|
54
|
+
await this.config.failedAttempts.resetFailedAttempts?.(identifier);
|
|
55
|
+
}
|
|
56
|
+
async finalizeAuthentication(user, context) {
|
|
57
|
+
await this.checkMfa(user, context);
|
|
58
|
+
await this.isAuthorized(user);
|
|
59
|
+
await this.storeUserSession(user, context);
|
|
60
|
+
}
|
|
16
61
|
async authenticate(context) {
|
|
17
62
|
try {
|
|
18
63
|
const credentials = await this.extractCredentials(context);
|
|
19
64
|
if (!credentials)
|
|
20
65
|
throw new errors_1.MissingCredentialsError();
|
|
21
|
-
await this.
|
|
22
|
-
await this.
|
|
23
|
-
await this.checkRateLimit(credentials.identifier);
|
|
24
|
-
await this.checkPasswordExpiry(credentials.identifier);
|
|
25
|
-
const valid = await this.verifyCredentials(credentials);
|
|
66
|
+
await this.preAuthChecks(credentials.identifier);
|
|
67
|
+
const valid = await this.verifyCredentials(credentials.identifier, credentials.password);
|
|
26
68
|
if (!valid) {
|
|
27
|
-
await this.
|
|
69
|
+
await this.handleFailedLogin(credentials.identifier);
|
|
28
70
|
throw new errors_1.InvalidCredentialsError();
|
|
29
71
|
}
|
|
30
|
-
await this.
|
|
31
|
-
const user = await this.retrieveUser(credentials);
|
|
72
|
+
await this.handleSuccessfulLogin(credentials.identifier);
|
|
73
|
+
const user = await this.retrieveUser(credentials.identifier);
|
|
32
74
|
if (!user)
|
|
33
75
|
throw new errors_1.UserNotFoundError();
|
|
34
|
-
await this.
|
|
35
|
-
|
|
36
|
-
await this.handleSession(user, context);
|
|
76
|
+
await this.finalizeAuthentication(user, context);
|
|
77
|
+
this.auditLoginAttempt(credentials.identifier, true, context);
|
|
37
78
|
return { user };
|
|
38
79
|
}
|
|
39
80
|
catch (e) {
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
await this.config.logout.onFailure?.({ context, error: error });
|
|
43
|
-
throw error;
|
|
81
|
+
this.auditLoginAttempt(null, false, context);
|
|
82
|
+
return this.handleAuthenticationError(e, context);
|
|
44
83
|
}
|
|
45
84
|
}
|
|
46
85
|
async handleSession(user, context) {
|
|
@@ -53,78 +92,87 @@ class CredentialBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy
|
|
|
53
92
|
try {
|
|
54
93
|
if (this.session) {
|
|
55
94
|
const sessionId = this.session.getSessionId?.(context);
|
|
56
|
-
if (!sessionId)
|
|
95
|
+
if (!sessionId)
|
|
57
96
|
throw new Error("Session ID is missing in the context.");
|
|
58
|
-
}
|
|
59
97
|
await this.session.destroy(sessionId);
|
|
60
|
-
this.logger
|
|
98
|
+
this.logger?.info(`Session destroyed: ${sessionId}`);
|
|
61
99
|
}
|
|
62
|
-
await this.
|
|
63
|
-
this.logger.info(`User logged out successfully.`);
|
|
100
|
+
await this.onSuccess("logout", context);
|
|
64
101
|
}
|
|
65
102
|
catch (e) {
|
|
66
103
|
const error = new errors_1.AuthError(e, "Logout process failed.");
|
|
67
|
-
this.logger
|
|
68
|
-
await this.
|
|
104
|
+
this.logger?.error("Error during logout:", error);
|
|
105
|
+
await this.onFailure("logout", { context, error });
|
|
69
106
|
throw error;
|
|
70
107
|
}
|
|
71
108
|
}
|
|
72
109
|
async requestPasswordReset(identifier, email) {
|
|
73
110
|
try {
|
|
74
|
-
if (!this.config.
|
|
111
|
+
if (!this.config?.passwordPolicy.generateResetToken) {
|
|
75
112
|
throw new Error("Password reset token generation is not configured.");
|
|
76
113
|
}
|
|
77
|
-
const token = await this.config.
|
|
114
|
+
const token = await this.config.passwordPolicy.generateResetToken(identifier);
|
|
78
115
|
if (email) {
|
|
79
|
-
await this.config.
|
|
116
|
+
await this.config.passwordPolicy.sendResetEmail?.(email, token);
|
|
80
117
|
}
|
|
81
|
-
await this.
|
|
118
|
+
await this.onSuccess("request_password_reset", { identifier });
|
|
82
119
|
this.logger.info(`Password reset requested for identifier: ${identifier}`);
|
|
83
120
|
}
|
|
84
121
|
catch (e) {
|
|
85
122
|
const error = new errors_1.AuthError(e, "Password reset request error.");
|
|
86
123
|
this.logger.error("Password reset request error:", e);
|
|
87
|
-
await this.
|
|
124
|
+
await this.onFailure("request_password_reset", {
|
|
125
|
+
identifier,
|
|
126
|
+
error: e,
|
|
127
|
+
});
|
|
88
128
|
throw error;
|
|
89
129
|
}
|
|
90
130
|
}
|
|
91
131
|
async resetPassword(identifier, token, newPassword) {
|
|
92
132
|
try {
|
|
93
|
-
if (!this.config.
|
|
133
|
+
if (!this.config.passwordPolicy?.validateResetToken) {
|
|
94
134
|
throw new Error("Password reset token validation is not configured.");
|
|
95
135
|
}
|
|
96
|
-
const isValid = await this.config.
|
|
136
|
+
const isValid = await this.config.passwordPolicy.validateResetToken(token);
|
|
97
137
|
if (!isValid) {
|
|
98
138
|
throw new Error("Invalid or expired reset token.");
|
|
99
139
|
}
|
|
100
|
-
await this.config.
|
|
101
|
-
await this.
|
|
140
|
+
await this.config.passwordPolicy.updatePassword(identifier, newPassword);
|
|
141
|
+
await this.onSuccess("password_reset", { identifier });
|
|
102
142
|
this.logger.info(`Password successfully reset for identifier: ${identifier}`);
|
|
143
|
+
this.auditPasswordChange(identifier);
|
|
103
144
|
}
|
|
104
145
|
catch (e) {
|
|
105
146
|
const error = new errors_1.AuthError(e, "Password reset error");
|
|
106
147
|
this.logger.error("Password reset error:", e);
|
|
107
|
-
await this.
|
|
148
|
+
await this.onFailure("password_reset", {
|
|
149
|
+
identifier,
|
|
150
|
+
error: e,
|
|
151
|
+
});
|
|
108
152
|
throw error;
|
|
109
153
|
}
|
|
110
154
|
}
|
|
111
155
|
async changePassword(identifier, oldPassword, newPassword) {
|
|
112
156
|
try {
|
|
113
|
-
if (!this.config.
|
|
157
|
+
if (!this.config.credentials.verifyCredentials) {
|
|
114
158
|
throw new Error("Credential verification is not configured.");
|
|
115
159
|
}
|
|
116
|
-
const isAuthenticated = await this.config.
|
|
160
|
+
const isAuthenticated = await this.config.credentials.verifyCredentials(identifier, oldPassword);
|
|
117
161
|
if (!isAuthenticated) {
|
|
118
162
|
throw new errors_1.InvalidCredentialsError();
|
|
119
163
|
}
|
|
120
|
-
await this.config.
|
|
121
|
-
await this.
|
|
164
|
+
await this.config.passwordPolicy?.updatePassword?.(identifier, newPassword);
|
|
165
|
+
await this.onSuccess("change_password", { identifier });
|
|
122
166
|
this.logger.info(`Password changed successfully for identifier: ${identifier}`);
|
|
167
|
+
this.auditPasswordChange(identifier);
|
|
123
168
|
}
|
|
124
169
|
catch (e) {
|
|
125
170
|
const error = new errors_1.AuthError(e, "Change password error");
|
|
126
171
|
this.logger.error("Change password error:", e);
|
|
127
|
-
await this.
|
|
172
|
+
await this.onFailure("change_password", {
|
|
173
|
+
identifier,
|
|
174
|
+
error: e,
|
|
175
|
+
});
|
|
128
176
|
throw error;
|
|
129
177
|
}
|
|
130
178
|
}
|
|
@@ -140,7 +188,8 @@ class CredentialBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy
|
|
|
140
188
|
async checkFailedAttempts(identifier) {
|
|
141
189
|
try {
|
|
142
190
|
if (this.config.security?.maxFailedLoginAttempts) {
|
|
143
|
-
const failedAttempts = (await this.config.
|
|
191
|
+
const failedAttempts = (await this.config.failedAttempts.getFailedAttempts?.(identifier)) ||
|
|
192
|
+
0;
|
|
144
193
|
if (failedAttempts >= this.config.security.maxFailedLoginAttempts) {
|
|
145
194
|
this.logger.warn(`User ${identifier} is temporarily locked out.`);
|
|
146
195
|
throw new errors_1.AccountLockedError();
|
|
@@ -151,8 +200,8 @@ class CredentialBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy
|
|
|
151
200
|
this.logger.error("Check failed attempts:", e);
|
|
152
201
|
}
|
|
153
202
|
}
|
|
154
|
-
async isAccountLocked(account
|
|
155
|
-
if (await this.config.lock.isAccountLocked?.(account
|
|
203
|
+
async isAccountLocked(account) {
|
|
204
|
+
if (await this.config.lock.isAccountLocked?.(account)) {
|
|
156
205
|
throw new errors_1.AccountLockedError();
|
|
157
206
|
}
|
|
158
207
|
if (typeof account === "string" && this.config.security?.lockoutDuration) {
|
|
@@ -172,9 +221,9 @@ class CredentialBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy
|
|
|
172
221
|
return false;
|
|
173
222
|
}
|
|
174
223
|
async incrementFailedAttempts(account) {
|
|
175
|
-
if (this.config.
|
|
176
|
-
await this.config.
|
|
177
|
-
const failedAttempts = (await this.config.
|
|
224
|
+
if (this.config.failedAttempts.incrementFailedAttempts) {
|
|
225
|
+
await this.config.failedAttempts.incrementFailedAttempts(account);
|
|
226
|
+
const failedAttempts = (await this.config.failedAttempts.getFailedAttempts?.(account)) || 0;
|
|
178
227
|
if (this.config.security?.maxFailedLoginAttempts &&
|
|
179
228
|
failedAttempts >= this.config.security.maxFailedLoginAttempts) {
|
|
180
229
|
const lockoutKey = `lockout:${account}`;
|
|
@@ -202,4 +251,4 @@ class CredentialBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy
|
|
|
202
251
|
}
|
|
203
252
|
}
|
|
204
253
|
}
|
|
205
|
-
exports.
|
|
254
|
+
exports.CredentialAuthStrategy = CredentialAuthStrategy;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./api-key/api-key.errors";
|
|
2
|
+
export * from "./api-key/api-key.strategy";
|
|
3
|
+
export * from "./api-key/api-key.types";
|
|
4
|
+
export * from "./base-auth.strategy";
|
|
5
|
+
export * from "./basic/basic.strategy";
|
|
6
|
+
export * from "./basic/basic.types";
|
|
7
|
+
export * from "./credential-auth.strategy";
|
|
8
|
+
export * from "./jwt/jwt.strategy";
|
|
9
|
+
export * from "./jwt/jwt.tools";
|
|
10
|
+
export * from "./jwt/jwt.types";
|
|
11
|
+
export * from "./local/local.strategy";
|
|
12
|
+
export * from "./local/local.types";
|
|
13
|
+
export * from "./oauth2/oauth2.strategy";
|
|
14
|
+
export * from "./oauth2/oauth2.tools";
|
|
15
|
+
export * from "./oauth2/oauth2.types";
|
|
16
|
+
export * from "./token-auth.strategy";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./api-key/api-key.errors"), exports);
|
|
18
|
+
__exportStar(require("./api-key/api-key.strategy"), exports);
|
|
19
|
+
__exportStar(require("./api-key/api-key.types"), exports);
|
|
20
|
+
__exportStar(require("./base-auth.strategy"), exports);
|
|
21
|
+
__exportStar(require("./basic/basic.strategy"), exports);
|
|
22
|
+
__exportStar(require("./basic/basic.types"), exports);
|
|
23
|
+
__exportStar(require("./credential-auth.strategy"), exports);
|
|
24
|
+
__exportStar(require("./jwt/jwt.strategy"), exports);
|
|
25
|
+
__exportStar(require("./jwt/jwt.tools"), exports);
|
|
26
|
+
__exportStar(require("./jwt/jwt.types"), exports);
|
|
27
|
+
__exportStar(require("./local/local.strategy"), exports);
|
|
28
|
+
__exportStar(require("./local/local.types"), exports);
|
|
29
|
+
__exportStar(require("./oauth2/oauth2.strategy"), exports);
|
|
30
|
+
__exportStar(require("./oauth2/oauth2.tools"), exports);
|
|
31
|
+
__exportStar(require("./oauth2/oauth2.types"), exports);
|
|
32
|
+
__exportStar(require("./token-auth.strategy"), exports);
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import * as Soap from "@soapjs/soap";
|
|
2
|
-
import {
|
|
2
|
+
import { TokenAuthStrategy } from "../token-auth.strategy";
|
|
3
3
|
import { JwtConfig } from "./jwt.types";
|
|
4
4
|
import { SessionHandler } from "../../session/session-handler";
|
|
5
|
-
|
|
5
|
+
import { TokenConfig } from "../../types";
|
|
6
|
+
export declare class JwtStrategy<TContext = unknown, TUser = unknown> extends TokenAuthStrategy<TContext, TUser> {
|
|
6
7
|
protected config: JwtConfig<TContext, TUser>;
|
|
7
8
|
protected session?: SessionHandler;
|
|
8
9
|
protected logger?: Soap.Logger;
|
|
10
|
+
protected accessTokenConfig: TokenConfig<TContext>;
|
|
11
|
+
protected refreshTokenConfig: TokenConfig<TContext>;
|
|
9
12
|
constructor(config: JwtConfig<TContext, TUser>, session?: SessionHandler, logger?: Soap.Logger);
|
|
13
|
+
protected invalidateRefreshToken(token: string): Promise<void>;
|
|
14
|
+
protected verifyAccessToken(token: string): Promise<any>;
|
|
15
|
+
protected verifyRefreshToken(token: string): Promise<any>;
|
|
16
|
+
protected generateAccessToken(payload: any): Promise<string>;
|
|
17
|
+
protected generateRefreshToken(payload: any): Promise<string>;
|
|
18
|
+
protected storeAccessToken(token: string, context: TContext): Promise<void>;
|
|
19
|
+
protected storeRefreshToken(token: string, context: TContext): Promise<void>;
|
|
20
|
+
protected embedAccessToken(token: string, context: TContext): void;
|
|
21
|
+
protected embedRefreshToken(token: string, context: TContext): void;
|
|
22
|
+
protected retrieveAccessToken(context: TContext): Promise<string | undefined>;
|
|
23
|
+
protected retrieveRefreshToken(context: TContext): Promise<string | undefined>;
|
|
24
|
+
logout(context: TContext): Promise<void>;
|
|
10
25
|
}
|