scim/pkg/supplier/keycloak.go
2022-06-10 13:51:19 +02:00

97 lines
2.3 KiB
Go

package supplier
import (
"context"
"github.com/Nerzal/gocloak/v11"
"github.com/google/uuid"
)
type KeycloakSupplier struct {
host string
realm string
username string
password string
}
func NewKeycloakSupplier(host, realm, username, password string) KeycloakSupplier {
return KeycloakSupplier{
host: host,
realm: realm,
username: username,
password: password,
}
}
type ScimClient struct {
Name string
Endpoint string
Username string
Password string
}
func (r *KeycloakSupplier) login(ctx context.Context) (gocloak.GoCloak, *gocloak.JWT, error) {
client := gocloak.NewClient(r.host, gocloak.SetAuthAdminRealms("admin/realms"), gocloak.SetAuthRealms("realms"))
token, err := client.LoginAdmin(ctx, r.username, r.password, r.realm)
if err != nil {
return nil, nil, err
}
return client, token, nil
}
func (r *KeycloakSupplier) Reconcile(ctx context.Context, scim ScimClient) error {
client, token, err := r.login(ctx)
if err != nil {
return err
}
var providerId string
components, err := client.GetComponents(ctx, token.AccessToken, r.realm)
if err != nil {
return err
}
for _, v := range components {
if *v.ProviderType == "org.keycloak.storage.UserStorageProvider" && *v.ProviderID == "scim" && *v.Name == scim.Name {
providerId = *v.ID
break
}
}
realm, err := client.GetRealm(ctx, token.AccessToken, r.realm)
if err != nil {
return err
}
pId := "scim"
pType := "org.keycloak.storage.UserStorageProvider"
component := gocloak.Component{
ID: &providerId,
ParentID: realm.ID,
Name: &scim.Name,
ProviderID: &pId,
ProviderType: &pType,
ComponentConfig: &map[string][]string{
"priority": {"0"},
"endpoint": {scim.Endpoint},
"content-type": {"application/json"},
"auth-mode": {"BASIC_AUTH"},
"auth-user": {scim.Username},
"auth-pass": {scim.Password},
"sync-import": {"false"},
"sync-import-action": {"CREATE_LOCAL"},
"propagation-user": {"true"},
"propagation-group": {"true"},
},
}
if providerId == "" {
providerId = uuid.NewString()
_, err = client.CreateComponent(ctx, token.AccessToken, r.realm, component)
if err != nil {
return err
}
} else {
_, err = client.UpdateComponent(ctx, token.AccessToken, r.realm, component)
if err != nil {
return err
}
}
return nil
}