def _ldap_bind(self):
        """
        Set LDAP binding
        """

        #ldap.set_option(ldap.OPT_DEBUG_LEVEL, 4095)

        if self.auth_type == 'gssapi' :
            if not ldap.SASL_AVAIL:
                raise AnsibleLookupError("Cannot use auth=gssapi when SASL is not configured with the local LDAP install")
            # if self.username or self.password:
            #     raise AnsibleError("Explicit credentials are not supported when auth_type='gssapi'. Call kinit outside of Ansible")
        elif self.auth_type == 'simple' and not (self.username and  self.password):
            raise AnsibleError("The username and password values are required when auth_type=simple")
        else:
            if self.username and self.password:
                pass
                # self.auth_type = 'simple'
            if ldap.SASL_AVAIL:
                self.auth_type == 'gssapi'
            else:
                raise AnsibleError("Invalid auth_type value '%s': expecting either 'gssapi', or 'simple'" % self.auth_type)
        
        if ldapurl.isLDAPUrl(self.domain):
            ldap_url = ldapurl.LDAPUrl(ldapUrl=self.domain)
        else:
            self.port = self.port if self.port else 389 if self.scheme == 'ldap' else 636
            ldap_url = ldapurl.LDAPUrl(hostport="%s:%d" % (self.domain, self.port), urlscheme=self.scheme)             
        
        if self.validate_certs is False :
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) 
        
        if not ldap.TLS_AVAIL and conn_url.urlscheme == 'ldaps':
            raise AnsibleLookupError("Cannot use TLS as the local LDAP installed has not been configured to support it")
        
        conn_url = ldap_url.initializeUrl()
        #self.ldap_session = MyLDAPObject(conn_url, trace_level=3)  # higher trace levels
        self.ldap_session = MyLDAPObject(conn_url)
        self.ldap_session.page_size = 900
        self.ldap_session.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
        self.ldap_session.set_option(ldap.OPT_REFERRALS, 0)
 
        if self.auth_type == 'simple':
            try:
                self.ldap_session.bind_s(self.username, self.password, ldap.AUTH_SIMPLE)
            except ldap.LDAPError as err:
                raise AnsibleError("Failed to simple bind against LDAP host '%s': %s " % (conn_url, to_native(err)))
        else:
            cmd = ['kinit', self.username]
            error_code = subprocess.run(cmd, input=self.password.encode(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode
            if error_code > 0:
                raise AnsibleError("kinit failure")
            try:
                self.ldap_session.sasl_gssapi_bind_s()
            except ldap.AUTH_UNKNOWN as err:
                # The SASL GSSAPI binding is not installed, e.g. cyrus-sasl-gssapi. Give a better error message than what python-ldap provides
                raise AnsibleError("Failed to do a sasl bind against LDAP host '%s', the GSSAPI mech is not installed: %s" % (conn_url, to_native(err)))
            except ldap.LDAPError as err:
                raise AnsibleError("Failed to do a sasl bind against LDAP host '%s': %s" % (conn_url, to_native(err)))                
Example #2
0
    def authLDAP(self, username, password):
        import ldap, ldapurl
        ld = ldapurl.LDAPUrl(self.ldapUrl)

        ldapConnector = ldap.open(ld.hostport.split(':')[0])
        ldapConnector.protocol_version = ldap.VERSION3

        ldapConnector.simple_bind(self.authdn, self.password)
        searchScope = ldap.SCOPE_SUBTREE
        retrieveAttributes = ["userPassword"]
        if ld.filterstr:
            searchFilter = "(&(%s=%s)%s)" % (ld.attrs[0],username,ld.filterstr)
        else:
            searchFilter = "%s=%s" % (ld.attrs[0],username)

        try:
            ldap_result_id = ldapConnector.search(ld.dn, searchScope, searchFilter, retrieveAttributes)
            result_set = []
            while 1:
                result_type, result_data = ldapConnector.result(ldap_result_id, 0)
                if (result_data == []):
                    break
                else:
                    if result_type == ldap.RES_SEARCH_ENTRY:
                        result_set.append(result_data)
            if not result_set:
                return False

            return result_set[0][0][1]

        except ldap.LDAPError, e:
            print "[Enamel Error] Error in LDAP user lookup."
            print e
            return False
Example #3
0
    def __init__(self, host, port, encoding, dn='', password=''):
        """
        Connects to a LDAP server
        can raise ldap.LDAPError
        """
        if not host.startswith('ldap://'):
            uri = 'ldap://' + host
        else:
            uri = host

        if port != 389:
            uri += ':' + str(port)

        log.debug('Connecting to %s', uri)

        ldap_conn = ldap.initialize(uri)
        ldap_conn.protocol_version = ldap.VERSION3

        if dn != '' and password != '':
            log.debug('Binding %s', dn)
            ldap_conn.simple_bind_s(dn, password)

        self._ldap_url = ldapurl.LDAPUrl(uri)
        self._connection = ldap_conn
        self._encoding = encoding
Example #4
0
def changePassword(user_identifier, old_pass, new_pass):

    lu = ldapurl.LDAPUrl(LDAP_URL)

    l = ldap.initialize(lu.initializeUrl())

    l.protocol_version = ldap.VERSION3

    l.simple_bind_s(LDAP_ROOT_USER_DN, LDAP_ROOT_USER_PASS)

    user_dn, detail = get_user_dn(l, user_identifier)

    if user_dn:
        try:
            output = l.passwd_s(user_dn, old_pass, new_pass)
            res = ResponseStatus(200, "SUCCESS",
                                 "Password changed successfully")
        except ldap.UNWILLING_TO_PERFORM:
            res = ResponseStatus(400, "OLDPASSWRONG",
                                 "Old Password not correct")
        except:
            res = ResponseStatus(400, "WENTWRONG", "Something went wrong")
    else:
        res = ResponseStatus(400, "NOUSERNAMEFOREMAIL",
                             "No dn found for email")

    l.unbind_s()

    return res
Example #5
0
def reset_password(user_email, new_pass):

    lu = ldapurl.LDAPUrl(LDAP_URL)

    l = ldap.initialize(lu.initializeUrl())
    l.set_option(ldap.OPT_REFERRALS, 0)
    l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
    l.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND)
    l.set_option(ldap.OPT_X_TLS_DEMAND, True)
    l.simple_bind_s(LDAP_ROOT_USER_DN, LDAP_ROOT_USER_PASS)

    user_dn, detail = get_user_dn(l, user_email)

    if not user_dn:
        res = ResponseStatus(400, "NOUSERNAMEFOREMAIL",
                             "No dn found for email")
    else:
        sha1coded = hashlib.sha1(bytes(new_pass, "utf-8")).hexdigest()
        password_value = bytes(
            "{SHA}" +
            base64.b64encode(binascii.unhexlify(sha1coded)).decode('utf-8'),
            'utf-8')

        add_pass = [(ldap.MOD_REPLACE, 'userPassword', [password_value])]
        try:
            l.modify_s(user_dn, add_pass)
            res = ResponseStatus(200, "SUCCESS",
                                 "Password changed successfully")
        except Exception as e:
            res = ResponseStatus(400, "WENTWRONG", e.args[0])

    l.unbind_s()

    return res
Example #6
0
 def __wait_for_connection(self, timeout):
     lurl = ldapurl.LDAPUrl(self.uri)
     if lurl.urlscheme == 'ldapi':
         wait_for_open_socket(lurl.hostport, timeout)
     else:
         (host,port) = lurl.hostport.split(':')
         wait_for_open_ports(host, int(port), timeout)
Example #7
0
File: ldap.py Project: peuter/gosa
def check_auth(user, password, get_dn=False):
    get = Environment.getInstance().config.get
    log = logging.getLogger(__name__)

    url = ldapurl.LDAPUrl(get("ldap.url"))
    bind_user = get('ldap.bind-user', default=None)
    bind_dn = get('ldap.bind-dn', default=None)
    bind_secret = get('ldap.bind-secret', default=None)

    conn = ldap.ldapobject.ReconnectLDAPObject(
        "%s://%s" % (url.urlscheme, url.hostport),
        retry_max=int(get("ldap.retry-max", default=3)),
        retry_delay=int(get("ldap.retry-delay", default=5)))

    # We only want v3
    conn.protocol_version = ldap.VERSION3

    # If no SSL scheme used, try TLS
    if get("ldap.tls", default="True").lower(
    ) == "true" and ldap.TLS_AVAIL and url.urlscheme != "ldaps":
        try:
            conn.start_tls_s()
        except ldap.PROTOCOL_ERROR as detail:
            log.debug("cannot use TLS, falling back to unencrypted session")

    try:
        # Get a connection
        if bind_dn:
            log.debug("starting simple bind using '%s'" % bind_dn)
            conn.simple_bind_s(bind_dn, bind_secret)
        elif bind_user:
            log.debug("starting SASL bind using '%s'" % bind_user)
            auth_tokens = ldap.sasl.digest_md5(bind_user, bind_secret)
            conn.sasl_interactive_bind_s("", auth_tokens)
        else:
            log.debug("starting anonymous bind")
            conn.simple_bind_s()

        # Search for the given user UID
        res = conn.search_s(
            url.dn, ldap.SCOPE_SUBTREE,
            filter_format(
                "(|(&(objectClass=registeredDevice)(deviceUUID=%s))(&(objectClass=person)(uid=%s)))",
                [user, user]), ['dn'])

        if len(res) == 1:
            dn = res[0][0]
            log.debug("starting simple bind using '%s'" % dn)
            conn.simple_bind_s(dn, password)
            return True if not get_dn else dn
        elif len(res) > 1:
            log.error("LDAP authentication failed: user %s not unique" % user)
        else:
            log.error("LDAP authentication failed: user %s not found" % user)

    except ldap.INVALID_CREDENTIALS as detail:
        log.error("LDAP authentication failed: %s" % str(detail))

    return False
Example #8
0
 def removeServer(self, host, port, protocol):
     """ Remove a server definition from the list of servers used
     """
     hp = '%s:%s' % (host, port)
     conn = ldapurl.LDAPUrl(urlscheme=protocol, hostport=hp)
     server_url = conn.initializeUrl()
     if server_url in self.servers.keys():
         del self.servers[server_url]
Example #9
0
    def __init__(self, username, passwd):
        self.username = username
        self.passwd = passwd

        self.use_tls = False
        self.ldap_url = ldapurl.LDAPUrl(settings.LDAP_HOST)
        if self.ldap_url.urlscheme == 'ldaps':
            self.use_tls = True
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW)
Example #10
0
 def __init__(self,ldap_url):
   self.ldap_url = ldapurl.LDAPUrl(ldap_url)
   # Open the connection
   self.l = ldap.ldapobject.SimpleLDAPObject(
     self.ldap_url.initializeUrl(),trace_level=0
   )
   self.stop_event = threading.Event()
   threading.Thread.__init__(self)
   self.setName(self.__class__.__name__+self.getName()[6:])
   print 'Initialized',self.getName(),self.ldap_url.unparse()
Example #11
0
    def test_remove_server(self):
        conn = self._makeSimple()
        existing = list(conn.servers.values())[0]
        ldap_url = ldapurl.LDAPUrl(existing['url'])
        host, port = ldap_url.hostport.split(':')
        protocol = ldap_url.urlscheme

        conn.removeServer(host, port, protocol)

        self.assertEqual(len(conn.servers.values()), 0)
Example #12
0
def urlfetch(uri, trace_level=0):
    """
  Fetches a parsed schema entry by uri.

  If uri is a LDAP URL the LDAP server is queried directly.
  Otherwise uri is assumed to point to a LDIF file which
  is loaded with urllib.
  """
    uri = uri.strip()
    if uri.startswith('ldap:') or uri.startswith('ldaps:') or uri.startswith(
            'ldapi:'):
        import ldapurl
        ldap_url = ldapurl.LDAPUrl(uri)

        # This is an internal function; don't enable bytes_mode.
        l = ldap.initialize(ldap_url.initializeUrl(),
                            trace_level,
                            bytes_mode=False)
        l.protocol_version = ldap.VERSION3
        l.simple_bind_s(ldap_url.who or '', ldap_url.cred or '')
        subschemasubentry_dn = l.search_subschemasubentry_s(ldap_url.dn)
        if subschemasubentry_dn is None:
            s_temp = None
        else:
            if ldap_url.attrs is None:
                schema_attrs = SCHEMA_ATTRS
            else:
                schema_attrs = ldap_url.attrs
            s_temp = l.read_subschemasubentry_s(subschemasubentry_dn,
                                                attrs=schema_attrs)
        l.unbind_s()
        del l
    else:
        import ldif
        from ldap.compat import urlopen
        ldif_file = urlopen(uri)
        ldif_parser = ldif.LDIFRecordList(ldif_file, max_entries=1)
        ldif_parser.parse()
        subschemasubentry_dn, s_temp = ldif_parser.all_records[0]
    # Work-around for mixed-cased attribute names
    subschemasubentry_entry = ldap.cidict.cidict()
    s_temp = s_temp or {}
    for at, av in s_temp.items():
        if at in SCHEMA_CLASS_MAPPING:
            try:
                subschemasubentry_entry[at].extend(av)
            except KeyError:
                subschemasubentry_entry[at] = av
    # Finally parse the schema
    if subschemasubentry_dn != None:
        parsed_sub_schema = ldap.schema.SubSchema(subschemasubentry_entry)
    else:
        parsed_sub_schema = None
    return subschemasubentry_dn, parsed_sub_schema
    def __init__(self, config_file):
        """
        Initializes LDAP server communication wrapper with provided config file
        """
        config = ConfigParser.ConfigParser()
        config.read(config_file)
        try:
            self.ldap_username = config.get('active_directory', 'username')
            self.ldap_password = config.get('active_directory', 'password')
            self.ldap_provider_url = config.get('active_directory',
                                                'provider_url')
            self.ldap_dn = config.get('active_directory', 'dn')
            self.ldap_protocol_version = config.get('active_directory',
                                                    'protocol_version')
            self.ldap_enable_tls = config.get('active_directory',
                                              'tls_enabled')
            self.ldap_filter = config.get('active_directory', 'ldap_filter')
            self.ldap_user_name = config.get('active_directory',
                                             'ldap_user_name')
            self.ldap_user_surname = config.get('active_directory',
                                                'ldap_user_surname')
            self.ldap_user_email = config.get('active_directory',
                                              'ldap_user_email')
            self.ldap_user_uid = config.get('active_directory',
                                            'ldap_user_uid')
        except ConfigParser.NoOptionError as e:
            print "[x] Error: Config file is not complete! Section '%s' must contain option '%s'. " \
                  "Check config examples at https://github.com/Oomnitza.\nExiting." % (e.section, e.option)
            sys.exit(2)
        ldap.set_option(ldap.OPT_REFERRALS, 0)
        ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 30)

        # the default LDAP protocol version - if not recognized - is v3
        if self.ldap_protocol_version == '2':
            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION2)
        else:
            self.ldap_protocol_version = '3'
            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)
        try:
            parsed_url = ldapurl.LDAPUrl(self.ldap_provider_url)
        except ValueError:
            print "[x] Error: Invalid url to LDAP service. Check config examples at https://github.com/Oomnitza." \
                  "\nExiting"
            sys.exit(2)
        self.ldap_connection = ldap.initialize(parsed_url.unparse())
        if self.ldap_enable_tls in ['True', 'true', '1'
                                    ] and self.ldap_protocol_version == '3':
            try:
                self.ldap_connection.start_tls_s()
            except ldap.PROTOCOL_ERROR:
                print "[x] Error: LDAP server do not support TLS connection. Change the 'tls_enabled' to 'False' if " \
                      "you allow insecure data transfer.\nExiting"
                sys.exit(2)
