Twice the identity provider's admin kept an older password than the one the mesh minted (an adopted, then a moved database), and the provisioner failed every consumer until it was repaired by hand (hq issue 179). The module now checks the admin's login and repairs a refusal itself through the server's bootstrap command, verifies, brakes a failed repair and announces it, and stops asking the server while refused. Ported to Go to change it.
69 lines
2.4 KiB
Go
69 lines
2.4 KiB
Go
// keycloak-provider: keycloak's code, one binary the node's runtime launches and speaks MCP to over
|
|
// stdio through the Go SDK (novox/hq ADR 0188, 0193). It serves keycloak's tools and, beside them,
|
|
// runs long: the provisioner that makes keycloak the provider of the mesh `oidc-client` interface,
|
|
// and the guard that keeps the admin logging in with the mesh's secret (novox/hq issue 179).
|
|
//
|
|
// stdout is the MCP channel; everything this module says, it says on stderr.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
func say(format string, args ...any) { logStderr("[keycloak] "+format, args...) }
|
|
|
|
// announce emits an event without letting a broker hiccup fail what it announces: the change already
|
|
// happened in Keycloak.
|
|
func announce(event string, body map[string]any) {
|
|
if err := stdio.Emit(event, body); err != nil {
|
|
say("emit %s failed: %v", event, err)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
kc, err := ClientFromEnv(os.Getenv)
|
|
if err != nil {
|
|
// Without the admin password there is nothing to serve, provision or guard; said, not fatal,
|
|
// so the runtime does not restart a process that cannot do better.
|
|
say("%v; serving no tools and provisioning nothing", err)
|
|
if err := stdio.Serve("", nil); err != nil {
|
|
say("%v", err)
|
|
os.Exit(1)
|
|
}
|
|
return
|
|
}
|
|
guard := &Guard{
|
|
KC: kc, Container: os.Getenv("MESH_KEYCLOAK_CONTAINER"),
|
|
Log: logStderr, Announce: announce,
|
|
}
|
|
kc.onRejected = guard.Nudge
|
|
go guard.Run(context.Background())
|
|
|
|
if receives := os.Getenv("MESH_RECEIVES"); receives == "" {
|
|
say("MESH_RECEIVES is not set — the provisioner cannot run without it")
|
|
} else if issuer, err := Issuer(os.Getenv); err != nil {
|
|
say("%v — the provisioner cannot run without it", err)
|
|
} else if realm, err := RealmOf(issuer); err != nil {
|
|
say("%v — the provisioner cannot run without it", err)
|
|
} else {
|
|
h := &Harness{
|
|
Resource: "oidc-client",
|
|
Receives: receives,
|
|
Adapter: provisioner{clients: OidcClients{KC: kc, Realm: realm}, guard: guard, announce: announce, log: logStderr},
|
|
Log: logStderr,
|
|
// A consumer failed for minutes is said on the bus, where the controller hears it and
|
|
// `status` names it (novox/hq ADR 0224).
|
|
Announce: announce,
|
|
Node: os.Getenv("MESH_NODE"),
|
|
}
|
|
go h.Run(context.Background())
|
|
}
|
|
if err := stdio.Serve("", Tools(kc, guard)); err != nil {
|
|
say("%v", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|