2021-05-12 12:38:18 +00:00
|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
2021-07-13 15:16:35 +00:00
|
|
|
"bytes"
|
2021-05-12 12:38:18 +00:00
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-07-13 15:16:35 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2021-10-15 14:57:44 +00:00
|
|
|
"os"
|
2021-05-12 12:38:18 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
2021-07-22 09:25:30 +00:00
|
|
|
// mockClient is the mock of the HTTP Client
|
|
|
|
// It can be used to mock HTTP request/response from the rgw admin ops API
|
|
|
|
type mockClient struct {
|
|
|
|
// mockDo is a type that mock the Do method from the HTTP package
|
|
|
|
mockDo mockDoType
|
|
|
|
}
|
|
|
|
|
|
|
|
// mockDoType is a custom type that allows setting the function that our Mock Do func will run instead
|
|
|
|
type mockDoType func(req *http.Request) (*http.Response, error)
|
|
|
|
|
|
|
|
// Do is the mock client's `Do` func
|
|
|
|
func (m *mockClient) Do(req *http.Request) (*http.Response, error) { return m.mockDo(req) }
|
|
|
|
|
2021-05-12 12:38:18 +00:00
|
|
|
var (
|
|
|
|
fakeUserResponse = []byte(`
|
|
|
|
{
|
|
|
|
"tenant": "",
|
|
|
|
"user_id": "dashboard-admin",
|
|
|
|
"display_name": "dashboard-admin",
|
|
|
|
"email": "",
|
|
|
|
"suspended": 0,
|
|
|
|
"max_buckets": 1000,
|
2022-02-24 17:07:30 +00:00
|
|
|
"subusers": [
|
|
|
|
{
|
|
|
|
"id": "dashboard-admin:swift",
|
|
|
|
"permissions": "read"
|
|
|
|
}
|
|
|
|
],
|
2021-05-12 12:38:18 +00:00
|
|
|
"keys": [
|
|
|
|
{
|
|
|
|
"user": "dashboard-admin",
|
|
|
|
"access_key": "4WD1FGM5PXKLC97YC0SZ",
|
|
|
|
"secret_key": "YSaT5bEcJTjBJCDG5yvr2NhGQ9xzoTIg8B1gQHa3"
|
|
|
|
}
|
|
|
|
],
|
2022-02-24 17:07:30 +00:00
|
|
|
"swift_keys": [
|
|
|
|
{
|
|
|
|
"user": "dashboard-admin:swift",
|
|
|
|
"secret_key": "VERY_SECRET"
|
|
|
|
}
|
|
|
|
],
|
2021-05-12 12:38:18 +00:00
|
|
|
"caps": [],
|
|
|
|
"op_mask": "read, write, delete",
|
|
|
|
"system": "true",
|
|
|
|
"admin": "false",
|
|
|
|
"default_placement": "",
|
|
|
|
"default_storage_class": "",
|
|
|
|
"placement_tags": [],
|
|
|
|
"bucket_quota": {
|
|
|
|
"enabled": false,
|
|
|
|
"check_on_raw": false,
|
|
|
|
"max_size": -1,
|
|
|
|
"max_size_kb": 0,
|
|
|
|
"max_objects": -1
|
|
|
|
},
|
|
|
|
"user_quota": {
|
|
|
|
"enabled": false,
|
|
|
|
"check_on_raw": false,
|
|
|
|
"max_size": -1,
|
|
|
|
"max_size_kb": 0,
|
|
|
|
"max_objects": -1
|
|
|
|
},
|
|
|
|
"temp_url_keys": [],
|
|
|
|
"type": "rgw",
|
|
|
|
"mfa_ids": []
|
|
|
|
}`)
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestUnmarshal(t *testing.T) {
|
|
|
|
u := &User{}
|
|
|
|
err := json.Unmarshal(fakeUserResponse, &u)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *RadosGWTestSuite) TestUser() {
|
|
|
|
suite.SetupConnection()
|
2021-07-27 16:21:53 +00:00
|
|
|
co, err := New(suite.endpoint, suite.accessKey, suite.secretKey, newDebugHTTPClient(http.DefaultClient))
|
2021-05-12 12:38:18 +00:00
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
|
|
|
|
suite.T().Run("fail to create user since no UID provided", func(t *testing.T) {
|
|
|
|
_, err = co.CreateUser(context.Background(), User{Email: "leseb@example.com"})
|
|
|
|
assert.Error(suite.T(), err)
|
|
|
|
assert.EqualError(suite.T(), err, errMissingUserID.Error())
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("fail to create user since no no display name provided", func(t *testing.T) {
|
|
|
|
_, err = co.CreateUser(context.Background(), User{ID: "leseb", Email: "leseb@example.com"})
|
|
|
|
assert.Error(suite.T(), err)
|
|
|
|
assert.EqualError(suite.T(), err, errMissingUserDisplayName.Error())
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("user creation success", func(t *testing.T) {
|
2021-08-09 18:54:02 +00:00
|
|
|
usercaps := "users=read"
|
|
|
|
user, err := co.CreateUser(context.Background(), User{ID: "leseb", DisplayName: "This is leseb", Email: "leseb@example.com", UserCaps: usercaps})
|
2021-05-12 12:38:18 +00:00
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), "leseb@example.com", user.Email)
|
|
|
|
})
|
|
|
|
|
2021-10-15 14:57:44 +00:00
|
|
|
suite.T().Run("get user leseb by uid", func(t *testing.T) {
|
2021-05-12 12:38:18 +00:00
|
|
|
user, err := co.GetUser(context.Background(), User{ID: "leseb"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), "leseb@example.com", user.Email)
|
2021-08-09 18:54:02 +00:00
|
|
|
assert.Equal(suite.T(), "users", user.Caps[0].Type)
|
|
|
|
assert.Equal(suite.T(), "read", user.Caps[0].Perm)
|
2021-10-15 14:57:44 +00:00
|
|
|
os.Setenv("LESEB_ACCESS_KEY", user.Keys[0].AccessKey)
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("get user leseb by key", func(t *testing.T) {
|
|
|
|
user, err := co.GetUser(context.Background(), User{Keys: []UserKeySpec{{AccessKey: os.Getenv("LESEB_ACCESS_KEY")}}})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), "leseb@example.com", user.Email)
|
|
|
|
os.Unsetenv("LESEB_ACCESS_KEY")
|
2021-05-12 12:38:18 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("modify user email", func(t *testing.T) {
|
|
|
|
user, err := co.ModifyUser(context.Background(), User{ID: "leseb", Email: "leseb@leseb.com"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), "leseb@leseb.com", user.Email)
|
|
|
|
})
|
|
|
|
|
2021-06-04 11:22:52 +00:00
|
|
|
suite.T().Run("modify user max bucket", func(t *testing.T) {
|
|
|
|
maxBuckets := -1
|
|
|
|
user, err := co.ModifyUser(context.Background(), User{ID: "leseb", MaxBuckets: &maxBuckets})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), "leseb@leseb.com", user.Email)
|
|
|
|
assert.Equal(suite.T(), -1, *user.MaxBuckets)
|
|
|
|
})
|
|
|
|
|
2021-05-12 12:38:18 +00:00
|
|
|
suite.T().Run("user already exists", func(t *testing.T) {
|
|
|
|
_, err := co.CreateUser(context.Background(), User{ID: "admin", DisplayName: "Admin user"})
|
|
|
|
assert.Error(suite.T(), err)
|
|
|
|
assert.True(suite.T(), errors.Is(err, ErrUserExists), fmt.Sprintf("%+v", err))
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("get users", func(t *testing.T) {
|
|
|
|
users, err := co.GetUsers(context.Background())
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), 2, len(*users))
|
|
|
|
})
|
|
|
|
|
2021-06-04 11:22:52 +00:00
|
|
|
suite.T().Run("set user quota", func(t *testing.T) {
|
|
|
|
quotaEnable := true
|
|
|
|
maxObjects := int64(100)
|
|
|
|
err := co.SetUserQuota(context.Background(), QuotaSpec{QuotaType: "user", UID: "leseb", MaxObjects: &maxObjects, Enabled: "aEnable})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("get user quota", func(t *testing.T) {
|
|
|
|
q, err := co.GetUserQuota(context.Background(), QuotaSpec{QuotaType: "user", UID: "leseb"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.Equal(suite.T(), int64(100), *q.MaxObjects)
|
|
|
|
})
|
|
|
|
|
2021-08-05 08:39:09 +00:00
|
|
|
suite.T().Run("get user stat", func(t *testing.T) {
|
|
|
|
statEnable := true
|
|
|
|
user, err := co.GetUser(context.Background(), User{ID: "leseb", GenerateStat: &statEnable})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
assert.NotNil(suite.T(), user.Stat.Size)
|
|
|
|
})
|
|
|
|
|
2022-02-24 17:07:30 +00:00
|
|
|
suite.T().Run("create a subuser", func(t *testing.T) {
|
|
|
|
err := co.CreateSubuser(context.Background(), User{ID: "leseb"}, SubuserSpec{Name: "foo", Access: SubuserAccessReadWrite})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
|
|
|
|
user, err := co.GetUser(context.Background(), User{ID: "leseb"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
if err == nil {
|
|
|
|
assert.Equal(suite.T(), user.Subusers[0].Name, "leseb:foo")
|
|
|
|
// Note: the returned values are not equal to the input values ...
|
|
|
|
assert.Equal(suite.T(), user.Subusers[0].Access, SubuserAccess("read-write"))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("modify a subuser", func(t *testing.T) {
|
|
|
|
err := co.ModifySubuser(context.Background(), User{ID: "leseb"}, SubuserSpec{Name: "foo", Access: SubuserAccessRead})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
|
|
|
|
user, err := co.GetUser(context.Background(), User{ID: "leseb"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
if err == nil {
|
|
|
|
assert.Equal(suite.T(), user.Subusers[0].Name, "leseb:foo")
|
|
|
|
assert.Equal(suite.T(), user.Subusers[0].Access, SubuserAccess("read"))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
suite.T().Run("remove a subuser", func(t *testing.T) {
|
|
|
|
err := co.RemoveSubuser(context.Background(), User{ID: "leseb"}, SubuserSpec{Name: "foo"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
|
|
|
|
user, err := co.GetUser(context.Background(), User{ID: "leseb"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
if err == nil {
|
|
|
|
assert.Equal(suite.T(), len(user.Subusers), 0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-05-12 12:38:18 +00:00
|
|
|
suite.T().Run("remove user", func(t *testing.T) {
|
|
|
|
err = co.RemoveUser(context.Background(), User{ID: "leseb"})
|
|
|
|
assert.NoError(suite.T(), err)
|
|
|
|
})
|
|
|
|
}
|
2021-07-13 15:16:35 +00:00
|
|
|
|
|
|
|
func TestGetUserMockAPI(t *testing.T) {
|
2021-10-15 14:57:44 +00:00
|
|
|
t.Run("test simple api mock", func(t *testing.T) {
|
|
|
|
api, err := New("127.0.0.1", "accessKey", "secretKey", returnMockClient())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
u, err := api.GetUser(context.TODO(), User{ID: "dashboard-admin"})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "dashboard-admin", u.DisplayName, u)
|
|
|
|
})
|
|
|
|
t.Run("test get user with access key", func(t *testing.T) {
|
|
|
|
api, err := New("127.0.0.1", "accessKey", "secretKey", returnMockClient())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
u, err := api.GetUser(context.TODO(), User{Keys: []UserKeySpec{{AccessKey: "4WD1FGM5PXKLC97YC0SZ"}}})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "dashboard-admin", u.DisplayName, u)
|
|
|
|
})
|
|
|
|
t.Run("test get user with nothing", func(t *testing.T) {
|
|
|
|
api, err := New("127.0.0.1", "accessKey", "secretKey", returnMockClient())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
_, err = api.GetUser(context.TODO(), User{})
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.EqualError(t, err, "missing user ID")
|
|
|
|
})
|
|
|
|
t.Run("test get user with missing correct key", func(t *testing.T) {
|
|
|
|
api, err := New("127.0.0.1", "accessKey", "secretKey", returnMockClient())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
_, err = api.GetUser(context.TODO(), User{Keys: []UserKeySpec{{SecretKey: "4WD1FGM5PXKLC97YC0SZ"}}})
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.EqualError(t, err, "missing user access key")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func returnMockClient() *mockClient {
|
2021-07-13 15:16:35 +00:00
|
|
|
r := ioutil.NopCloser(bytes.NewReader(fakeUserResponse))
|
2021-10-15 14:57:44 +00:00
|
|
|
return &mockClient{
|
2021-07-22 09:25:30 +00:00
|
|
|
mockDo: func(req *http.Request) (*http.Response, error) {
|
2021-10-15 14:57:44 +00:00
|
|
|
if req.Method == http.MethodGet && req.URL.Path == "127.0.0.1/admin/user" {
|
2021-07-13 15:16:35 +00:00
|
|
|
return &http.Response{
|
|
|
|
StatusCode: 200,
|
|
|
|
Body: r,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("unexpected request: %q. method %q. path %q", req.URL.RawQuery, req.Method, req.URL.Path)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|