From 826c5ab7f9c75e72687acf7d115b901ad292e664 Mon Sep 17 00:00:00 2001 From: Tit Petric Date: Fri, 20 Jul 2018 18:08:10 +0200 Subject: [PATCH] import full test suite --- rbac/client.go | 22 ++++++++++-- rbac/client_test.go | 17 ++++++++++ rbac/resources.go | 56 +++++++++++++++++++++++++++++++ rbac/resources_test.go | 28 ++++++++++++++++ rbac/roles.go | 52 +++++++++++++++++++++++++++++ rbac/roles_test.go | 28 ++++++++++++++++ rbac/sessions.go | 76 ++++++++++++++++++++++++++++++++++++++++++ rbac/sessions_test.go | 38 +++++++++++++++++++++ rbac/types/structs.go | 7 +++- rbac/users.go | 38 +++++++++++++++++++++ rbac/users_test.go | 43 ++++++------------------ 11 files changed, 369 insertions(+), 36 deletions(-) create mode 100644 rbac/client_test.go create mode 100644 rbac/resources.go create mode 100644 rbac/resources_test.go create mode 100644 rbac/roles.go create mode 100644 rbac/roles_test.go create mode 100644 rbac/sessions.go create mode 100644 rbac/sessions_test.go diff --git a/rbac/client.go b/rbac/client.go index d305408eb..0753a2008 100644 --- a/rbac/client.go +++ b/rbac/client.go @@ -13,6 +13,8 @@ import ( "time" ) +var _ = tls.Config{} + type ( Client struct { Transport *http.Transport @@ -21,9 +23,21 @@ type ( isDebug bool config configuration } + + ClientInterface interface { + Users() *Users + Roles() *Roles + Resources() *Resources + Sessions() *Sessions + } ) -func (c *Client) Users() *Users { return &Users{c} } +func (c *Client) Users() *Users { return &Users{c} } +func (c *Client) Roles() *Roles { return &Roles{c} } +func (c *Client) Resources() *Resources { return &Resources{c} } +func (c *Client) Sessions() *Sessions { return &Sessions{c} } + +var _ ClientInterface = &Client{} func New() (*Client, error) { if err := config.validate(); err != nil { @@ -38,7 +52,7 @@ func New() (*Client, error) { }).Dial, TLSHandshakeTimeout: timeout, // @todo: === remove this line === - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + //TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{ @@ -70,6 +84,10 @@ func (c *Client) Post(url string, body interface{}) (*http.Response, error) { return c.Request("POST", url, body) } +func (c *Client) Patch(url string, body interface{}) (*http.Response, error) { + return c.Request("PATCH", url, body) +} + func (c *Client) Delete(url string) (*http.Response, error) { return c.Request("DELETE", url, nil) } diff --git a/rbac/client_test.go b/rbac/client_test.go new file mode 100644 index 000000000..72fdd42ee --- /dev/null +++ b/rbac/client_test.go @@ -0,0 +1,17 @@ +package rbac_test + +import ( + "github.com/crusttech/crust/rbac" + "github.com/namsral/flag" +) + +var loaded bool + +func getClient() (*rbac.Client, error) { + if !loaded { + rbac.Flags() + flag.Parse() + loaded = true + } + return rbac.New() +} diff --git a/rbac/resources.go b/rbac/resources.go new file mode 100644 index 000000000..e1bbe4765 --- /dev/null +++ b/rbac/resources.go @@ -0,0 +1,56 @@ +package rbac + +import ( + "fmt" + "github.com/pkg/errors" +) + +type ( + Resources struct { + *Client + } + + ResourcesInterface interface { + Create(resourceID string, operations []string) error + Delete(resourceID string) error + } +) + +const ( + resourcesCreate = "/resources/%s" + resourcesDelete = "/resources/%s" +) + +func (u *Resources) Create(resourceID string, operations []string) error { + body := struct { + Operations []string `json:"operations"` + }{operations} + + resp, err := u.Client.Post(fmt.Sprintf(resourcesCreate, resourceID), body) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +func (u *Resources) Delete(resourceID string) error { + resp, err := u.Client.Delete(fmt.Sprintf(resourcesCreate, resourceID)) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +var _ ResourcesInterface = &Resources{} diff --git a/rbac/resources_test.go b/rbac/resources_test.go new file mode 100644 index 000000000..ccdc90876 --- /dev/null +++ b/rbac/resources_test.go @@ -0,0 +1,28 @@ +package rbac_test + +import ( + "testing" +) + +func TestResources(t *testing.T) { + rbac, err := getClient() + if err != nil { + t.Errorf("Unexpected error when creating RBAC instance: %+v", err) + } + rbac.Debug(false) + + resources := rbac.Resources() + resources.Delete("test-resource") + + if err := resources.Create("test-resource", []string{"view", "edit", "delete"}); err != nil { + t.Errorf("Error when creating test-resource, %+v", err) + } + + if err := resources.Delete("test-resource"); err != nil { + t.Errorf("Unexpected error deleting a resource, %+v", err) + } + + if err := resources.Delete("test-resource"); err == nil { + t.Errorf("Expected error when deleting unexistant resource, got none") + } +} diff --git a/rbac/roles.go b/rbac/roles.go new file mode 100644 index 000000000..3e7d9749e --- /dev/null +++ b/rbac/roles.go @@ -0,0 +1,52 @@ +package rbac + +import ( + "fmt" + "github.com/pkg/errors" +) + +type ( + Roles struct { + *Client + } + + RolesInterface interface { + Create(role string) error + Delete(role string) error + } +) + +const ( + rolesCreate = "/roles/%s" + rolesDelete = "/roles/%s" +) + +func (u *Roles) Create(role string) error { + resp, err := u.Client.Post(fmt.Sprintf(rolesCreate, role), nil) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +func (u *Roles) Delete(role string) error { + resp, err := u.Client.Delete(fmt.Sprintf(rolesDelete, role)) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +var _ RolesInterface = &Roles{} diff --git a/rbac/roles_test.go b/rbac/roles_test.go new file mode 100644 index 000000000..4cb21158d --- /dev/null +++ b/rbac/roles_test.go @@ -0,0 +1,28 @@ +package rbac_test + +import ( + "testing" +) + +func TestRoles(t *testing.T) { + rbac, err := getClient() + if err != nil { + t.Errorf("Unexpected error when creating RBAC instance: %+v", err) + } + rbac.Debug(false) + + roles := rbac.Roles() + roles.Delete("test-role") + + if err := roles.Create("test-role"); err != nil { + t.Errorf("Error when creating test-role: %+v", err) + } + + if err := roles.Delete("test-role"); err != nil { + t.Errorf("Error when deleting test-role: %+v", err) + } + + if err := roles.Delete("non-existant"); err == nil { + t.Errorf("Expected error on deleting a non-existant role") + } +} diff --git a/rbac/sessions.go b/rbac/sessions.go new file mode 100644 index 000000000..fc5667e6c --- /dev/null +++ b/rbac/sessions.go @@ -0,0 +1,76 @@ +package rbac + +import ( + "encoding/json" + "fmt" + "github.com/crusttech/crust/rbac/types" + "github.com/pkg/errors" +) + +type ( + Sessions struct { + *Client + } + + SessionsInterface interface { + Create(sessionID string, username string, roles []string) error + Get(sessionID string) (*types.Session, error) + Delete(sessionID string) error + } +) + +const ( + sessionsCreate = "/sessions/%s" + sessionsGet = "/sessions/%s" + sessionsDelete = "/sessions/%s" +) + +func (u *Sessions) Create(sessionID string, username string, roles []string) error { + body := struct { + Username string `json:"username"` + Roles []string `json:"roles,omitempty"` + }{username, roles} + + resp, err := u.Client.Post(fmt.Sprintf(sessionsCreate, sessionID), body) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +func (u *Sessions) Get(sessionID string) (*types.Session, error) { + resp, err := u.Client.Get(fmt.Sprintf(sessionsGet, sessionID)) + if err != nil { + return nil, errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + session := &types.Session{} + return session, errors.Wrap(json.NewDecoder(resp.Body).Decode(session), "decoding json failed") + default: + return nil, toError(resp) + } +} + +func (u *Sessions) Delete(sessionID string) error { + resp, err := u.Client.Delete(fmt.Sprintf(sessionsDelete, sessionID)) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +var _ SessionsInterface = &Sessions{} diff --git a/rbac/sessions_test.go b/rbac/sessions_test.go new file mode 100644 index 000000000..82b260cfc --- /dev/null +++ b/rbac/sessions_test.go @@ -0,0 +1,38 @@ +package rbac_test + +import ( + "testing" +) + +func TestSessions(t *testing.T) { + rbac, err := getClient() + if err != nil { + t.Errorf("Unexpected error when creating RBAC instance: %+v", err) + } + rbac.Debug(false) + + sessions := rbac.Sessions() + users := rbac.Users() + + // clean up data + users.Delete("test-user") + sessions.Delete("test-session") + + if err := users.Create("test-user", "test-password"); err != nil { + t.Errorf("Unexpected error when creating test-user, %+v", err) + return + } + if err := sessions.Create("test-session", "test-user", []string{}); err != nil { + t.Errorf("Unexpected error when creating test-session, %+v", err) + } + + if _, err := sessions.Get("test-session"); err != nil { + t.Errorf("Unexpected error when getting test-session, %+v", err) + } + + if err := sessions.Delete("test-session"); err != nil { + t.Errorf("Unexpected error when deleting test-session, %+v", err) + } + + // Write tests (need users, roles) +} diff --git a/rbac/types/structs.go b/rbac/types/structs.go index 7d5060404..e14fbf4f2 100644 --- a/rbac/types/structs.go +++ b/rbac/types/structs.go @@ -2,6 +2,11 @@ package types type ( User struct { - username string + Username string `json:"username"` + } + + Session struct { + Username string `json:"username"` + Roles []string `json:"roles"` } ) diff --git a/rbac/users.go b/rbac/users.go index d47110286..60e958f3c 100644 --- a/rbac/users.go +++ b/rbac/users.go @@ -15,6 +15,8 @@ type ( Create(username, password string) error Get(username string) (*types.User, error) Delete(username string) error + + Assign(username string, roles []string) error } ) @@ -36,6 +38,42 @@ func (u *Users) Create(username, password string) error { } } +func (u *Users) Assign(username string, roles []string) error { + body := struct { + Roles []string `json:"roles"` + }{roles} + + resp, err := u.Client.Patch("/users/"+username+"/assignRoles", body) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + +func (u *Users) Deassign(username string, roles []string) error { + body := struct { + Roles []string `json:"roles"` + }{roles} + + resp, err := u.Client.Patch("/users/"+username+"/deassignRoles", body) + if err != nil { + return errors.Wrap(err, "request failed") + } + defer resp.Body.Close() + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } +} + func (u *Users) Get(username string) (*types.User, error) { resp, err := u.Client.Get("/users/" + username) if err != nil { diff --git a/rbac/users_test.go b/rbac/users_test.go index 43b076fc1..41b9b6519 100644 --- a/rbac/users_test.go +++ b/rbac/users_test.go @@ -1,55 +1,32 @@ package rbac_test import ( - "os" "testing" - - "github.com/crusttech/crust/rbac" - "github.com/namsral/flag" ) -var _ = os.Setenv - func TestUsers(t *testing.T) { - rbac.Flags() - flag.Parse() - - rbac, err := rbac.New() + rbac, err := getClient() if err != nil { t.Errorf("Unexpected error when creating RBAC instance: %+v", err) } rbac.Debug(false) users := rbac.Users() + users.Delete("test-user") - // clean up env - { - // just making sure we don't have one - // and we're ignoring possible err's - users.Delete("test-user") + if err := users.Create("test-user", "test-password"); err != nil { + t.Errorf("Error when creating test-user: %+v", err) } - // create a user - { - err := users.Create("test-user", "test-password") - if err != nil { - t.Errorf("Error when creating test-user: %+v", err) - } + if err := users.Delete("test-user"); err != nil { + t.Errorf("Error when deleting test-user: %+v", err) } - // delete a user - { - err := users.Delete("test-user") - if err != nil { - t.Errorf("Error when deleting test-user: %+v", err) - } + if _, err := users.Get("non-existant"); err == nil { + t.Errorf("Expected error on retrieving a non-existant user") } - // check getting a non-existant user fails - { - _, err := users.Get("non-existant") - if err == nil { - t.Errorf("Expected error on retrieving a non-existant user") - } + if err := users.Delete("non-existant"); err == nil { + t.Errorf("Expected error on deleting a non-existant user") } }