Example #14
0
def test_ticket48013(topology_st):
    '''
    Content Synchonization: Test that invalid cookies are caught
    '''

    cookies = ('#', '##', 'a#a#a', 'a#a#1')

    # Enable dynamic plugins
    try:
        topology_st.standalone.modify_s(
            DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', b'on')])
    except ldap.LDAPError as e:
        log.error('Failed to enable dynamic plugin! {}'.format(
            e.args[0]['desc']))
        assert False

    # Enable retro changelog
    topology_st.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG)

    # Enbale content sync plugin
    topology_st.standalone.plugins.enable(name=PLUGIN_REPL_SYNC)

    # Set everything up
    ldap_url = ldapurl.LDAPUrl('ldap://%s:%s' %
                               (HOST_STANDALONE, PORT_STANDALONE))
    ldap_connection = SyncObject(ldap_url.initializeUrl())

    # Authenticate
    try:
        ldap_connection.simple_bind_s(DN_DM, PASSWORD)
    except ldap.LDAPError as e:
        log.error('Login to LDAP server failed: {}'.format(e.args[0]['desc']))
        assert False

    # Test invalid cookies
    for invalid_cookie in cookies:
        log.info('Testing cookie: %s' % invalid_cookie)
        try:
            ldap_connection.sync_search(invalid_cookie)
            ldap_connection.poll()
            log.fatal('Invalid cookie accepted!')
            assert False
        except Exception as e:
            log.info('Invalid cookie correctly rejected: {}'.format(
                e.args[0]['info']))
            pass

    # Success
    log.info('Test complete')
Example #15
0
    def __init__(self, who=None, cred="", method="", auth=None):
        # Parse the openldap config file
        try:
            configfile = open("/etc/openldap/ldap.conf")
            regexBase = re.compile("^BASE\s+(.*)$")
            regexHost = re.compile("^URI\s+(.*)$")
            for line in configfile.xreadlines():
                find = regexBase.search(line)
                if find != None:
                    self.dnBase = find.expand(r"\1").strip()
                else:
                    find = regexHost.search(line)
                    if find != None:
                        self.strLDAPServer = find.expand(r"\1").strip()
#                       if self.strLDAPServer.startswith('ldap://'):
#                           self.strLDAPServer = self.strLDAPServer[7:]
#                           self.strLDAPServer = self.strLDAPServer.rstrip('/')
            if self.dnBase == None:
                raise RuntimeError, "No BASE statement in config file"
            if self.strLDAPServer == None:
                raise RuntimeError, "No HOST statement in config file"
            servers = self.strLDAPServer.split()

        except:
            raise RuntimeError, "could not read LDAP configuration: %s (line %d)" % (
                sys.exc_value, sys.exc_traceback.tb_lineno)
        # Open the LDAP database
        connected = "N"
        for strLDAPServer in servers:
            try:
                # print "Connecting to %s" %strLDAPServer
                #ldapdb_url=ldapurl.LDAPUrl(hostport=strLDAPServer, dn=self.dnBase)
                ldapdb_url = ldapurl.LDAPUrl(strLDAPServer + "/" + self.dnBase)
                self.ldapHandle = ldap.initialize(ldapdb_url.unparse())
                if who == None:
                    # Bind as user anonymous
                    self.ldapHandle.simple_bind_s()
                elif auth == None:
                    # Bind using the simple authentication
                    self.ldapHandle.bind_s(who, cred, method)
                else:
                    self.ldapHandle.sasl_interactive_bind_s(who, auth)
                connected = "Y"
                break
            except:
                print "Unable to connect to server. Will try the next one."
            if (connected == "N"):
                raise RuntimeError, "could not connect to LDAP: %s (line %d)" % (
                    sys.exc_value, sys.exc_traceback.tb_lineno)
Example #16
0
def get_email_from_identifier(user_identifier):
    lu = ldapurl.LDAPUrl(LDAP_URL)

    l = ldap.initialize(lu.initializeUrl())

    l.protocol_version = ldap.VERSION3

    l.simple_bind_s(LDAP_ROOT_USER_DN, LDAP_ROOT_USER_PASS)

    user_dn, detail = get_user_dn(l, user_identifier)

    if detail and "mail" in detail and detail["mail"]:
        return detail["mail"][0].decode("utf-8")
    else:
        return None
Example #17
0
    def _handle_referral(self, exception):
        """ Handle a referral specified in the passed-in exception
        """
        payload = exception.args[0]
        info = payload.get('info')
        ldap_url = info[info.find('ldap'):]

        if ldapurl.isLDAPUrl(ldap_url):
            conn_str = ldapurl.LDAPUrl(ldap_url).initializeUrl()
            conn = self._connect(conn_str)
            conn.simple_bind_s(self._encode_incoming(self.bind_dn),
                               self._encode_incoming(self.bind_pwd))
            return conn
        else:
            raise ldap.CONNECT_ERROR('Bad referral "%s"' % str(exception))
Example #18
0
    def test_add_server_existing(self):
        # If a LDAP server definition with the same LDAP URL exists, it
        # will be replaced with the new values.
        conn = self._makeSimple()
        existing = list(conn.servers.values())[0]
        ldap_url = ldapurl.LDAPUrl(existing['url'])
        host, port = ldap_url.hostport.split(':')
        protocol = ldap_url.urlscheme

        conn.addServer(host, port, protocol, conn_timeout=10, op_timeout=15)

        self.assertEqual(len(conn.servers.values()), 1)
        server = list(conn.servers.values())[0]
        self.assertEqual(server['url'], 'ldap://host:636')
        self.assertEqual(server['conn_timeout'], 10)
        self.assertEqual(server['op_timeout'], 15)
Example #19
0
 def addServer(self, host, port, protocol, conn_timeout=-1, op_timeout=-1):
     """ Add a server definition to the list of servers used
     """
     start_tls = False
     if protocol == 'ldaptls':
         protocol = 'ldap'
         start_tls = True
     hp = '%s:%s' % (host, port)
     conn = ldapurl.LDAPUrl(urlscheme=protocol, hostport=hp)
     server_url = conn.initializeUrl()
     self.servers[server_url] = {
         'url': server_url,
         'conn_timeout': conn_timeout,
         'op_timeout': op_timeout,
         'start_tls': start_tls
     }
