Repository: ansible/ansible

Issue:
ldap_entry and ldap_attr: add validate_certs option
##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
ldap_entry
ldap_attr

##### ANSIBLE VERSION
```
ansible 2.3.0.0
  config file = /data/ut2bvd/bdod-its/iac/hdp0015/axp/ansible.cfg
  configured module search path = [u'/usr/share/ansible', u'/data/ut2bvd/bdod-builder/roles/hadoop-user/hdfs_modules/library']
  python version = 2.7.5 (default, Oct 11 2015, 17:47:16) [GCC 4.8.3 20140911 (Red Hat 4.8.3-9)]
```

##### CONFIGURATION

##### OS / ENVIRONMENT
linux centos 7

##### SUMMARY
provide a validate_certs ( default true) option on both ldap_entry and ldp_attr modules to be able to connect to ldaps using selfsigned certificates
by specifying validate_certs=false
 
it is quite easy to implement , in _connect_to_ldap we just need to use the         ldap.set_option below
    def _connect_to_ldap(self):
        ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)

##### STEPS TO REPRODUCE
setup a ldap with selfsigned certs and try to add an entry

##### EXPECTED RESULTS


##### ACTUAL RESULTS
any ldap_entry task connecting to a ldap using selfsigned certificates currently fails 

failed: [en1] (item={u'type': u'group', u'name': u'BIG_src-src1-rw', u'members': [u'BIG_src-src1-rw-user']}) => {"details": "{'info': \"TLS error -8179:Peer's Certificate issuer is not recognized.\", 'desc': \"Can't contact LDAP server\"}", "failed": true, "item": {"members": ["BIG_src-src1-rw-user"], "name": "BIG_src-src1-rw", "type": "group"}, "msg": "Cannot bind to the server."}



Discussion:
cc @jtyr
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/net_tools/ldap/ldap_attr.py b/lib/ansible/modules/net_tools/ldap/ldap_attr.py
--- a/lib/ansible/modules/net_tools/ldap/ldap_attr.py
+++ b/lib/ansible/modules/net_tools/ldap/ldap_attr.py
@@ -101,6 +101,14 @@
       - The value(s) to add or remove. This can be a string or a list of
         strings. The complex argument format is required in order to pass
         a list of strings (see examples).
+  validate_certs:
+    required: false
+    choices: ['yes', 'no']
+    default: 'yes'
+    description:
+      - If C(no), SSL certificates will not be validated. This should only be
+        used on sites using self-signed certificates.
+    version_added: "2.4"
 """
 
 
@@ -208,6 +216,7 @@ def __init__(self, module):
         self.server_uri = self.module.params['server_uri']
         self.start_tls = self.module.params['start_tls']
         self.state = self.module.params['state']
+        self.verify_cert = self.module.params['validate_certs']
 
         # Normalize values
         if isinstance(self.module.params['values'], list):
@@ -276,6 +285,9 @@ def _is_value_absent(self, value):
         return not self._is_value_present(value)
 
     def _connect_to_ldap(self):
+        if not self.verify_cert:
+            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
+
         connection = ldap.initialize(self.server_uri)
 
         if self.start_tls:
@@ -312,13 +324,14 @@ def main():
                 default='present',
                 choices=['present', 'absent', 'exact']),
             'values': dict(required=True, type='raw'),
+            'validate_certs': dict(default=True, type='bool'),
         },
         supports_check_mode=True,
     )
 
     if not HAS_LDAP:
         module.fail_json(
-            msg="Missing requried 'ldap' module (pip install python-ldap)")
+            msg="Missing required 'ldap' module (pip install python-ldap)")
 
     # Update module parameters with user's parameters if defined
     if 'params' in module.params and isinstance(module.params['params'], dict):
diff --git a/lib/ansible/modules/net_tools/ldap/ldap_entry.py b/lib/ansible/modules/net_tools/ldap/ldap_entry.py
--- a/lib/ansible/modules/net_tools/ldap/ldap_entry.py
+++ b/lib/ansible/modules/net_tools/ldap/ldap_entry.py
@@ -101,6 +101,14 @@
     default: present
     description:
       - The target state of the entry.
+  validate_certs:
+    required: false
+    choices: ['yes', 'no']
+    default: 'yes'
+    description:
+      - If C(no), SSL certificates will not be validated. This should only be
+        used on sites using self-signed certificates.
+    version_added: "2.4"
 """
 
 
@@ -171,6 +179,7 @@ def __init__(self, module):
         self.server_uri = self.module.params['server_uri']
         self.start_tls = self.module.params['start_tls']
         self.state = self.module.params['state']
+        self.verify_cert = self.module.params['validate_certs']
 
         # Add the objectClass into the list of attributes
         self.module.params['attributes']['objectClass'] = (
@@ -234,6 +243,9 @@ def _is_entry_present(self):
         return is_present
 
     def _connect_to_ldap(self):
+        if not self.verify_cert:
+            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
+
         connection = ldap.initialize(self.server_uri)
 
         if self.start_tls:
@@ -268,17 +280,18 @@ def main():
             'server_uri': dict(default='ldapi:///'),
             'start_tls': dict(default=False, type='bool'),
             'state': dict(default='present', choices=['present', 'absent']),
+            'validate_certs': dict(default=True, type='bool'),
         },
         supports_check_mode=True,
     )
 
     if not HAS_LDAP:
         module.fail_json(
-            msg="Missing requried 'ldap' module (pip install python-ldap).")
+            msg="Missing required 'ldap' module (pip install python-ldap).")
 
     state = module.params['state']
 
-    # Chek if objectClass is present when needed
+    # Check if objectClass is present when needed
     if state == 'present' and module.params['objectClass'] is None:
         module.fail_json(msg="At least one objectClass must be provided.")
 


Test patch: