id: active_directory
name: Active Directory
version: 1.0.0
description: "Active Directory over LDAP/LDAPS — query and manage users, computers, groups and contacts (search, enable/disable/unlock, set/expire password, group membership, OU moves, create/update/delete). Runs on a remote engine inside the AD network. Requires the Python 'ldap3' library on the engine host (pip install ldap3)."
changelog: "1.0.0 — Initial release: full directory administration over LDAP (search, get user/computer/group-members, create/update/delete user/contact/group, enable/disable/unlock, set/expire password, password-never-expire, add/remove group membership, move user/computer OU, test credentials)."
category: identity

# Per-instance configuration. The integration binds to a Domain Controller over
# LDAP (389) or LDAPS (636). Secure connection (SSL/Start TLS) is required for
# password operations. Run this integration on a remote engine that can reach the
# Domain Controller. The bundled scripts require the Python 'ldap3' library to be
# installed on the engine host: pip install ldap3
config_schema:
  properties:
    server_ip:
      type: string
      description: "Domain Controller host or IP (e.g. dc01.company.com or 192.168.0.1)"
    port:
      type: string
      description: "LDAP port. Default 389 for LDAP / Start TLS, 636 for LDAPS."
    username:
      type: string
      description: "Bind username (e.g. DOMAIN\\\\user or user@company.com)"
    password:
      type: string
      description: "Bind password"
      x-soar-sensitive: true
    base_dn:
      type: string
      description: "Base DN (e.g. dc=company,dc=com)"
    secure_connection:
      type: string
      description: "Connection security: None, SSL (LDAPS), TLS, or Start TLS. Password operations require SSL or TLS."
      default: SSL
    ssl_version:
      type: string
      description: "SSL/TLS protocol: None, TLS, TLSv1, TLSv1_1, TLSv1_2, or TLS_CLIENT. Default None (let the library negotiate)."
      default: None
    ntlm:
      type: boolean
      description: "Use NTLM authentication for the bind"
      default: false
    unsecure:
      type: boolean
      description: "Trust any TLS certificate (not secure)"
      default: false
    page_size:
      type: string
      description: "LDAP paging size for searches"
      default: "500"
    default_base_query:
      type: string
      description: "Default LDAP filter used by ad-get-user when no query argument is given"
      default: "(&(objectClass=User)(objectCategory=person))"
  required:
    - server_ip
    - username
    - password
    - base_dn

