diff --git a/rbac/client.go b/rbac/client.go index 57e95eb05..d305408eb 100644 --- a/rbac/client.go +++ b/rbac/client.go @@ -1,10 +1,14 @@ package rbac import ( + "bytes" + "crypto/tls" "encoding/base64" + "encoding/json" "fmt" "net" "net/http" + "net/http/httputil" "strings" "time" ) @@ -33,6 +37,8 @@ func New() (*Client, error) { Timeout: timeout, }).Dial, TLSHandshakeTimeout: timeout, + // @todo: === remove this line === + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{ @@ -51,6 +57,11 @@ func New() (*Client, error) { }, nil } +func (c *Client) Debug(debug bool) *Client { + c.isDebug = debug + return c +} + func (c *Client) Get(url string) (*http.Response, error) { return c.Request("GET", url, nil) } @@ -67,21 +78,62 @@ func (c *Client) Request(method string, url string, body interface{}) (*http.Res link := strings.TrimRight(c.config.baseURL, "/") + "/" + strings.TrimLeft(url, "/") if c.isDebug { - fmt.Println("RBAC >>> ", link) + fmt.Println("RBAC >>>", method, link) } - req, err := http.NewRequest(method, link, nil) + request := func() (*http.Request, error) { + if body != nil { + b, err := json.Marshal(body) + if err != nil { + return nil, err + } + return http.NewRequest(method, link, bytes.NewBuffer(b)) + } + return http.NewRequest(method, link, nil) + } + + req, err := request() if err != nil { return nil, err } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.config.auth))) - req.Header.Add("X-TENANT-ID", c.config.tenant) + // req.Header.Add("X-TENANT-ID", c.config.tenant) + req.Header["X-TENANT-ID"] = []string{c.config.tenant} + + if c.isDebug { + fmt.Println("RBAC >>> (request)") + b, err := httputil.DumpRequestOut(req, true) + if err != nil { + fmt.Println("RBAC >>> Error:", err) + } else { + if b != nil { + fmt.Println(strings.TrimSpace(string(b))) + } + } + fmt.Println("---") + } resp, err := c.Client.Do(req) + if c.isDebug { + fmt.Println("RBAC <<< (response)") + if err != nil { + fmt.Println("RBAC <<< Error:", err) + } else { + + b, err := httputil.DumpResponse(resp, true) + if err != nil { + fmt.Println("RBAC <<< Error:", err) + } else { + if b != nil { + fmt.Println(string(b)) + } + } + } + fmt.Println("-----------------") + } if err != nil { - fmt.Println(err) return nil, err } diff --git a/rbac/users.go b/rbac/users.go index 0cc83c0c5..d47110286 100644 --- a/rbac/users.go +++ b/rbac/users.go @@ -2,8 +2,8 @@ package rbac import ( "encoding/json" - "github.com/crusttech/crust/rbac/types" + "github.com/pkg/errors" ) type ( @@ -25,29 +25,44 @@ func (u *Users) Create(username, password string) error { resp, err := u.Client.Post("/users/"+username, body) if err != nil { - return err + return errors.Wrap(err, "request failed") } defer resp.Body.Close() - return nil + 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 { - return nil, err + return nil, errors.Wrap(err, "request failed") } - user := &types.User{} defer resp.Body.Close() - return user, json.NewDecoder(resp.Body).Decode(user) + switch resp.StatusCode { + case 200: + user := &types.User{} + return user, errors.Wrap(json.NewDecoder(resp.Body).Decode(user), "decoding json failed") + default: + return nil, toError(resp) + } } func (u *Users) Delete(username string) error { resp, err := u.Client.Delete("/users/" + username) if err != nil { - return err + return errors.Wrap(err, "request failed") } defer resp.Body.Close() - return nil + switch resp.StatusCode { + case 200: + return nil + default: + return toError(resp) + } } var _ UsersInterface = &Users{} diff --git a/rbac/users_test.go b/rbac/users_test.go new file mode 100644 index 000000000..43b076fc1 --- /dev/null +++ b/rbac/users_test.go @@ -0,0 +1,55 @@ +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() + if err != nil { + t.Errorf("Unexpected error when creating RBAC instance: %+v", err) + } + rbac.Debug(false) + + users := rbac.Users() + + // clean up env + { + // just making sure we don't have one + // and we're ignoring possible err's + users.Delete("test-user") + } + + // create a user + { + err := users.Create("test-user", "test-password") + if err != nil { + t.Errorf("Error when creating test-user: %+v", err) + } + } + + // delete a user + { + err := users.Delete("test-user") + if err != nil { + t.Errorf("Error when deleting test-user: %+v", err) + } + } + + // 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") + } + } +} diff --git a/rbac/util.go b/rbac/util.go new file mode 100644 index 000000000..5b3c9f9ed --- /dev/null +++ b/rbac/util.go @@ -0,0 +1,15 @@ +package rbac + +import ( + "github.com/pkg/errors" + "io/ioutil" + "net/http" +) + +func toError(resp *http.Response) error { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return errors.Errorf("unexpected response (%d)", resp.StatusCode) + } + return errors.New(string(body)) +}