Example #20
0
    def info_from_ldap(self, config=None, password=''):
        """
        Get information about this user from LDAP.
        """

        import ldap, ldapurl
        resp = {"result": "ERROR"}
        if not config:
            config = CRITsConfig.objects().first()
        # Make sure we have the rquired settings, else return failure
        if not config.ldap_server or not config.ldap_userdn:
            return resp
        ldap_server = config.ldap_server.split(':')
        scheme = "ldap"
        if config.ldap_tls:
            scheme = "ldaps"
        url = ldapurl.LDAPUrl('%s://%s' % (scheme, ldap_server[0]))
        if len(ldap_server) == 2:
            l = ldap.initialize('%s:%s' % (url.unparse(),
                                           ldap_server[1]))
        else:
            l = ldap.initialize(url.unparse())
        l.protocol_version = 3
        l.set_option(ldap.OPT_REFERRALS, 0)
        l.set_option(ldap.OPT_TIMEOUT, 10)
        # setup auth for custom cn's
        cn = "cn="
        if config.ldap_usercn:
            cn = config.ldap_usercn
        # setup auth for custom cn's
        if len(config.ldap_usercn) > 0:
            un = "%s%s,%s" % (config.ldap_usercn,
                              self.username,
                              config.ldap_userdn)
        elif "@" in config.ldap_userdn:
            un = "%s%s" % (self.username, config.ldap_userdn)
        else:
            un = self.username
	try:
            # Try auth bind first
            l.simple_bind_s(un, password)
            logger.info("Bound to LDAP for: %s" % self.username)
        except Exception, e:
            logger.error("Error binding to LDAP for: %s" % self.username)
            logger.error("ERR: %s" % e)
Example #21
0
File: ldap.py Project: peuter/gosa
    def __init__(self):
        self.env = Environment.getInstance()
        self.log = logging.getLogger(__name__)

        # Initialize from configuration
        get = self.env.config.get
        self.__url = ldapurl.LDAPUrl(get("ldap.url"))
        self.__bind_user = get('ldap.bind-user', default=None)
        self.__bind_dn = get('ldap.bind-dn', default=None)
        self.__bind_secret = get('ldap.bind-secret', default=None)
        self.__pool = int(get('ldap.pool-size', default=10))

        # Sanity check
        if self.__bind_user and not ldap.SASL_AVAIL:
            raise LDAPException(C.make_error("NO_SASL_SUPPORT"))

        # Initialize static pool
        LDAPHandler.connection_handle = [None] * self.__pool
        LDAPHandler.connection_usage = [False] * self.__pool
Example #22
0
def validate_ldap_url(param, options=None):
    """
    Raises ParamValidationError if provided param is not a valid LDAP URL
    """
    if not param:
        return
    try:
        import ldapurl
    except ImportError:
        msg = (
            'The python ldap package is required to use this functionality.')
        raise ParamValidationError(msg)

    try:
        ldapurl.LDAPUrl(param)
    except ValueError as ve:
        msg = ('The given string [%s] is not a valid LDAP URL: %s' %
               (param, ve))
        raise ParamValidationError(msg)
Example #23
0
def urlfetch(uri, trace_level=0):
    """
  Fetches a parsed schema entry by uri.

  If uri is a LDAP URL the LDAP server is queried directly.
  Otherwise uri is assumed to point to a LDIF file which
  is loaded with urllib.
  """
    uri = uri.strip()
    if uri.startswith('ldap:') or uri.startswith('ldaps:') or uri.startswith(
            'ldapi:'):
        import ldapurl
        ldap_url = ldapurl.LDAPUrl(uri)
        l = ldap.initialize(ldap_url.initializeUrl(), trace_level)
        l.protocol_version = ldap.VERSION3
        l.simple_bind_s(ldap_url.who or '', ldap_url.cred or '')
        subschemasubentry_dn = l.search_subschemasubentry_s(
            ldap_url.dn).decode()
        if subschemasubentry_dn is None:
            subschemasubentry_entry = None
        else:
            if ldap_url.attrs is None:
                schema_attrs = SCHEMA_ATTRS
            else:
                schema_attrs = ldap_url.attrs
            subschemasubentry_entry = l.read_subschemasubentry_s(
                subschemasubentry_dn, attrs=schema_attrs)
        subschemasubentry_entry = By2Str(subschemasubentry_entry)
        l.unbind_s()
        del l
    else:
        import urllib.request, ldif
        ldif_file = urllib.request.urlopen(uri)
        ldif_parser = ldif.LDIFRecordList(ldif_file, max_entries=1)
        ldif_parser.parse()
        subschemasubentry_dn, subschemasubentry_entry = ldif_parser.all_records[
            0]
    if subschemasubentry_dn != None:
        parsed_sub_schema = ldap.schema.SubSchema(subschemasubentry_entry)
    else:
        parsed_sub_schema = None
    return subschemasubentry_dn, parsed_sub_schema
Example #24
0
def ldap_connect(dn=None, pwd=None, host=None):
    #    '''Connects to LDAP. The connection is cached.
    #
    #    If uid is not None, it is taken as the user to connect as,
    #    otherwise it chooses the current user. If password is None, it
    #    will attempt to connect first without a password and if that fails
    #    it will try to read a password from the terminal
    #    '''
    #    global _ldap_conn
    #    if uid is None and pwd is None and _ldap_conn is not None:
    #        return _ldap_conn
    #    if uid is None:
    #        dn = ldap_myself()
    #    else:
    #        dn = ldap_byuid(uid)

    #    l = _ldap_conn
    #    l.simple_bind_s(dn, pwd)
    #    return l
    global _ldap_conn
    if dn is None:
        # if no DN is specified, we try ldapi first
        try:
            l = ldap.initialize("ldapi:///")
            l.sasl_interactive_bind_s("", ldap.sasl.external())
        except:
            l = ldap.initialize(options.HOST)
            if options.UseTLS:
                l.set_option(ldap.OPT_X_TLS_CACERTFILE, options.TLS_CACERTFILE)
                l.start_tls_s()
            uid = mod_pwd.getpwuid(os.getuid())[0]
            passwd = getpass.getpass()
            l.simple_bind_s(uidfmt % uid, passwd)
    else:
        if host is None:
            host = "127.0.0.1"
            l = ldap.initialize(str(ldapurl.LDAPUrl(host)))
            l.simple_bind(dn, pwd)
    _ldap_conn = l
    return l
