@clemax/nest-keycloak-connect 2.0.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/LICENSE +21 -0
- package/README.md +298 -0
- package/dist/constants.d.ts +69 -0
- package/dist/constants.js +76 -0
- package/dist/decorators/access-token.decorator.d.ts +5 -0
- package/dist/decorators/access-token.decorator.js +13 -0
- package/dist/decorators/enforcer-options.decorator.d.ts +8 -0
- package/dist/decorators/enforcer-options.decorator.js +12 -0
- package/dist/decorators/keycloak-user.decorator.d.ts +5 -0
- package/dist/decorators/keycloak-user.decorator.js +13 -0
- package/dist/decorators/public.decorator.d.ts +7 -0
- package/dist/decorators/public.decorator.js +12 -0
- package/dist/decorators/resource.decorator.d.ts +6 -0
- package/dist/decorators/resource.decorator.js +11 -0
- package/dist/decorators/roles.decorator.d.ts +10 -0
- package/dist/decorators/roles.decorator.js +15 -0
- package/dist/decorators/scopes.decorator.d.ts +19 -0
- package/dist/decorators/scopes.decorator.js +28 -0
- package/dist/guards/auth.guard.d.ts +19 -0
- package/dist/guards/auth.guard.js +172 -0
- package/dist/guards/resource.guard.d.ts +18 -0
- package/dist/guards/resource.guard.js +175 -0
- package/dist/guards/role.guard.d.ts +17 -0
- package/dist/guards/role.guard.js +139 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/interface/keycloak-connect-module-async-options.interface.d.ts +9 -0
- package/dist/interface/keycloak-connect-module-async-options.interface.js +2 -0
- package/dist/interface/keycloak-connect-options-factory.interface.d.ts +4 -0
- package/dist/interface/keycloak-connect-options-factory.interface.js +2 -0
- package/dist/interface/keycloak-connect-options.interface.d.ts +166 -0
- package/dist/interface/keycloak-connect-options.interface.js +3 -0
- package/dist/internal.util.d.ts +8 -0
- package/dist/internal.util.js +69 -0
- package/dist/keycloak-connect.module.d.ts +32 -0
- package/dist/keycloak-connect.module.js +126 -0
- package/dist/keycloak-connect.providers.d.ts +7 -0
- package/dist/keycloak-connect.providers.js +81 -0
- package/dist/services/keycloak-multitenant.service.d.ts +24 -0
- package/dist/services/keycloak-multitenant.service.js +174 -0
- package/dist/util.d.ts +1 -0
- package/dist/util.js +8 -0
- package/package.json +100 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { PolicyEnforcementMode, RoleMerge, TokenValidation } from '../constants';
|
|
2
|
+
export type KeycloakConnectOptions = string | KeycloakConnectConfig;
|
|
3
|
+
/**
|
|
4
|
+
* Multi tenant configuration.
|
|
5
|
+
*/
|
|
6
|
+
export interface MultiTenantOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Option to always resolve the realm and secret. Disabled by default.
|
|
9
|
+
*/
|
|
10
|
+
resolveAlways?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The realm resolver function.
|
|
13
|
+
*/
|
|
14
|
+
realmResolver: (request: any) => Promise<string> | string;
|
|
15
|
+
/**
|
|
16
|
+
* The realm secret resolver function.
|
|
17
|
+
*/
|
|
18
|
+
realmSecretResolver?: (realm: string, request?: any) => Promise<string> | string;
|
|
19
|
+
/**
|
|
20
|
+
* The realm auth server url resolver function.
|
|
21
|
+
*/
|
|
22
|
+
realmAuthServerUrlResolver?: (realm: string, request?: any) => Promise<string> | string;
|
|
23
|
+
/**
|
|
24
|
+
* The realm client id resolver function.
|
|
25
|
+
*/
|
|
26
|
+
realmClientIdResolver: (realm: string, request?: any) => Promise<string> | string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Library only configuration.
|
|
30
|
+
*/
|
|
31
|
+
export interface NestKeycloakConfig {
|
|
32
|
+
/**
|
|
33
|
+
* Cookie key.
|
|
34
|
+
*/
|
|
35
|
+
cookieKey?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Sets the policy enforcement mode for this adapter, defaults to {@link PolicyEnforcementMode.PERMISSIVE}.
|
|
38
|
+
*/
|
|
39
|
+
policyEnforcement?: PolicyEnforcementMode;
|
|
40
|
+
/**
|
|
41
|
+
* Sets the token validation method, defaults to {@link TokenValidation.ONLINE}.
|
|
42
|
+
*/
|
|
43
|
+
tokenValidation?: TokenValidation;
|
|
44
|
+
/**
|
|
45
|
+
* Multi tenant options.
|
|
46
|
+
*/
|
|
47
|
+
multiTenant?: MultiTenantOptions;
|
|
48
|
+
/**
|
|
49
|
+
* Role merging options.
|
|
50
|
+
*/
|
|
51
|
+
roleMerge?: RoleMerge;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Keycloak Connect options.
|
|
55
|
+
* @see {@link https://github.com/keycloak/keycloak-nodejs-connect/blob/f8e011aea5/middleware/auth-utils/config.js}
|
|
56
|
+
*/
|
|
57
|
+
export interface KeycloakConnectConfig extends NestKeycloakConfig {
|
|
58
|
+
/**
|
|
59
|
+
* Realm ID.
|
|
60
|
+
*/
|
|
61
|
+
realm?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Client/Application ID.
|
|
64
|
+
*/
|
|
65
|
+
resource?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Client/Application ID.
|
|
68
|
+
* @see {KeycloakConnectOptions#resource}
|
|
69
|
+
*/
|
|
70
|
+
'client-id'?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Client/Application ID.
|
|
73
|
+
* @see {KeycloakConnectOptions#resource}
|
|
74
|
+
*/
|
|
75
|
+
clientId?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Client/Application secret.
|
|
78
|
+
*/
|
|
79
|
+
credentials?: KeycloakCredentials;
|
|
80
|
+
/**
|
|
81
|
+
* Client/Application secret.
|
|
82
|
+
* @see {KeycloakCredentials#secret}
|
|
83
|
+
*/
|
|
84
|
+
secret: string;
|
|
85
|
+
/**
|
|
86
|
+
* If this is a public application or confidential.
|
|
87
|
+
* @see {KeycloakConnectOptions#public}
|
|
88
|
+
*/
|
|
89
|
+
'public-client'?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* If this is a public application or confidential.
|
|
92
|
+
*/
|
|
93
|
+
public?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Authentication server URL.
|
|
96
|
+
* @see {KeycloakConnectOptions#authServerUrl}
|
|
97
|
+
*/
|
|
98
|
+
'auth-server-url'?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Authentication server URL.
|
|
101
|
+
* @see {KeycloakConnectOptions#authServerUrl}
|
|
102
|
+
*/
|
|
103
|
+
'server-url'?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Authentication server URL.
|
|
106
|
+
* @see {KeycloakConnectOptions#authServerUrl}
|
|
107
|
+
*/
|
|
108
|
+
serverUrl?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Authentication server URL.
|
|
111
|
+
*/
|
|
112
|
+
authServerUrl?: string;
|
|
113
|
+
/**
|
|
114
|
+
* How many minutes before retrying getting the keys.
|
|
115
|
+
* @see {KeycloakConnectOptions#minTimeBetweenJwksRequests}
|
|
116
|
+
*/
|
|
117
|
+
'min-time-between-jwks-requests'?: number;
|
|
118
|
+
/**
|
|
119
|
+
* How many minutes before retrying getting the keys.
|
|
120
|
+
*/
|
|
121
|
+
minTimeBetweenJwksRequests?: number;
|
|
122
|
+
/**
|
|
123
|
+
* If this is a Bearer Only application.
|
|
124
|
+
* @see {KeycloakConnectOptions#bearerOnly}
|
|
125
|
+
*/
|
|
126
|
+
'bearer-only'?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* If this is a Bearer Only application.
|
|
129
|
+
*/
|
|
130
|
+
bearerOnly?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Formatted public-key.
|
|
133
|
+
* @see {KeycloakConnectOptions#realmPublicKey}
|
|
134
|
+
*/
|
|
135
|
+
'realm-public-key'?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Formatted public-key.
|
|
138
|
+
*/
|
|
139
|
+
realmPublicKey?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Verify token audience.
|
|
142
|
+
* @see {KeycloakConnectOptions#verifyTokenAudience}
|
|
143
|
+
*/
|
|
144
|
+
'verify-token-audience'?: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Verify token audience.
|
|
147
|
+
*/
|
|
148
|
+
verifyTokenAudience?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Confidential port.
|
|
151
|
+
*/
|
|
152
|
+
'confidential-port'?: string | number;
|
|
153
|
+
/**
|
|
154
|
+
* Require SSL.
|
|
155
|
+
*/
|
|
156
|
+
'ssl-required'?: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Represents Keycloak credentials.
|
|
160
|
+
*/
|
|
161
|
+
export interface KeycloakCredentials {
|
|
162
|
+
/**
|
|
163
|
+
* Client/Application secret.
|
|
164
|
+
*/
|
|
165
|
+
secret: string;
|
|
166
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ExecutionContext } from '@nestjs/common';
|
|
2
|
+
import KeycloakConnect from 'keycloak-connect';
|
|
3
|
+
import { KeycloakConnectConfig } from './interface/keycloak-connect-options.interface';
|
|
4
|
+
import { KeycloakMultiTenantService } from './services/keycloak-multitenant.service';
|
|
5
|
+
export declare const useKeycloak: (request: any, jwt: string, singleTenant: KeycloakConnect.Keycloak, multiTenant: KeycloakMultiTenantService, opts: KeycloakConnectConfig) => Promise<KeycloakConnect.Keycloak>;
|
|
6
|
+
export declare const attachCookieToHeader: (request: any, cookieKey: string) => any;
|
|
7
|
+
export declare const extractRequest: (context: ExecutionContext) => [any, any];
|
|
8
|
+
export declare const extractRequestAndAttachCookie: (context: ExecutionContext, cookieKey: string) => any[];
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.extractRequestAndAttachCookie = exports.extractRequest = exports.attachCookieToHeader = exports.useKeycloak = void 0;
|
|
13
|
+
const util_1 = require("./util");
|
|
14
|
+
// Confusing and all, but I needed to extract this fn to avoid more repeating code
|
|
15
|
+
// TODO: Rework in 2.0
|
|
16
|
+
const useKeycloak = (request, jwt, singleTenant, multiTenant, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
if (opts.multiTenant && opts.multiTenant.realmResolver) {
|
|
18
|
+
const resolvedRealm = opts.multiTenant.realmResolver(request);
|
|
19
|
+
const realm = resolvedRealm instanceof Promise ? yield resolvedRealm : resolvedRealm;
|
|
20
|
+
return yield multiTenant.get(realm, request);
|
|
21
|
+
}
|
|
22
|
+
else if (!opts.realm) {
|
|
23
|
+
const payload = (0, util_1.parseToken)(jwt);
|
|
24
|
+
const issuerRealm = payload.iss.split('/').pop();
|
|
25
|
+
return yield multiTenant.get(issuerRealm, request);
|
|
26
|
+
}
|
|
27
|
+
return singleTenant;
|
|
28
|
+
});
|
|
29
|
+
exports.useKeycloak = useKeycloak;
|
|
30
|
+
const attachCookieToHeader = (request, cookieKey) => {
|
|
31
|
+
// Attach cookie as authorization header
|
|
32
|
+
if (request && request.cookies && request.cookies[cookieKey]) {
|
|
33
|
+
request.headers.authorization = `Bearer ${request.cookies[cookieKey]}`;
|
|
34
|
+
}
|
|
35
|
+
return request;
|
|
36
|
+
};
|
|
37
|
+
exports.attachCookieToHeader = attachCookieToHeader;
|
|
38
|
+
const extractRequest = (context) => {
|
|
39
|
+
let request, response;
|
|
40
|
+
// Check if request is coming from graphql or http
|
|
41
|
+
if (context.getType() === 'http') {
|
|
42
|
+
// http request
|
|
43
|
+
const httpContext = context.switchToHttp();
|
|
44
|
+
request = httpContext.getRequest();
|
|
45
|
+
response = httpContext.getResponse();
|
|
46
|
+
}
|
|
47
|
+
else if (context.getType() === 'graphql') {
|
|
48
|
+
let gql;
|
|
49
|
+
// Check if graphql is installed
|
|
50
|
+
try {
|
|
51
|
+
gql = require('@nestjs/graphql');
|
|
52
|
+
}
|
|
53
|
+
catch (er) {
|
|
54
|
+
throw new Error('@nestjs/graphql is not installed, cannot proceed');
|
|
55
|
+
}
|
|
56
|
+
// graphql request
|
|
57
|
+
const gqlContext = gql.GqlExecutionContext.create(context).getContext();
|
|
58
|
+
request = gqlContext.req;
|
|
59
|
+
response = gqlContext.res;
|
|
60
|
+
}
|
|
61
|
+
return [request, response];
|
|
62
|
+
};
|
|
63
|
+
exports.extractRequest = extractRequest;
|
|
64
|
+
const extractRequestAndAttachCookie = (context, cookieKey) => {
|
|
65
|
+
const [tmpRequest, response] = (0, exports.extractRequest)(context);
|
|
66
|
+
const request = (0, exports.attachCookieToHeader)(tmpRequest, cookieKey);
|
|
67
|
+
return [request, response];
|
|
68
|
+
};
|
|
69
|
+
exports.extractRequestAndAttachCookie = extractRequestAndAttachCookie;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DynamicModule, Logger } from '@nestjs/common';
|
|
2
|
+
import { KeycloakConnectModuleAsyncOptions } from './interface/keycloak-connect-module-async-options.interface';
|
|
3
|
+
import { KeycloakConnectOptions, NestKeycloakConfig } from './interface/keycloak-connect-options.interface';
|
|
4
|
+
export * from './constants';
|
|
5
|
+
export * from './decorators/access-token.decorator';
|
|
6
|
+
export * from './decorators/enforcer-options.decorator';
|
|
7
|
+
export * from './decorators/keycloak-user.decorator';
|
|
8
|
+
export * from './decorators/public.decorator';
|
|
9
|
+
export * from './decorators/resource.decorator';
|
|
10
|
+
export * from './decorators/roles.decorator';
|
|
11
|
+
export * from './decorators/scopes.decorator';
|
|
12
|
+
export * from './guards/auth.guard';
|
|
13
|
+
export * from './guards/resource.guard';
|
|
14
|
+
export * from './guards/role.guard';
|
|
15
|
+
export * from './interface/keycloak-connect-module-async-options.interface';
|
|
16
|
+
export * from './interface/keycloak-connect-options-factory.interface';
|
|
17
|
+
export * from './interface/keycloak-connect-options.interface';
|
|
18
|
+
export * from './services/keycloak-multitenant.service';
|
|
19
|
+
export * from './util';
|
|
20
|
+
export declare class KeycloakConnectModule {
|
|
21
|
+
static logger: Logger;
|
|
22
|
+
/**
|
|
23
|
+
* Register the `KeycloakConnect` module.
|
|
24
|
+
* @param opts `keycloak.json` path in string or {@link NestKeycloakConfig} object.
|
|
25
|
+
* @param config {@link NestKeycloakConfig} when using `keycloak.json` path, optional
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
static register(opts: KeycloakConnectOptions, config?: NestKeycloakConfig): DynamicModule;
|
|
29
|
+
static registerAsync(opts: KeycloakConnectModuleAsyncOptions): DynamicModule;
|
|
30
|
+
private static createAsyncProviders;
|
|
31
|
+
private static createAsyncOptionsProvider;
|
|
32
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
14
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
16
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
17
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
18
|
+
};
|
|
19
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
20
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
+
};
|
|
22
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
23
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
24
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
25
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
26
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
27
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
28
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
var KeycloakConnectModule_1;
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.KeycloakConnectModule = void 0;
|
|
34
|
+
const common_1 = require("@nestjs/common");
|
|
35
|
+
const constants_1 = require("./constants");
|
|
36
|
+
const keycloak_connect_providers_1 = require("./keycloak-connect.providers");
|
|
37
|
+
const keycloak_multitenant_service_1 = require("./services/keycloak-multitenant.service");
|
|
38
|
+
__exportStar(require("./constants"), exports);
|
|
39
|
+
__exportStar(require("./decorators/access-token.decorator"), exports);
|
|
40
|
+
__exportStar(require("./decorators/enforcer-options.decorator"), exports);
|
|
41
|
+
__exportStar(require("./decorators/keycloak-user.decorator"), exports);
|
|
42
|
+
__exportStar(require("./decorators/public.decorator"), exports);
|
|
43
|
+
__exportStar(require("./decorators/resource.decorator"), exports);
|
|
44
|
+
__exportStar(require("./decorators/roles.decorator"), exports);
|
|
45
|
+
__exportStar(require("./decorators/scopes.decorator"), exports);
|
|
46
|
+
__exportStar(require("./guards/auth.guard"), exports);
|
|
47
|
+
__exportStar(require("./guards/resource.guard"), exports);
|
|
48
|
+
__exportStar(require("./guards/role.guard"), exports);
|
|
49
|
+
__exportStar(require("./interface/keycloak-connect-module-async-options.interface"), exports);
|
|
50
|
+
__exportStar(require("./interface/keycloak-connect-options-factory.interface"), exports);
|
|
51
|
+
__exportStar(require("./interface/keycloak-connect-options.interface"), exports);
|
|
52
|
+
__exportStar(require("./services/keycloak-multitenant.service"), exports);
|
|
53
|
+
__exportStar(require("./util"), exports);
|
|
54
|
+
let KeycloakConnectModule = KeycloakConnectModule_1 = class KeycloakConnectModule {
|
|
55
|
+
/**
|
|
56
|
+
* Register the `KeycloakConnect` module.
|
|
57
|
+
* @param opts `keycloak.json` path in string or {@link NestKeycloakConfig} object.
|
|
58
|
+
* @param config {@link NestKeycloakConfig} when using `keycloak.json` path, optional
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
static register(opts, config) {
|
|
62
|
+
const keycloakConnectProviders = [
|
|
63
|
+
(0, keycloak_connect_providers_1.createKeycloakConnectOptionProvider)(opts, config),
|
|
64
|
+
keycloak_connect_providers_1.keycloakProvider,
|
|
65
|
+
keycloak_multitenant_service_1.KeycloakMultiTenantService,
|
|
66
|
+
{
|
|
67
|
+
provide: constants_1.KEYCLOAK_MULTITENANT_SERVICE,
|
|
68
|
+
useClass: keycloak_multitenant_service_1.KeycloakMultiTenantService,
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
return {
|
|
72
|
+
module: KeycloakConnectModule_1,
|
|
73
|
+
providers: keycloakConnectProviders,
|
|
74
|
+
exports: keycloakConnectProviders,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
static registerAsync(opts) {
|
|
78
|
+
const optsProvider = this.createAsyncProviders(opts);
|
|
79
|
+
return {
|
|
80
|
+
module: KeycloakConnectModule_1,
|
|
81
|
+
imports: opts.imports || [],
|
|
82
|
+
providers: optsProvider,
|
|
83
|
+
exports: optsProvider,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
static createAsyncProviders(options) {
|
|
87
|
+
const reqProviders = [
|
|
88
|
+
this.createAsyncOptionsProvider(options),
|
|
89
|
+
keycloak_connect_providers_1.keycloakProvider,
|
|
90
|
+
keycloak_multitenant_service_1.KeycloakMultiTenantService,
|
|
91
|
+
{
|
|
92
|
+
provide: constants_1.KEYCLOAK_MULTITENANT_SERVICE,
|
|
93
|
+
useClass: keycloak_multitenant_service_1.KeycloakMultiTenantService,
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
if (options.useExisting || options.useFactory) {
|
|
97
|
+
return reqProviders;
|
|
98
|
+
}
|
|
99
|
+
return [
|
|
100
|
+
...reqProviders,
|
|
101
|
+
{
|
|
102
|
+
provide: options.useClass,
|
|
103
|
+
useClass: options.useClass,
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
static createAsyncOptionsProvider(options) {
|
|
108
|
+
if (options.useFactory) {
|
|
109
|
+
return {
|
|
110
|
+
provide: constants_1.KEYCLOAK_CONNECT_OPTIONS,
|
|
111
|
+
useFactory: options.useFactory,
|
|
112
|
+
inject: options.inject || [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
provide: constants_1.KEYCLOAK_CONNECT_OPTIONS,
|
|
117
|
+
useFactory: (optionsFactory) => __awaiter(this, void 0, void 0, function* () { return yield optionsFactory.createKeycloakConnectOptions(); }),
|
|
118
|
+
inject: [options.useExisting || options.useClass],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
exports.KeycloakConnectModule = KeycloakConnectModule;
|
|
123
|
+
KeycloakConnectModule.logger = new common_1.Logger(KeycloakConnectModule_1.name);
|
|
124
|
+
exports.KeycloakConnectModule = KeycloakConnectModule = KeycloakConnectModule_1 = __decorate([
|
|
125
|
+
(0, common_1.Module)({})
|
|
126
|
+
], KeycloakConnectModule);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Provider } from '@nestjs/common';
|
|
2
|
+
import { KeycloakConnectConfig, KeycloakConnectOptions, NestKeycloakConfig } from './interface/keycloak-connect-options.interface';
|
|
3
|
+
export declare const keycloakProvider: Provider;
|
|
4
|
+
export declare const createKeycloakConnectOptionProvider: (opts: KeycloakConnectOptions, config?: NestKeycloakConfig) => {
|
|
5
|
+
provide: string;
|
|
6
|
+
useValue: KeycloakConnectConfig;
|
|
7
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.createKeycloakConnectOptionProvider = exports.keycloakProvider = void 0;
|
|
30
|
+
const fs = __importStar(require("fs"));
|
|
31
|
+
const keycloak_connect_1 = __importDefault(require("keycloak-connect"));
|
|
32
|
+
const path = __importStar(require("path"));
|
|
33
|
+
const constants_1 = require("./constants");
|
|
34
|
+
const keycloak_connect_module_1 = require("./keycloak-connect.module");
|
|
35
|
+
exports.keycloakProvider = {
|
|
36
|
+
provide: constants_1.KEYCLOAK_INSTANCE,
|
|
37
|
+
useFactory: (opts) => {
|
|
38
|
+
const keycloakOpts = opts;
|
|
39
|
+
const keycloak = new keycloak_connect_1.default({}, keycloakOpts);
|
|
40
|
+
// Warn if using token validation none
|
|
41
|
+
if (typeof opts !== 'string' &&
|
|
42
|
+
opts.tokenValidation &&
|
|
43
|
+
opts.tokenValidation === constants_1.TokenValidation.NONE) {
|
|
44
|
+
keycloak_connect_module_1.KeycloakConnectModule.logger.warn(`Token validation is disabled, please only do this on development/special use-cases.`);
|
|
45
|
+
}
|
|
46
|
+
// Access denied is called, add a flag to request so our resource guard knows
|
|
47
|
+
keycloak.accessDenied = (req, res, next) => {
|
|
48
|
+
req.resourceDenied = true;
|
|
49
|
+
next();
|
|
50
|
+
};
|
|
51
|
+
return keycloak;
|
|
52
|
+
},
|
|
53
|
+
inject: [constants_1.KEYCLOAK_CONNECT_OPTIONS],
|
|
54
|
+
};
|
|
55
|
+
const parseConfig = (opts, config) => {
|
|
56
|
+
if (typeof opts === 'string') {
|
|
57
|
+
const configPathRelative = path.join(__dirname, opts);
|
|
58
|
+
const configPathRoot = path.join(process.cwd(), opts);
|
|
59
|
+
let configPath;
|
|
60
|
+
if (fs.existsSync(configPathRelative)) {
|
|
61
|
+
configPath = configPathRelative;
|
|
62
|
+
}
|
|
63
|
+
else if (fs.existsSync(configPathRoot)) {
|
|
64
|
+
configPath = configPathRoot;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
throw new Error(`Cannot find files, looked in [ ${configPathRelative}, ${configPathRoot} ]`);
|
|
68
|
+
}
|
|
69
|
+
const json = fs.readFileSync(configPath);
|
|
70
|
+
const keycloakConfig = JSON.parse(json.toString());
|
|
71
|
+
return Object.assign(keycloakConfig, config);
|
|
72
|
+
}
|
|
73
|
+
return opts;
|
|
74
|
+
};
|
|
75
|
+
const createKeycloakConnectOptionProvider = (opts, config) => {
|
|
76
|
+
return {
|
|
77
|
+
provide: constants_1.KEYCLOAK_CONNECT_OPTIONS,
|
|
78
|
+
useValue: parseConfig(opts, config),
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
exports.createKeycloakConnectOptionProvider = createKeycloakConnectOptionProvider;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import KeycloakConnect from 'keycloak-connect';
|
|
2
|
+
import { KeycloakConnectOptions } from '../interface/keycloak-connect-options.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Stores all keycloak instances when multi tenant option is defined.
|
|
5
|
+
*/
|
|
6
|
+
export declare class KeycloakMultiTenantService {
|
|
7
|
+
private keycloakOpts;
|
|
8
|
+
private instances;
|
|
9
|
+
constructor(keycloakOpts: KeycloakConnectOptions);
|
|
10
|
+
/**
|
|
11
|
+
* Clears the cached Keycloak instances.
|
|
12
|
+
*/
|
|
13
|
+
clear(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves a keycloak instance based on the realm provided.
|
|
16
|
+
* @param realm the realm to retrieve from
|
|
17
|
+
* @param request the request instance, defaults to undefined
|
|
18
|
+
* @returns the multi tenant keycloak instance
|
|
19
|
+
*/
|
|
20
|
+
get(realm: string, request?: any): Promise<KeycloakConnect.Keycloak>;
|
|
21
|
+
resolveAuthServerUrl(realm: string, request?: any): Promise<string>;
|
|
22
|
+
resolveClientId(realm: string, request?: any): Promise<string>;
|
|
23
|
+
resolveSecret(realm: string, request?: any): Promise<string>;
|
|
24
|
+
}
|