From cd2eb0e39b2d83e62f584043e1dd1b9ffb6c7a50 Mon Sep 17 00:00:00 2001 From: Ilja Neumann Date: Fri, 18 Dec 2020 08:45:22 +0100 Subject: [PATCH] Accounts UserBackend tests --- proxy/go.mod | 2 + proxy/go.sum | 3 + proxy/pkg/middleware/account_resolver_test.go | 3 +- proxy/pkg/user/backend/accounts_test.go | 181 ++++++++++++++++++ proxy/pkg/user/backend/cs3.go | 1 - .../user/backend/{ => test}/backend_mock.go | 5 +- 6 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 proxy/pkg/user/backend/accounts_test.go rename proxy/pkg/user/backend/{ => test}/backend_mock.go (98%) diff --git a/proxy/go.mod b/proxy/go.mod index 077644803f..4f2ac481ab 100644 --- a/proxy/go.mod +++ b/proxy/go.mod @@ -10,6 +10,7 @@ require ( github.com/cs3org/go-cs3apis v0.0.0-20201118090759-87929f5bae21 github.com/cs3org/reva v1.4.1-0.20201216095137-5207197217f1 github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/golang/mock v1.4.4 // indirect github.com/justinas/alice v1.2.0 github.com/micro/cli/v2 v2.1.2 github.com/micro/go-micro/v2 v2.9.1 @@ -23,6 +24,7 @@ require ( github.com/owncloud/ocis/store v0.0.0-00010101000000-000000000000 github.com/prometheus/client_golang v1.7.1 github.com/restic/calens v0.2.0 + github.com/rs/zerolog v1.20.0 github.com/spf13/viper v1.7.0 github.com/stretchr/testify v1.6.1 go.opencensus.io v0.22.5 diff --git a/proxy/go.sum b/proxy/go.sum index 356c17708c..9e4d6055f6 100644 --- a/proxy/go.sum +++ b/proxy/go.sum @@ -317,6 +317,8 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -417,6 +419,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/haya14busa/goverage v0.0.0-20180129164344-eec3514a20b5 h1:FdBGmSkD2QpQzRWup//SGObvWf2nq89zj9+ta9OvI3A= github.com/haya14busa/goverage v0.0.0-20180129164344-eec3514a20b5/go.mod h1:0YZ2wQSuwviXXXGUiK6zXzskyBLAbLXhamxzcFHSLoM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= diff --git a/proxy/pkg/middleware/account_resolver_test.go b/proxy/pkg/middleware/account_resolver_test.go index c30364230f..f0b456a6ed 100644 --- a/proxy/pkg/middleware/account_resolver_test.go +++ b/proxy/pkg/middleware/account_resolver_test.go @@ -8,6 +8,7 @@ import ( "github.com/owncloud/ocis/ocis-pkg/oidc" "github.com/owncloud/ocis/proxy/pkg/config" "github.com/owncloud/ocis/proxy/pkg/user/backend" + "github.com/owncloud/ocis/proxy/pkg/user/backend/test" "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" @@ -104,7 +105,7 @@ func TestInternalServerErrorOnMissingMailAndUsername(t *testing.T) { } func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr error) http.Handler { - mock := &backend.UserBackendMock{ + mock := &test.UserBackendMock{ GetUserByClaimsFunc: func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, error) { return userBackendResult, userBackendErr }, diff --git a/proxy/pkg/user/backend/accounts_test.go b/proxy/pkg/user/backend/accounts_test.go new file mode 100644 index 0000000000..14e979a598 --- /dev/null +++ b/proxy/pkg/user/backend/accounts_test.go @@ -0,0 +1,181 @@ +package backend + +import ( + "context" + userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + "github.com/micro/go-micro/v2/client" + accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0" + "github.com/owncloud/ocis/ocis-pkg/log" + "github.com/owncloud/ocis/ocis-pkg/oidc" + settings "github.com/owncloud/ocis/settings/pkg/proto/v0" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "testing" +) + +var mockAccResp = []*accounts.Account{ + { + Id: "1234", + AccountEnabled: true, + DisplayName: "foo", + PreferredName: "prefname", + UidNumber: 1, + GidNumber: 2, + Mail: "foo@example.org", + OnPremisesSamAccountName: "samaccount", + MemberOf: []*accounts.Group{ + {OnPremisesSamAccountName: "g1"}, + {OnPremisesSamAccountName: "g2"}, + }, + }, +} + +var expectedRoles = []*settings.UserRoleAssignment{ + {Id: "abc", AccountUuid: "1234", RoleId: "a"}, + {Id: "def", AccountUuid: "1234", RoleId: "b"}, +} + +func TestGetUserByClaimsFound(t *testing.T) { + type testCase struct { + id, claim, value string + } + + var tests = []testCase{ + {id: "Mail", claim: "mail", value: "foo@example.org"}, + {id: "Username", claim: "username", value: "prefname"}, + {id: "ID", claim: "id", value: "1234"}, + } + + accBackend := newAccountsBackend(mockAccResp, expectedRoles) + + for k := range tests { + t.Run(tests[k].id, func(t *testing.T) { + u, err := accBackend.GetUserByClaims(context.Background(), tests[k].claim, tests[k].value, true) + + assert.NoError(t, err) + assert.NotNil(t, u) + assertUserMatchesAccount(t, mockAccResp[0], u) + + }) + } +} + +func TestGetUserByClaimsNotFound(t *testing.T) { + accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles) + + u, err := accBackend.GetUserByClaims(context.Background(), "mail", "foo@example.com", true) + + assert.Error(t, err) + assert.Nil(t, u) + assert.Equal(t, ErrAccountNotFound, err) +} + +func TestGetUserByClaimsInvalidClaim(t *testing.T) { + accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles) + u, err := accBackend.GetUserByClaims(context.Background(), "invalidClaimName", "efwfwfwfe", true) + + assert.Nil(t, u) + assert.Error(t, err) +} + +func TestGetUserByClaimsDisabledAccount(t *testing.T) { + accBackend := newAccountsBackend([]*accounts.Account{{AccountEnabled: false}}, expectedRoles) + u, err := accBackend.GetUserByClaims(context.Background(), "mail", "foo@example.com", true) + + assert.Nil(t, u) + assert.Error(t, err) + assert.Equal(t, ErrAccountDisabled, err) +} + +func TestAuthenticate(t *testing.T) { + accBackend := newAccountsBackend(mockAccResp, expectedRoles) + u, err := accBackend.Authenticate(context.Background(), "foo", "secret") + + assert.NoError(t, err) + assert.NotNil(t, u) + assertUserMatchesAccount(t, mockAccResp[0], u) +} + +func TestAuthenticateFailed(t *testing.T) { + accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles) + u, err := accBackend.Authenticate(context.Background(), "foo", "secret") + + assert.Nil(t, u) + assert.Error(t, err) +} + +func TestCreateUserFromClaims(t *testing.T) { + exp := mockAccResp[0] + accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles) + act, _ := accBackend.CreateUserFromClaims(context.Background(), &oidc.StandardClaims{ + DisplayName: mockAccResp[0].DisplayName, + PreferredUsername: mockAccResp[0].OnPremisesSamAccountName, + Email: mockAccResp[0].Mail, + UIDNumber: "1", + GIDNumber: "2", + Groups: []string{"g1", "g2"}, + }) + + assert.NotNil(t, act.Id) + assert.Equal(t, exp.Id, act.Id.OpaqueId) + assert.Equal(t, exp.Mail, act.Mail) + assert.Equal(t, exp.DisplayName, act.DisplayName) + assert.Equal(t, exp.OnPremisesSamAccountName, act.Username) +} + +func TestGetUserGroupsUnimplemented(t *testing.T) { + accBackend := newAccountsBackend([]*accounts.Account{}, expectedRoles) + assert.Panics(t, func() { accBackend.GetUserGroups(context.Background(), "foo") }) +} + +func assertUserMatchesAccount(t *testing.T, exp *accounts.Account, act *userv1beta1.User) { + // User + assert.NotNil(t, act.Id) + assert.Equal(t, exp.Id, act.Id.OpaqueId) + assert.Equal(t, exp.Mail, act.Mail) + assert.Equal(t, exp.DisplayName, act.DisplayName) + assert.Equal(t, exp.OnPremisesSamAccountName, act.Username) + + // Groups + assert.ElementsMatch(t, []string{"g1", "g2"}, act.Groups) + + // Roles + assert.NotNil(t, act.Opaque.Map["roles"]) + assert.Equal(t, `["a","b"]`, string(act.Opaque.Map["roles"].GetValue())) + + // UID/GID + assert.NotNil(t, act.Opaque.Map["uid"]) + assert.Equal(t, "1", string(act.Opaque.Map["uid"].GetValue())) + + assert.NotNil(t, act.Opaque.Map["gid"]) + assert.Equal(t, "2", string(act.Opaque.Map["gid"].GetValue())) +} + +func newAccountsBackend(mockAccounts []*accounts.Account, mockRoles []*settings.UserRoleAssignment) UserBackend { + accSvc, roleSvc := getAccountService(mockAccounts, nil), getRoleService(mockRoles, nil) + accBackend := NewAccountsServiceUserBackend(accSvc, roleSvc, "https://idp.example.org", log.NewLogger()) + zerolog.SetGlobalLevel(zerolog.Disabled) + return accBackend +} + +func getAccountService(expectedResponse []*accounts.Account, err error) *accounts.MockAccountsService { + return &accounts.MockAccountsService{ + ListFunc: func(ctx context.Context, in *accounts.ListAccountsRequest, opts ...client.CallOption) (*accounts.ListAccountsResponse, error) { + return &accounts.ListAccountsResponse{Accounts: expectedResponse}, err + }, + CreateFunc: func(ctx context.Context, in *accounts.CreateAccountRequest, opts ...client.CallOption) (*accounts.Account, error) { + a := in.Account + a.Id = "1234" + return a, nil + }, + } +} + +func getRoleService(expectedRespone []*settings.UserRoleAssignment, err error) *settings.MockRoleService { + return &settings.MockRoleService{ + ListRoleAssignmentsFunc: func(ctx context.Context, req *settings.ListRoleAssignmentsRequest, opts ...client.CallOption) (*settings.ListRoleAssignmentsResponse, error) { + return &settings.ListRoleAssignmentsResponse{Assignments: expectedRespone}, err + }, + } + +} diff --git a/proxy/pkg/user/backend/cs3.go b/proxy/pkg/user/backend/cs3.go index 8d830d0715..72a1920e3b 100644 --- a/proxy/pkg/user/backend/cs3.go +++ b/proxy/pkg/user/backend/cs3.go @@ -58,7 +58,6 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, w if len(roleIDs) == 0 { return user, nil - } enc, err := encodeRoleIDs(roleIDs) diff --git a/proxy/pkg/user/backend/backend_mock.go b/proxy/pkg/user/backend/test/backend_mock.go similarity index 98% rename from proxy/pkg/user/backend/backend_mock.go rename to proxy/pkg/user/backend/test/backend_mock.go index a1c21370c1..29287eefa4 100644 --- a/proxy/pkg/user/backend/backend_mock.go +++ b/proxy/pkg/user/backend/test/backend_mock.go @@ -1,18 +1,19 @@ // Code generated by moq; DO NOT EDIT. // github.com/matryer/moq -package backend +package test import ( "context" "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" "github.com/owncloud/ocis/ocis-pkg/oidc" + "github.com/owncloud/ocis/proxy/pkg/user/backend" "sync" ) // Ensure, that UserBackendMock does implement UserBackend. // If this is not the case, regenerate this file with moq. -var _ UserBackend = &UserBackendMock{} +var _ backend.UserBackend = &UserBackendMock{} // UserBackendMock is a mock implementation of UserBackend. //