Authenticate Handler API and SDK, and much more (#183)
This commit is contained in:
1 parent
acce195dcb
commit
28dbcd84bd
89 files changed
+5296
-1943
No files matched your search
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user