-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
login: stop using npm-registry-client for SSO auth
- Loading branch information
Showing
4 changed files
with
63 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,73 @@ | ||
var log = require('npmlog') | ||
var npm = require('../npm.js') | ||
var output = require('../utils/output') | ||
var openUrl = require('../utils/open-url') | ||
'use strict' | ||
|
||
const BB = require('bluebird') | ||
|
||
const figgyPudding = require('figgy-pudding') | ||
const log = require('npmlog') | ||
const npmConfig = require('../config/figgy-config.js') | ||
const npmFetch = require('npm-registry-fetch') | ||
const output = require('../utils/output.js') | ||
const openUrl = BB.promisify(require('../utils/open-url.js')) | ||
const otplease = require('../utils/otplease.js') | ||
const profile = require('libnpm/profile') | ||
|
||
const SsoOpts = figgyPudding({ | ||
ssoType: 'sso-type', | ||
'sso-type': {}, | ||
ssoPollFrequency: 'sso-poll-frequency', | ||
'sso-poll-frequency': {} | ||
}) | ||
|
||
module.exports.login = function login (creds, registry, scope, cb) { | ||
var ssoType = npm.config.get('sso-type') | ||
const opts = SsoOpts(npmConfig()).concat({creds, registry, scope}) | ||
const ssoType = opts.ssoType | ||
if (!ssoType) { return cb(new Error('Missing option: sso-type')) } | ||
|
||
var params = { | ||
// We're reusing the legacy login endpoint, so we need some dummy | ||
// stuff here to pass validation. They're never used. | ||
auth: { | ||
username: 'npm_' + ssoType + '_auth_dummy_user', | ||
password: 'placeholder', | ||
email: '[email protected]', | ||
authType: ssoType | ||
} | ||
// We're reusing the legacy login endpoint, so we need some dummy | ||
// stuff here to pass validation. They're never used. | ||
const auth = { | ||
username: 'npm_' + ssoType + '_auth_dummy_user', | ||
password: 'placeholder', | ||
email: '[email protected]', | ||
authType: ssoType | ||
} | ||
npm.registry.adduser(registry, params, function (er, doc) { | ||
if (er) return cb(er) | ||
if (!doc || !doc.token) return cb(new Error('no SSO token returned')) | ||
if (!doc.sso) return cb(new Error('no SSO URL returned by services')) | ||
|
||
openUrl(doc.sso, 'to complete your login please visit', function () { | ||
pollForSession(registry, doc.token, function (err, username) { | ||
if (err) return cb(err) | ||
|
||
log.info('adduser', 'Authorized user %s', username) | ||
var scopeMessage = scope ? ' to scope ' + scope : '' | ||
output('Logged in as %s%s on %s.', username, scopeMessage, registry) | ||
|
||
cb(null, { token: doc.token }) | ||
}) | ||
otplease(opts, | ||
opts => profile.loginCouch(auth.username, auth.password, opts) | ||
).then(({token, sso}) => { | ||
if (!token) { throw new Error('no SSO token returned') } | ||
if (!sso) { throw new Error('no SSO URL returned by services') } | ||
return openUrl(sso, 'to complete your login please visit').then(() => { | ||
return pollForSession(registry, token, opts) | ||
}).then(username => { | ||
log.info('adduser', 'Authorized user %s', username) | ||
var scopeMessage = scope ? ' to scope ' + scope : '' | ||
output('Logged in as %s%s on %s.', username, scopeMessage, registry) | ||
return {token} | ||
}) | ||
}) | ||
}).nodeify(cb) | ||
} | ||
|
||
function pollForSession (registry, token, cb) { | ||
function pollForSession (registry, token, opts) { | ||
log.info('adduser', 'Polling for validated SSO session') | ||
npm.registry.whoami(registry, { | ||
auth: { | ||
token: token | ||
} | ||
}, function (er, username) { | ||
if (er && er.statusCode !== 401) { | ||
cb(er) | ||
} else if (!username) { | ||
setTimeout(function () { | ||
pollForSession(registry, token, cb) | ||
}, npm.config.get('sso-poll-frequency')) | ||
} else { | ||
cb(null, username) | ||
return npmFetch.json( | ||
'/-/whoami', opts.concat({registry, forceAuth: {token}}) | ||
).then( | ||
({username}) => username, | ||
err => { | ||
if (err.code === 'E401') { | ||
return sleep(opts['sso-poll-frequency']).then(() => { | ||
return pollForSession(registry, token, opts) | ||
}) | ||
} else { | ||
throw err | ||
} | ||
} | ||
) | ||
} | ||
|
||
function sleep (time) { | ||
return new BB((resolve) => { | ||
setTimeout(resolve, time) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters