
    VhpD                        d Z dZddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ dd	lmZ d
Z	 ddlmZ dZ	 ddlZddlmZ ddlmZ ddlmZ dZdZ G d dee      Z!y# e$ r Y /w xY w# e$ rZ d
Ze ZY dZ [ &dZ [ ww xY w)a  
name: ldap
author: Jordan Borean (@jborean93)
short_description: Inventory plugin for Active Directory
version_added: 1.1.0
description:
- Inventory plugin for Active Directory or other LDAP sources.
- Uses a YAML configuration file that ends with C(microsoft.ad.ldap.{yml|yaml}).
- Each host that is added will set the C(inventory_hostname) to the C(name) of
  the LDAP computer object and C(ansible_host) to the value of the
  C(dNSHostName) LDAP attribute if set. If the C(dNSHostName) attribute is not
  set on the computer object then C(ansible_host) is not set. See
  R(LDAP inventory hostname,ansible_collections.microsoft.ad.docsite.guide_ldap_inventory.inventory_hostname)
  for more information on how these values are set and how to adjust them.
- The host fact C(microsoft_ad_distinguished_name) will also be set to the
  distinguished name of the host that was used to derive the host entry.
- Any other fact that is needed, needs to be defined in the I(attributes)
  option.
options:
  attributes:
    description:
    - The LDAP attributes to retrieve.
    - The keys specified are the LDAP attributes requested and the values for
      each attribute is a dictionary that reflects what host var to set it to
      and how.
    - Each key of the inner dictionary value is the host variable name to set
      and the value is the template to use to derive the value. If no value is
      explicitly set then it will use the coerced value as returned from the
      LDAP attribute.
    - Attributes that are denoted as single value in the LDAP schema are
      returned as that single value, multi valued attributes are returned as a
      list of values.
    - See R(LDAP inventory attributes,ansible_collections.microsoft.ad.docsite.guide_ldap_inventory.attributes)
      for more information.
    default: {}
    type: dict
  filter:
    description:
    - The LDAP filter string used to query the computer objects.
    - By default, this will be combined with the filter
      "(objectCategory=computer)". Use I(filter_without_computer) to override
      this behavior and have I(filter) be the only filter used.
    type: str
  filter_without_computer:
    description:
    - Will not combine the I(filter) value with the default filter
      "(objectCategory=computer)".
    - In most cases this should be C(false) but can be set to C(true) to have
      the I(filter) value specified be the only filter used.
    type: bool
    default: false
    version_added: '1.3.0'
  search_base:
    description:
    - The LDAP search base to find the computer objects in.
    - Defaults to the C(defaultNamingContext) of the Active Directory server
      if not specified.
    - If searching a larger Active Directory database, it is recommended to
      narrow the search base to speed up the queries.
    type: str
  search_scope:
    description:
    - The scope of the LDAP search to perform.
    - C(base) will search only the current path or object specified by
      I(search_base). This is typically not useful for inventory plugins.
    - C(one_level) will search only the immediate child objects in
      I(search_base).
    - C(subtree) will search the immediate child objects and any nested
      objects in I(search_base).
    choices:
    - base
    - one_level
    - subtree
    default: subtree
    type: str
notes:
- See R(LDAP inventory,ansible_collections.microsoft.ad.docsite.guide_ldap_inventory)
  for more details on how to use this inventory plugin.
- See R(LAPS,ansible_collections.microsoft.ad.docsite.guide_ldap_inventory.laps)
  for more details on how this plugin can retrieve the LAPS password
  information.
- This plugin is a tech preview and the module options are subject to change
  based on feedback received.
- Unless specified otherwise in the option description, the value specified in
  the config file is used as is. Only the LDAP connection options allow using
  a Jinja2 template.
extends_documentation_fragment:
- constructed
- microsoft.ad.ldap_connection
a  
# Set in the file ending with microsoft.ad.ldap.yml or microsoft.ad.ldap.yaml
plugin: microsoft.ad.ldap


####################################################################
#                        Connection Options                        #
#                                                                  #
# These options control how the plugin connects to the LDAP server #
####################################################################

# Connects to ldap://dc01.domain.com:389
server: dc01.domain.com
port: 389

# Connects to ldaps://dc01.domain.com:636
server: dc01.domain.com
tls_mode: ldaps

# Connects to the global catalog
# ldap://dc01.domain.com:3268
server: dc01.domain.com
port: 3268

# Provides explicit user, will use the current Kerberos ticket if no credential
# is provided.
username: domain-user@DOMAIN.COM
password: Password123!

# Only allow Kerberos authentication.
auth_protocol: kerberos

# Verify LDAPS CA chain with custom CA chain.
tls_mode: ldaps
ca_cert: /home/user/certs/ldap.pem

# The username and password can be retrieved using a template with a lookup.
# Other connection options can also be set this way, the option description
# tells you whether it can be set to a template.
username: '{{ lookup("ansible.builtin.env", "LDAP_USERNAME") }}'
password: '{{ lookup("ansible.builtin.env", "LDAP_PASSWORD") }}'


##############################################
#               Search Options               #
#                                            #
# These options control the searching rules  #
##############################################

# Search for computer accounts in the Workshop OU.
search_base: OU=Workshop A,DC=domain,DC=com

# Filter the computer accounts returned for only ones with the dNSDomainName
# attribute set.
filter: (dNSDomainName=*)

# Filter computer accounts returned for ones starting with PROD and with the
# LAPS password set.
filter: (&(sAMAccountName=PROD*)(ms-Mcs-AdmPwd=*))

# See documentation for more details
attributes:
  sAMAccountName:
    sam_account_name:
  objectSid:
    computer_sid:
  pwdLastSet:
    password_last_set: this | microsoft.ad.as_datetime
  comment:
    host_comment
  memberOf:
    # Gets the value (1) of the first RDN (0) of each memberOf instance (this).
    # For example 'CN=Domain Admins,CN=Users,DC=domain,DC=test'
    # will be returned as just 'Domain Admins'
    computer_membership: this | microsoft.ad.parse_dn | map(attribute="0.1")
  location:


############################################################################
#                             LAPS Integration                             #
#                                                                          #
# Examples on how to use the new Windows LAPS values as connection options #
############################################################################

attributes:
  # msLAPS-Password is used if no encryption has been configured.
  # Currently an encrypted LAPS password is not supported.
  msLAPS-Password:
    ansible_user: (this | from_json).n
    ansible_password: (this | from_json).p

  # msLAPS-EncryptedPassword is used if encryption has been configured.
  # If the Python dpapi-ng library is installed the `this`` value will
  # contain the entry `value` which is the decrypted value. The ``info``
  # entry will contain the reason why the value could not be decrypted.
  msLAPS-EncryptedPassword:
    ansible_user: (this.value | from_json).n
    ansible_password: (this.value | from_json).p

  # ms-Mcs-AdmPwd is used for Legacy LAPS and stores just the password.
  # The username needs to be hardcoded as a string value for this template.
  ms-Mcs-AdmPwd:
    ansible_user: '"Administrator"'
    ansible_password: this


#####################################################################
#                        Constructed Options                        #
#                                                                   #
# These options control the constructed values like vars and groups #
#####################################################################

# Build composed host variables. Requires attributes to be set in the
# attributes option to be referenced here.
compose:
  host_var: computer_sid

# Conditionals that adds found hosts to the groups specified.
groups:
  # Adds all hosts to the windows group
  windows: true

  # Uses the memberOf fact documented above to place the host in the production
  # group if it's a member of that group
  production: '"Production Group" in computer_membership'

# Adds the host to a group site_{{ location }} with the default group of
# site_unknown if the location isn't defined
keyed_groups:
  - key: location | default(omit)
    prefix: site
    default_value: unknown
    N)AnsibleError)InventoryData)missing_required_lib)
