Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added support for retrieving userProfile from profileEndpoint #7

Merged
merged 1 commit into from
Jul 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"morgan": "1.9.1",
"mustache": "2.2.1",
"nocache": "^2.0.0",
"openid-client": "2.5.0",
"passport": "0.3.2",
"passport-facebook": "2.1.1",
"passport-github2": "0.1.10",
Expand Down
4 changes: 3 additions & 1 deletion src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ export interface OAuth2IdpConfig extends OAuth2IdpConfigBase {
// Additional parameters for authorization request
params?: any,
// Specify "false" to not attempt authentication with "prompt=none" in case provided with /authorize call
doesNotSupportPrompt?: boolean
doesNotSupportPrompt?: boolean,
// Specify to retrieve profile information from profileEndpoint
retrieveProfile?: boolean
}

export interface SamlSpOptions {
Expand Down
71 changes: 49 additions & 22 deletions src/providers/oauth2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { debug, info, warn, error } = require('portal-env').Logger('portal-auth:o
const Router = require('express').Router;
const request = require('request');
const passport = require('passport');
const { Issuer } = require('openid-client');
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
var jwt = require('jsonwebtoken');

Expand Down Expand Up @@ -70,7 +71,29 @@ export class OAuth2IdP implements IdentityProvider {
oauthStrategy.authorizationParams = this.authorizationParams;

oauthStrategy.userProfile = function (accessToken, done) {
done(null, accessToken);
debug(`userProfile(${this.authMethodId})`);
if (authMethodConfig.retrieveProfile) {
debug(`userProfile(${this.authMethodId}): Retrieve userProfile from profileEndpoint`);
let issuer = new Issuer({
issuer: "IdP Issuer",
authorization_endpoint: authMethodConfig.endpoints.authorizeEndpoint,
token_endpoint: authMethodConfig.endpoints.tokenEndpoint,
userinfo_endpoint: authMethodConfig.endpoints.profileEndpoint});
let client = new issuer.Client({
client_id: authMethodConfig.clientId,
client_secret: authMethodConfig.clientSecret,
redirect_uris: [callbackUrl],
response_types: ['code']
});
client.userinfo(accessToken)
.then(function(userInfo) {
debug(`retrieveUserProfileCallback: Successfully retrieved profile from endpoint`);
done(null, userInfo);
})

} else {
done(null, accessToken);
}
};

passport.use(authMethodId, oauthStrategy);
Expand Down Expand Up @@ -101,28 +124,20 @@ export class OAuth2IdP implements IdentityProvider {
return this.genericFlow.getRouter();
}

private verifyProfile = (req, accessToken, refreshTokenNotUsed, profileNotUsed, done) => {
private verifyProfile = (req, accessToken, refreshTokenNotUsed, profile, done) => {
debug(`verifyProfile(${this.authMethodId})`);

let profile;
// Verify signing?
try {
if (this.authMethodConfig.certificate) {
// Decode Oauth token and verify that it has been signed by the given public cert
debug(`verifyProfile(${this.authMethodId}): Verifying JWT signature and decoding profile`);
profile = jwt.verify(accessToken, this.authMethodConfig.certificate);
debug(`verifyProfile(${this.authMethodId}): Verified JWT successfully`);
} else {
// Do not check signing, just decode
warn(`verifyProfile(${this.authMethodId}): Decoding JWT signature, NOT verifying signature, "certificate" not specified`)
profile = jwt.decode(accessToken);
if (!this.authMethodConfig.retrieveProfile) {
// Verify signing?
try {
profile = this.verifyJWT(accessToken);
debug(`verifyProfile(${this.authMethodId}): Decoded JWT Profile:`);
} catch (ex) {
error(`verifyProfile(${this.authMethodId}): JWT decode/verification failed.`);
return done(null, false, { message: ex });
}
} catch (ex) {
error(`verifyProfile(${this.authMethodId}): JWT decode/verification failed.`);
return done(null, false, { message: ex });
}

debug(`verifyProfile(${this.authMethodId}): Decoded JWT Profile:`);
}
debug(`verifyProfile(${this.authMethodId}): Retrieved Profile:`);
debug(profile);

try {
Expand All @@ -131,7 +146,19 @@ export class OAuth2IdP implements IdentityProvider {
} catch (err) {
return done(null, false, { message: err });
}
};
}

private verifyJWT = (accessToken) => {
if (this.authMethodConfig.certificate) {
// Decode Oauth token and verify that it has been signed by the given public cert
debug(`verifyJWT(${this.authMethodId}): Verifying JWT signature and decoding profile`);
return jwt.verify(accessToken, this.authMethodConfig.certificate);
} else {
// Do not check signing, just decode
warn(`verifyJWT(${this.authMethodId}): Decoding JWT signature, NOT verifying signature, "certificate" not specified`)
return jwt.decode(accessToken);
}
}

private authorizationParams = (options) => {
let params: any = {};
Expand All @@ -148,7 +175,7 @@ export class OAuth2IdP implements IdentityProvider {
params.prompt = options.prompt;
}
return params;
}
}

/**
* In case the user isn't already authenticated, this method will
Expand Down