@mindconnect/mindconnect-nodejs
Version:
MindConnect Library for NodeJS (community based)
184 lines • 7.96 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const debug = require("debug");
const jwt = require("jsonwebtoken");
const node_fetch_1 = require("node-fetch");
const mindconnect_base_1 = require("./mindconnect-base");
const utils_1 = require("./utils");
const log = debug("mindconnect-credentialauth");
class CredentialAuth extends mindconnect_base_1.MindConnectBase {
/**
* Creates an instance of CredentialAuth.
* @param {string} _gateway
* @param {string} _basicAuth
* @param {string} _tenant
*
* @memberOf CredentialAuth
*/
constructor(_gateway, _basicAuth, _tenant) {
super();
this._gateway = _gateway;
this._basicAuth = _basicAuth;
this._tenant = _tenant;
if (!_basicAuth || !_basicAuth.startsWith("Basic")) {
throw new Error("You have to pass the basic authentication header (Basic: <base64encoded login:password> in the constructor. Wrong Passkey in CLI?");
}
if (!utils_1.isUrl(_gateway)) {
throw new Error("the gateway must be an URL (e.g. https://gateway.eu1.mindsphere.io");
}
if (!_tenant) {
throw new Error("You have to provide a tenant");
}
}
AcquireToken() {
return __awaiter(this, void 0, void 0, function* () {
const headers = Object.assign(Object.assign({}, this._urlEncodedHeaders), { Authorization: this._basicAuth });
const url = `${utils_1.getPiamUrl(this._gateway, this._tenant)}oauth/token`;
log(`AcquireToken Headers: ${JSON.stringify(headers)} Url: ${url}`);
const body = "grant_type=client_credentials";
try {
const response = yield node_fetch_1.default(url, {
method: "POST",
body: body,
headers: headers,
agent: this._proxyHttpAgent
});
if (!response.ok) {
throw new Error(`${response.statusText} ${yield response.text()}`);
}
if (response.status >= 200 && response.status <= 299) {
const json = yield response.json();
log(`AcquireToken Response ${JSON.stringify(json)}`);
this._accessToken = json;
}
else {
throw new Error(`invalid response ${JSON.stringify(response)}`);
}
}
catch (err) {
log(err);
throw new Error(`Network error occured ${err.message}`);
}
return true;
});
}
ValidateToken() {
return __awaiter(this, void 0, void 0, function* () {
yield utils_1.retry(5, () => this.AcquirePublicKey());
const fullToken = jwt.decode(this._accessToken.access_token, {
complete: true
});
const tokenkey = fullToken.header.kid;
// console.log(tokenkey);
let publicKey = this.getPublicKey(tokenkey);
if (!publicKey) {
this._oauthResponse = undefined; // maybe we have an old token and there was a key rotation
yield utils_1.retry(5, () => this.AcquirePublicKey());
publicKey = this.getPublicKey(tokenkey);
}
if (!publicKey) {
throw new Error(`Token validation error, can't find certificate for ${tokenkey}`);
}
if (!this._accessToken.access_token)
throw new Error("Invalid access token");
const result = jwt.verify(this._accessToken.access_token, publicKey);
log("Token validated, still good");
return result ? true : false;
});
}
getPublicKey(tokenkey) {
let publicKey = undefined;
for (const key of this._oauthResponse.keys) {
if (key.kid === tokenkey) {
publicKey = key.value;
}
break;
}
return publicKey;
}
AcquirePublicKey() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._oauthResponse) {
const headers = this._headers;
const url = `${utils_1.getPiamUrl(this._gateway, this._tenant)}token_keys`;
log(`AcquirePublicKey Headers: ${JSON.stringify(headers)} Url: ${url}`);
try {
const response = yield node_fetch_1.default(url, {
method: "GET",
headers: headers,
agent: this._proxyHttpAgent
});
if (!response.ok) {
throw new Error(`${response.statusText} ${yield response.text()}`);
}
if (response.status >= 200 && response.status <= 299) {
const json = yield response.json();
log(`OauthPublicKey Response ${JSON.stringify(json)}`);
this._oauthResponse = json;
}
else {
throw new Error(`invalid response ${JSON.stringify(response)}`);
}
}
catch (err) {
log(err);
throw new Error(`Network error occured ${err.message}`);
}
}
return true;
});
}
RenewToken() {
return __awaiter(this, void 0, void 0, function* () {
if (this._accessToken) {
try {
yield this.ValidateToken();
}
catch (err) {
log(`jwt exchange token expired - renewing : ${err}`);
this._accessToken = undefined;
if (err.name === "JsonWebTokenError" &&
err.message === "invalid signature") {
log("invalid certificate - renewing");
this._oauthResponse = undefined;
}
}
}
if (!this._accessToken) {
yield this.AcquireToken();
yield this.ValidateToken();
if (!this._accessToken) {
throw new Error("Error aquiering the new token!");
}
}
return true;
});
}
/**
* Returns the current agent token.
* This token can be used in e.g. in Postman to call mindspher APIs.
*
* @returns {(Promise<string>)}
*
* @memberOf AgentAuth
*/
GetServiceToken() {
return __awaiter(this, void 0, void 0, function* () {
yield this.RenewToken();
if (!this._accessToken || !this._accessToken.access_token)
throw new Error("Error getting the new token!");
return this._accessToken.access_token;
});
}
}
exports.CredentialAuth = CredentialAuth;
//# sourceMappingURL=credential-auth.js.map