DataLoader)BaseInventoryPluginConstructable)wrap_varF)trust_as_templateT   )create_ldap_connection)
LDAPSchema)LAPSDecryptorc            
            e Zd ZdZdedef fdZdededededdf
 fd	Z	de
j                  ee
j                  eef   f   fd
Z xZS )InventoryModulezmicrosoft.ad.ldappathreturnc                 F    t         |   |      r|j                  d      S y)N)zmicrosoft.ad.ldap.ymlzmicrosoft.ad.ldap.yamlF)superverify_fileendswith)selfr   	__class__s     g/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/microsoft/ad/plugins/inventory/ldap.pyr   zInventoryModule.verify_file	  s#    7t$==!TUU    	inventoryloadercacheNc                    t         /|   ||||       | j                          | j                  |       t        s't        ddd      }t        | dt               t        | j                  d      }| j                  d      }| j                  d      }| j                  d	      }	| j                  d
      }
| j                  d      }| j                  d      }| j                  d      }t        j                  j                  t        j                  j                  t        j                  j                  d|   }t        j                  dd      }|	r=t        j                  j!                  |	      }|
r|}nt        j"                  ||g      }n|}| j%                         }ddhj'                  |j)                         D cg c]  }|j+                          c}      }|j-                  dd       }|rd|i|d<   | j/                         }h d}i }t0        sd|d<   |j3                         D ]e  \  }}||v s| j4                  j7                  |      s'| j8                  j;                  d|         | j4                  j<                  d%d|i|||<   g t?        d%i |}tA        d%i |5 }tC        jD                  |      }|jG                  |tI        |      ||      j3                         D ]@  \  }}|j3                         D  !ci c]  \  } }!| j+                         |! }"} }!|"d   d   jK                  d      }#d|i}$|"jM                  dd       }%|%r|%d   jK                  d      |$d<   |j3                         D ]  \  }&}'|"jM                  |&j+                         g       }(|jO                  |&|(      })tQ        |(D *cg c]%  }*tS        jT                  |*      jK                         ' c}*      |$d<   |&j+                         d k(  r#|(r!tQ        |jW                  |(d               |$d!<   ntQ        |)      |$d!<   |'j3                         D ].  \  }+}!t0        rtY        |!      }!	 | j[                  |!|$      },|,|$|+<   0 |$j-                  d       |$j-                  d!        |$jM                  d|#      }.|j_                  |.       |$j3                         D ]  \  }+}!|+dk(  r|ja                  |.|+|!         | jc                  ||$|.|$       | je                  ||$|.|$       | jg                  ||$|.|$       C 	 d d d        y c c}w c c}!} w c c}*w # t\        $ r"}-|rt        d"|+ d#|# d|-       |-Y d }-~-,d }-~-ww xY w# 1 sw Y   y xY w)&Nzsansldap and pyspnegozIhttps://pypi.org/project/sansldap/ and https://pypi.org/project/pyspnego/zfor ldap lookups)urlreasonz: composegroupskeyed_groupsfilterfilter_without_computersearch_basesearch_scopestrict)base	one_levelsubtreeobjectCategorys   computer)filtersnamednshostnameinventory_hostname>   portserverca_certencryptpasswordtls_modeusernamecertificateauth_protocolcert_validationcertificate_keyconnection_timeoutcertificate_passwordFdisable_lookupszTemplating option variable)r$   
attributesr&   r'   r   zutf-8microsoft_ad_distinguished_nameansible_hostrawzmslaps-encryptedpasswordthiszCould not set z
 for host )r(    )4r   parseset_options_read_config_dataHAS_LDAPr   r   LDAP_IMP_ERR
