|
@ -8,7 +8,7 @@ const mongoose = require('mongoose'); |
|
|
|
|
|
|
|
|
const OAuth2Client = mongoose.model('OAuth2Client'); |
|
|
const OAuth2Client = mongoose.model('OAuth2Client'); |
|
|
const OAuth2AuthorizationCode = mongoose.model('OAuth2AuthorizationCode'); |
|
|
const OAuth2AuthorizationCode = mongoose.model('OAuth2AuthorizationCode'); |
|
|
const OAuth2AccessToken = mongoose.model('OAuth2AccessToken'); |
|
|
const OAuth2Token = mongoose.model('OAuth2Token'); |
|
|
|
|
|
|
|
|
const uuidv4 = require('uuid').v4; |
|
|
const uuidv4 = require('uuid').v4; |
|
|
const striptags = require('striptags'); |
|
|
const striptags = require('striptags'); |
|
@ -28,7 +28,7 @@ class OAuth2Service extends SiteService { |
|
|
constructor (dtp) { |
|
|
constructor (dtp) { |
|
|
super(dtp, module.exports); |
|
|
super(dtp, module.exports); |
|
|
|
|
|
|
|
|
this.populateOAuth2AccessToken = [ |
|
|
this.populateOAuth2Token = [ |
|
|
{ |
|
|
{ |
|
|
path: 'user', |
|
|
path: 'user', |
|
|
select: 'username username_lc displayName picture', |
|
|
select: 'username username_lc displayName picture', |
|
@ -47,7 +47,7 @@ class OAuth2Service extends SiteService { |
|
|
|
|
|
|
|
|
this.log.info('registering OAuth2 action handlers'); |
|
|
this.log.info('registering OAuth2 action handlers'); |
|
|
this.server.grant(oauth2orize.grant.code(this.processGrant.bind(this))); |
|
|
this.server.grant(oauth2orize.grant.code(this.processGrant.bind(this))); |
|
|
this.server.exchange(oauth2orize.exchange.code(this.processExchange.bind(this))); |
|
|
this.server.exchange(oauth2orize.exchange.code(this.processExchangeCode.bind(this))); |
|
|
|
|
|
|
|
|
this.log.info('registering OAuth2 serialization routines'); |
|
|
this.log.info('registering OAuth2 serialization routines'); |
|
|
this.server.serializeClient(this.serializeClient.bind(this)); |
|
|
this.server.serializeClient(this.serializeClient.bind(this)); |
|
@ -168,7 +168,40 @@ class OAuth2Service extends SiteService { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async processExchange (client, code, redirectUri, done) { |
|
|
async issueTokens (authCode) { |
|
|
|
|
|
const response = { |
|
|
|
|
|
params: { |
|
|
|
|
|
coreUserId: authCode.user._id, |
|
|
|
|
|
username: authCode.user.username, |
|
|
|
|
|
username_lc: authCode.user.username_lc, |
|
|
|
|
|
displayName: authCode.user.displayName, |
|
|
|
|
|
bio: authCode.user.bio, |
|
|
|
|
|
permissions: authCode.user.permissions, |
|
|
|
|
|
flags: authCode.user.flags, |
|
|
|
|
|
}, |
|
|
|
|
|
accessToken: generatePassword(256, false), |
|
|
|
|
|
refreshToken: generatePassword(256, false), |
|
|
|
|
|
}; |
|
|
|
|
|
await Promise.all([ |
|
|
|
|
|
OAuth2Token.create({ |
|
|
|
|
|
type: 'access', |
|
|
|
|
|
token: response.accessToken, |
|
|
|
|
|
user: authCode.user._id, |
|
|
|
|
|
client: authCode.client._id, |
|
|
|
|
|
scope: authCode.scope, |
|
|
|
|
|
}), |
|
|
|
|
|
OAuth2Token.create({ |
|
|
|
|
|
type: 'refresh', |
|
|
|
|
|
token: response.refreshToken, |
|
|
|
|
|
user: authCode.user._id, |
|
|
|
|
|
client: authCode.client._id, |
|
|
|
|
|
scope: authCode.scope, |
|
|
|
|
|
}), |
|
|
|
|
|
]); |
|
|
|
|
|
return response; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async processExchangeCode (client, code, redirectUri, done) { |
|
|
try { |
|
|
try { |
|
|
const ac = await OAuth2AuthorizationCode |
|
|
const ac = await OAuth2AuthorizationCode |
|
|
.findOne({ code }) |
|
|
.findOne({ code }) |
|
@ -178,7 +211,7 @@ class OAuth2Service extends SiteService { |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
path: 'user', |
|
|
path: 'user', |
|
|
select: 'username username_lc displayName picture', |
|
|
select: 'username username_lc displayName picture bio permissions flags', |
|
|
}, |
|
|
}, |
|
|
]); |
|
|
]); |
|
|
|
|
|
|
|
@ -191,17 +224,9 @@ class OAuth2Service extends SiteService { |
|
|
return done(null, false); |
|
|
return done(null, false); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var token = uuidv4(); |
|
|
const response = await this.issueTokens(ac); |
|
|
var at = new OAuth2AccessToken({ |
|
|
|
|
|
token, |
|
|
|
|
|
user: ac.user._id, |
|
|
|
|
|
client: ac.client._id, |
|
|
|
|
|
scope: ac.scope, |
|
|
|
|
|
}); |
|
|
|
|
|
await at.save(); |
|
|
|
|
|
|
|
|
|
|
|
this.log.info('OAuth2 grant exchanged for token', { clientID: client._id }); |
|
|
this.log.info('OAuth2 grant exchanged for token', { clientID: client._id }); |
|
|
return done(null, token); |
|
|
return done(null, response.accessToken, response.refreshToken, response.params); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
this.log.error('failed to process OAuth2 exchange', { error }); |
|
|
this.log.error('failed to process OAuth2 exchange', { error }); |
|
|
return done(error); |
|
|
return done(error); |
|
@ -306,9 +331,9 @@ class OAuth2Service extends SiteService { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async getAccessToken (accessToken) { |
|
|
async getAccessToken (accessToken) { |
|
|
const token = await OAuth2AccessToken |
|
|
const token = await OAuth2Token |
|
|
.findOne({ token: accessToken }) |
|
|
.findOne({ type: 'access', token: accessToken }) |
|
|
.populate(this.populateOAuth2AccessToken) |
|
|
.populate(this.populateOAuth2Token) |
|
|
.lean(); |
|
|
.lean(); |
|
|
return token; |
|
|
return token; |
|
|
} |
|
|
} |
|
|