//
// Copyright (c) 2011, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 4 Jul 11 Brian Frank Yeah USA!
//
using web
using util
**
** WebRepoAuth is used to plug in authentication and permission
** authorization for a WebRepoMod.
**
const abstract class WebRepoAuth
{
//////////////////////////////////////////////////////////////////////////
// Authentication
//////////////////////////////////////////////////////////////////////////
** What algorithms are supported to compute the "secret" to use
** for digital signatures. They should be sorted from most
** preferred to least preferred. Standard values are:
** - 'PASSWORD': simple plaintext password is used as secret
** - 'SALTED-HMAC-SHA1': HMAC of "user:salt" with password as key
abstract Str[] secretAlgorithms()
** What algorithms are supported for computing the signature of a request.
** They should be sorted from most preferred to least preferred.
** Standard values are:
** - 'HMAC-SHA1': SHA-1 HMAC using secret as key
** The default implementation of both client and server only
** supports "HMAC-SHA1".
virtual Str[] signatureAlgorithms() { ["HMAC-SHA1"] }
** Given a username, return an implementation specific object
** which models the user for the given username. Or return null
** if username doesn't map to a valid user.
abstract Obj? user(Str username)
** Get the salt used for the SALTED-HMAC-SHA1 secret algorithm for
** the given user. If the user doesn't exist or salts aren't
** supported, then return null.
abstract Str? salt(Obj? user)
** Get the secret as a byte buffer for the given user and algorithm
** which can be used to verify the digital signature of a request.
** See `secretAlgorithms` for list of algorithms (parameter is guaranteed
** to be in all upper case).
abstract Buf secret(Obj? user, Str algorithm)
//////////////////////////////////////////////////////////////////////////
// Permissions
//////////////////////////////////////////////////////////////////////////
** Is the given user allowed to query the given pod?
** If pod is null, return if user is allowed to query anything.
abstract Bool allowQuery(Obj? user, PodSpec? pod)
** Is the given user allowed to read/download/install the given pod?
** If pod is null, return if user is allowed to install anything.
abstract Bool allowRead(Obj? user, PodSpec? pod)
** Is the given user allowed to publish the given pod?
** If pod is null, return if user is allowed to publish anything.
abstract Bool allowPublish(Obj? user, PodSpec? pod)
}
**************************************************************************
** PublicWebRepoAuth
**************************************************************************
internal const class PublicWebRepoAuth : WebRepoAuth
{
override Obj? user(Str username) { null }
override Str? salt(Obj? user) { publicSalt }
override Buf secret(Obj? user, Str algorithm) { Buf() }
override Str[] secretAlgorithms() { ["PASSWORD", "SALTED-HMAC-SHA1"] }
override Bool allowQuery(Obj? u, PodSpec? p) { true }
override Bool allowRead(Obj? u, PodSpec? p) { true }
override Bool allowPublish(Obj? u, PodSpec? p) { true }
private const Str publicSalt := Buf.random(16).toHex
}
**************************************************************************
** SimpleWebRepoAuth
**************************************************************************
internal const class SimpleWebRepoAuth : WebRepoAuth
{
new make(Str username, Str password)
{
this.username = username
this.userSalt = Buf.random(16).toHex
this.password = password
}
override Obj? user(Str username) { username == this.username ? this : null }
override Buf secret(Obj? user, Str algorithm)
{
if (user != this) throw Err("Invalid user: $user")
switch (algorithm)
{
case "PASSWORD":
return Buf().print(password)
case "SALTED-HMAC-SHA1":
return Buf().print("$username:$userSalt").hmac("SHA-1", password.toBuf)
default:
throw Err("Unexpected secret algorithm: $algorithm")
}
}
override Str? salt(Obj? user) { user != null ? userSalt : null }
override Str[] secretAlgorithms() { ["PASSWORD", "SALTED-HMAC-SHA1"] }
override Bool allowQuery(Obj? u, PodSpec? p) { u != null }
override Bool allowRead(Obj? u, PodSpec? p) { u != null }
override Bool allowPublish(Obj? u, PodSpec? p) { u != null }
private const Str username
private const Str userSalt
private const Str password
}