Remove "accounts" service

This commit is contained in:
Ralf Haferkamp
2022-05-11 15:29:34 +02:00
committed by Ralf Haferkamp
parent 5ba1b8f2c1
commit d25aa7b20f
123 changed files with 80 additions and 28807 deletions
-19
View File
@@ -8,12 +8,9 @@ import (
"os"
"time"
accountssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/accounts/v0"
storesvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/cs3org/reva/v2/pkg/token/manager/jwt"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/justinas/alice"
"github.com/oklog/run"
@@ -137,22 +134,6 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config)
revaClient, err := cs3.GetGatewayServiceClient(cfg.Reva.Address)
var userProvider backend.UserBackend
switch cfg.AccountBackend {
case "accounts":
tokenManager, err := jwt.New(map[string]interface{}{
"secret": cfg.TokenManager.JWTSecret,
"expires": int64(24 * 60 * 60),
})
if err != nil {
logger.Error().Err(err).
Msg("Failed to create token manager")
}
userProvider = backend.NewAccountsServiceUserBackend(
accountssvc.NewAccountsService("com.owncloud.api.accounts", grpc.DefaultClient),
rolesClient,
cfg.OIDC.Issuer,
tokenManager,
logger,
)
case "cs3":
userProvider = backend.NewCS3UserBackend(rolesClient, revaClient, cfg.MachineAuthAPIKey, logger)
default:
+3 -11
View File
@@ -96,10 +96,9 @@ type UserinfoCache struct {
// PolicySelector is the toplevel-configuration for different selectors
type PolicySelector struct {
Static *StaticSelectorConf `yaml:"static"`
Migration *MigrationSelectorConf `yaml:"migration"`
Claims *ClaimsSelectorConf `yaml:"claims"`
Regex *RegexSelectorConf `yaml:"regex"`
Static *StaticSelectorConf `yaml:"static"`
Claims *ClaimsSelectorConf `yaml:"claims"`
Regex *RegexSelectorConf `yaml:"regex"`
}
// StaticSelectorConf is the config for the static-policy-selector
@@ -118,13 +117,6 @@ type PreSignedURL struct {
Enabled bool `yaml:"enabled" env:"PROXY_ENABLE_PRESIGNEDURLS"`
}
// MigrationSelectorConf is the config for the migration-selector
type MigrationSelectorConf struct {
AccFoundPolicy string `yaml:"acc_found_policy"`
AccNotFoundPolicy string `yaml:"acc_not_found_policy"`
UnauthenticatedPolicy string `yaml:"unauthenticated_policy"`
}
// ClaimsSelectorConf is the config for the claims-selector
type ClaimsSelectorConf struct {
DefaultPolicy string `yaml:"default_policy"`
@@ -124,7 +124,6 @@ func newBasicAuth(options Options) func(http.Handler) http.Handler {
UserProvider(options.UserProvider),
Logger(options.Logger),
EnableBasicAuth(options.EnableBasicAuth),
AccountsClient(options.AccountsClient),
OIDCIss(options.OIDCIss),
UserOIDCClaim(options.UserOIDCClaim),
UserCS3Claim(options.UserCS3Claim),
@@ -6,7 +6,6 @@ import (
"github.com/owncloud/ocis/v2/extensions/proxy/pkg/user/backend"
accountssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/accounts/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
storesvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0"
@@ -28,8 +27,6 @@ type Options struct {
PolicySelector config.PolicySelector
// HTTPClient to use for communication with the oidcAuth provider
HTTPClient *http.Client
// AccountsClient for resolving accounts
AccountsClient accountssvc.AccountsService
// UP
UserProvider backend.UserBackend
// SettingsRoleService for the roles API in settings
@@ -99,13 +96,6 @@ func HTTPClient(c *http.Client) Option {
}
}
// AccountsClient provides a function to set the accounts client config option.
func AccountsClient(ac accountssvc.AccountsService) Option {
return func(o *Options) {
o.AccountsClient = ac
}
}
// SettingsRoleService provides a function to set the role service option.
func SettingsRoleService(rc settingssvc.RoleService) Option {
return func(o *Options) {
+1 -48
View File
@@ -6,10 +6,7 @@ import (
"regexp"
"sort"
accountssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/accounts/v0"
revactx "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/go-micro/plugins/v4/client/grpc"
"github.com/owncloud/ocis/v2/extensions/proxy/pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
)
@@ -58,9 +55,6 @@ type Selector func(r *http.Request) (string, error)
func LoadSelector(cfg *config.PolicySelector) (Selector, error) {
selCount := 0
if cfg.Migration != nil {
selCount++
}
if cfg.Static != nil {
selCount++
}
@@ -74,7 +68,7 @@ func LoadSelector(cfg *config.PolicySelector) (Selector, error) {
return nil, ErrMultipleSelectors
}
if cfg.Migration == nil && cfg.Static == nil && cfg.Claims == nil && cfg.Regex == nil {
if cfg.Static == nil && cfg.Claims == nil && cfg.Regex == nil {
return nil, ErrSelectorConfigIncomplete
}
@@ -82,12 +76,6 @@ func LoadSelector(cfg *config.PolicySelector) (Selector, error) {
return NewStaticSelector(cfg.Static), nil
}
if cfg.Migration != nil {
return NewMigrationSelector(
cfg.Migration,
accountssvc.NewAccountsService("com.owncloud.accounts", grpc.NewClient())), nil
}
if cfg.Claims != nil {
if cfg.Claims.SelectorCookieName == "" {
cfg.Claims.SelectorCookieName = SelectorCookieName
@@ -118,41 +106,6 @@ func NewStaticSelector(cfg *config.StaticSelectorConf) Selector {
}
}
// NewMigrationSelector selects the policy based on the existence of the oidc "preferred_username" claim in the accounts-service.
// The policy for each case is configurable:
// "policy_selector": {
// "migration": {
// "acc_found_policy" : "ocis",
// "acc_not_found_policy": "oc10",
// "unauthenticated_policy": "oc10"
// }
// },
//
// This selector can be used in migration-scenarios where some users have already migrated from ownCloud10 to OCIS and
// thus have an entry in ocis-accounts. All users without accounts entry are routed to the legacy ownCloud10 instance.
func NewMigrationSelector(cfg *config.MigrationSelectorConf, ss accountssvc.AccountsService) Selector {
var acc = ss
return func(r *http.Request) (s string, err error) {
var claims map[string]interface{}
if claims = oidc.FromContext(r.Context()); claims == nil {
return cfg.UnauthenticatedPolicy, nil
}
var userID string
var ok bool
if userID, ok = claims[oidc.PreferredUsername].(string); !ok {
// TODO clarify: what if the user just has no username ...
return cfg.AccNotFoundPolicy, nil
}
if _, err := acc.GetAccount(r.Context(), &accountssvc.GetAccountRequest{Id: userID}); err != nil {
return cfg.AccNotFoundPolicy, nil
}
return cfg.AccFoundPolicy, nil
}
}
// NewClaimsSelector selects the policy based on the "ocis.routing.policy" claim
// The policy for corner cases is configurable:
// "policy_selector": {
@@ -2,7 +2,6 @@ package policy
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"testing"
@@ -11,9 +10,6 @@ import (
revactx "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/owncloud/ocis/v2/extensions/proxy/pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
accountsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/accounts/v0"
accountssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/accounts/v0"
"go-micro.dev/v4/client"
)
func TestLoadSelector(t *testing.T) {
@@ -22,20 +18,13 @@ func TestLoadSelector(t *testing.T) {
expectedErr error
}
sCfg := &config.StaticSelectorConf{Policy: "reva"}
mcfg := &config.MigrationSelectorConf{
AccFoundPolicy: "found",
AccNotFoundPolicy: "not_found",
UnauthenticatedPolicy: "unauth",
}
ccfg := &config.ClaimsSelectorConf{}
rcfg := &config.RegexSelectorConf{}
table := []test{
{cfg: &config.PolicySelector{Static: sCfg, Migration: mcfg}, expectedErr: ErrMultipleSelectors},
{cfg: &config.PolicySelector{Static: sCfg, Claims: ccfg, Regex: rcfg}, expectedErr: ErrMultipleSelectors},
{cfg: &config.PolicySelector{}, expectedErr: ErrSelectorConfigIncomplete},
{cfg: &config.PolicySelector{Static: sCfg}, expectedErr: nil},
{cfg: &config.PolicySelector{Migration: mcfg}, expectedErr: nil},
{cfg: &config.PolicySelector{Claims: ccfg}, expectedErr: nil},
{cfg: &config.PolicySelector{Regex: rcfg}, expectedErr: nil},
}
@@ -74,60 +63,6 @@ func TestStaticSelector(t *testing.T) {
}
}
type migrationTestCase struct {
AccSvcShouldReturnError bool
Claims map[string]interface{}
Expected string
}
func TestMigrationSelector(t *testing.T) {
cfg := config.MigrationSelectorConf{
AccFoundPolicy: "found",
AccNotFoundPolicy: "not_found",
UnauthenticatedPolicy: "unauth",
}
var tests = []migrationTestCase{
{true, map[string]interface{}{oidc.PreferredUsername: "Hans"}, "not_found"},
{true, map[string]interface{}{oidc.Email: "hans@example.test"}, "not_found"},
{false, map[string]interface{}{oidc.PreferredUsername: "Hans"}, "found"},
{false, nil, "unauth"},
}
for _, tc := range tests {
tc := tc
sut := NewMigrationSelector(&cfg, mockAccSvc(tc.AccSvcShouldReturnError))
r := httptest.NewRequest("GET", "https://example.com", nil)
ctx := oidc.NewContext(r.Context(), tc.Claims)
nr := r.WithContext(ctx)
got, err := sut(nr)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if got != tc.Expected {
t.Errorf("Expected Policy %v got %v", tc.Expected, got)
}
}
}
func mockAccSvc(retErr bool) accountssvc.AccountsService {
if retErr {
return &accountssvc.MockAccountsService{
GetFunc: func(ctx context.Context, in *accountssvc.GetAccountRequest, opts ...client.CallOption) (record *accountsmsg.Account, err error) {
return nil, fmt.Errorf("error returned by mockAccountsService GET")
},
}
}
return &accountssvc.MockAccountsService{
GetFunc: func(ctx context.Context, in *accountssvc.GetAccountRequest, opts ...client.CallOption) (record *accountsmsg.Account, err error) {
return &accountsmsg.Account{}, nil
},
}
}
type testCase struct {
Name string
Context context.Context
@@ -1,257 +0,0 @@
package backend
import (
"context"
"fmt"
"net/http"
"strings"
accountsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/accounts/v0"
accountssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/accounts/v0"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/auth/scope"
"github.com/cs3org/reva/v2/pkg/token"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
)
// NewAccountsServiceUserBackend creates a user-provider which fetches users from the ocis accounts-service
func NewAccountsServiceUserBackend(ac accountssvc.AccountsService, rs settingssvc.RoleService, oidcISS string, tokenManager token.Manager, logger log.Logger) UserBackend {
return &accountsServiceBackend{
accountsClient: ac,
settingsRoleService: rs,
OIDCIss: oidcISS,
tokenManager: tokenManager,
logger: logger,
}
}
type accountsServiceBackend struct {
accountsClient accountssvc.AccountsService
settingsRoleService settingssvc.RoleService
OIDCIss string
logger log.Logger
tokenManager token.Manager
}
func (a accountsServiceBackend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error) {
var account *accountsmsg.Account
var status int
var query string
switch claim {
case "mail":
query = fmt.Sprintf("mail eq '%s'", strings.ReplaceAll(value, "'", "''"))
case "username":
query = fmt.Sprintf("preferred_name eq '%s'", strings.ReplaceAll(value, "'", "''"))
case "id":
query = fmt.Sprintf("id eq '%s'", strings.ReplaceAll(value, "'", "''"))
default:
return nil, "", fmt.Errorf("invalid user by claim lookup must be 'mail', 'username' or 'id")
}
account, status = a.getAccount(ctx, query)
if status == http.StatusNotFound {
return nil, "", ErrAccountNotFound
}
if status != 0 || account == nil {
return nil, "", fmt.Errorf("could not get account, got status: %d", status)
}
if !account.AccountEnabled {
return nil, "", ErrAccountDisabled
}
user := a.accountToUser(account)
if withRoles {
if err := injectRoles(ctx, user, a.settingsRoleService); err != nil {
a.logger.Warn().Err(err).Msgf("Could not load roles... continuing without")
}
}
token, err := a.generateToken(ctx, user)
if err != nil {
return nil, "", err
}
return user, token, nil
}
// Authenticate authenticates against the accounts services and returns the user on success
func (a *accountsServiceBackend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error) {
query := fmt.Sprintf(
"login eq '%s' and password eq '%s'",
strings.ReplaceAll(username, "'", "''"),
strings.ReplaceAll(password, "'", "''"),
)
account, status := a.getAccount(ctx, query)
if status != 0 {
return nil, "", fmt.Errorf("could not authenticate with username, password for user %s. Status: %d", username, status)
}
user := a.accountToUser(account)
token, err := a.generateToken(ctx, user)
if err != nil {
return nil, "", err
}
if err := injectRoles(ctx, user, a.settingsRoleService); err != nil {
a.logger.Warn().Err(err).Msgf("Could not load roles... continuing without")
}
return user, token, nil
}
func (a accountsServiceBackend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error) {
req := &accountssvc.CreateAccountRequest{
Account: &accountsmsg.Account{
CreationType: "LocalAccount",
AccountEnabled: true,
},
}
var ok bool
if req.Account.DisplayName, ok = claims[oidc.Name].(string); !ok {
a.logger.Debug().Msg("Missing name claim, trying displayname")
if req.Account.DisplayName, ok = claims["displayname"].(string); !ok {
a.logger.Debug().Msg("Missing displayname claim")
}
}
if req.Account.PreferredName, ok = claims[oidc.PreferredUsername].(string); !ok {
a.logger.Warn().Msg("Missing preferred_username claim, falling back to email")
if req.Account.PreferredName, ok = claims[oidc.Email].(string); !ok {
a.logger.Debug().Msg("Missing email claim as well")
}
}
if req.Account.PreferredName != "" {
// also use as on premises samaccount name
req.Account.OnPremisesSamAccountName = req.Account.PreferredName
}
if req.Account.Mail, ok = claims[oidc.Email].(string); !ok {
a.logger.Warn().Msg("Missing email claim")
}
created, err := a.accountsClient.CreateAccount(context.Background(), req)
if err != nil {
return nil, err
}
user := a.accountToUser(created)
if err := injectRoles(ctx, user, a.settingsRoleService); err != nil {
a.logger.Warn().Err(err).Msg("Could not load roles... continuing without")
}
return user, nil
}
func (a accountsServiceBackend) GetUserGroups(ctx context.Context, userID string) {
panic("implement me")
}
// accountToUser converts an owncloud account struct to a reva user struct. In the proxy
// we work with the reva struct as a token can be minted from it.
func (a *accountsServiceBackend) accountToUser(account *accountsmsg.Account) *cs3.User {
user := &cs3.User{
Id: &cs3.UserId{
OpaqueId: account.Id,
Idp: a.OIDCIss,
Type: cs3.UserType_USER_TYPE_PRIMARY, // TODO: once we have support for other user types, this needs to be inferred
},
Username: account.OnPremisesSamAccountName,
DisplayName: account.DisplayName,
Mail: account.Mail,
MailVerified: account.ExternalUserState == "" || account.ExternalUserState == "Accepted",
Groups: expandGroups(account),
UidNumber: account.UidNumber,
GidNumber: account.GidNumber,
}
return user
}
func (a *accountsServiceBackend) getAccount(ctx context.Context, query string) (account *accountsmsg.Account, status int) {
resp, err := a.accountsClient.ListAccounts(ctx, &accountssvc.ListAccountsRequest{
Query: query,
PageSize: 2,
})
if err != nil {
a.logger.Error().Err(err).Str("query", query).Msgf("error fetching from accounts-service")
status = http.StatusInternalServerError
return
}
if len(resp.Accounts) <= 0 {
a.logger.Error().Str("query", query).Msgf("account not found")
status = http.StatusNotFound
return
}
if len(resp.Accounts) > 1 {
a.logger.Error().Str("query", query).Msgf("more than one account found, aborting")
status = http.StatusForbidden
return
}
account = resp.Accounts[0]
return
}
func (a *accountsServiceBackend) generateToken(ctx context.Context, u *cs3.User) (string, error) {
s, err := scope.AddOwnerScope(nil)
if err != nil {
a.logger.Error().Err(err).Msg("could not get owner scope")
return "", err
}
token, err := a.tokenManager.MintToken(ctx, u, s)
if err != nil {
a.logger.Error().Err(err).Msg("could not mint token")
return "", err
}
return token, nil
}
func expandGroups(account *accountsmsg.Account) []string {
groups := make([]string, len(account.MemberOf))
for i := range account.MemberOf {
// reva needs the unix group name
groups[i] = account.MemberOf[i].OnPremisesSamAccountName
}
return groups
}
// injectRoles adds roles from the roles-service to the user-struct by mutating an existing struct
func injectRoles(ctx context.Context, u *cs3.User, ss settingssvc.RoleService) error {
roleIDs, err := loadRolesIDs(ctx, u.Id.OpaqueId, ss)
if err != nil {
return err
}
if len(roleIDs) == 0 {
return nil
}
enc, err := encodeRoleIDs(roleIDs)
if err != nil {
return err
}
if u.Opaque == nil {
u.Opaque = &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"roles": enc,
},
}
} else {
u.Opaque.Map["roles"] = enc
}
return nil
}
@@ -1,186 +0,0 @@
package backend
import (
"context"
"testing"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/v2/pkg/token/manager/jwt"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
accountsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/accounts/v0"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
accountssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/accounts/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"go-micro.dev/v4/client"
)
var mockAccResp = []*accountsmsg.Account{
{
Id: "1234",
AccountEnabled: true,
DisplayName: "foo",
PreferredName: "prefname",
UidNumber: 1,
GidNumber: 2,
Mail: "foo@example.org",
OnPremisesSamAccountName: "samaccount",
MemberOf: []*accountsmsg.Group{
{OnPremisesSamAccountName: "g1"},
{OnPremisesSamAccountName: "g2"},
},
},
}
var expectedRoles = []*settingsmsg.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([]*accountsmsg.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([]*accountsmsg.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([]*accountsmsg.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([]*accountsmsg.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([]*accountsmsg.Account{}, expectedRoles)
act, _ := accBackend.CreateUserFromClaims(context.Background(), map[string]interface{}{
oidc.Name: mockAccResp[0].DisplayName,
oidc.PreferredUsername: mockAccResp[0].OnPremisesSamAccountName,
oidc.Email: mockAccResp[0].Mail,
oidc.UIDNumber: "1",
oidc.GIDNumber: "2",
oidc.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([]*accountsmsg.Account{}, expectedRoles)
assert.Panics(t, func() { accBackend.GetUserGroups(context.Background(), "foo") })
}
func assertUserMatchesAccount(t *testing.T, exp *accountsmsg.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.Equal(t, int64(1), act.UidNumber)
assert.Equal(t, int64(2), act.GidNumber)
}
func newAccountsBackend(mockAccounts []*accountsmsg.Account, mockRoles []*settingsmsg.UserRoleAssignment) UserBackend {
accSvc, roleSvc := getAccountService(mockAccounts, nil), getRoleService(mockRoles, nil)
tokenManager, _ := jwt.New(map[string]interface{}{
"secret": "change-me",
"expires": int64(24 * 60 * 60),
})
accBackend := NewAccountsServiceUserBackend(accSvc, roleSvc, "https://idp.example.org", tokenManager, log.NewLogger())
zerolog.SetGlobalLevel(zerolog.Disabled)
return accBackend
}
func getAccountService(expectedResponse []*accountsmsg.Account, err error) *accountssvc.MockAccountsService {
return &accountssvc.MockAccountsService{
ListFunc: func(ctx context.Context, in *accountssvc.ListAccountsRequest, opts ...client.CallOption) (*accountssvc.ListAccountsResponse, error) {
return &accountssvc.ListAccountsResponse{Accounts: expectedResponse}, err
},
CreateFunc: func(ctx context.Context, in *accountssvc.CreateAccountRequest, opts ...client.CallOption) (*accountsmsg.Account, error) {
a := in.Account
a.Id = "1234"
return a, nil
},
}
}
func getRoleService(expectedResponse []*settingsmsg.UserRoleAssignment, err error) *settingssvc.MockRoleService {
return &settingssvc.MockRoleService{
ListRoleAssignmentsFunc: func(ctx context.Context, req *settingssvc.ListRoleAssignmentsRequest, opts ...client.CallOption) (*settingssvc.ListRoleAssignmentsResponse, error) {
return &settingssvc.ListRoleAssignmentsResponse{Assignments: expectedResponse}, err
},
}
}