-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
maintain: track provider groups separate from users
- join group membership from provider group relation - unlink provider groups from groups on deletion - migrate provider user groups to provider groups
- Loading branch information
Showing
23 changed files
with
1,389 additions
and
200 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Identity Provider Tracking | ||
Infra tracks users and groups that exist in external identity providers and maps them access. The following database diagram shows how the relation of groups and users in identity providers are mapped to users and groups within Infra. | ||
|
||
Our identity system has two different type of relations, one of which exists in Infra (users and groups controlled by Infra), and the other relation which exists externally (information about users and groups which exist in an identity provider). | ||
|
||
To get all the groups a user belongs to as a combination of direct group membership and membership in a mapped identity provider group use the `resolved_identity_groups` view. | ||
|
||
## Users and Groups Managed by Infra | ||
The following tables represent users whose identity is managed by Infra and groups which are controlled by Infra. | ||
- **Identities**: Known information about a user. This may be a an email and password hash that can be used to login to Infra directly, or information about a user that has logged via an identity provider. | ||
- **Groups**: Groups which exist in Infra that membership to grants access to some resource. | ||
- **Identities_Groups**: Identities that have been added as a member of a group within Infra, this membership is added through either membership in an external identity provider group or through direct assignment (represented in the database as being part of an Infra provider group). | ||
|
||
## Users and Groups Managed by an Identity Provider | ||
- **Provider_User**: A user that exists in an identity provider. | ||
- **Provider_Group**: A group that exists in an identity provider. | ||
- **Provider_Groups_Provider_Users**: This relation shows which users of an identity provders are members of which groups in the same identity provider. | ||
|
||
```mermaid | ||
erDiagram | ||
PROVIDER_GROUPS_MAPPINGS }o--|| PROVIDER : "" | ||
GROUP ||--o{ IDENTITIES_GROUPS : "direct membership to infra group" | ||
IDENTITIES_GROUPS }o--|| IDENTITY : "direct membership to infra group" | ||
IDENTITY ||--o{ PROVIDER_USER : "infra identity composed of identity provider users" | ||
PROVIDER_GROUP }o--|| PROVIDER : "sync groups to infra" | ||
PROVIDER_GROUP ||--o{ PROVIDER_GROUPS_PROVIDER_USERS : "sync members to infra" | ||
PROVIDER_GROUPS_PROVIDER_USERS }o--|| PROVIDER_USER : "sync members to infra" | ||
PROVIDER_USER }o--|| PROVIDER : "sync identities to infra" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,11 +71,14 @@ func TestOIDCAuthenticate(t *testing.T) { | |
// user should be created | ||
assert.Equal(t, authnIdentity.Identity.Name, "[email protected]") | ||
|
||
syncGroups, err := data.ListGroups(db, nil, data.ByGroupMember(authnIdentity.Identity.ID)) | ||
assert.NilError(t, err) | ||
|
||
groups := make(map[string]bool) | ||
for _, g := range authnIdentity.Identity.Groups { | ||
for _, g := range syncGroups { | ||
groups[g.Name] = true | ||
} | ||
assert.Assert(t, len(authnIdentity.Identity.Groups) == 2) | ||
assert.Equal(t, len(syncGroups), 2) | ||
assert.Equal(t, groups["Everyone"], true) | ||
assert.Equal(t, groups["developers"], true) | ||
|
||
|
@@ -198,31 +201,21 @@ func TestExchangeAuthCodeForProviderTokens(t *testing.T) { | |
err := data.CreateIdentity(db, user) | ||
assert.NilError(t, err) | ||
|
||
for _, name := range []string{"Foo", "existing3"} { | ||
group := &models.Group{Name: name} | ||
err = data.CreateGroup(db, group) | ||
assert.NilError(t, err) | ||
err = data.AddUsersToGroup(db, group.ID, []uid.ID{user.ID}) | ||
assert.NilError(t, err) | ||
} | ||
|
||
g, err := data.GetGroup(db, data.ByName("Foo")) | ||
group := &models.Group{Name: "Foo"} | ||
err = data.CreateGroup(db, group) | ||
assert.NilError(t, err) | ||
assert.Assert(t, g != nil) | ||
|
||
user, err = data.GetIdentity(db, data.GetIdentityOptions{ByID: user.ID, LoadGroups: true}) | ||
err = data.AddUsersToGroup(db, group.ID, group.Name, data.InfraProvider(db).ID, []uid.ID{user.ID}) | ||
assert.NilError(t, err) | ||
assert.Assert(t, user != nil) | ||
assert.Equal(t, len(user.Groups), 2) | ||
|
||
p, err := data.GetProvider(db, data.ByName("mockoidc")) | ||
assert.NilError(t, err) | ||
|
||
pu, err := data.CreateProviderUser(db, p, user) | ||
assert.NilError(t, err) | ||
|
||
pu.Groups = []string{"existing3"} | ||
assert.NilError(t, data.UpdateProviderUser(db, pu)) | ||
err = data.AssignUserToProviderGroups(db, pu, p, []string{"existing3"}) | ||
assert.NilError(t, err) | ||
|
||
return &mockOIDCImplementation{ | ||
UserEmailResp: "[email protected]", | ||
|
@@ -234,7 +227,7 @@ func TestExchangeAuthCodeForProviderTokens(t *testing.T) { | |
assert.Equal(t, "mockoidc", a.Provider.Name) | ||
assert.Assert(t, a.SessionExpiry.Equal(sessionExpiry)) | ||
|
||
assert.Assert(t, len(a.Identity.Groups) == 3) | ||
assert.Equal(t, len(a.Identity.Groups), 3) | ||
|
||
var groupNames []string | ||
for _, g := range a.Identity.Groups { | ||
|
@@ -261,15 +254,12 @@ func TestExchangeAuthCodeForProviderTokens(t *testing.T) { | |
|
||
a, err := loginMethod.Authenticate(context.Background(), db, sessionExpiry) | ||
assert.NilError(t, err) | ||
tc.expected(t, a) | ||
|
||
if err == nil { | ||
// make sure the associations are still set when you reload the object. | ||
u, err := data.GetIdentity(db, data.GetIdentityOptions{ByID: a.Identity.ID, LoadGroups: true}) | ||
assert.NilError(t, err) | ||
a.Identity = u | ||
tc.expected(t, a) | ||
} | ||
syncGroups, err := data.ListGroups(db, nil, data.ByGroupMember(a.Identity.ID)) | ||
assert.NilError(t, err) | ||
a.Identity.Groups = syncGroups | ||
|
||
tc.expected(t, a) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,6 +96,12 @@ func TestListGroups(t *testing.T) { | |
Groups: []models.Group{everyone, product}, | ||
} | ||
createIdentities(t, db, &firstUser, &secondUser) | ||
err := AddUsersToGroup(db, everyone.ID, everyone.Name, InfraProvider(db).ID, []uid.ID{firstUser.ID, secondUser.ID}) | ||
assert.NilError(t, err) | ||
err = AddUsersToGroup(db, engineers.ID, engineers.Name, InfraProvider(db).ID, []uid.ID{firstUser.ID}) | ||
assert.NilError(t, err) | ||
err = AddUsersToGroup(db, product.ID, product.Name, InfraProvider(db).ID, []uid.ID{secondUser.ID}) | ||
assert.NilError(t, err) | ||
|
||
t.Run("all", func(t *testing.T) { | ||
actual, err := ListGroups(db, nil) | ||
|
@@ -226,27 +232,23 @@ func TestAddUsersToGroup(t *testing.T) { | |
createGroups(t, db, &everyone, &other) | ||
|
||
var ( | ||
bond = models.Identity{ | ||
Name: "[email protected]", | ||
Groups: []models.Group{everyone}, | ||
} | ||
bond = models.Identity{Name: "[email protected]"} | ||
bourne = models.Identity{Name: "[email protected]"} | ||
bauer = models.Identity{Name: "[email protected]"} | ||
forth = models.Identity{ | ||
Name: "[email protected]", | ||
Groups: []models.Group{everyone}, | ||
} | ||
forth = models.Identity{Name: "[email protected]"} | ||
) | ||
|
||
createIdentities(t, db, &bond, &bourne, &bauer, &forth) | ||
err := AddUsersToGroup(db, everyone.ID, everyone.Name, InfraProvider(db).ID, []uid.ID{bond.ID, forth.ID}) | ||
assert.NilError(t, err) | ||
|
||
t.Run("add identities to group", func(t *testing.T) { | ||
actual, err := ListIdentities(db, ListIdentityOptions{ByGroupID: everyone.ID}) | ||
assert.NilError(t, err) | ||
expected := []models.Identity{forth, bond} | ||
assert.DeepEqual(t, actual, expected, cmpModelsIdentityShallow) | ||
|
||
err = AddUsersToGroup(db, everyone.ID, []uid.ID{bourne.ID, bauer.ID, forth.ID}) | ||
err = AddUsersToGroup(db, everyone.ID, everyone.Name, InfraProvider(db).ID, []uid.ID{bourne.ID, bauer.ID, forth.ID}) | ||
assert.NilError(t, err) | ||
|
||
actual, err = ListIdentities(db, ListIdentityOptions{ByGroupID: everyone.ID}) | ||
|
@@ -286,6 +288,10 @@ func TestRemoveUsersFromGroup(t *testing.T) { | |
Groups: []models.Group{everyone}, | ||
} | ||
createIdentities(t, tx, &bond, &bourne, &bauer, &forth) | ||
err := AddUsersToGroup(tx, everyone.ID, everyone.Name, InfraProvider(db).ID, []uid.ID{bond.ID, bourne.ID, bauer.ID, forth.ID}) | ||
assert.NilError(t, err) | ||
err = AddUsersToGroup(tx, other.ID, other.Name, InfraProvider(db).ID, []uid.ID{bond.ID, bourne.ID, bauer.ID}) | ||
assert.NilError(t, err) | ||
|
||
users, err := ListIdentities(tx, ListIdentityOptions{ByGroupID: everyone.ID}) | ||
assert.NilError(t, err) | ||
|
@@ -309,3 +315,33 @@ func TestRemoveUsersFromGroup(t *testing.T) { | |
assert.DeepEqual(t, actual, expected, cmpModelsIdentityShallow) | ||
}) | ||
} | ||
|
||
func TestCountUsersInGroup(t *testing.T) { | ||
runDBTests(t, func(t *testing.T, db *DB) { | ||
everyone := models.Group{Name: "Everyone"} | ||
createGroups(t, db, &everyone) | ||
|
||
mockta := &models.Provider{Name: "mokta", Kind: models.ProviderKindOkta} | ||
err := CreateProvider(db, mockta) | ||
assert.NilError(t, err) | ||
|
||
var ( | ||
bond = models.Identity{Name: "[email protected]"} | ||
bourne = models.Identity{Name: "[email protected]"} | ||
bauer = models.Identity{Name: "[email protected]"} | ||
forth = models.Identity{Name: "[email protected]"} | ||
) | ||
|
||
createIdentities(t, db, &bond, &bourne, &bauer, &forth) | ||
err = AddUsersToGroup(db, everyone.ID, everyone.Name, InfraProvider(db).ID, []uid.ID{bond.ID, forth.ID}) | ||
assert.NilError(t, err) | ||
err = AddUsersToGroup(db, everyone.ID, everyone.Name, mockta.ID, []uid.ID{bond.ID, bourne.ID, bauer.ID}) | ||
assert.NilError(t, err) | ||
|
||
t.Run("count users in group", func(t *testing.T) { | ||
count, err := CountUsersInGroup(db, everyone.ID) | ||
assert.NilError(t, err) | ||
assert.Equal(t, int(count), 4) | ||
}) | ||
}) | ||
} |
Oops, something went wrong.