mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-02-03 23:09:17 -05:00
auth refactoring: part 2
auth plugins
This commit is contained in:
parent
86394b25ee
commit
430a479113
3 changed files with 124 additions and 56 deletions
136
lib/auth.js
136
lib/auth.js
|
@ -1,53 +1,126 @@
|
||||||
var Path = require('path')
|
var Path = require('path')
|
||||||
, crypto = require('crypto')
|
, crypto = require('crypto')
|
||||||
, UError = require('./error').UError
|
, UError = require('./error').UserError
|
||||||
|
, Logger = require('./logger')
|
||||||
|
, assert = require('assert')
|
||||||
|
|
||||||
module.exports = Auth
|
module.exports = Auth
|
||||||
|
|
||||||
function Auth(config) {
|
function Auth(config) {
|
||||||
if (!(this instanceof Auth)) return new Auth(config)
|
if (!(this instanceof Auth)) return new Auth(config)
|
||||||
this.config = config
|
this.config = config
|
||||||
|
this.logger = Logger.logger.child({sub: 'auth'})
|
||||||
|
var stuff = {
|
||||||
|
config: config,
|
||||||
|
logger: this.logger,
|
||||||
|
}
|
||||||
|
|
||||||
if (config.users_file) {
|
if (config.users_file) {
|
||||||
this.HTPasswd = require('./htpasswd')(
|
if (!config.auth || !config.auth.htpasswd) {
|
||||||
Path.resolve(
|
// b/w compat
|
||||||
Path.dirname(config.self_path),
|
config.auth = config.auth || {}
|
||||||
config.users_file
|
config.auth.htpasswd = {file: config.users_file}
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Auth.prototype.authenticate = function(user, password, cb) {
|
|
||||||
if (this.config.users != null && this.config.users[user] != null) {
|
|
||||||
// if user exists in this.users, verify password against it no matter what is in htpasswd
|
|
||||||
return cb(null, crypto.createHash('sha1').update(password).digest('hex') === this.config.users[user].password ? [user] : null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.HTPasswd) return cb(null, false)
|
this.plugins = Object.keys(config.auth || {}).map(function(p) {
|
||||||
this.HTPasswd.reload(function() {
|
var plugin, name
|
||||||
cb(null, this.HTPasswd.verify(user, password) ? [user] : null)
|
try {
|
||||||
}.bind(this))
|
name = 'sinopia-' + p
|
||||||
}
|
plugin = require(name)
|
||||||
|
} catch(x) {
|
||||||
|
try {
|
||||||
|
name = p
|
||||||
|
plugin = require(name)
|
||||||
|
} catch(x) {}
|
||||||
|
}
|
||||||
|
|
||||||
Auth.prototype.add_user = function(user, password, cb) {
|
if (plugin == null) {
|
||||||
if (this.config.users && this.config.users[user]) return cb(new UError({
|
throw Error('"' + p + '" auth plugin not found\n'
|
||||||
|
+ 'try "npm install sinopia-' + p + '"')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(plugin) !== 'function')
|
||||||
|
throw Error('"' + name + '" doesn\'t look like a valid auth plugin')
|
||||||
|
|
||||||
|
plugin = plugin(config.auth[p], stuff)
|
||||||
|
|
||||||
|
if (plugin == null || typeof(plugin.authenticate) !== 'function')
|
||||||
|
throw Error('"' + name + '" doesn\'t look like a valid auth plugin')
|
||||||
|
|
||||||
|
return plugin
|
||||||
|
})
|
||||||
|
|
||||||
|
this.plugins.unshift({
|
||||||
|
authenticate: function(user, password, cb) {
|
||||||
|
if (config.users != null
|
||||||
|
&& config.users[user] != null
|
||||||
|
&& (crypto.createHash('sha1').update(password).digest('hex')
|
||||||
|
=== config.users[user].password)
|
||||||
|
) {
|
||||||
|
return cb(null, [ user ])
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb()
|
||||||
|
},
|
||||||
|
|
||||||
|
adduser: function(user, password, cb) {
|
||||||
|
if (config.users && config.users[user]) return cb(new UError({
|
||||||
status: 403,
|
status: 403,
|
||||||
message: 'this user already exists',
|
message: 'this user already exists',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (this.HTPasswd) {
|
return cb()
|
||||||
if (this.max_users || this.max_users == null) {
|
},
|
||||||
var max_users = Number(this.max_users || Infinity)
|
})
|
||||||
this.HTPasswd.add_user(user, password, max_users, cb)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.plugins.push({
|
||||||
|
authenticate: function(user, password, cb) {
|
||||||
|
return cb(new UError({
|
||||||
|
status: 403,
|
||||||
|
message: 'bad username/password, access denied',
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
|
||||||
|
adduser: function(user, password, cb) {
|
||||||
return cb(new UError({
|
return cb(new UError({
|
||||||
status: 409,
|
status: 409,
|
||||||
message: 'registration is disabled',
|
message: 'registration is disabled',
|
||||||
}))
|
}))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth.prototype.authenticate = function(user, password, cb) {
|
||||||
|
var plugins = this.plugins.slice(0)
|
||||||
|
|
||||||
|
!function next() {
|
||||||
|
var p = plugins.shift()
|
||||||
|
p.authenticate(user, password, function(err, groups) {
|
||||||
|
if (err || groups) return cb(err, groups)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth.prototype.add_user = function(user, password, cb) {
|
||||||
|
var plugins = this.plugins.slice(0)
|
||||||
|
|
||||||
|
!function next() {
|
||||||
|
var p = plugins.shift()
|
||||||
|
var n = 'adduser'
|
||||||
|
if (typeof(p[n]) !== 'function') {
|
||||||
|
n = 'add_user'
|
||||||
|
}
|
||||||
|
if (typeof(p[n]) !== 'function') {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
p[n](user, password, function(err, ok) {
|
||||||
|
if (err || ok) return cb(err, ok)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth.prototype.middleware = function() {
|
Auth.prototype.middleware = function() {
|
||||||
|
@ -90,17 +163,14 @@ Auth.prototype.middleware = function() {
|
||||||
var user = credentials.slice(0, index)
|
var user = credentials.slice(0, index)
|
||||||
, pass = credentials.slice(index + 1)
|
, pass = credentials.slice(index + 1)
|
||||||
|
|
||||||
|
debugger
|
||||||
self.authenticate(user, pass, function(err, groups) {
|
self.authenticate(user, pass, function(err, groups) {
|
||||||
if (err) return next(err)
|
if (!err && groups != null && groups != false) {
|
||||||
if (groups != null && groups != false) {
|
|
||||||
req.remote_user = AuthenticatedUser(user, groups)
|
req.remote_user = AuthenticatedUser(user, groups)
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
req.remote_user = AnonymousUser()
|
req.remote_user = AnonymousUser()
|
||||||
next({
|
next(err)
|
||||||
status: 403,
|
|
||||||
message: 'bad username/password, access denied',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,11 +75,6 @@ function Config(config) {
|
||||||
Array.isArray(hash[action])
|
Array.isArray(hash[action])
|
||||||
, 'CONFIG: bad "'+i+'" package '+action+' description (array or string expected)')
|
, 'CONFIG: bad "'+i+'" package '+action+' description (array or string expected)')
|
||||||
hash[action] = flatten(hash[action])
|
hash[action] = flatten(hash[action])
|
||||||
hash[action].forEach(function(user) {
|
|
||||||
assert(
|
|
||||||
users[user] != null
|
|
||||||
, 'CONFIG: "'+i+'" package: user "'+user+'" doesn\'t exist')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i in this.packages) {
|
for (var i in this.packages) {
|
||||||
|
|
|
@ -12,11 +12,12 @@ users:
|
||||||
title: Sinopia
|
title: Sinopia
|
||||||
# logo: logo.png
|
# logo: logo.png
|
||||||
|
|
||||||
users_file: ./htpasswd
|
auth:
|
||||||
|
htpasswd:
|
||||||
# Maximum amount of users allowed to register, defaults to "+inf".
|
users_file: ./htpasswd
|
||||||
# You can set this to 0 to disable registration.
|
# Maximum amount of users allowed to register, defaults to "+inf".
|
||||||
#max_users: 1000
|
# You can set this to 0 to disable registration.
|
||||||
|
#max_users: 1000
|
||||||
|
|
||||||
# a list of other known repositories we can talk to
|
# a list of other known repositories we can talk to
|
||||||
uplinks:
|
uplinks:
|
||||||
|
@ -51,9 +52,11 @@ packages:
|
||||||
# storage: 'local_storage'
|
# storage: 'local_storage'
|
||||||
|
|
||||||
'*':
|
'*':
|
||||||
# allow all users to read packages ('all' is a keyword)
|
# allow all users to read packages (including non-authenticated users)
|
||||||
# this includes non-authenticated users
|
#
|
||||||
allow_access: all
|
# you can specify usernames/groupnames (depending on your auth plugin)
|
||||||
|
# and three keywords: "@all", "@anonymous", "@authenticated"
|
||||||
|
allow_access: @all
|
||||||
|
|
||||||
# allow 'admin' to publish packages
|
# allow 'admin' to publish packages
|
||||||
allow_publish: admin
|
allow_publish: admin
|
||||||
|
|
Loading…
Add table
Reference in a new issue