UNPKG

kopi-id

Version:
356 lines (277 loc) 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _constants = _interopRequireDefault(require("../constants")); var _auth = _interopRequireDefault(require("../services/auth")); var _jwt = _interopRequireDefault(require("../services/jwt")); var _token = _interopRequireDefault(require("../services/token")); var _hash = _interopRequireDefault(require("../services/hash")); var _logger = _interopRequireDefault(require("../services/logger")); var _flowUtils = _interopRequireDefault(require("../services/flowUtils")); var _redirect = _interopRequireDefault(require("../services/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"])('Controller'), L = _loggerService.L; var authService = (0, _auth["default"])(oidcConfig); var jwtService = (0, _jwt["default"])(oidcConfig); var tokenService = (0, _token["default"])(oidcConfig, jwtService); var handleAuthenticationRequest = /*#__PURE__*/function () { var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(authenticationRequest, req, res, next) { var responseTypes, clientId, redirectUri, idTokenHint, prompt, state, maxAge, client, redirectUriValid, authenticationRequestId, idToken, sub, authTime, currentTime, loginPath, loginUrl; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.prev = 0; responseTypes = authenticationRequest.response_type, clientId = authenticationRequest.client_id, redirectUri = authenticationRequest.redirect_uri, idTokenHint = authenticationRequest.id_token_hint, prompt = authenticationRequest.prompt, state = authenticationRequest.state, maxAge = authenticationRequest.max_age; // Validate Client _context.next = 4; return oidcConfig.onGetClient(clientId); case 4: client = _context.sent; if (!(client == null)) { _context.next = 7; break; } return _context.abrupt("return", _redirect["default"].redirectInvalidRequest(res, redirectUri, state)); case 7: // Validate Redirect URI redirectUriValid = client.redirectUri.includes(redirectUri); if (redirectUriValid) { _context.next = 10; break; } return _context.abrupt("return", _redirect["default"].redirectInvalidRequestUri(res, redirectUri, state)); case 10: // Create new Authentication Request authenticationRequest.auth_time = Math.floor(new Date().getTime() / 1000); _context.next = 13; return oidcConfig.onSaveAuthenticationRequest(authenticationRequest); case 13: authenticationRequestId = _context.sent; if (!(prompt && prompt.includes(_constants["default"].authenticationRequest.prompt.NONE))) { _context.next = 36; break; } if (!(prompt.length > 1)) { _context.next = 17; break; } return _context.abrupt("return", _redirect["default"].redirectInvalidRequest(res, redirectUri, state)); case 17: if (!(idTokenHint == null)) { _context.next = 21; break; } return _context.abrupt("return", _redirect["default"].redirectInternalServiceError(res, redirectUri, state)); case 21: _context.prev = 21; _context.next = 24; return jwtService.verifyIdToken(idTokenHint, client); case 24: idToken = _context.sent; sub = idToken.sub, authTime = idToken.auth_time; // Check Max Age currentTime = Math.floor(new Date().getTime() / 1000); if (!(maxAge && currentTime > authTime + maxAge)) { _context.next = 29; break; } throw new Error('Maximum Authentication Age has reached.'); case 29: return _context.abrupt("return", authService.handleAuthenticated(res, authenticationRequestId, sub, true, true)); case 32: _context.prev = 32; _context.t0 = _context["catch"](21); L.warn("Error caught when verifying ID Token: ".concat(_context.t0.message)); // Send Redirect with Error (login_required) return _context.abrupt("return", _redirect["default"].redirectLoginRequired(res, redirectUri, state)); case 36: // Redirect to Login Page loginPath = oidcConfig.loginUrl || "".concat(oidcConfig.host, "/").concat(oidcConfig.loginPage); loginUrl = "".concat(loginPath, "?authenticationRequestId=").concat(authenticationRequestId); res.redirect(loginUrl); _context.next = 44; break; case 41: _context.prev = 41; _context.t1 = _context["catch"](0); next(_context.t1); case 44: case "end": return _context.stop(); } } }, _callee, null, [[0, 41], [21, 32]]); })); return function handleAuthenticationRequest(_x, _x2, _x3, _x4) { return _ref.apply(this, arguments); }; }(); var handleTokenRequest = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(tokenRequest, req, res, next) { var _req$body, code, redirectUri, clientId, client, authorizationRequestId, authorizationRequest, sub, authenticationRequestId, authenticationRequest, scope, requestClientId, requestRedirectUri, authTime, nonce, cHashBuffer, cHash, accessToken, atHashBuffer, atHash, idToken, accessTokenExpiresIn, response; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: _context2.prev = 0; _req$body = req.body, code = _req$body.code, redirectUri = _req$body.redirect_uri; clientId = req.clientId; _context2.next = 5; return oidcConfig.onGetClient(clientId); case 5: client = _context2.sent; _context2.next = 8; return oidcConfig.onLoadAuthorization(code); case 8: authorizationRequestId = _context2.sent; if (!(authorizationRequestId == null)) { _context2.next = 11; break; } throw new Error('Invalid Code'); case 11: _context2.next = 13; return oidcConfig.onLoadAuthorizationRequest(authorizationRequestId); case 13: authorizationRequest = _context2.sent; sub = authorizationRequest.sub, authenticationRequestId = authorizationRequest.authenticationRequestId; _context2.next = 17; return oidcConfig.onLoadAuthenticationRequest(authenticationRequestId); case 17: authenticationRequest = _context2.sent; scope = authenticationRequest.scope, requestClientId = authenticationRequest.client_id, requestRedirectUri = authenticationRequest.redirect_uri, authTime = authenticationRequest.auth_time, nonce = authenticationRequest.nonce; if (!(clientId !== requestClientId)) { _context2.next = 21; break; } throw new Error('Client ID does not match requested authentication'); case 21: if (!(redirectUri != null && redirectUri !== requestRedirectUri)) { _context2.next = 23; break; } throw new Error('Redirect URI does not match requested authentication'); case 23: if (scope.includes('openid')) { _context2.next = 25; break; } throw new Error('Scope did not include openid'); case 25: _context2.next = 27; return oidcConfig.onRevokeAuthorization(code); case 27: // Generate Access Token (should have c_hash) cHashBuffer = _hash["default"].hash(code, oidcConfig.hashAlgorithm); cHash = cHashBuffer.slice(0, cHashBuffer.length / 2).toString('base64'); _context2.next = 31; return tokenService.generateToken(client, sub, scope, authTime, nonce, cHash); case 31: accessToken = _context2.sent; // Generate ID Token (should have at_hash) atHashBuffer = _hash["default"].hash(accessToken, oidcConfig.hashAlgorithm); atHash = atHashBuffer.slice(0, atHashBuffer.length / 2).toString('base64'); _context2.next = 36; return tokenService.generateIdToken(client, sub, authTime, nonce, cHash, atHash); case 36: idToken = _context2.sent; accessTokenExpiresIn = oidcConfig.accessTokenExpiresIn; response = { access_token: accessToken, token_type: 'Bearer', expires_in: accessTokenExpiresIn, id_token: idToken }; if (res.headers == null) { res.headers = {}; } res.headers['Cache-Control'] = 'no-store'; res.headers['Pragma'] = 'no-cache'; res.status(200).json(response); _context2.next = 53; break; case 45: _context2.prev = 45; _context2.t0 = _context2["catch"](0); L.error(_context2.t0.message); L.debug(_context2.t0); if (res.headers == null) { res.headers = {}; } res.headers['Cache-Control'] = 'no-store'; res.headers['Pragma'] = 'no-cache'; res.status(400).json({ error: 'invalid_request' }); case 53: case "end": return _context2.stop(); } } }, _callee2, null, [[0, 45]]); })); return function handleTokenRequest(_x5, _x6, _x7, _x8) { return _ref2.apply(this, arguments); }; }(); var handleUserInfo = /*#__PURE__*/function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(req, res, next) { var tokenPayload, sub, scope, user; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: _context3.prev = 0; tokenPayload = req.tokenPayload; sub = tokenPayload.sub, scope = tokenPayload.scope; _context3.next = 5; return oidcConfig.onGetUserInfo(sub, scope); case 5: user = _context3.sent; user.sub = user.sub || user.id; res.status(200).json(user); _context3.next = 13; break; case 10: _context3.prev = 10; _context3.t0 = _context3["catch"](0); next(_context3.t0); case 13: case "end": return _context3.stop(); } } }, _callee3, null, [[0, 10]]); })); return function handleUserInfo(_x9, _x10, _x11) { return _ref3.apply(this, arguments); }; }(); var authenticationRequestGet = function authenticationRequestGet(req, res, next) { return handleAuthenticationRequest(req.query, req, res, next); }; var authenticationRequestPost = function authenticationRequestPost(req, res, next) { return handleAuthenticationRequest(req.body, req, res, next); }; var tokenRequestPost = function tokenRequestPost(req, res, next) { return handleTokenRequest(req.body, req, res, next); }; var userInfoGet = function userInfoGet(req, res, next) { return handleUserInfo(req, res, next); }; var userInfoPost = function userInfoPost(req, res, next) { return handleUserInfo(req, res, next); }; return { authenticationRequestGet: authenticationRequestGet, authenticationRequestPost: authenticationRequestPost, tokenRequestPost: tokenRequestPost, userInfoGet: userInfoGet, userInfoPost: userInfoPost }; }; exports["default"] = _default;