realm-object-server
Version:
131 lines • 5.77 kB
JavaScript
;
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