get_optionsansldapSearchScopeBASE	ONE_LEVELSUBTREEFilterEquality
LDAPFilterfrom_string	FilterAnd_get_custom_attributesunionkeyslowerpopget_optionsUSE_DATA_TAGGINGitemstemplaris_templatedisplayvvvtemplater   r   r   load_schemasearchlistdecodegetcast_objectr	   base64	b64encodedecryptr
   _compose	Exceptionadd_hostset_variable_set_composite_vars_add_host_to_composed_groups_add_host_to_keyed_groups)0r   r   r   r   r   msgr!   r"   r#   ldap_filterldap_filter_without_computerr&   r'   r(   ldap_search_scopecomputer_filterldap_filter_objfinal_filtercustom_attributesar@   r0   connection_optionstemplate_fieldstemplated_option_kwargsoption_nameoption_valuelaps_decryptorclientschemadninfokvinsensitive_info	host_name	host_varsdns_host_namer.   var_info
raw_valuesvaluesrn	compositeeactual_host_namer   s0                                                  r   rF   zInventoryModule.parse  s    	iu5t$&'_)C
 #b78lJ//),*~6ooh/'+7P'Q$oom4~6* ((--!--77++33
 	 #112BKP&11==kJO+.'11,o>  +L 779m,22 1 6 6 891QWWY9

 %[[)=tD$&8723 "--/
 #%9>#$56);)A)A)C 	%Ko-$,,2J2J3   #5k]!CD2G$,,2G2G 3)3-3";/	 '<);<#9&89 B	V++F3F"MM#
+'.	 * 
 eg?D >BZZ\#JTQAGGIqL#J #J,V4Q7>>wG	5r1	 !1 4 4]D I 0=a0@0G0G0PIn-&7&=&=&? *ND(!1!5!5djjlB!GJ#//jAF'/?IJ!))!,335J(Ie$ zz|'AAj,4^5K5KJWXM5Z,[	&),4V,<	&) ( 0 11+ 1! 4A%(,a(CI (1	!1 MM%(MM&);*> $-==1Ey#Q ""#34%OO- CDAq00 **+;QBC
 ((Y(8 )  11I'7 2  .. )-=f / {?B	 B	Y :j $K  K  ) %%&2&4QCz)Bqc$R'"'(!) %%OB	 B	s^   T9)AU7T>
 BU7;*U%A5U7U	-CU7>U7		U4U/)U7/U44U77V c                    | j                  d      }i }|j                         D ]  \  }}|s|j                  dd      di}nZt        |t              r|j                  dd      |i}n5t        |t
              s%t        d| dt        |      j                   d      t        |j                               D ]G  }||   }|sd||<   t        |t              r!t        d| d| d	t        |      j                   d
       |||<    |S )Nr@   -_rD   z
