moleculer-iam
Version:
Centralized IAM module for moleculer. Including a certified OIDC provider and an Identity provider for user profile, credentials, and custom claims management. Custom claims could be defined/updated by declarative schema which contains claims validation a
125 lines • 5.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAPIGatewayMixin = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
// will publish public API only if IAM service is connected to API gateway service.
const api = {
branch: "master",
protocol: {
REST: {
basePath: "/iam",
description: "Issue access token for API gateway on purpose of debugging.",
routes: [
{
path: "/login",
method: "GET",
call: {
action: "iam.$login",
params: {
request: "@context.request",
callback: "@query.callback",
scope: "@query.scope",
},
},
},
{
path: "/login/callback",
method: "GET",
call: {
action: "iam.$loginCallback",
params: {},
},
}
],
},
},
policy: {},
};
function createAPIGatewayMixin(gatewayURI) {
const URIs = [
`${gatewayURI}`,
`https://localhost:9090`
];
const loginURIs = URIs.map(uri => uri + "/iam/login");
const loginCallbackURIs = loginURIs.map(uri => uri + "/callback");
const clientParams = {
client_id: "api-gateway",
client_name: "API Gateway",
client_uri: gatewayURI,
redirect_uris: loginCallbackURIs,
skip_consent: true,
};
const loginCallbackHTML = fs_1.default.readFileSync(path_1.default.join(__dirname, "./api.login.callback.html")).toString("utf-8");
const mixin = {
metadata: {
api,
},
events: {
"$broker.started": {
async handler() {
// create/update API gateway client
const client = await this.broker.call("iam.client.find", { id: clientParams.client_id }, { nodeID: this.broker.nodeID });
if (!client) {
await this.broker.call("iam.client.create", clientParams, { nodeID: this.broker.nodeID });
}
else {
await this.broker.call("iam.client.update", clientParams, { nodeID: this.broker.nodeID });
}
this.broker.logger.info(`API Gateway client initialized for debugging purpose: ${loginURIs.join(", ")}`);
},
},
},
actions: {
$report: {
handler({ params: { table, messages } }) {
this.broker.logger.info(table);
},
},
$login: {
params: {
callback: {
type: "string",
optional: true,
},
scope: {
type: "string",
optional: true,
},
},
async handler({ params: { request, callback, scope = "" } }) {
// gather all scopes except offline access scope
const givenScopes = scope.split(" ").filter(s => !!s);
const scopesSet = new Set(givenScopes.length > 0 ? givenScopes : await this.idp.claims.getActiveClaimsSchemata().then(schemata => schemata.map(s => s.scope)));
scopesSet.delete("offline_access");
const scopes = [...scopesSet];
// create authorization endpoint
const redirectURI = request.host && loginCallbackURIs.find(uri => uri.includes(request.host)) || loginCallbackURIs[0];
const callbackURI = callback || request && request.referer || gatewayURI;
const nonce = Math.floor(Math.random() * 10000).toString();
const authURI = `${this.op.issuer}/op/auth?client_id=${clientParams.client_id}&response_type=code%20token&scope=${encodeURIComponent(scopes.join(" "))}&prompt=login&redirect_uri=${encodeURIComponent(redirectURI)}&state=${encodeURIComponent(callbackURI)}&nonce=${nonce}`;
return {
$status: 303,
$headers: {
"Location": authURI,
},
};
},
},
$loginCallback: {
params: {},
handler() {
// handle token and redirection in client-side (#id_token=xxx&acess_token=xxx&state=xxx...)
return {
$status: 200,
$body: loginCallbackHTML,
};
},
},
},
};
return mixin;
}
exports.createAPIGatewayMixin = createAPIGatewayMixin;
//# sourceMappingURL=api.js.map