package idp import ( "context" "crypto/hkdf" "crypto/sha256" "encoding/base64" "errors" "fmt" dexstorage "github.com/dexidp/dex/storage" ) const ( ForwardClientID = "_forward" PortalClientID = "_portal" AdminClientID = "_admin" ) func FirstPartySecret(masterKey []byte, clientID string) (string, error) { if len(masterKey) != 32 { return "", errors.New("idp: the master key is not 32 bytes") } secret, err := hkdf.Key(sha256.New, masterKey, nil, "tug client "+clientID+" v1", 32) if err != nil { return "", fmt.Errorf("idp: derive the %s secret: %w", clientID, err) } return base64.RawURLEncoding.EncodeToString(secret), nil } func staticClients(cfg Config) ([]dexstorage.Client, error) { clients := make([]dexstorage.Client, 0, len(cfg.Clients)+3) for _, c := range cfg.Clients { client := dexstorage.Client{ID: c.ID, Name: c.ID, RedirectURIs: append([]string(nil), c.RedirectURIs...), Public: c.Public} if !c.Public { secret := cfg.ClientSecrets[c.ID].Bytes() if len(secret) == 0 { return nil, fmt.Errorf("idp: confidential client %q has no secret", c.ID) } client.Secret = string(secret) } clients = append(clients, client) } forward := make([]string, 0, len(cfg.Apps)) for _, app := range cfg.Apps { origin, ok := cfg.AppOrigins[app.Domain] if !ok { origin = "https://" + app.Domain } forward = append(forward, origin+"/.sso/callback") } for _, fp := range []struct { id string redirect []string }{ {ForwardClientID, forward}, {PortalClientID, []string{cfg.AccountOrigin + "/oidc/callback"}}, {AdminClientID, []string{cfg.AdminOrigin + "/oidc/callback"}}, } { secret, err := FirstPartySecret(cfg.MasterKey.Bytes(), fp.id) if err != nil { return nil, err } clients = append(clients, dexstorage.Client{ID: fp.id, Name: fp.id, Secret: secret, RedirectURIs: fp.redirect}) } return clients, nil } func deleteStoredClients(ctx context.Context, dex dexstorage.Storage) error { stored, err := dex.ListClients(ctx) if err != nil { return fmt.Errorf("idp: list stored clients: %w", err) } for _, c := range stored { if err := dex.DeleteClient(ctx, c.ID); err != nil { return fmt.Errorf("idp: delete stored client %q: %w", c.ID, err) } } return nil }