diff --git a/lib/fixtures/keycloak.go b/lib/fixtures/keycloak.go index 00df88dd32..bf8848479e 100644 --- a/lib/fixtures/keycloak.go +++ b/lib/fixtures/keycloak.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "log/slog" + "math" "net/http" "strings" @@ -24,17 +25,23 @@ type KeycloakData struct { type RealmToCreate struct { RealmRepresentation gocloak.RealmRepresentation `yaml:"realm_repepresentation" json:"realm_repepresentation"` Clients []Client `yaml:"clients,omitempty" json:"clients,omitempty"` - Users []gocloak.User `yaml:"users,omitempty" json:"users,omitempty"` + Users []User `yaml:"users,omitempty" json:"users,omitempty"` CustomRealmRoles []gocloak.Role `yaml:"custom_realm_roles,omitempty" json:"custom_realm_roles,omitempty"` CustomClientRoles map[string][]gocloak.Role `yaml:"custom_client_roles,omitempty" json:"custom_client_roles,omitempty"` CustomGroups []gocloak.Group `yaml:"custom_groups,omitempty" json:"custom_groups,omitempty"` TokenExchanges []TokenExchange `yaml:"token_exchanges,omitempty" json:"token_exchanges,omitempty"` } +type User struct { + gocloak.User + Copies int `yaml:"copies,omitempty" json:"copies,omitempty"` +} + type Client struct { Client gocloak.Client `yaml:"client" json:"client"` SaRealmRoles []string `yaml:"sa_realm_roles,omitempty" json:"sa_realm_roles,omitempty"` SaClientRoles map[string][]string `yaml:"sa_client_roles,omitempty" json:"sa_client_roles,omitempty"` + Copies int `yaml:"copies,omitempty" json:"copies,omitempty"` } type TokenExchange struct { @@ -379,7 +386,7 @@ func SetupCustomKeycloak(ctx context.Context, kcParams KeycloakConnectParams, ke } // create the clients - if realmToCreate.Clients != nil { + if realmToCreate.Clients != nil { //nolint:nestif // need to create clients in order for _, customClient := range realmToCreate.Clients { realmRoles, err := getRealmRolesByList(ctx, kcConnectParams.Realm, client, token, customClient.SaRealmRoles) if err != nil { @@ -401,6 +408,21 @@ func SetupCustomKeycloak(ctx context.Context, kcParams KeycloakConnectParams, ke if err != nil { return err } + if customClient.Copies < 1 { + continue + } + baseClientID := *customClient.Client.ClientID + baseClientName := *customClient.Client.Name + numDigits := int(math.Log10(float64(customClient.Copies-1))) + 1 + padFormat := fmt.Sprintf("%%s-%%%dd", numDigits) + for i := 0; i < customClient.Copies; i++ { + customClient.Client.ClientID = gocloak.StringP(fmt.Sprintf(padFormat, baseClientID, i)) + customClient.Client.Name = gocloak.StringP(fmt.Sprintf(padFormat, baseClientName, i)) + _, err = createClient(ctx, client, token, &kcConnectParams, customClient.Client, realmRoles, clientRoleMap) + if err != nil { + return err + } + } } } @@ -419,10 +441,25 @@ func SetupCustomKeycloak(ctx context.Context, kcParams KeycloakConnectParams, ke // create the users if realmToCreate.Users != nil { for _, customUser := range realmToCreate.Users { - _, err = createUser(ctx, client, token, &kcConnectParams, customUser) + _, err = createUser(ctx, client, token, &kcConnectParams, customUser.User) if err != nil { return err } + if customUser.Copies < 1 { + continue + } + baseUserName := *customUser.User.Username + baseEmail := *customUser.User.Email + numDigits := int(math.Log10(float64(customUser.Copies-1))) + 1 + padFormat := fmt.Sprintf("%%s-%%%dd", numDigits) + for i := 0; i < customUser.Copies; i++ { + customUser.User.Username = gocloak.StringP(fmt.Sprintf(padFormat, baseUserName, i)) + customUser.User.Email = gocloak.StringP(fmt.Sprintf("%d-%s", i, baseEmail)) + _, err = createUser(ctx, client, token, &kcConnectParams, customUser.User) + if err != nil { + return err + } + } } } diff --git a/service/cmd/keycloak_data.yaml b/service/cmd/keycloak_data.yaml index 201a2b6544..57ef4698ee 100644 --- a/service/cmd/keycloak_data.yaml +++ b/service/cmd/keycloak_data.yaml @@ -21,7 +21,7 @@ realms: custom_groups: - name: mygroup attributes: - mygroupattribute: + mygroupattribute: - mygroupvalue clients: - client: @@ -33,8 +33,9 @@ realms: secret: secret protocolMappers: - *customAudMapper - sa_realm_roles: + sa_realm_roles: - opentdf-admin + copies: 10 - client: clientID: opentdf-sdk enabled: true @@ -44,7 +45,7 @@ realms: secret: secret protocolMappers: - *customAudMapper - sa_realm_roles: + sa_realm_roles: - opentdf-standard - client: clientID: tdf-entity-resolution @@ -90,9 +91,9 @@ realms: - value: testuser123 type: password attributes: - superhero_name: + superhero_name: - thor - superhero_group: + superhero_group: - avengers groups: - mygroup @@ -106,8 +107,7 @@ realms: - query-users tdf-entity-resolution: - entity-resolution-test-role + copies: 10 token_exchanges: - start_client: opentdf target_client: opentdf-sdk - - \ No newline at end of file