open-vault/vendor/github.com/michaelklishin/rabbit-hole/users.go

189 lines
4.6 KiB
Go

package rabbithole
import (
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/json"
"math/rand"
"net/http"
)
type HashingAlgorithm string
func (algo HashingAlgorithm) String() string {
return string(algo)
}
const (
HashingAlgorithmSHA256 HashingAlgorithm = "rabbit_password_hashing_sha256"
HashingAlgorithmSHA512 HashingAlgorithm = "rabbit_password_hashing_sha512"
// deprecated, provided to support responses that include users created
// before RabbitMQ 3.6 and other legacy scenarios. MK.
HashingAlgorithmMD5 HashingAlgorithm = "rabbit_password_hashing_md5"
)
type UserInfo struct {
Name string `json:"name"`
PasswordHash string `json:"password_hash"`
HashingAlgorithm HashingAlgorithm `json:"hashing_algorithm,omitempty"`
// Tags control permissions. Built-in tags: administrator, management, policymaker.
Tags string `json:"tags"`
}
// Settings used to create users. Tags must be comma-separated.
type UserSettings struct {
Name string `json:"name"`
// Tags control permissions. Administrator grants full
// permissions, management grants management UI and HTTP API
// access, policymaker grants policy management permissions.
Tags string `json:"tags"`
// *never* returned by RabbitMQ. Set by the client
// to create/update a user. MK.
Password string `json:"password,omitempty"`
PasswordHash string `json:"password_hash,omitempty"`
HashingAlgorithm HashingAlgorithm `json:"hashing_algorithm,omitempty"`
}
//
// GET /api/users
//
// Example response:
// [{"name":"guest","password_hash":"8LYTIFbVUwi8HuV/dGlp2BYsD1I=","tags":"administrator"}]
// Returns a list of all users in a cluster.
func (c *Client) ListUsers() (rec []UserInfo, err error) {
req, err := newGETRequest(c, "users/")
if err != nil {
return []UserInfo{}, err
}
if err = executeAndParseRequest(c, req, &rec); err != nil {
return []UserInfo{}, err
}
return rec, nil
}
//
// GET /api/users/{name}
//
// Returns information about individual user.
func (c *Client) GetUser(username string) (rec *UserInfo, err error) {
req, err := newGETRequest(c, "users/"+PathEscape(username))
if err != nil {
return nil, err
}
if err = executeAndParseRequest(c, req, &rec); err != nil {
return nil, err
}
return rec, nil
}
//
// PUT /api/users/{name}
//
// Updates information about individual user.
func (c *Client) PutUser(username string, info UserSettings) (res *http.Response, err error) {
body, err := json.Marshal(info)
if err != nil {
return nil, err
}
req, err := newRequestWithBody(c, "PUT", "users/"+PathEscape(username), body)
if err != nil {
return nil, err
}
res, err = executeRequest(c, req)
if err != nil {
return nil, err
}
return res, nil
}
func (c *Client) PutUserWithoutPassword(username string, info UserSettings) (res *http.Response, err error) {
body, err := json.Marshal(UserInfo{Tags: info.Tags})
if err != nil {
return nil, err
}
req, err := newRequestWithBody(c, "PUT", "users/"+PathEscape(username), body)
if err != nil {
return nil, err
}
res, err = executeRequest(c, req)
if err != nil {
return nil, err
}
return res, nil
}
//
// DELETE /api/users/{name}
//
// Deletes user.
func (c *Client) DeleteUser(username string) (res *http.Response, err error) {
req, err := newRequestWithBody(c, "DELETE", "users/"+PathEscape(username), nil)
if err != nil {
return nil, err
}
res, err = executeRequest(c, req)
if err != nil {
return nil, err
}
return res, nil
}
//
// Password Hash generation
//
const characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func GenerateSalt(n int) string {
bs := make([]byte, n)
for i := range bs {
bs[i] = characters[rand.Intn(len(characters))]
}
return string(bs)
}
func SaltedPasswordHashSHA256(password string) (string, string) {
salt := GenerateSalt(4)
hashed := sha256.Sum256([]byte(salt + password))
return salt, string(hashed[:])
}
// Produces a salted hash value expected by the HTTP API.
// See https://www.rabbitmq.com/passwords.html#computing-password-hash
// for details.
func Base64EncodedSaltedPasswordHashSHA256(password string) string {
salt, saltedHash := SaltedPasswordHashSHA256(password)
return base64.URLEncoding.EncodeToString([]byte(salt + saltedHash))
}
func SaltedPasswordHashSHA512(password string) (string, string) {
salt := GenerateSalt(4)
hashed := sha512.Sum512([]byte(salt + password))
return salt, string(hashed[:])
}
func Base64EncodedSaltedPasswordHashSHA512(password string) string {
salt, saltedHash := SaltedPasswordHashSHA512(password)
return base64.URLEncoding.EncodeToString([]byte(salt + saltedHash))
}