0
Fork 0
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:
Alex Kocharin 2014-09-02 04:27:04 +04:00
parent 86394b25ee
commit 430a479113
3 changed files with 124 additions and 56 deletions

View file

@ -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',
})
} }
}) })
} }

View file

@ -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) {

View file

@ -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