Browse Source

Passport integrations for OAuth2 bearer, basic, and client password

pull/1/head
Rob Colbert 3 years ago
parent
commit
ad4a4d2c2b
  1. 4
      app/models/oauth2-access-token.js
  2. 65
      app/services/oauth2.js
  3. 1
      lib/site-platform.js
  4. 3
      package.json
  5. 21
      yarn.lock

4
app/models/oauth2-access-token.js

@ -10,8 +10,8 @@ const Schema = mongoose.Schema;
const OAuth2AccessTokenSchema = new Schema({
token: { type: String, required: true, unique: true, index: 1 },
user: { type: Schema.ObjectId, required: true, index: 1 },
clientId: { type: Schema.ObjectId, required: true, index: 1 },
user: { type: Schema.ObjectId, required: true, index: 1, ref: 'User' },
client: { type: Schema.ObjectId, required: true, index: 1, ref: 'OAuth2Client' },
scope: { type: [String], required: true },
});

65
app/services/oauth2.js

@ -14,16 +14,29 @@ const uuidv4 = require('uuid').v4;
const striptags = require('striptags');
const oauth2orize = require('oauth2orize');
const passport = require('passport');
const generatePassword = require('password-generator');
const passport = require('passport');
const BasicStrategy = require('passport-http').BasicStrategy;
const ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
const BearerStrategy = require('passport-http-bearer').Strategy;
const { SiteService/*, SiteError*/ } = require('../../lib/site-lib');
class OAuth2Service extends SiteService {
constructor (dtp) {
super(dtp, module.exports);
this.populateOAuth2AccessToken = [
{
path: 'user',
select: 'username username_lc displayName picture',
},
{
path: 'client'
},
];
}
async start ( ) {
@ -41,6 +54,23 @@ class OAuth2Service extends SiteService {
this.server.deserializeClient(this.deserializeClient.bind(this));
}
registerPassport ( ) {
const verifyClient = this.verifyClient.bind(this);
const verifyHttpBearer = this.verifyHttpBearer.bind(this);
const basicStrategy = new BasicStrategy(verifyClient);
this.log.info('registering Basic strategy', { basicStrategy });
passport.use(basicStrategy);
const clientPasswordStrategy = new ClientPasswordStrategy(verifyClient);
this.log.info('registering ClientPassword strategy', { clientPasswordStrategy });
passport.use(clientPasswordStrategy);
const httpBearerStrategy = new BearerStrategy(verifyHttpBearer);
this.log.info('registering Bearer strategy', { httpBearerStrategy });
passport.use(httpBearerStrategy);
}
async serializeClient (client, done) {
this.log.debug('serializeClient', { client });
return done(null, client.id);
@ -148,7 +178,7 @@ class OAuth2Service extends SiteService {
var at = new OAuth2AccessToken({
token,
user: ac.userId,
clientId: ac.clientId,
client: ac.clientId,
scope: ac.scope,
});
await at.save();
@ -243,6 +273,35 @@ class OAuth2Service extends SiteService {
.lean();
return client;
}
async verifyClient(clientId, clientSecret, done) {
const client = await this.getClientById(clientId);
if (!client) {
this.log.alert('OAuth2 request from unknown client', { clientId });
return done(null, false);
}
if (client.clientSecret !== clientSecret) {
this.log.alert('OAuth2 client secret mismatch', { clientId });
return done(null, false);
}
return done(null, client);
}
async getAccessToken (accessToken) {
const token = await OAuth2AccessToken
.findOne({ token: accessToken })
.populate(this.populateOAuth2AccessToken)
.lean();
return token;
}
async verifyHttpBearer (accessToken, done) {
const token = await this.getAccessToken(accessToken);
if (!token) {
return done(null, false);
}
return done(null, token.user, { scope: token.scope });
}
}
module.exports = {

1
lib/site-platform.js

@ -312,6 +312,7 @@ module.exports.startWebServer = async (dtp) => {
module.app.use(passport.initialize());
module.app.use(passport.session());
module.services.oauth2.registerPassport();
module.app.use(module.services.session.middleware());
/*

3
package.json

@ -57,8 +57,11 @@
"oauth2orize": "^1.11.1",
"otplib": "^12.0.1",
"passport": "^0.5.2",
"passport-http": "^0.3.0",
"passport-http-bearer": "^1.0.1",
"passport-local": "^1.0.0",
"passport-oauth2": "^1.6.1",
"passport-oauth2-client-password": "^0.1.2",
"password-generator": "^2.3.2",
"pug": "^3.0.2",
"qrcode": "^1.5.0",

21
yarn.lock

@ -6347,6 +6347,20 @@ pascalcase@^0.1.1:
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
passport-http-bearer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz#147469ea3669e2a84c6167ef99dbb77e1f0098a8"
integrity sha512-SELQM+dOTuMigr9yu8Wo4Fm3ciFfkMq5h/ZQ8ffi4ELgZrX1xh9PlglqZdcUZ1upzJD/whVyt+YWF62s3U6Ipw==
dependencies:
passport-strategy "1.x.x"
passport-http@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/passport-http/-/passport-http-0.3.0.tgz#8ee53d4380be9c60df2151925029826f77115603"
integrity sha512-OwK9DkqGVlJfO8oD0Bz1VDIo+ijD3c1ZbGGozIZw+joIP0U60pXY7goB+8wiDWtNqHpkTaQiJ9Ux1jE3Ykmpuw==
dependencies:
passport-strategy "1.x.x"
passport-local@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
@ -6354,6 +6368,13 @@ passport-local@^1.0.0:
dependencies:
passport-strategy "1.x.x"
passport-oauth2-client-password@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/passport-oauth2-client-password/-/passport-oauth2-client-password-0.1.2.tgz#4f378b678b92d16dbbd233a6c706520093e561ba"
integrity sha512-GHQH4UtaEZvCLulAxGKHYoSsPRoPRmGsdmaZtMh5nmz80yMLQbdMA9Bg2sp4/UW3PIxJH/143hVjPTiXaNngTQ==
dependencies:
passport-strategy "1.x.x"
passport-oauth2@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b"

Loading…
Cancel
Save