UNPKG

realm-object-server

Version:

Realm Object Server

131 lines 5.77 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const AuthProvider_1 = require("../AuthProvider"); const errors = require("../../errors"); const superagent = require("superagent"); const jwt = require("jsonwebtoken"); const pem_jwk_1 = require("pem-jwk"); const LRU = require("lru-cache"); const URI = require("urijs"); class AzureAuthProvider extends AuthProvider_1.AuthProvider { constructor(config) { super(); this.name = "azuread"; this.responseCache = new LRU({ maxAge: 60 * 60 * 1000 }); this.validIssuers = ["sts.windows.net", "login.microsoftonline.com"]; this.tenantId = config.tenant_id; this.skipVerification = config.skipVerification; this.audience = config.audience; this.validTenantIds = [this.tenantId]; if (config.allowConsumerLogins) { this.validTenantIds.push("9188040d-6c67-4c5b-b112-36a304b66dad"); } this.userIdField = config.userIdField || "sub"; this.appId = config.appId; } authenticateOrCreateUser(body) { return __awaiter(this, void 0, void 0, function* () { const accessToken = body.data; if (accessToken === undefined) { throw new errors.realm.MissingParameters("access token"); } const decoded = jwt.decode(accessToken, { complete: true }); if (!decoded || !decoded.payload || !decoded.header) { throw new errors.realm.InvalidCredentials({ detail: "The access token is not a valid signed JWT.", }); } if (this.validTenantIds.indexOf(decoded.payload.tid) < 0) { throw new errors.realm.InvalidCredentials({ detail: `Invalid tenant Id: ${decoded.payload.tid}. Expected any of ${this.validTenantIds.join(", ")}`, }); } if (this.audience && decoded.payload.aud !== this.audience) { throw new errors.realm.InvalidCredentials({ detail: `Invalid audience. Expected ${this.audience}, got ${decoded.payload.aud}` }); } const issuerUri = URI.parse(decoded.payload.iss); if (this.validIssuers.indexOf(issuerUri.hostname) < 0) { throw new errors.realm.InvalidCredentials({ detail: `Invalid issuer hostname: ${issuerUri.hostname}. Expected any of ${this.validIssuers.join(", ")}` }); } if (this.validTenantIds.indexOf(issuerUri.path.split("/")[1]) < 0) { throw new errors.realm.InvalidCredentials({ detail: `Invalid issuer tenantId: ${issuerUri.path}. Expected any of ${this.validTenantIds.join(", ")}` }); } if (!this.skipVerification) { const configResponse = yield this.httpGet(this.getOpenIdUrl(decoded.payload.iss)); const keyConfigResponse = yield this.httpGet(configResponse.jwks_uri); this.validateSignature(accessToken, keyConfigResponse.keys, decoded.header.kid); } const userId = decoded.payload[this.userIdField]; let user = this.service.getUserByProviderId("azuread", userId); if (!user) { user = yield this.service.createOrUpdateUser(userId, this.name, false); } return user; }); } httpGet(uri) { return __awaiter(this, void 0, void 0, function* () { try { let result = this.responseCache.get(uri); if (result === undefined) { const response = yield superagent.get(uri) .set("Accept", "application/json"); result = response.body; this.responseCache.set(uri, result); } return result; } catch (err) { throw new errors.JSONError({ title: "Bad Gateway", detail: err.toString(), status: 502 }); } }); } validateSignature(accessToken, keys, kid) { for (const key of keys) { if (key.kid === kid) { try { jwt.verify(accessToken, pem_jwk_1.jwk2pem(key)); return; } catch (err) { throw new errors.realm.InvalidCredentials({ detail: err.message, }); } } } throw new errors.realm.InvalidCredentials({ detail: "Unable to find jwt public key.", }); } getOpenIdUrl(issuer) { if (!issuer.endsWith("/")) { issuer += "/"; } let result = `${issuer}.well-known/openid-configuration`; if (this.appId) { result += `?appid=${this.appId}`; } return result; } } exports.AzureAuthProvider = AzureAuthProvider; //# sourceMappingURL=AzureAuthProvider.js.map