Merge pull request #90 from j-delaney/create-user-api

Dedicated API endpoint for creating users
This commit is contained in:
Nick Sullivan
2015-10-09 13:27:50 -07:00
5 changed files with 166 additions and 17 deletions

View File

@@ -72,6 +72,7 @@ format is POSTed and JSON is returned.
- `/create`: Create the first admin account.
- `/delegate`: Delegate a password to Red October
- `/create-user`: Create a user
- `/modify`: Modify permissions
- `/encrypt`: Encrypt
- `/decrypt`: Decrypt
@@ -109,6 +110,16 @@ Example query:
$ curl --cacert cert/server.crt https://localhost:8080/delegate \
-d '{"Name":"Dodo","Password":"Dodgson","Time":"2h34m","Uses":3}'
{"Status":"ok"}
### Create User
Create Users creates a new user account.
Example query:
$ curl --cacert cert/server.crt https://localhost:8080/create-user \
-d '{"Name":"Bill","Password":"Lizard"}'
{"Status":"ok"}
### Summary

View File

@@ -149,6 +149,21 @@ func (c *RemoteServer) Delegate(req core.DelegateRequest) (*core.ResponseData, e
return unmarshalResponseData(respBytes)
}
// CreateUser issues a create-user request to the remote server
func (c *RemoteServer) CreateUser(req core.CreateUserRequest) (*core.ResponseData, error) {
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
respBytes, err := c.doAction("create-user", reqBytes)
if err != nil {
return nil, err
}
return unmarshalResponseData(respBytes)
}
// Purge issues a purge request to the remote server
func (c *RemoteServer) Purge(req core.DelegateRequest) (*core.ResponseData, error) {
reqBytes, err := json.Marshal(req)

View File

@@ -51,6 +51,12 @@ type DelegateRequest struct {
Labels []string
}
type CreateUserRequest struct {
Name string
Password string
UserType string
}
type PasswordRequest struct {
Name string
Password string
@@ -338,6 +344,51 @@ func Delegate(jsonIn []byte) ([]byte, error) {
return jsonStatusOk()
}
// Create User processes a create-user request.
func CreateUser(jsonIn []byte) ([]byte, error) {
var s CreateUserRequest
var err error
defer func() {
if err != nil {
log.Printf("core.create-user failed: user=%s %v", s.Name, err)
} else {
log.Printf("core.create-user success: user=%s", s.Name)
}
}()
if err = json.Unmarshal(jsonIn, &s); err != nil {
return jsonStatusError(err)
}
// If no UserType if provided use the default one
if s.UserType == "" {
s.UserType = passvault.DefaultRecordType
}
if records.NumRecords() == 0 {
err = errors.New("Vault is not created yet")
return jsonStatusError(err)
}
// Validate the Name and Password as valid
if err = validateName(s.Name, s.Password); err != nil {
return jsonStatusError(err)
}
_, found := records.GetRecord(s.Name)
if found {
err = errors.New("User with that name already exists")
return jsonStatusError(err)
}
if _, err = records.AddNewRecord(s.Name, s.Password, false, s.UserType); err != nil {
return jsonStatusError(err)
}
return jsonStatusOk()
}
// Password processes a password change request.
func Password(jsonIn []byte) ([]byte, error) {
var err error

View File

@@ -215,6 +215,76 @@ func TestSummary(t *testing.T) {
}
}
func TestCreateUser(t *testing.T) {
createUserJson := []byte("{\"Name\":\"Bill\",\"Password\":\"Lizard\"}")
createUserECCJson := []byte("{\"Name\":\"Cat\",\"Password\":\"Cheshire\",\"UserType\":\"ECC\"}")
createVaultJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
Init("memory")
// Check that users cannot be created before a vault is
respJson, err := CreateUser(createUserJson)
if err != nil {
t.Fatalf("Error in creating user before vault is created, %v", err)
}
var s ResponseData
err = json.Unmarshal(respJson, &s)
if err != nil {
t.Fatalf("Error in creating user before vault is created, %v", err)
}
if s.Status == "ok" {
t.Fatalf("Error in creating user before vault is created, %v", s.Status)
}
// Check that a user can be created after a vault has been created
respJson, err = Create(createVaultJson)
if err != nil {
t.Fatalf("Error in creating account, %v", err)
}
respJson, err = CreateUser(createUserJson)
if err != nil {
t.Fatalf("Error in creating user, %v", err)
}
err = json.Unmarshal(respJson, &s)
if err != nil {
t.Fatalf("Error in creating user, %v", err)
}
if s.Status != "ok" {
t.Fatalf("Error in creating user, %v", s.Status)
}
// Check that user creation can't happen twice with the same name
respJson, err = CreateUser(createUserJson)
if err != nil {
t.Fatalf("Error in creating user when one exists, %v", err)
}
err = json.Unmarshal(respJson, &s)
if err != nil {
t.Fatalf("Error in creating user when one exists, %v", err)
}
if s.Status == "ok" {
t.Fatalf("Error in creating user when one exists, %v", s.Status)
}
// Check that a UserType can be specified for a user
respJson, err = CreateUser(createUserECCJson)
if err != nil {
t.Fatalf("Error in creating user with ECC UserType, %v", err)
}
err = json.Unmarshal(respJson, &s)
if err != nil {
t.Fatalf("Error in creating user with ECC UserType, %v", err)
}
if s.Status != "ok" {
t.Fatalf("Error in creating user with ECC UserType, %v", s.Status)
}
}
func TestPassword(t *testing.T) {
createJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"2h\",\"Uses\":1}")

View File

@@ -27,17 +27,18 @@ import (
// List of URLs to register and their related functions
var functions = map[string]func([]byte) ([]byte, error){
"/create": core.Create,
"/summary": core.Summary,
"/purge": core.Purge,
"/delegate": core.Delegate,
"/password": core.Password,
"/encrypt": core.Encrypt,
"/re-encrypt": core.ReEncrypt,
"/decrypt": core.Decrypt,
"/owners": core.Owners,
"/modify": core.Modify,
"/export": core.Export,
"/create": core.Create,
"/summary": core.Summary,
"/purge": core.Purge,
"/delegate": core.Delegate,
"/create-user": core.CreateUser,
"/password": core.Password,
"/encrypt": core.Encrypt,
"/re-encrypt": core.ReEncrypt,
"/decrypt": core.Decrypt,
"/owners": core.Owners,
"/modify": core.Modify,
"/export": core.Export,
}
type userRequest struct {
@@ -381,7 +382,7 @@ var indexHtml = []byte(`<!DOCTYPE html>
<h3>Create User</h3>
<form id="user-create" class="ro-user-create" role="form" action="/delegate" method="post">
<form id="user-create" class="ro-user-create" role="form" action="/create-user" method="post">
<div class="feedback create-feedback"></div>
<div class="form-group row">
@@ -395,11 +396,12 @@ var indexHtml = []byte(`<!DOCTYPE html>
</div>
</div>
<div class="form-group row">
<div class="col-md-6">
<input type="hidden" name="Time" class="form-control" id="create-user-time" value="0h" required />
</div>
<div class="col-md-6">
<input type="hidden" name="Uses" class="form-control" id="create-uses" value="0" required />
<div class="col-md-12">
<label for="create-user-type">User Type</label>
<select name="UserType" class="form-control" id="create-user-type">
<option value="RSA">RSA</option>
<option value="ECC">ECC</option>
</select>
</div>
</div>
<button type="submit" class="btn btn-primary">Create</button>