Synit ADProxy

Beispiele

Praxisnahe Synit ADProxy Beispiele für Plan-only, Apply, Benutzeranlage, Gruppen, Account-Einstellungen, Queries, JSON-RPC und Templates.

Beispiele

Diese Beispiele zeigen typische Request-Muster für Enterprise Active Directory. .example.test Domains und Platzhalter dienen nur als Orientierung. Produktive DNs, Tokens, Benutzer, Gruppen und Passwörter gehören nicht in öffentliche Repositories.

Plan-only und Apply trennen

Plan-only ist der empfohlene Start. Der Plan liest den aktuellen Active-Directory-Zustand, prüft Regeln, ordnet Abhängigkeiten und liefert ein Ergebnis, ohne zu schreiben.

curl -sS -X POST https://adproxy.example.test/api/v1/mutations/plan \
  -H "Authorization: Bearer <read-or-write-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "mutation_id": "group-access-jane",
    "actor": "alice@example.test",
    "source": "service-desk",
    "response_detail": "standard",
    "operations": [
      {
        "id": "add_jane_to_engineering",
        "operation_type": "add_group_member",
        "target": {
          "dn": "CN=Engineering Users,OU=Groups,DC=example,DC=test"
        },
        "object_class": "group",
        "member_dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
      }
    ]
  }'

Wenn der Plan akzeptiert wurde, wird nur die plan_id angewendet:

curl -sS -X POST https://adproxy.example.test/api/v1/mutations/apply \
  -H "Authorization: Bearer <write-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "plan_id": "<plan-id-aus-plan-response>",
    "actor": "alice@example.test"
  }'

Für sensible Operationen kann zusätzlich force oder eine Approval-Policy erforderlich sein.

Idempotente kombinierte Ausführung

Der kombinierte Endpoint plant und wendet in einem Request an. Für technische Retries sollte ein stabiler Idempotency-Key gesetzt werden.

curl -sS -X POST https://adproxy.example.test/api/v1/mutations \
  -H "Authorization: Bearer <write-token>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: onboard-jane-2026-07-01" \
  -d @request.json

Ein erneuter Request mit gleichem Key und gleichem Body liefert dasselbe Ergebnis zurück. Ein gleicher Key mit anderem Body wird abgelehnt.

Operationen

Benutzer anlegen

{
  "mutation_id": "create-jane",
  "actor": "alice@example.test",
  "source": "iam-workflow",
  "operations": [
    {
      "id": "create_jane",
      "operation_type": "create_user",
      "target": {
        "dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
      },
      "object_class": "user",
      "attributes": {
        "cn": "Jane Doe",
        "givenName": "Jane",
        "sn": "Doe",
        "displayName": "Jane Doe",
        "sAMAccountName": "jdoe",
        "userPrincipalName": "jdoe@example.test",
        "mail": "jane.doe@example.test",
        "department": "Engineering"
      }
    }
  ]
}

Benutzer anlegen und Gruppe setzen

{
  "mutation_id": "onboard-jane",
  "actor": "alice@example.test",
  "source": "iam-workflow",
  "operations": [
    {
      "id": "create_jane",
      "operation_type": "create_user",
      "target": {
        "dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
      },
      "object_class": "user",
      "attributes": {
        "cn": "Jane Doe",
        "givenName": "Jane",
        "sn": "Doe",
        "displayName": "Jane Doe",
        "sAMAccountName": "jdoe",
        "userPrincipalName": "jdoe@example.test",
        "mail": "jane.doe@example.test"
      }
    },
    {
      "id": "add_jane_to_engineering",
      "operation_type": "add_group_member",
      "target": {
        "dn": "CN=Engineering Users,OU=Groups,DC=example,DC=test"
      },
      "object_class": "group",
      "member_dn": "CN=Jane Doe,OU=Users,DC=example,DC=test",
      "depends_on": ["create_jane"]
    }
  ]
}

Passwort setzen

{
  "force": true,
  "show_secret_outputs": true,
  "operations": [
    {
      "id": "set_initial_password",
      "operation_type": "set_password",
      "target": {
        "dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
      },
      "object_class": "user",
      "generated_password": {
        "output_name": "jane.initial_password",
        "length": 24
      }
    }
  ]
}

Generierte Passwörter werden nur in der Apply-Antwort ausgegeben, wenn show_secret_outputs gesetzt ist. Sie werden nicht in Audit, Snapshot oder Mutation History gespeichert.

Attribute ändern

{
  "operations": [
    {
      "id": "update_title",
      "operation_type": "modify_attributes",
      "target": {
        "sAMAccountName": "jdoe"
      },
      "object_class": "user",
      "attributes": {
        "title": "Senior Engineer",
        "telephoneNumber": "__DELETE__"
      }
    }
  ]
}

Account deaktivieren und verschieben

{
  "mutation_id": "offboard-jane",
  "actor": "alice@example.test",
  "source": "service-desk",
  "force": true,
  "operations": [
    {
      "id": "disable_user",
      "operation_type": "disable_account",
      "target": {
        "dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
      },
      "object_class": "user"
    },
    {
      "id": "remove_from_engineering",
      "operation_type": "remove_group_member",
      "target": {
        "dn": "CN=Engineering Users,OU=Groups,DC=example,DC=test"
      },
      "object_class": "group",
      "member_dn": "CN=Jane Doe,OU=Users,DC=example,DC=test",
      "depends_on": ["disable_user"]
    },
    {
      "id": "move_to_disabled_ou",
      "operation_type": "move_object",
      "target": {
        "dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
      },
      "object_class": "user",
      "new_parent": "OU=Disabled Users,DC=example,DC=test",
      "depends_on": ["disable_user"]
    }
  ]
}

Manager setzen

{
  "operations": [
    {
      "id": "set_manager",
      "operation_type": "set_manager",
      "target": {
        "sAMAccountName": "jdoe"
      },
      "object_class": "user",
      "manager_dn": "CN=Erika Manager,OU=Users,DC=example,DC=test"
    }
  ]
}

Account-Einstellungen ändern

{
  "force": true,
  "operations": [
    {
      "id": "update_settings",
      "operation_type": "update_account_settings",
      "target": {
        "sAMAccountName": "jdoe"
      },
      "object_class": "user",
      "account_settings": {
        "enabled": true,
        "expires_at": "2026-12-31T23:59:59Z",
        "password_never_expires": false,
        "must_change_password_at_next_logon": true,
        "cannot_change_password": false,
        "smartcard_required": false,
        "delegation_allowed": false,
        "logon_to": ["WS1", "WS2"]
      }
    }
  ]
}

Objekt suchen und Ergebnis weiterverwenden

lookup_object kann ein Objekt suchen. Spätere Operationen können das Ergebnis referenzieren.

{
  "operations": [
    {
      "id": "find_user",
      "operation_type": "lookup_object",
      "target": {
        "sAMAccountName": "jdoe"
      },
      "object_class": "user"
    },
    {
      "id": "move_user",
      "operation_type": "move_object",
      "object_class": "user",
      "target": {
        "dn": "$.operations['find_user'].Result.DistinguishedName"
      },
      "new_parent": "OU=Engineering,DC=example,DC=test",
      "depends_on": ["find_user"]
    }
  ]
}

Desired-State Beispiele

Desired-State Requests beschreiben den Zielzustand. ADProxy liest den aktuellen Zustand und plant die nötigen Schritte.

Benutzer-Zielzustand

{
  "force": true,
  "show_secret_outputs": true,
  "desired_users": [
    {
      "name": "jane",
      "dn": "CN=Jane Doe,OU=Users,DC=example,DC=test",
      "attributes": {
        "mail": {
          "mode": "exact",
          "values": ["jane.doe@example.test"]
        },
        "department": {
          "mode": "exact",
          "values": ["Engineering"]
        }
      },
      "generated_password": {
        "output_name": "jane.initial_password",
        "length": 24
      },
      "enabled": true,
      "groups": ["CN=Engineering Users,OU=Groups,DC=example,DC=test"],
      "move_to_ou_dn": "OU=Engineering,DC=example,DC=test"
    }
  ]
}

Gruppen-Zielzustand

{
  "desired_groups": [
    {
      "name": "engineering_users",
      "dn": "CN=Engineering Users,OU=Groups,DC=example,DC=test",
      "group_type": "security",
      "group_scope": "global",
      "members": [
        "CN=Jane Doe,OU=Users,DC=example,DC=test",
        "CN=Bob Smith,OU=Users,DC=example,DC=test"
      ],
      "manager_dn": "CN=Erika Manager,OU=Users,DC=example,DC=test"
    }
  ]
}

Objekt entfernen

{
  "desired_objects": [
    {
      "name": "old_group",
      "object_class": "group",
      "dn": "CN=Old Group,OU=Groups,DC=example,DC=test",
      "absent": true
    }
  ]
}

Read-only Queries

Diese Abfragen schreiben nie in Active Directory.

curl -sS -X POST https://adproxy.example.test/api/v1/query \
  -H "Authorization: Bearer <read-token>" \
  -H "Content-Type: application/json" \
  -d '{"operation":"search_user_by_sam","parameters":{"sam_account_name":"jdoe"}}'
curl -sS -X POST https://adproxy.example.test/api/v1/query \
  -H "Authorization: Bearer <read-token>" \
  -H "Content-Type: application/json" \
  -d '{"operation":"search_user_by_mail","parameters":{"mail":"jane.doe@example.test"}}'
curl -sS -X POST https://adproxy.example.test/api/v1/query \
  -H "Authorization: Bearer <read-token>" \
  -H "Content-Type: application/json" \
  -d '{"operation":"list_group_members","parameters":{"group_dn":"CN=Engineering Users,OU=Groups,DC=example,DC=test","recursive":true}}'
curl -sS -X POST https://adproxy.example.test/api/v1/query \
  -H "Authorization: Bearer <read-token>" \
  -H "Content-Type: application/json" \
  -d '{"operation":"get_object","parameters":{"dn":"CN=Jane Doe,OU=Users,DC=example,DC=test","force_refresh":true}}'

JSON-RPC

JSON-RPC nutzt denselben Plan/Apply-Kern.

curl -sS -X POST https://adproxy.example.test/api/v1/rpc \
  -H "Authorization: Bearer <read-or-write-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "mutation.plan",
    "params": {
      "actor": "alice@example.test",
      "operations": [
        {
          "id": "add_member",
          "operation_type": "add_group_member",
          "target": {
            "dn": "CN=Engineering Users,OU=Groups,DC=example,DC=test"
          },
          "object_class": "group",
          "member_dn": "CN=Jane Doe,OU=Users,DC=example,DC=test"
        }
      ]
    }
  }'

Apply per JSON-RPC:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "mutation.apply",
  "params": {
    "plan_id": "<plan-id>",
    "actor": "alice@example.test"
  }
}

Schema-Endpunkte

Schema-Endpunkte helfen Integrationen, gültige Requests zu bauen.

curl -sS -u "<client-id>:<secret>" https://adproxy.example.test/api/v1/schema
curl -sS -u "<client-id>:<secret>" https://adproxy.example.test/api/v1/schema/classes/user
curl -sS -u "<client-id>:<secret>" https://adproxy.example.test/api/v1/schema/attributes/sAMAccountName

Template: Onboarding

user_onboarding.template.json:

{
  "name": "user_onboarding",
  "payload": {
    "mutation_id": "{{ $mutation_id }}",
    "actor": "{{ $actor }}",
    "operations": [
      {
        "id": "create_user",
        "operation_type": "create_user",
        "object_class": "user",
        "target": {
          "dn": "CN={{ $display_name }},{{ $ou_dn }}"
        },
        "attributes": {
          "cn": "{{ $display_name }}",
          "givenName": "{{ $given_name }}",
          "sn": "{{ $surname }}",
          "sAMAccountName": "{{ $user_name }}",
          "mail": "{{ $user_name }}@example.test",
          "company": "{{ $company }}",
          "department": "{{ $department }}"
        }
      },
      {
        "id": "add_to_group",
        "operation_type": "add_group_member",
        "target": {
          "dn": "{{ $primary_group_dn }}"
        },
        "object_class": "group",
        "member_dn": "CN={{ $display_name }},{{ $ou_dn }}",
        "depends_on": ["create_user"]
      }
    ]
  }
}

Plan aus Template:

curl -sS -X POST https://adproxy.example.test/api/v1/templates/user_onboarding/plan \
  -H "Authorization: Bearer <read-or-write-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "mutation_id": "onboard-jane",
    "actor": "alice@example.test",
    "display_name": "Jane Doe",
    "given_name": "Jane",
    "surname": "Doe",
    "user_name": "jdoe",
    "company": "Example GmbH",
    "department": "Engineering",
    "ou_dn": "OU=Users,DC=example,DC=test",
    "primary_group_dn": "CN=Engineering Users,OU=Groups,DC=example,DC=test"
  }'

Template: Offboarding

{
  "name": "user_offboarding",
  "payload": {
    "mutation_id": "{{ $mutation_id }}",
    "actor": "{{ $actor }}",
    "force": true,
    "operations": [
      {
        "id": "disable_user",
        "operation_type": "disable_account",
        "target": {
          "dn": "{{ $user_dn }}"
        },
        "object_class": "user"
      },
      {
        "id": "remove_from_group",
        "operation_type": "remove_group_member",
        "target": {
          "dn": "{{ $group_dn }}"
        },
        "object_class": "group",
        "member_dn": "{{ $user_dn }}",
        "depends_on": ["disable_user"]
      },
      {
        "id": "move_to_disabled_ou",
        "operation_type": "move_object",
        "target": {
          "dn": "{{ $user_dn }}"
        },
        "object_class": "user",
        "new_parent": "{{ $disabled_ou_dn }}",
        "depends_on": ["disable_user"]
      }
    ]
  }
}

Regeln für produktive Beispiele

operations, desired_users, desired_groups und desired_objects nicht in einem Request mischen. Operationen mit set_password, enable_account, disable_account, unlock oder update_account_settings benötigen in der Regel force oder eine passende Approval-Policy. Generated Secrets nur für die direkte Weitergabe an freigegebene Zielsysteme anzeigen lassen. Vor dem ersten Apply immer einen Plan-only Durchlauf prüfen.

United in Diversity