Example #25
0
    def __init__(self):
        self.config = Config.get_instance()
        self.log = logging.getLogger(__name__)

        # Initialize from configuration
        get = self.config.get
        self.__url = ldapurl.LDAPUrl(get("ldap.url"))
        self.__bind_user = get('ldap.bind_user', default=None)
        self.__bind_dn = get('ldap.bind_dn', default=None)
        self.__bind_secret = get('ldap.bind_secret', default=None)
        self.__pool = int(get('ldap.pool_size', default=10))

        # Sanity check
        if self.__bind_user and not ldap.SASL_AVAIL:
            self.log.error("bind_user needs SASL support, which doesn't seem to be available in python-ldap")
            sys.exit(1)

        if not self.__url:
            self.log.error("there is no 'url' specified in the 'ldap' section of the configuration file")
            sys.exit(1)

        # Initialize static pool
        LDAPHandler.connection_handle = [None] * self.__pool
        LDAPHandler.connection_usage = [False] * self.__pool
Example #26
0
    def authenticate(self):
        # ldap.set_option(ldap.OPT_DEBUG_LEVEL, 1)
        ldap.set_option(ldap.OPT_REFERRALS, 0)
        ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 30)

        # the default LDAP protocol version - if not recognized - is v3
        if self.settings['protocol_version'] == '2':
            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION2)
        else:
            if self.settings['protocol_version'] != '3':
                LOG.warning("Unrecognized Protocol Version '%s', setting to '3'.", self.settings['protocol_version'])
                self.settings['protocol_version'] = '3'
            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)

        try:
            parsed_url = ldapurl.LDAPUrl(self.settings['url'])
        except ValueError:
            raise AuthenticationError("Invalid url to LDAP service. "
                                      "Check config examples at https://github.com/Oomnitza/oomnitza-connector")
        self.ldap_connection = ldap.initialize(parsed_url.unparse())

        cacert_file = self.settings.get('cacert_file', '')
        if cacert_file:
            cacert_file = os.path.abspath(cacert_file)
            if not os.path.isfile(cacert_file):
                raise ConfigError("%s is not a valid file!" % cacert_file)
            LOG.info("Setting CACert File to: %r.", cacert_file)
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, cacert_file)
        cacert_dir = self.settings.get('cacert_dir', '')
        if cacert_dir:
            cacert_dir = os.path.abspath(cacert_dir)
            if not os.path.isdir(cacert_dir):
                raise ConfigError("%s is not a valid directory!" % cacert_dir)
            LOG.info("Setting CACert Dir to: %r.", cacert_dir)
            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, cacert_dir)

        # check for tls
        # if self.settings['enable_tls'] in self.TrueValues and self.settings['protocol_version'] == '3':
        if self.settings.get('verify_ssl', True) in TrueValues:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
        else:
            LOG.warning("verify_ssl = '%s' so SSL certificate validation has been disabled.", self.settings.get('verify_ssl', True))
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW)

        try:
            if self.settings['username'].lower() == 'anonymous':
                self.ldap_connection.simple_bind_s()
            else:
                password = self.settings['password']
                if not password:
                    LOG.warning("No password set for LDAP. Connecting without password.")
                    password = u""

                self.ldap_connection.simple_bind_s(self.settings['username'], password)
        except ldap.INVALID_CREDENTIALS:
            LOG.exception("Error calling simple_bind_s()")
            raise AuthenticationError("Cannot connect to the LDAP server with given credentials. "
                                      "Check the 'username', 'password' and 'dn' options "
                                      "in the config file in the '[ldap]' section.")
        except ldap.UNWILLING_TO_PERFORM as exp:
            LOG.exception("Error calling simple_bind_s()")
            raise AuthenticationError("Cannot connect to the LDAP server with given credentials: " + exp.args[0]['info'])
    def run(self, terms, variables=None, **kwargs):
        if not HAS_LDAP:
            msg = missing_required_lib("python-ldap", url="https://pypi.org/project/python-ldap/")
            msg += ". Import Error: %s" % LDAP_IMP_ERR
            raise AnsibleLookupError(msg)

        # Load the variables and direct args into the lookup options
        self.set_options(var_options=variables, direct=kwargs)
        domain = self.get_option('domain')
        port = self.get_option('port')
        scheme = self.get_option('scheme')
        start_tls = self.get_option('start_tls')
        validate_certs = self.get_option('validate_certs')
        cacert_file = self.get_option('ca_cert')
        search_base = self.get_option('search_base')
        username = self.get_option('username')
        password = self.get_option('password')
        auth = self.get_option('auth')
        allow_plaintext = self.get_option('allow_plaintext')

        # Validate and set input values
        # https://www.openldap.org/lists/openldap-software/200202/msg00456.html
        validate_certs_map = {
            'never': ldap.OPT_X_TLS_NEVER,
            'allow': ldap.OPT_X_TLS_ALLOW,
            'try': ldap.OPT_X_TLS_TRY,
            'demand': ldap.OPT_X_TLS_DEMAND,  # Same as OPT_X_TLS_HARD
        }
        validate_certs_value = validate_certs_map.get(validate_certs, None)
        if validate_certs_value is None:
            valid_keys = list(validate_certs_map.keys())
            valid_keys.sort()
            raise AnsibleLookupError("Invalid validate_certs value '%s': valid values are '%s'"
                                     % (validate_certs, "', '".join(valid_keys)))

        if auth not in ['gssapi', 'simple']:
            raise AnsibleLookupError("Invalid auth value '%s': expecting either 'gssapi', or 'simple'" % auth)
        elif auth == 'gssapi':
            if not ldap.SASL_AVAIL:
                raise AnsibleLookupError("Cannot use auth=gssapi when SASL is not configured with the local LDAP "
                                         "install")
            if username or password:
                raise AnsibleLookupError("Explicit credentials are not supported when auth='gssapi'. Call kinit "
                                         "outside of Ansible")
        elif auth == 'simple' and not (username and password):
            raise AnsibleLookupError("The username and password values are required when auth=simple")

        if ldapurl.isLDAPUrl(domain):
            ldap_url = ldapurl.LDAPUrl(ldapUrl=domain)
        else:
            port = port if port else 389 if scheme == 'ldap' else 636
            ldap_url = ldapurl.LDAPUrl(hostport="%s:%d" % (domain, port), urlscheme=scheme)

        # We have encryption if using LDAPS, or StartTLS is used, or we auth with SASL/GSSAPI
        encrypted = ldap_url.urlscheme == 'ldaps' or start_tls or auth == 'gssapi'
        if not encrypted and not allow_plaintext:
            raise AnsibleLookupError("Current configuration will result in plaintext traffic exposing credentials. "
                                     "Set auth=gssapi, scheme=ldaps, start_tls=True, or allow_plaintext=True to "
                                     "continue")

        if ldap_url.urlscheme == 'ldaps' or start_tls:
            # We cannot use conn.set_option as OPT_X_TLS_NEWCTX (required to use the new context) is not supported on
            # older distros like EL7. Setting it on the ldap object works instead
            if not ldap.TLS_AVAIL:
                raise AnsibleLookupError("Cannot use TLS as the local LDAP installed has not been configured to support it")

            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, validate_certs_value)
            if cacert_file:
                cacert_path = os.path.expanduser(os.path.expandvars(cacert_file))
                if not os.path.exists(to_bytes(cacert_path)):
                    raise AnsibleLookupError("The cacert_file specified '%s' does not exist" % to_native(cacert_path))

                try:
                    # While this is a path, python-ldap expects a str/unicode and not bytes
                    ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, to_text(cacert_path))
                except ValueError:
                    # https://keathmilligan.net/python-ldap-and-macos/
                    raise AnsibleLookupError("Failed to set path to cacert file, this is a known issue with older "
                                             "OpenLDAP libraries on the host. Update OpenLDAP and reinstall "
                                             "python-ldap to continue")

        conn_url = ldap_url.initializeUrl()
        conn = ldap.initialize(conn_url, bytes_mode=False)
        conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
        conn.set_option(ldap.OPT_REFERRALS, 0)  # Allow us to search from the base

        # Make sure we run StartTLS before doing the bind to protect the credentials
        if start_tls:
            try:
                conn.start_tls_s()
            except ldap.LDAPError as err:
                raise AnsibleLookupError("Failed to send StartTLS to LDAP host '%s': %s"
                                         % (conn_url, to_native(err)))

        if auth == 'simple':
            try:
                conn.bind_s(to_text(username), to_text(password))
            except ldap.LDAPError as err:
                raise AnsibleLookupError("Failed to simple bind against LDAP host '%s': %s"
                                         % (conn_url, to_native(err)))
        else:
            try:
                conn.sasl_gssapi_bind_s()
            except ldap.AUTH_UNKNOWN as err:
                # The SASL GSSAPI binding is not installed, e.g. cyrus-sasl-gssapi. Give a better error message than
                # what python-ldap provides
                raise AnsibleLookupError("Failed to do a sasl bind against LDAP host '%s', the GSSAPI mech is not "
                                         "installed: %s" % (conn_url, to_native(err)))
            except ldap.LDAPError as err:
                raise AnsibleLookupError("Failed to do a sasl bind against LDAP host '%s': %s"
                                         % (conn_url, to_native(err)))

        try:
            if not search_base:
                root_dse = conn.read_rootdse_s()
                search_base = root_dse['defaultNamingContext'][0]

            ret = []
            # TODO: change method to search for all servers in 1 request instead of multiple requests
            for server in terms:
                ret.append(get_laps_password(conn, server, search_base))
        finally:
            conn.unbind_s()

        return ret
