Skip to content

Instantly share code, notes, and snippets.

@Noxsios
Last active April 8, 2025 22:41
Show Gist options
  • Save Noxsios/2901c752a371f9d48493cd879c41e9c4 to your computer and use it in GitHub Desktop.
Save Noxsios/2901c752a371f9d48493cd879c41e9c4 to your computer and use it in GitHub Desktop.
create doug user
// This example is a naive translation of the shell task into Go,
// there are many optimizations + reuse needed before this would be fully accepted as a builtin
// + unit tests
// BuiltinSetupDougUser sets up a doug user in Keycloak
type BuiltinSetupDougUser struct {
KeycloakGroup string `json:"keycloak_group,omitempty" jsonschema:"description=Optional Keycloak group to add the user to"`
}
func (b BuiltinSetupDougUser) Execute(ctx context.Context) error {
logger := log.FromContext(ctx)
// Get Keycloak admin password
const namespace = "keycloak"
const secretName = "keycloak-admin-password"
const passwordKey = "password"
config, err := rest.InClusterConfig()
if err != nil {
return fmt.Errorf("error creating Kubernetes config: %w", err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return fmt.Errorf("error creating Kubernetes client: %w", err)
}
var secret *corev1.Secret
secret, err = clientset.CoreV1().Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("error getting secret %s in namespace %s: %w", secretName, namespace, err)
}
encodedPassword, ok := secret.Data[passwordKey]
if !ok {
return fmt.Errorf("key %s not found in secret %s in namespace %s", passwordKey, secretName, namespace)
}
keycloakAdminPassword, err := base64.StdEncoding.DecodeString(string(encodedPassword))
if err != nil {
return fmt.Errorf("error decoding password: %w", err)
}
// Get Keycloak admin token
keycloakURL := "https://keycloak.admin.uds.dev"
tokenURL := fmt.Sprintf("%s/realms/master/protocol/openid-connect/token", keycloakURL)
data := url.Values{}
data.Set("username", "admin")
data.Set("password", string(keycloakAdminPassword))
data.Set("client_id", "admin-cli")
data.Set("grant_type", "password")
req, err := http.NewRequestWithContext(ctx, "POST", tokenURL, strings.NewReader(data.Encode()))
if err != nil {
return fmt.Errorf("error creating token request: %w", err)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error getting admin token: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("error getting admin token, status: %s, body: %s", resp.Status, string(body))
}
var tokenResponse struct {
AccessToken string `json:"access_token"`
}
if err := json.NewDecoder(resp.Body).Decode(&tokenResponse); err != nil {
return fmt.Errorf("error decoding token response: %w", err)
}
keycloakAdminToken := tokenResponse.AccessToken
logger.Info("Got Keycloak admin token")
// Create the doug user in the UDS Realm
userURL := fmt.Sprintf("%s/admin/realms/uds/users", keycloakURL)
userPayload := map[string]interface{}{
"username": "doug",
"firstName": "Doug",
"lastName": "Unicorn",
"email": "[email protected]",
"attributes": map[string][]string{"mattermostid": {"1"}},
"emailVerified": true,
"enabled": true,
"requiredActions": []string{},
"credentials": []map[string]interface{}{
{
"type": "password",
"value": "unicorn123!@#UN",
"temporary": false,
},
},
}
// Add group if specified
if b.KeycloakGroup != "" {
userPayload["groups"] = []string{b.KeycloakGroup}
}
userJSON, err := json.Marshal(userPayload)
if err != nil {
return fmt.Errorf("error marshaling user JSON: %w", err)
}
req, err = http.NewRequestWithContext(ctx, "POST", userURL, bytes.NewBuffer(userJSON))
if err != nil {
return fmt.Errorf("error creating user request: %w", err)
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer "+keycloakAdminToken)
resp, err = client.Do(req)
if err != nil {
return fmt.Errorf("error creating user: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("error creating user, status: %s, body: %s", resp.Status, string(body))
}
logger.Info("Created user doug")
// Disable 2FA
flowsURL := fmt.Sprintf("%s/admin/realms/uds/authentication/flows/Authentication/executions", keycloakURL)
req, err = http.NewRequestWithContext(ctx, "GET", flowsURL, nil)
if err != nil {
return fmt.Errorf("error creating flows request: %w", err)
}
req.Header.Add("Authorization", "Bearer "+keycloakAdminToken)
resp, err = client.Do(req)
if err != nil {
return fmt.Errorf("error getting flows: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("error getting flows, status: %s, body: %s", resp.Status, string(body))
}
var flows []map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&flows); err != nil {
return fmt.Errorf("error decoding flows response: %w", err)
}
var conditionalOTPID string
for _, flow := range flows {
if displayName, ok := flow["displayName"].(string); ok && displayName == "Conditional OTP" {
if id, ok := flow["id"].(string); ok {
conditionalOTPID = id
break
}
}
}
if conditionalOTPID == "" {
return fmt.Errorf("could not find Conditional OTP flow")
}
// Update the flow to disable 2FA
flowUpdateURL := fmt.Sprintf("%s/admin/realms/uds/authentication/flows/Authentication/executions", keycloakURL)
flowUpdatePayload := map[string]string{
"id": conditionalOTPID,
"requirement": "DISABLED",
}
flowUpdateJSON, err := json.Marshal(flowUpdatePayload)
if err != nil {
return fmt.Errorf("error marshaling flow update JSON: %w", err)
}
req, err = http.NewRequestWithContext(ctx, "PUT", flowUpdateURL, bytes.NewBuffer(flowUpdateJSON))
if err != nil {
return fmt.Errorf("error creating flow update request: %w", err)
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer "+keycloakAdminToken)
resp, err = client.Do(req)
if err != nil {
return fmt.Errorf("error updating flow: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("error updating flow, status: %s, body: %s", resp.Status, string(body))
}
logger.Info("Disabled 2FA")
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment