# Authorize Commands with Directory Groups Use the `ActiveDirectoryGroup` [rule](https://docs.workflowengine.io/get-started/concepts/rule/) to make a [command](https://docs.workflowengine.io/get-started/concepts/command/) available only to direct members of a group in Microsoft Entra Domain Services, AD DS, or a compatible LDAP directory. Add a directory-backed actor to the [scheme](https://docs.workflowengine.io/get-started/concepts/scheme/), assign it to an `Allow` restriction on the command transition, and query available commands with the same user name that the LDAP source returns. The built-in presets use `cn`; a custom source can map another attribute. **Prerequisites:** - [Configure LDAP Sources](https://docs.workflowengine.io/plugins/active-directory-plugin/configure-ldap-sources/) - register a source that can read the target users and groups. - [Rule](https://docs.workflowengine.io/get-started/concepts/rule/) - understand how actors connect rules to transition restrictions. - [Command](https://docs.workflowengine.io/get-started/concepts/command/) - prepare a command-triggered transition to protect. ## Create a directory actor An actor connects a name used in transition restrictions to the `ActiveDirectoryGroup` rule and one directory group. In the Designer, open **Actors**, select **Create**, and set these fields: | Field | Value | |-------|-------| | **Name** | `DirectoryAdministrators` | | **Rule** | `ActiveDirectoryGroup` | | **Value** | Select the directory group and source from autocomplete | A DirectoryAdministrators actor that uses the ActiveDirectoryGroup rule and the admin group from the local-ldap source The example selects `Group: admin | Source: local-ldap`. Use the corresponding group and source in your environment. Choose the item from autocomplete instead of typing the value: the Designer stores the selected group and source together. If the list is empty, return to [Verify the source configuration](https://docs.workflowengine.io/plugins/active-directory-plugin/configure-ldap-sources/#verify-the-source-configuration). ## Restrict the command transition A transition restriction connects the directory actor to command availability. 1. Open the command-triggered transition in the Designer. 2. Under **Trigger**, select **Command** and choose the command to protect. 3. Under **Restrictions**, choose `DirectoryAdministrators` as the actor and **Allow** as the type. 4. Save the transition. A command transition with an Allow restriction for the DirectoryAdministrators actor When [WorkflowRuntime](https://docs.workflowengine.io/get-started/concepts/workflow-runtime/) calculates available commands, the rule loads the selected group from the selected source and checks whether the supplied identity matches a direct group member. The `GetAvailableCommandsAsync` overload used below checks transition restrictions without evaluating [transition conditions](https://docs.workflowengine.io/get-started/concepts/condition/). Use `GetAvailableCommandsWithConditionCheckAsync` to also exclude commands whose transition conditions fail. ## Match the workflow identity to LDAP Pass the directory value configured as the user's name whenever the application asks WorkflowRuntime which commands the user can execute. The built-in presets use `cn`, so an LDAP entry with `cn=Test User` must be queried as `Test User`. If the application authenticates users by UPN, email address, object ID, or an application account ID, translate that identity first or [map the corresponding LDAP attribute](https://docs.workflowengine.io/plugins/active-directory-plugin/configure-ldap-sources/#map-a-custom-schema). Matching is exact and case-sensitive. ```csharp filename="DirectoryCommandAuthorization.cs" using OptimaJet.Workflow.Core.Runtime; public static class DirectoryCommandAuthorization { public static async Task CanExecuteAsync( WorkflowRuntime runtime, Guid processId, string userCommonName, string commandName) { var commands = await runtime.GetAvailableCommandsAsync( processId, userCommonName); return commands.Any(command => command.CommandName == commandName); } } ``` The call evaluates the scheme restrictions, including `ActiveDirectoryGroup`. `CanExecuteAsync` returns `true` only when the named command is available to the supplied directory identity. If it returns `true`, execute the command through the ordinary command execution API after the application performs its own authentication and request authorization. ## Verify command authorization Run the `GetAvailableCommandsAsync` check with at least these two identities: | Identity used in the query | Expected result | |----------------------------|-----------------| | The configured directory name of a direct member | The protected command is available | | The configured directory name of a user outside the group | The protected command is absent | Then change the directory membership, wait for the directory service to expose the change, and run the check again. The plugin performs another live read; it has no membership cache to clear. > **Direct membership:** Use a direct member for this test. The built-in providers do not > recursively expand nested groups. The plugin queries LDAP during rule evaluation. A slow or unavailable directory can delay or fail command discovery. ## Troubleshoot missing commands The `ActiveDirectoryGroup` rule requires the scheme value, identity mapping, and directory data to agree exactly. | Symptom | Likely cause | Fix | |---------|--------------|-----| | The actor group list is empty | The group search base, filter, bind permission, or endpoint is wrong | [Verify the source configuration](https://docs.workflowengine.io/plugins/active-directory-plugin/configure-ldap-sources/#verify-the-source-configuration), then reopen the group selector | | A direct member cannot see the command | The workflow identity does not match the configured LDAP user name | Log the value passed to `GetAvailableCommandsAsync` and compare it with the mapped LDAP value (`cn` by default) | | A nested-group member cannot see the command | The built-in providers do not expand nested groups | Add the user directly or implement a custom workflow rule | | The actor value was entered manually | The value does not match the stored group and source selection | Select the group from autocomplete | | Every user can see the command | The actor is missing from the transition restriction | Add an `Allow` restriction to the command-triggered transition | ## Frequently asked questions **What identity value does ActiveDirectoryGroup expect?** Use the directory value configured as the user's name. The built-in presets use `cn`; a custom source can map another attribute. The comparison is exact and case-sensitive. **Does ActiveDirectoryGroup include nested group members?** No. `ActiveDirectoryGroup` checks member entries loaded directly from the selected group. It does not resolve users transitively through nested groups. **Does ActiveDirectoryGroup cache membership?** No. `ActiveDirectoryGroup` queries the directory for each rule evaluation. A later command query can observe a membership change as soon as the LDAP endpoint returns it. **Can the same scheme use groups from several directories?** Yes. Create actors whose values select different source names. Each `ActiveDirectoryGroup` actor stores both its group and source in the `Group: ... | Source: ...` value.