UNPKG

@mvx/identity

Version:

identity is oidc for mvc, type-mvc is base on koa. Decorator, Ioc, AOP mvc framework on server.

324 lines (322 loc) 14.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OAuth2Strategy = void 0; var tslib_1 = require("tslib"); var components_1 = require("@tsdi/components"); var errors_1 = require("../errors"); var oauth2_1 = require("./oauth2"); var Strategy_1 = require("./Strategy"); var stores_1 = require("../stores"); var url_1 = require("url"); var results_1 = require("./results"); /** * Creates an instance of `OAuth2Strategy`. * * The OAuth 2.0 authentication strategy authenticates requests using the OAuth * 2.0 framework. * * OAuth 2.0 provides a facility for delegated authentication, whereby users can * authenticate using a third-party service such as Facebook. Delegating in * this manner involves a sequence of events, including redirecting the user to * the third-party service for authorization. Once authorization has been * granted, the user is redirected back to the application and an authorization * code can be used to obtain credentials. * * Applications must supply a `verify` callback, for which the function * signature is: * * function(accessToken, refreshToken, profile, done) { ... } * * The verify callback is responsible for finding or creating the user, and * invoking `done` with the following arguments: * * done(err, user, info); * * `user` should be set to `false` to indicate an authentication failure. * Additional `info` can optionally be passed as a third argument, typically * used to display informational messages. If an exception occured, `err` * should be set. * * Params: * * - `authorizationURL` URL used to obtain an authorization grant * - `tokenURL` URL used to obtain an access token * - `clientId` identifies client to service provider * - `clientSecret` secret used to establish ownership of the client identifer * - `callbackURL` URL to which the service provider will redirect the user after obtaining authorization * - `passReqToCallback` when `true`, `req` is the first argument to the verify callback (default: `false`) * * Examples: * * passport.use(new OAuth2Strategy({ * authorizationURL: 'https://www.example.com/oauth2/authorize', * tokenURL: 'https://www.example.com/oauth2/token', * clientId: '123-456-789', * clientSecret: 'shhh-its-a-secret' * callbackURL: 'https://www.example.net/auth/example/callback' * }, * function(accessToken, refreshToken, profile, done) { * User.findOrCreate(..., function (err, user) { * done(err, user); * }); * } * )); * */ var OAuth2Strategy = /** @class */ (function (_super) { tslib_1.__extends(OAuth2Strategy, _super); function OAuth2Strategy() { return _super !== null && _super.apply(this, arguments) || this; } OAuth2Strategy.prototype.onAfterInit = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { if (!this.name) { this.name = 'oauth2'; } // NOTE: The _oauth2 property is considered "protected". Subclasses are // allowed to use it when making protected resource requests to retrieve // the user profile. this.oauth2 = new oauth2_1.OAuth2(this.clientId, this.clientSecret, '', this.authorizationURL, this.tokenURL, this.customHeaders); if (!this.sessionKey) { this.sessionKey = ('oauth2:' + url_1.parse(this.authorizationURL).hostname); } if (!this.stateStore) { // if stateStore is `true`, use default session stateStore this.stateStore = new stores_1.SessionStore(this.sessionKey); } if (!this.userProfile) { this.userProfile = function (accessToken) { return new Object(); }; } if (!this.tokenParams) { this.tokenParams = function (options) { return new Object(); }; } if (!this.authorizationParams) { this.authorizationParams = function (options) { return new Object(); }; } return [2 /*return*/]; }); }); }; OAuth2Strategy.prototype.authenticate = function (ctx, options) { if (options === void 0) { options = {}; } return tslib_1.__awaiter(this, void 0, void 0, function () { var callbackURL, parsed, meta, state, _a, verifiedResult, verifiedMsg, code, params, accessToken, refreshToken, accessTokenResult, err_1, profile, _b, user, info, params, scope, state, parsed, location_1; var _c; return tslib_1.__generator(this, function (_d) { switch (_d.label) { case 0: if (ctx.query && ctx.query.error) { if (ctx.query.error === 'access_denied') { return [2 /*return*/, new results_1.FailResult(ctx.query.error_description, 401)]; } throw new errors_1.AuthenticationError(ctx.status || 403, ctx.query.error_uri, ctx.query.error_description || ctx.query.error); } callbackURL = options.callbackURL || this.callbackURL; if (callbackURL) { parsed = url_1.parse(callbackURL); if (!parsed.protocol) { // The callback URL is relative, resolve a fully qualified URL from the // URL of the originating request. callbackURL = url_1.resolve(ctx.request.origin, callbackURL); } } meta = { authorizationURL: this.authorizationURL, tokenURL: this.tokenURL, clientId: this.clientId, }; if (!(ctx.query && ctx.query.code)) return [3 /*break*/, 8]; state = ctx.query.state; return [4 /*yield*/, this.stateStore.verify(ctx, state)]; case 1: _a = _d.sent(), verifiedResult = _a.result, verifiedMsg = _a.message; if (!verifiedResult) { return [2 /*return*/, new results_1.FailResult(verifiedMsg, 403)]; } code = ctx.query.code; params = this.tokenParams(options); params.grant_type = 'authorization_code'; if (callbackURL) { params.redirect_uri = callbackURL; } accessToken = void 0; refreshToken = void 0; accessTokenResult = void 0; _d.label = 2; case 2: _d.trys.push([2, 4, , 5]); return [4 /*yield*/, this.oauth2.getOAuthAccessToken(code, params)]; case 3: (_c = _d.sent(), accessToken = _c.accessToken, refreshToken = _c.refreshToken, accessTokenResult = _c.result); return [3 /*break*/, 5]; case 4: err_1 = _d.sent(); throw this.parseOAuthError(err_1); case 5: return [4 /*yield*/, this.loadUserProfile(accessToken)]; case 6: profile = _d.sent(); return [4 /*yield*/, this.verify(accessToken, refreshToken, accessTokenResult, profile)]; case 7: _b = _d.sent(), user = _b.user, info = _b.info; if (!user) { // TODO, not sure 401 is the correct meaning return [2 /*return*/, new results_1.FailResult(info, 401)]; } return [2 /*return*/, new results_1.SuccessResult(options, user, info)]; case 8: params = this.authorizationParams(options); params.response_type = 'code'; if (callbackURL) { params.redirect_uri = callbackURL; } scope = options.scope || this.scope; if (scope) { if (Array.isArray(scope)) { scope = scope.join(this.scopeSeparator); } params.scope = scope; } state = options.state; if (!state) return [3 /*break*/, 9]; params.state = state; return [3 /*break*/, 11]; case 9: return [4 /*yield*/, this.stateStore.store(ctx, meta)]; case 10: state = _d.sent(); if (state) { params.state = state; } _d.label = 11; case 11: parsed = url_1.parse(this.oauth2.AuthorizeUrl, true); parsed.query = Object.assign({}, parsed.query, params); parsed.query.client_id = this.oauth2.ClientId; delete parsed.search; location_1 = url_1.format(parsed); return [2 /*return*/, new results_1.RedirectResult(location_1)]; } }); }); }; /** * Parse error response from OAuth 2.0 endpoint. * * OAuth 2.0-based authentication strategies can overrride this function in * order to parse error responses received from the token endpoint, allowing the * most informative message to be displayed. * * If this function is not overridden, the body will be parsed in accordance * with RFC 6749, section 5.2. * */ OAuth2Strategy.prototype.parseOAuthError = function (err) { var e; if (err instanceof oauth2_1.OAuth2Error) { try { var json = JSON.parse(err.message); if (json.error) { e = new errors_1.InternalOAuthError("Failed to obtain access token:" + json.error_description, json.error); } } catch (_) { // console.warn('============This error can be ignored=============='); // console.warn(_); // console.warn('==================================================='); } } if (!e) { err.message = "Failed to obtain access token:" + err.message; e = err; } return e; }; /** * Load user profile, contingent upon options. * */ OAuth2Strategy.prototype.loadUserProfile = function (accessToken) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (this.skipUserProfile) { return [2 /*return*/, Promise.resolve(null)]; } return [4 /*yield*/, this.userProfile(accessToken)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; OAuth2Strategy.ρAnn = function () { return { "name": "OAuth2Strategy", "params": { "authenticate": ["ctx", "options"], "parseOAuthError": ["err"], "loadUserProfile": ["accessToken"] } }; }; tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", stores_1.StateStore) ], OAuth2Strategy.prototype, "stateStore", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "clientId", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "authorizationURL", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "tokenURL", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", Function) ], OAuth2Strategy.prototype, "verify", void 0); tslib_1.__decorate([ components_1.Input({ defaultValue: false }), tslib_1.__metadata("design:type", Boolean) ], OAuth2Strategy.prototype, "skipUserProfile", void 0); tslib_1.__decorate([ components_1.Input({ defaultValue: ' ' }), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "scopeSeparator", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "callbackURL", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", Object) ], OAuth2Strategy.prototype, "scope", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "sessionKey", void 0); tslib_1.__decorate([ components_1.Input({ defaultValue: '' }), tslib_1.__metadata("design:type", String) ], OAuth2Strategy.prototype, "clientSecret", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", Object) ], OAuth2Strategy.prototype, "customHeaders", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", Function) ], OAuth2Strategy.prototype, "userProfile", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", Function) ], OAuth2Strategy.prototype, "tokenParams", void 0); tslib_1.__decorate([ components_1.Input(), tslib_1.__metadata("design:type", Function) ], OAuth2Strategy.prototype, "authorizationParams", void 0); OAuth2Strategy = tslib_1.__decorate([ components_1.Component({ selector: 'oauth2' }) ], OAuth2Strategy); return OAuth2Strategy; }(Strategy_1.Strategy)); exports.OAuth2Strategy = OAuth2Strategy; //# sourceMappingURL=../sourcemaps/passports/OAuth2Strategy.js.map