Example #28
0
    def authenticate(self, username=None, password=None, user_agent=None,
                     remote_addr=None, accept_language=None,
                     totp_enabled='Disabled'):
        """
        Perform the authentication of the user.

        :param username: The user to authenticate.
        :type username: str
        :param password: The password provided to authenticate with.
        :type password: str
        :param user_agent: The user-agent in the request.
        :type user_agent: str
        :param remote_addr: The hostname/ip in the request.
        :type remote_addr: str
        :param accept_language: The Accept Language in the request.
        :type accept_language: str
        :param totp_enabled: If TOTP is enabled and should be checked as well.
        :type totp_enabled: str
        :returns: :class:`crits.core.user.CRITsUser`, None
        """

        # Need username and password for logins, checkem both
        if not all([username, password]):
            return None

        e = EmbeddedLoginAttempt()
        e.user_agent = user_agent
        e.remote_addr = remote_addr
        e.accept_language = accept_language
        fusername = username
        if '\\' in username:
            username = username.split("\\")[1]
        user = CRITsUser.objects(username=username).first()
        if user:
            # If the user needs TOTP and it is not disabled system-wide, and
            # the user has exceeded the login threshold for this time period
            # don't go any further. Track the invalid login and return.
            if (((user.totp and totp_enabled == 'Optional') or
                    totp_enabled == 'Required') and
                    self._exceeded_login_threshold(user)):
                e.success = False
                self.track_login_attempt(user, e)
                user.reload()
                return None
            config = CRITsConfig.objects().first()
            if not config:
                return None
            if config.ldap_auth:
                import ldap, ldapurl
                try:
                    # If you are using Oracle's server that's based on
                    # Netscape's code, and your users can't login after
                    # password expiration warning kicks in, you need:
                    # python-ldap 2.4.15 installed and
                    # import ldap.controls.pwdpolicy to fix it
                    #
                    import ldap.controls.pwdpolicy
                except ImportError:
                    logger.info("ldap.controls.pwdpolicy not present.")
                try:
                    # don't parse the port if there is one
                    ldap_server = config.ldap_server.split(':')
                    scheme = "ldap"
                    if config.ldap_tls:
                        scheme = "ldaps"
                    url = ldapurl.LDAPUrl('%s://%s' % (scheme, ldap_server[0]))
                    if len(ldap_server) == 2:
                        l = ldap.initialize('%s:%s' % (url.unparse(),
                                                       ldap_server[1]))
                    else:
                        l = ldap.initialize(url.unparse())
                    l.protocol_version = 3
                    l.set_option(ldap.OPT_REFERRALS, 0)
                    l.set_option(ldap.OPT_TIMEOUT, 10)
                    # setup auth for custom cn's
                    if len(config.ldap_usercn) > 0:
                        un = "%s%s,%s" % (config.ldap_usercn,
                                          fusername,
                                          config.ldap_userdn)
                    elif "@" in config.ldap_userdn:
                        un = "%s%s" % (fusername, config.ldap_userdn)
                    else:
                        un = fusername
                    logger.info("Logging in user: %s" % un)
                    l.simple_bind_s(un, password)
                    user = self._successful_settings(user, e, totp_enabled)
                    if config.ldap_update_on_login:
                        user.update_from_ldap("Auto LDAP update", config, password)
                    l.unbind()
                    return user
                except ldap.INVALID_CREDENTIALS:
                    l.unbind()
                    logger.info("Invalid LDAP credentials for: %s" % un)
                except Exception, err:
                    logger.info("LDAP Auth error: %s" % err)
            # If LDAP auth fails, attempt normal CRITs auth.
            # This will help with being able to use local admin accounts when
            # you have LDAP auth enabled.
            if password and user.check_password(password):
                self._successful_settings(user, e, totp_enabled)
                if config.ldap_update_on_login:
                    user.update_from_ldap("Auto LDAP update", config)
                return user
            else:
                e.success = False
                user.invalid_login_attempts += 1

            if user.is_active and user.invalid_login_attempts > settings.INVALID_LOGIN_ATTEMPTS:
                user.is_active = False
                logger.info("Account disabled due to too many invalid login attempts: %s" %
                            user.username)

                if config.crits_email_end_tag:
                    subject = "CRITs Account Lockout" + config.crits_email_subject_tag
                else:
                    subject = config.crits_email_subject_tag + "CRITs Account Lockout"
                body = """

You are receiving this email because your CRITs account has been locked out due to
too many invalid login attempts.  If you did not perform this action,
someone may be attempting to access your account.

Please contact a site administrator to resolve.

"""
                user.email_user(subject, body)
            self.track_login_attempt(user, e)
            user.reload()
