UNPKG

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

138 lines 6.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IAMServer = void 0; const tslib_1 = require("tslib"); const http = tslib_1.__importStar(require("http")); const http2 = tslib_1.__importStar(require("http2")); const https = tslib_1.__importStar(require("https")); const kleur = tslib_1.__importStar(require("kleur")); const url = tslib_1.__importStar(require("url")); const koa_1 = tslib_1.__importDefault(require("koa")); const koa_helmet_1 = tslib_1.__importDefault(require("koa-helmet")); const koa_json_1 = tslib_1.__importDefault(require("koa-json")); const koa_mount_1 = tslib_1.__importDefault(require("koa-mount")); // @ts-ignore const koa_no_trailing_slash_1 = tslib_1.__importDefault(require("koa-no-trailing-slash")); // @ts-ignore const koa_locale_1 = tslib_1.__importDefault(require("koa-locale")); const logging_1 = require("./logging"); class IAMServer { constructor(props, opts) { this.props = props; this.working = false; const options = this.options = opts || {}; const { logger, op } = props; this.logger = logger || console; // create web server application const app = this.app = new koa_1.default(); app.env = op.app.env = "production"; app.proxy = op.app.proxy = true; // apply middleware app.use(logging_1.logging(this.logger, options.logging)); app.use(koa_no_trailing_slash_1.default()); app.use(koa_helmet_1.default(options.security)); app.use(koa_json_1.default({ pretty: true, spaces: 2, })); // set locale into context koa_locale_1.default(app, "locale"); // prepare to persist some query strings on redirection const { persistentQueryParamsKeys = [] } = this.options; const persistentQueryParamsKeysWithDefaults = [...new Set(persistentQueryParamsKeys.concat(["locale", "theme"]))]; app.use((ctx, next) => { // parsed by precedence of ?locale=ko-KR, Cookie: locale=ko-KR, Accept-Language: ko-KR // ref: https://github.com/koa-modules/locale // @ts-ignore const locale = op.parseLocale(ctx.getLocaleFromQuery() || ctx.getLocaleFromCookie() || ctx.getLocaleFromHeader()); ctx.locale = locale; // persist some query strings on redirection return next() .then(() => { // reassign locale/theme query for redirection response if (!ctx.headerSent) { const redirect = ctx.response.get("Location"); if (redirect.startsWith("/") || redirect.startsWith(op.issuer)) { const { protocol, auth, slashes, host, hash, query, pathname } = url.parse(redirect, true); for (const key of persistentQueryParamsKeysWithDefaults) { if (typeof ctx.query[key] !== "undefined") { query[key] = ctx.query[key]; } } ctx.response.set("Location", url.format({ protocol, auth, slashes, host, hash, query, pathname })); } } }); }); } async start() { if (this.working) { return; } // start op const { op } = this.props; await op.start(); // mount optional app routes and oidc provider routes if (this.options.app) { this.app.use(await this.options.app(op)); } // mount op app this.app.use(koa_mount_1.default(op.app)); // start servers const config = this.options; const handler = this.app.callback(); if (config.http2s) { const { hostname, port = 443, ...opts } = config.http2s; this.http2s = http2.createSecureServer(opts, handler); this.http2s.listen(port, hostname, undefined, this.listenCallback("http2", "https", hostname, port)); } if (config.http2) { const { hostname, port = 8080, ...opts } = config.http2; this.http2 = http2.createServer(opts, handler); this.http2.listen(port, hostname, undefined, this.listenCallback("http2", "http", hostname, port)); } if (config.https) { const { hostname, port = 443, ...opts } = config.https; this.https = https.createServer(opts, handler); this.https.listen(port, hostname, undefined, this.listenCallback("https", "https", hostname, port)); } if (config.http || !this.https && !this.http2 && !this.http2s) { const { hostname, port = 8080, ...opts } = config.http || { hostname: "localhost" }; this.http = http.createServer(opts, handler); this.http.listen(port, hostname, undefined, this.listenCallback("http", "http", hostname, port)); } this.working = true; this.logger.info(`IAM server has been started`); } listenCallback(protocol, scheme, hostname, port) { const { op } = this.props; const serverURL = kleur.blue(`${scheme}://${hostname}:${port}`); const discoveryURL = kleur.yellow(`${op.issuer}/.well-known/openid-configuration`); return () => { this.logger.info(`${kleur.blue(protocol.toUpperCase() + " server")} is listening\n* Web server bound to: ${serverURL}\n* OIDC discovery endpoint: ${discoveryURL}`); }; } async stop() { if (!this.working) { return; } if (this.http) { this.http.close(() => this.logger.info(`http server has been stopped`)); } if (this.https) { this.https.close(() => this.logger.info(`https server has been stopped`)); } if (this.http2) { this.http2.close(() => this.logger.info(`http2 server has been stopped`)); } if (this.http2s) { this.http2s.close(() => this.logger.info(`http2s server has been stopped`)); } // stop op await this.props.op.stop(); this.working = false; this.logger.info(`IAM server has been stopped`); } } exports.IAMServer = IAMServer; //# sourceMappingURL=server.js.map