Attribute z value was z but was expecting a dictionary.z template value was z but was expecting a string)rK   r\   replace
isinstancestrdictr   type__name__rd   rW   )r   ry   processed_attributesr.   r   var_namevar_templates          r   rU   z&InventoryModule._get_custom_attributes  s)    OOL9>@+113 	.JD$S#.7D#&S#.5d+" k$t*2E2E1FFef  !- #H~#%+DN#L#6&$TF!H:5I$|J\JeJeIf  gB  C  *. &)	., $#r   )r   
__module____qualname__NAMEr   boolr   r   r   rF   tDictrU   __classcell__)r   s   @r   r   r     s~    D  ` ` ` 	`
 ` 
`D$sAFF384D/D(E $r   r   )"DOCUMENTATIONEXAMPLESrh   typingr   ansible.errorsr   ansible.inventory.datar   ansible.module_utils.basicr   ansible.parsing.dataloaderr   ansible.plugins.inventoryr   r   ansible.utils.unsafe_proxyr	   r[   ansible.templater
   ImportErrorrL   plugin_utils._ldapr   plugin_utils._ldap.schemar   plugin_utils._ldap.lapsr   rI   rJ   rl   r   r   rE   r   r   <module>r      s   YvDL   ' 0 ; 1 H / 	2
;67HLE$)= E$%  		  HLs(   A& A1 &A.-A.1B6A??B