kopi-id
Version:
Simple OIDC Library
298 lines (231 loc) • 12.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _constants = _interopRequireDefault(require("../constants"));
var _jwt = _interopRequireDefault(require("./jwt"));
var _token = _interopRequireDefault(require("./token"));
var _flowUtils = _interopRequireDefault(require("./flowUtils"));
var _hash = _interopRequireDefault(require("./hash"));
var _logger = _interopRequireDefault(require("./logger"));
var _redirect = _interopRequireDefault(require("./redirect"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
var _default = function _default(oidcConfig) {
var _loggerService = (0, _logger["default"])('Auth Service', oidcConfig.logLevel),
L = _loggerService.L;
var jwtService = (0, _jwt["default"])(oidcConfig);
var tokenService = (0, _token["default"])(oidcConfig, jwtService);
var handleAuthenticated = /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(res, authenticationRequestId, sub, isUserAuthenticated, isSilentAuthenticated) {
var authenticationRequest, scope, clientId, idTokenHint, redirectUri, prompt, state, client, idToken, tokenSub, authorizationRequestId, consentPath, consentUrl, isConsentGiven;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return oidcConfig.onLoadAuthenticationRequest(authenticationRequestId);
case 3:
authenticationRequest = _context.sent;
scope = authenticationRequest.scope, clientId = authenticationRequest.client_id, idTokenHint = authenticationRequest.id_token_hint, redirectUri = authenticationRequest.redirect_uri, prompt = authenticationRequest.prompt, state = authenticationRequest.state; // Validate authenticated status
if (isUserAuthenticated) {
_context.next = 7;
break;
}
return _context.abrupt("return", _redirect["default"].redirectLoginRequired(res, redirectUri, state));
case 7:
if (!(isSilentAuthenticated && prompt && prompt.includes(_constants["default"].authenticationRequest.prompt.LOGIN))) {
_context.next = 9;
break;
}
return _context.abrupt("return", _redirect["default"].redirectLoginRequired(res, redirectUri, state));
case 9:
_context.next = 11;
return oidcConfig.onGetClient(clientId);
case 11:
client = _context.sent;
if (!(idTokenHint != null)) {
_context.next = 26;
break;
}
_context.prev = 13;
_context.next = 16;
return jwtService.verifyIdToken(idTokenHint, client);
case 16:
idToken = _context.sent;
tokenSub = idToken.sub;
if (!(sub !== tokenSub)) {
_context.next = 20;
break;
}
return _context.abrupt("return", _redirect["default"].redirectLoginRequired(res, redirectUri, state, 'user logged in as different id from the id_token'));
case 20:
_context.next = 26;
break;
case 22:
_context.prev = 22;
_context.t0 = _context["catch"](13);
L.warn("Error caught when verifying ID Token: ".concat(_context.t0.message)); // Send Redirect with Error (invalid_request)
return _context.abrupt("return", _redirect["default"].redirectInvalidRequest(res, redirectUri, state, 'invalid id_token'));
case 26:
_context.next = 28;
return oidcConfig.onSaveAuthorizationRequest(authenticationRequestId, sub);
case 28:
authorizationRequestId = _context.sent;
// Generate Consent Url
consentPath = oidcConfig.consentUrl || "".concat(oidcConfig.host, "/").concat(oidcConfig.consentPage);
consentUrl = "".concat(consentPath, "?authorizationRequestId=").concat(authorizationRequestId); // Check CONSENT prompt
if (!(prompt && prompt.includes(_constants["default"].authenticationRequest.prompt.CONSENT))) {
_context.next = 34;
break;
}
// Must show consent page, redirect to consent page
res.redirect(consentUrl);
return _context.abrupt("return");
case 34:
_context.next = 36;
return oidcConfig.onIsConsentGiven(sub, scope, clientId);
case 36:
isConsentGiven = _context.sent;
if (!isConsentGiven) {
_context.next = 39;
break;
}
return _context.abrupt("return", handleAuthorized(res, authorizationRequestId, true, true));
case 39:
// Redirect to consent page
res.redirect(consentUrl);
_context.next = 47;
break;
case 42:
_context.prev = 42;
_context.t1 = _context["catch"](0);
L.error(_context.t1.message);
L.debug(_context.t1);
res.status(500).send();
case 47:
case "end":
return _context.stop();
}
}
}, _callee, null, [[0, 42], [13, 22]]);
}));
return function handleAuthenticated(_x, _x2, _x3, _x4, _x5) {
return _ref.apply(this, arguments);
};
}();
var handleAuthorized = /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(res, authorizationRequestId, isConsentGiven, isSilentConsent) {
var authorizationRequest, authenticationRequestId, sub, authenticationRequest, authTime, responseTypes, scope, clientId, redirectUri, prompt, state, nonce, client, flowType, hasCode, hasIdToken, hasAccessToken, cHash, atHash, query, authorizationCode, buffer, accessToken, _buffer, idToken, clientUrl;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
_context2.next = 3;
return oidcConfig.onLoadAuthorizationRequest(authorizationRequestId);
case 3:
authorizationRequest = _context2.sent;
authenticationRequestId = authorizationRequest.authenticationRequestId, sub = authorizationRequest.sub;
_context2.next = 7;
return oidcConfig.onLoadAuthenticationRequest(authenticationRequestId);
case 7:
authenticationRequest = _context2.sent;
authTime = authenticationRequest.auth_time, responseTypes = authenticationRequest.response_type, scope = authenticationRequest.scope, clientId = authenticationRequest.client_id, redirectUri = authenticationRequest.redirect_uri, prompt = authenticationRequest.prompt, state = authenticationRequest.state, nonce = authenticationRequest.nonce;
_context2.next = 11;
return oidcConfig.onGetClient(clientId);
case 11:
client = _context2.sent;
if (isConsentGiven) {
_context2.next = 14;
break;
}
return _context2.abrupt("return", _redirect["default"].redirectConsentRequired(res, redirectUri, state));
case 14:
if (!(isSilentConsent && prompt && prompt.includes(_constants["default"].authenticationRequest.prompt.CONSENT))) {
_context2.next = 16;
break;
}
return _context2.abrupt("return", _redirect["default"].redirectConsentRequired(res, redirectUri, state));
case 16:
_context2.next = 18;
return oidcConfig.onSetConsentGiven(sub, scope, clientId);
case 18:
// Flow
flowType = _flowUtils["default"].getFlowType(responseTypes);
hasCode = responseTypes && responseTypes.includes(_constants["default"].authenticationRequest.responseTypes.CODE);
hasIdToken = responseTypes && responseTypes.includes(_constants["default"].authenticationRequest.responseTypes.ID_TOKEN);
hasAccessToken = responseTypes && responseTypes.includes(_constants["default"].authenticationRequest.responseTypes.TOKEN);
cHash = null;
atHash = null;
query = state && state !== '' ? "&state=".concat(encodeURIComponent(state)) : '';
if (!hasCode) {
_context2.next = 32;
break;
}
_context2.next = 28;
return oidcConfig.onSaveAuthorization(authorizationRequestId, sub);
case 28:
authorizationCode = _context2.sent;
// Hash Authorization Code
buffer = _hash["default"].hash(authorizationCode, oidcConfig.hashAlgorithm);
cHash = buffer.slice(0, buffer.length / 2).toString('base64');
query += "&code=".concat(encodeURIComponent(authorizationCode));
case 32:
if (!hasAccessToken) {
_context2.next = 41;
break;
}
_context2.next = 35;
return tokenService.generateToken(client, sub, scope, authTime, nonce, cHash);
case 35:
accessToken = _context2.sent;
// Hash Access Token
_buffer = _hash["default"].hash(accessToken, oidcConfig.hashAlgorithm);
atHash = _buffer.slice(0, _buffer.length / 2).toString('base64');
query += "&access_token=".concat(encodeURIComponent(accessToken));
query += "&expires_in=".concat(encodeURIComponent(oidcConfig.accessTokenExpiresIn));
query += "&token_type=Bearer";
case 41:
if (!hasIdToken) {
_context2.next = 46;
break;
}
_context2.next = 44;
return tokenService.generateIdToken(client, sub, authTime, nonce, cHash, atHash);
case 44:
idToken = _context2.sent;
query += "&id_token=".concat(encodeURIComponent(idToken));
case 46:
// Redirect to client redirect page
query = query.charAt(0) === '&' ? query.slice(1) : query;
clientUrl = "".concat(redirectUri, "#").concat(query);
res.redirect(clientUrl);
_context2.next = 56;
break;
case 51:
_context2.prev = 51;
_context2.t0 = _context2["catch"](0);
L.error(_context2.t0.message);
L.debug(_context2.t0);
res.status(500).send();
case 56:
case "end":
return _context2.stop();
}
}
}, _callee2, null, [[0, 51]]);
}));
return function handleAuthorized(_x6, _x7, _x8, _x9) {
return _ref2.apply(this, arguments);
};
}();
return {
handleAuthenticated: handleAuthenticated,
handleAuthorized: handleAuthorized
};
};
exports["default"] = _default;