commands:
  # ── Connectivity ──────────────────────────────────────────────────────────
  - id: test_connection
    name: ad-test-connection
    description: "Bind to the Domain Controller and verify the configured base DN (used by the Test button)."
    risk: read
    inputs_schema:
      properties: {}
      required: []
    outputs_schema: { properties: {} }

  # ── Search / read ─────────────────────────────────────────────────────────
  - id: ad_search
    name: ad-search
    description: "Run a raw LDAP query and return the matching entries. Paging is handled internally up to size-limit."
    risk: read
    inputs_schema:
      properties:
        filter: { type: string, description: "LDAP search filter, e.g. (&(objectCategory=person)(objectClass=user))" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
        attributes: { type: string, description: "CSV list of attributes to return, or ALL for every attribute" }
        size-limit: { type: number, description: "Maximum entries to return (default 50)" }
        time-limit: { type: number, description: "Maximum search time in seconds" }
        page-size: { type: number, description: "Paging size (overrides size-limit when set)" }
      required: [filter]
    outputs_schema: { properties: {} }
  - id: ad_get_user
    name: ad-get-user
    description: "Retrieve user accounts by DN, name, email, sAMAccountName or a custom attribute. Decodes userAccountControl flags."
    risk: read
    inputs_schema:
      properties:
        dn: { type: string, description: "Distinguished Name of the user" }
        name: { type: string, description: "Common name (cn) of the user" }
        email: { type: string, description: "User email (mail)" }
        username: { type: string, description: "sAMAccountName" }
        sAMAccountName: { type: string, description: "sAMAccountName (alias of username)" }
        custom-field-type: { type: string, description: "Attribute name to query by" }
        custom-field-data: { type: string, description: "Attribute value (required with custom-field-type)" }
        attributes: { type: string, description: "CSV list of extra attributes to add to the defaults" }
        attributes-to-exclude: { type: string, description: "CSV list of attributes to remove from the result" }
        limit: { type: number, description: "Maximum users to return (default 20)" }
        page-size: { type: number, description: "Paging size (overrides limit when set)" }
      required: []
    outputs_schema: { properties: {} }
  - id: ad_get_computer
    name: ad-get-computer
    description: "Retrieve computer accounts by DN, name or a custom attribute."
    risk: read
    inputs_schema:
      properties:
        dn: { type: string, description: "Distinguished Name of the computer" }
        name: { type: string, description: "Computer name" }
        custom-field-type: { type: string, description: "Attribute name to query by" }
        custom-field-data: { type: string, description: "Attribute value (required with custom-field-type)" }
        attributes: { type: string, description: "CSV list of extra attributes to add to the defaults" }
        limit: { type: number, description: "Maximum computers to return" }
        page-size: { type: number, description: "Paging size (overrides limit when set)" }
      required: []
    outputs_schema: { properties: {} }
  - id: ad_get_group_members
    name: ad-get-group-members
    description: "List the users, computers or nested groups that are members of a group (recursive by default)."
    risk: read
    inputs_schema:
      properties:
        group-dn: { type: string, description: "Distinguished Name of the group" }
        member-type: { type: string, description: "Member type to return: person, computer or group (default person)" }
        attributes: { type: string, description: "CSV list of extra attributes to add to the defaults" }
        time_limit: { type: number, description: "Search time limit in seconds (default 180)" }
        disable-nested-search: { type: string, description: "Set true to disable recursive membership resolution (default false)" }
        sAMAccountName: { type: string, description: "Filter members by sAMAccountName (default *)" }
        limit: { type: number, description: "Maximum members to return" }
        page-size: { type: number, description: "Paging size (overrides limit when set)" }
      required: [group-dn]
    outputs_schema: { properties: {} }

  # ── Account state ─────────────────────────────────────────────────────────
  - id: ad_enable_account
    name: ad-enable-account
    description: "Enable a previously disabled user account."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName of the account to enable" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
        restore_user: { type: string, description: "Set true to restore the account's previous userAccountControl flags" }
      required: [username]
    outputs_schema: { properties: {} }
  - id: ad_disable_account
    name: ad-disable-account
    description: "Disable a user account."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName of the account to disable" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [username]
    outputs_schema: { properties: {} }
  - id: ad_unlock_account
    name: ad-unlock-account
    description: "Unlock a locked-out user account."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName of the account to unlock" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [username]
    outputs_schema: { properties: {} }
  - id: ad_set_new_password
    name: ad-set-new-password
    description: "Set a new password for a user. Requires a secure connection (SSL or TLS)."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName whose password will be set" }
        password: { type: string, description: "New password", x-soar-sensitive: true }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [username, password]
    outputs_schema: { properties: {} }
  - id: ad_expire_password
    name: ad-expire-password
    description: "Force a user to change their password at next login."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName of the user" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [username]
    outputs_schema: { properties: {} }
  - id: ad_modify_password_never_expire
    name: ad-modify-password-never-expire
    description: "Set or clear the 'Password Never Expire' flag on a user account."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName of the user" }
        value: { type: string, description: "true to set 'Password Never Expire', false to clear it" }
      required: [username, value]
    outputs_schema: { properties: {} }

  # ── Group membership ──────────────────────────────────────────────────────
  - id: ad_add_to_group
    name: ad-add-to-group
    description: "Add a user, computer or nested group to a group."
    inputs_schema:
      properties:
        username: { type: string, description: "Username(s) to add (single or CSV). Mutually exclusive with computer-name." }
        computer-name: { type: string, description: "Computer name(s) to add (single or CSV)" }
        nested_group_cn: { type: string, description: "A group CN to add as a nested member" }
        group-cn: { type: string, description: "Target group CN" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [group-cn]
    outputs_schema: { properties: {} }
  - id: ad_remove_from_group
    name: ad-remove-from-group
    description: "Remove a user or computer from a group."
    inputs_schema:
      properties:
        username: { type: string, description: "Username to remove. Mutually exclusive with computer-name." }
        computer-name: { type: string, description: "Computer name to remove" }
        group-cn: { type: string, description: "Target group CN" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [group-cn]
    outputs_schema: { properties: {} }

  # ── Organizational unit ───────────────────────────────────────────────────
  - id: ad_modify_user_ou
    name: ad-modify-user-ou
    description: "Move a user to a different organizational unit within the domain."
    inputs_schema:
      properties:
        user-name: { type: string, description: "Name of the user to move" }
        full-superior-dn: { type: string, description: "Target OU DN, e.g. OU=users,DC=domain,DC=com" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [user-name, full-superior-dn]
    outputs_schema: { properties: {} }
  - id: ad_modify_computer_ou
    name: ad-modify-computer-ou
    description: "Move a computer to a different organizational unit within the domain."
    inputs_schema:
      properties:
        computer-name: { type: string, description: "Name of the computer to move" }
        full-superior-dn: { type: string, description: "Target OU DN, e.g. OU=computers,DC=domain,DC=com" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [computer-name, full-superior-dn]
    outputs_schema: { properties: {} }

  # ── Object lifecycle: users ───────────────────────────────────────────────
  - id: ad_create_user
    name: ad-create-user
    description: "Create a user account, set its initial password and enable it. Requires a secure connection (SSL or TLS)."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName for the new user" }
        password: { type: string, description: "Initial password (user must change at next login)", x-soar-sensitive: true }
        user-dn: { type: string, description: "Full DN of the new user" }
        display-name: { type: string, description: "Display name" }
        description: { type: string, description: "Description" }
        email: { type: string, description: "Email (mail)" }
        telephone-number: { type: string, description: "Telephone number" }
        title: { type: string, description: "Job title" }
        custom-attributes: { type: string, description: "JSON object of extra attributes, e.g. {\"company\":\"ACME\"}" }
      required: [username, password, user-dn]
    outputs_schema: { properties: {} }
  - id: ad_update_user
    name: ad-update-user
    description: "Replace a single attribute on an existing user."
    inputs_schema:
      properties:
        username: { type: string, description: "sAMAccountName of the user" }
        attribute-name: { type: string, description: "Attribute to modify (e.g. sn, displayName, mail)" }
        attribute-value: { type: string, description: "New value" }
        base-dn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [username, attribute-name, attribute-value]
    outputs_schema: { properties: {} }
  - id: ad_delete_user
    name: ad-delete-user
    description: "Delete a user (or any object) by its DN."
    inputs_schema:
      properties:
        user-dn: { type: string, description: "DN of the object to delete" }
      required: [user-dn]
    outputs_schema: { properties: {} }

  # ── Object lifecycle: contacts ────────────────────────────────────────────
  - id: ad_create_contact
    name: ad-create-contact
    description: "Create a contact object."
    inputs_schema:
      properties:
        contact-dn: { type: string, description: "Full DN of the new contact" }
        display-name: { type: string, description: "Display name" }
        description: { type: string, description: "Description" }
        email: { type: string, description: "Email (mail)" }
        telephone-number: { type: string, description: "Telephone number" }
        title: { type: string, description: "Job title" }
        custom-attributes: { type: string, description: "JSON object of extra attributes" }
      required: [contact-dn]
    outputs_schema: { properties: {} }
  - id: ad_update_contact
    name: ad-update-contact
    description: "Replace a single attribute on an existing contact."
    inputs_schema:
      properties:
        contact-dn: { type: string, description: "DN of the contact" }
        attribute-name: { type: string, description: "Attribute to modify" }
        attribute-value: { type: string, description: "New value" }
      required: [contact-dn, attribute-name, attribute-value]
    outputs_schema: { properties: {} }

  # ── Object lifecycle: groups ──────────────────────────────────────────────
  - id: ad_create_group
    name: ad-create-group
    description: "Create a security or distribution group."
    inputs_schema:
      properties:
        name: { type: string, description: "Group name (sAMAccountName)" }
        group-type: { type: string, description: "security or distribution" }
        dn: { type: string, description: "Full DN of the new group" }
        members: { type: array, description: "DNs of initial members" }
      required: [name, group-type, dn]
    outputs_schema: { properties: {} }
  - id: ad_update_group
    name: ad-update-group
    description: "Replace a single attribute on an existing group."
    inputs_schema:
      properties:
        groupname: { type: string, description: "Group name (cn) to update" }
        attributename: { type: string, description: "Attribute to modify (e.g. description, displayName)" }
        attributevalue: { type: string, description: "New value" }
        basedn: { type: string, description: "Search base (defaults to the instance base_dn)" }
      required: [attributename, attributevalue]
    outputs_schema: { properties: {} }
  - id: ad_delete_group
    name: ad-delete-group
    description: "Delete a security or distribution group by its DN."
    inputs_schema:
      properties:
        dn: { type: string, description: "DN of the group" }
      required: [dn]
    outputs_schema: { properties: {} }

  # ── Credentials ───────────────────────────────────────────────────────────
  - id: ad_test_credentials
    name: ad-test-credentials
    description: "Test whether a username/password can bind to the Domain Controller."
    risk: read
    inputs_schema:
      properties:
        username: { type: string, description: "Username to test (user or SERVER\\\\user)" }
        password: { type: string, description: "Password to test", x-soar-sensitive: true }
      required: [username, password]
    outputs_schema: { properties: {} }