Example #29
0
    if ldap_connection:
        ldap_connection.close_db()
        ldap_connection.unbind_s()
        del ldap_connection

    # Shutdown
    sys.exit(0)


# Time to actually begin execution
# Install our signal handlers
signal.signal(signal.SIGTERM, commenceShutdown)
signal.signal(signal.SIGINT, commenceShutdown)

try:
    ldap_url = ldapurl.LDAPUrl(sys.argv[1])
    database_path = sys.argv[2]
except IndexError, e:
    print('Usage:\n'
          '{script_name} <LDAP URL> <pathname of database>\n'
          '{script_name} "ldap://127.0.0.1/cn=users,dc=test'
          '?*'
          '?sub'
          '?(objectClass=*)'
          '?bindname=uid=admin%2ccn=users%2cdc=test,'
          'X-BINDPW=password" db.shelve').format(script_name=sys.argv[0])
    sys.exit(1)
except ValueError as e:
    print('Error parsing command-line arguments:', str(e))
    sys.exit(1)
Example #30
0
"""
Example showing the use of the password extended operation.
"""

import sys,ldap,ldapurl,getpass

# Set debugging level
ldap.set_option(ldap.OPT_DEBUG_LEVEL,255)
ldapmodule_trace_level = 2
ldapmodule_trace_file = sys.stderr

lu = ldapurl.LDAPUrl(sys.argv[1])

print('Old password')
oldpw = getpass.getpass()
print('New password')
newpw = getpass.getpass()

# Set path name of file containing all CA certificates
# needed to validate server certificates
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,'/etc/httpd/ssl.crt/myCA-cacerts.pem')

# Create LDAPObject instance
l = ldap.initialize(lu.initializeUrl(),trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)

l.protocol_version=ldap.VERSION3

l.simple_bind_s(lu.dn,oldpw)

l.passwd(lu.dn,oldpw,newpw)