Authenticate Handler API and SDK, and much more (#183)

This commit is contained in:
Todd Knight authored and GitHub committed 2020-07-14 17:32:47 -04:00
1 parent acce195dcb
commit 28dbcd84bd
89 files changed
+5296 -1943

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
package scopes
import (
"context"
"fmt"
"github.com/hashicorp/watchtower/api"
"github.com/hashicorp/watchtower/api/authtokens"
)
// TODO: This will need to be changed when we add Auth Method API to watchtower. We'll also need a better
// way to handle different auth method types.
func (s Org) Authenticate(ctx context.Context, authMethodId, name, password string) (*authtokens.AuthToken, *api.Error, error) {
if s.Client == nil {
return nil, nil, fmt.Errorf("nil client in Authenticate request")
}
if s.Id == "" {
// Assume the client has been configured with org already and
// move on
} else {
// If it's explicitly set here, override anything that might be in the
// client
ctx = context.WithValue(ctx, "org", s.Id)
}
reqBody := map[string]interface{}{
"credentials": map[string]string{
"name": name,
"password": password,
},
}
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s:authenticate", authMethodId), reqBody)
if err != nil {
return nil, nil, fmt.Errorf("error creating Authenticate request: %w", err)
}
resp, err := s.Client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Authenticate call: %w", err)
}
target := new(authtokens.AuthToken)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Authenticate response: %w", err)
}
if target.Token != "" {
s.Client.SetToken(target.Token)
}
return target, apiErr, nil
}
+34
View File
@@ -0,0 +1,34 @@
package scopes_test
import (
"context"
"net/http"
"testing"
"github.com/hashicorp/watchtower/api/scopes"
"github.com/hashicorp/watchtower/internal/servers/controller"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAuthenticate(t *testing.T) {
assert := assert.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := &scopes.Org{
Client: client,
}
ctx := context.Background()
tok, apiErr, err := org.Authenticate(ctx, "am_anything", "admin", "hunter2")
assert.NoError(err)
assert.Nil(apiErr)
assert.NotNil(tok)
_, apiErr, err = org.Authenticate(ctx, "am_anything", "wrong", "wrong")
assert.NoError(err)
require.NotNil(t, apiErr)
assert.EqualValuesf(http.StatusUnauthorized, apiErr.Status, "Expected unauthenticated, got %q", apiErr.Message)
}
+17 -2
View File
@@ -3,6 +3,7 @@ package scopes
import (
"encoding/json"
"strings"
"time"
"github.com/fatih/structs"
@@ -32,11 +33,25 @@ type Org struct {
}
func (s *Org) SetDefault(key string) {
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
lowerKey := strings.ToLower(key)
validMap := map[string]string{"createdtime": "created_time", "description": "description", "id": "id", "name": "name", "updatedtime": "updated_time"}
for k, v := range validMap {
if k == lowerKey || v == lowerKey {
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
return
}
}
}
func (s *Org) UnsetDefault(key string) {
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
lowerKey := strings.ToLower(key)
validMap := map[string]string{"createdtime": "created_time", "description": "description", "id": "id", "name": "name", "updatedtime": "updated_time"}
for k, v := range validMap {
if k == lowerKey || v == lowerKey {
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
return
}
}
}
func (s Org) MarshalJSON() ([]byte, error) {
+17 -2
View File
@@ -3,6 +3,7 @@ package scopes
import (
"encoding/json"
"strings"
"time"
"github.com/fatih/structs"
@@ -34,11 +35,25 @@ type Project struct {
}
func (s *Project) SetDefault(key string) {
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
lowerKey := strings.ToLower(key)
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
for k, v := range validMap {
if k == lowerKey || v == lowerKey {
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
return
}
}
}
func (s *Project) UnsetDefault(key string) {
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
lowerKey := strings.ToLower(key)
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
for k, v := range validMap {
if k == lowerKey || v == lowerKey {
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
return
}
}
}
func (s Project) MarshalJSON() ([]byte, error) {
+2 -2
View File
@@ -133,10 +133,10 @@ func TestProject_Errors(t *testing.T) {
assert.NoError(err)
// TODO: Should this be nil instead of just a Project that has no values set
assert.NotNil(apiErr)
assert.EqualValues(*apiErr.Status, http.StatusNotFound)
assert.EqualValues(apiErr.Status, http.StatusNotFound)
_, apiErr, err = org.ReadProject(ctx, &scopes.Project{Id: "invalid id"})
assert.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
}
+41 -41
View File
@@ -177,47 +177,6 @@ func (s Org) ReadUser(ctx context.Context, r *users.User) (*users.User, *api.Err
return target, apiErr, nil
}
func (s Project) ReadHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) {
if s.Client == nil {
return nil, nil, fmt.Errorf("nil client in ReadHostCatalog request")
}
if s.Id == "" {
// Assume the client has been configured with project already and move
// on
} else {
// If it's explicitly set here, override anything that might be in the
// client
ctx = context.WithValue(ctx, "project", s.Id)
}
if r.Id == "" {
return nil, nil, fmt.Errorf("empty hosts.HostCatalog ID field in ReadHostCatalog request")
}
req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "host-catalogs", r.Id), r)
if err != nil {
return nil, nil, fmt.Errorf("error creating ReadHostCatalog request: %w", err)
}
resp, err := s.Client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during ReadHostCatalog call: %w", err)
}
target := new(hosts.HostCatalog)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding ReadHostCatalog repsonse: %w", err)
}
target.Client = s.Client
return target, apiErr, nil
}
func (s Project) ReadGroup(ctx context.Context, r *groups.Group) (*groups.Group, *api.Error, error) {
if s.Client == nil {
return nil, nil, fmt.Errorf("nil client in ReadGroup request")
@@ -299,3 +258,44 @@ func (s Project) ReadRole(ctx context.Context, r *roles.Role) (*roles.Role, *api
return target, apiErr, nil
}
func (s Project) ReadHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) {
if s.Client == nil {
return nil, nil, fmt.Errorf("nil client in ReadHostCatalog request")
}
if s.Id == "" {
// Assume the client has been configured with project already and move
// on
} else {
// If it's explicitly set here, override anything that might be in the
// client
ctx = context.WithValue(ctx, "project", s.Id)
}
if r.Id == "" {
return nil, nil, fmt.Errorf("empty hosts.HostCatalog ID field in ReadHostCatalog request")
}
req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "host-catalogs", r.Id), r)
if err != nil {
return nil, nil, fmt.Errorf("error creating ReadHostCatalog request: %w", err)
}
resp, err := s.Client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during ReadHostCatalog call: %w", err)
}
target := new(hosts.HostCatalog)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding ReadHostCatalog repsonse: %w", err)
}
target.Client = s.Client
return target, apiErr, nil
}