def __init__(self, server, port, tls, no_verify, binddn, bindpw, anonymous): """ Bind to an LDAP directory using passed credentials. """ self.server = server self.port = port self.tls = tls self.binddn = binddn self.bindpw = bindpw schema = "ldap" if not HAS_LDAP: raise CommandExecutionError("Failed to connect to LDAP, module " "not loaded") try: if no_verify: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) if self.tls: schema = "ldaps" self.ldap = ldap.initialize("{0}://{1}:{2}".format(schema, self.server, self.port)) self.ldap.protocol_version = 3 # ldap.VERSION3 self.ldap.set_option(ldap.OPT_REFERRALS, 0) # Needed for AD if not anonymous: self.ldap.simple_bind_s(self.binddn, self.bindpw) except Exception as ldap_error: raise CommandExecutionError( "Failed to bind to LDAP server {0}:{1} as {2}: {3}".format( self.server, self.port, self.binddn, ldap_error ) )
def authenticate(self, username, password, options): """ See abstract method documentation. """ log.debug("Username: %s" % username) log.debug("Options: %s" % options) failure_mode = False # reject but continue if options.get('continue-on-failure', 'False') == 'False': failure_mode = None # reject and do not continue try: import ldap except: log.debug("User: %s, ACTIVEDIRECTORY: False (no ldap)" % (username)) return (failure_mode, '') # do AD search (if required) vars = {'username': username, 'password': password} if 'search-fields' in options: try: # setup connection ldap.set_option(ldap.OPT_REFERRALS, 0) l = ldap.initialize(_get_subs(options, 'server', vars)) l.protocol_version = 3 l.simple_bind_s(_get_subs(options, 'search-user', vars), _get_subs(options, 'search-password', vars)) scope = ldap.SCOPE_SUBTREE # setup search attributes = map(lambda s: s.strip().format(**vars), options['search-fields'].split(',')) result = l.search(_get_subs(options, 'search-base', vars), scope, _get_subs(options, 'search-filter', vars), attributes) # parse results _, suser = l.result(result, 60) _, attrs = suser[0] log.debug(("AD Search attributes: %s" % attrs)) if hasattr(attrs, 'has_key'): for attr in attributes: if attr in attrs: vars[attr] = str(attrs[attr][0]) else: vars[attr] = "" except Exception: log.exception('ACTIVEDIRECTORY Search Exception for User: %s' % username) return (failure_mode, '') # end search # bind as user to check their credentials try: # setup connection ldap.set_option(ldap.OPT_REFERRALS, 0) l = ldap.initialize(_get_subs(options, 'server', vars)) l.protocol_version = 3 l.simple_bind_s(_get_subs(options, 'bind-user', vars), _get_subs(options, 'bind-password', vars)) except Exception: log.exception('ACTIVEDIRECTORY Authenticate Exception for User %s' % username) return (failure_mode, '') log.debug("User: %s, ACTIVEDIRECTORY: True" % (username)) return (True, _get_subs(options, 'auto-register-username', vars))
def _ldget(self, url): """Get data from LDAP.""" result = [] ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, self._cacertdir) l = ldap.initialize(url) l.protocol_version = ldap.VERSION3 # Fetch paged results from ldap server. # This is needed because there is a size limit on the CERN ldap server # side to return at most 1000 entries per request. # For more information, see http://tools.ietf.org/html/rfc2696.html srv_ctrls = [ldap.controls.SimplePagedResultsControl(criticality=False, cookie="")] while True: srv_ctrls[0].size = 1000 # dont necessarily need to match the server limit s = l.search_ext('OU=Users,OU=Organic Units,DC=cern,DC=ch', ldap.SCOPE_SUBTREE, '(memberOf:1.2.840.113556.1.4.1941:=CN=cms-authorized-users,OU=e-groups,OU=Workgroups,DC=cern,DC=ch)', ['sAMAccountName','displayName','employeeID','mail','altSecurityIdentities','userAccountControl'], serverctrls=srv_ctrls, sizelimit=0) _, res_data, _, srv_ctrls = l.result3(s, timeout=100) result.extend(res_data) if not srv_ctrls[0].cookie: break if not result: raise RuntimeError("Ldap returned no data for %s" % url) return result
def __init__(self, uri, base, login, password, certfile=None, timelimit=30): """ Create a new LdapConnection. This already connects to the LDAP server. There is no lazy loading. """ ## native python-ldap connection instance self._lo = None ## URI indicating the LDAP instance we should connect to self._uri = uri ## The Base of the LDAP we are working in self._base = base ## The dn we are authenticating with self._login = login ## The password for the login dn self._password = password ## If using SSL/TLS this is certificate of the server self._certfile = certfile # After storing all information, we connect to the server self._connect() ## Defines how long we will wait for result answers from the LDAP server self._timeout = 0 ## Set timelimit, python-ldap defaults to 30 ldap.set_option(ldap.OPT_TIMELIMIT, timelimit)
def ldap_search(self, searchFilter, baseDN): searchScope = ldap.SCOPE_SUBTREE retrieveAttributes = None try: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) l = ldap.initialize(LDAP_URI) 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.set_option( ldap.OPT_DEBUG_LEVEL, 255 ) l.protocol_version = ldap.VERSION3 l.simple_bind_s(LDAP_USERNAME, LDAP_PASSWORD) ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes) result_set = [] while 1: result_type, result_data = l.result(ldap_result_id, 0) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: result_set.append(result_data) return result_set except ldap.LDAPError, e: logging.error(e) raise
def __init__(self, seid, sname, stype, surl, sconfig, login, password, verbose=0): """ Create a LDAPConnection instance. """ self.config = self.configure(seid, sname, stype, surl, sconfig, login, password) self.verbose = verbose self.is_active_directory = ( self.config["user-login-attr"] == "sAMAccountName") if verbose > 0: pprint(self.config) if self.is_active_directory: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, 0) self.ldapobject = ldap.initialize(self.config["url"]) self.ldapobject.protocol_version = 3 if self.is_active_directory: self.ldapobject.set_option(ldap.OPT_REFERRALS, 0) self.ldapobject.simple_bind_s(self.config["data-cnx-dn"], self.config["data-cnx-password"]) self.user_base_filters = [ filter_format("(%s=%s)", ("objectClass", o)) for o in self.config["user-classes"]] self.group_base_filters = [ filter_format("(%s=%s)", ("objectClass", o)) for o in self.config["group-classes"]] if verbose > 0: pprint(self.user_base_filters) pprint(self.group_base_filters)
def __init__(self, *args, **kwargs): self.priv_required = kwargs.get("priv_required", False) self.server = kwargs["server"] self.base_dn = kwargs["base_dn"] self.bind_dn = kwargs.get("bind_dn", "") self.bind_pw = kwargs.get("bind_pw", "") self.userfilter = kwargs.get("userfilter", "uid=%s") self.groupfilter = kwargs.get("groupfilter", "cn=%s") self.people_rdn = kwargs.get("people_rdn", "ou=people") self.group_rdn = kwargs.get("group_rdn", "ou=groups") self.people_dn = "%s,%s" % (self.people_rdn, self.base_dn) self.group_dn = "%s,%s" % (self.group_rdn, self.base_dn) logger.info("Trying to connect to %s" % self.server) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) self.conn = ldap.initialize(self.server) # debug version # self.conn = ldap.initialize(self.server,trace_level=2) if not self.conn: logger.error("Could not initialize connection to %s" % self.server) return if self.priv_required: self.bind_priv()
def _search(cls, users, attr_idx): """Search LDAP directory for the indexed attr for users. Attr index can be UID_IDX, CN_IDX or MAIL_IDX. Return a list containing the results. """ conf = ResourceLocator.default().get_conf() uri = conf.get_value(["rosa-ldap", "uri"]) binddn = conf.get_value(["rosa-ldap", "binddn"]) passwd = "" passwd_file = conf.get_value(["rosa-ldap", "password-file"], cls.PASSWD_FILE) if passwd_file: passwd = open(os.path.expanduser(passwd_file)).read().strip() basedn = conf.get_value(["rosa-ldap", "basedn"], "") filter_str = "(|(uid=" + ")(uid=".join(users) + "))" filter_more_str = conf.get_value(["rosa-ldap", "filter-more"], "") if filter_more_str: filter_str = "(&" + filter_str + filter_more_str + ")" user_attr_str = conf.get_value(["rosa-ldap", "attrs"], cls.USER_ATTRS) attr = user_attr_str.split()[attr_idx] tls_ca_file = conf.get_value(["rosa-ldap", "tls-ca-file"]) if tls_ca_file: ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_ca_file) conn = ldap.initialize(uri) conn.bind_s(binddn, passwd) results = conn.search_s(basedn, ldap.SCOPE_SUBTREE, filter_str, [attr]) conn.unbind() return [result[1][attr][0] for result in results]
def query_user(UID,env): DN="%s,%s"%(env.PEOPLE,env.BASEDN) FILTER="(&(objectClass=posixAccount)(uid=%s))"%(UID) ATTR=[ "sn", "loginShell", "employeeType", "employeeNumber", "uidnumber", "gidnumber", "uid", "gecos", "cn", "homeDirectory", "objectClass", "userPassword" ] options = [(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)] ldap.set_option(*options[0]) connection = ldap.initialize(env.LDAPSERVER) connection.simple_bind_s() try:result = connection.search_s(DN, ldap.SCOPE_SUBTREE, FILTER, ATTR) except ldap.LDAPError, e:result = [("Generic error occured (are you logged in?)",{"": ""})] if result == []:result = [("No such user!",{"": ""})] connection.unbind() return result
def helper_next_free(TYPE, env): error = "OK" toprange = highest = 0 DN="%s,%s"%(env.PEOPLE,env.BASEDN) FILTER="(uid=*)" ATTR=["uidNumber"] try: ranges = env.user_ranges() begin = ranges[TYPE][1] end= ranges[TYPE][2] except:begin=end=100 try: options = [(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)] ldap.set_option(*options[0]) connection = ldap.initialize(env.LDAPSERVER) connection.simple_bind_s() result = connection.search_s(DN, ldap.SCOPE_SUBTREE, FILTER, ATTR) except ldap.LDAPError, error: return "Generic error occured (are you logged in?)", toprange connection.unbind() for dn,entry in result: current=entry[ATTR[0]][0] # get highest of all if (int(highest) < int(current)):highest=current # get highest in range if (int(current) < int(begin)):continue elif (int(current) > int(end)):continue elif (int(current) >= int(toprange)):toprange=current if (int(toprange) == int(end)):toprange=int(highest) + 1 elif (int(toprange) == 0):toprange=int(highest) + 1 else: toprange = int(toprange) + 1 return error, toprange
def authenticate(self, username=None, password=None, **kwargs): if len(password) == 0: return None user = None try: #ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, 'cacert.pem') # HEFTODO re enable strict checking ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) l = ldap.initialize(settings.AD_URL) l.set_option(ldap.OPT_PROTOCOL_VERSION, 3) binddn = "{0}@{1}".format(username, settings.AD_DOMAIN) l.simple_bind_s(binddn, password) # would throw if bind fails #get user info filter_string ='(sAMAccountName={0})'.format(username) ldap_user = l.search_ext_s(settings.AD_BASEDN ,ldap.SCOPE_ONELEVEL, filterstr=filter_string)[0][1] search_guid = ''.join('\\%02x' % ord(x) for x in ldap_user['objectGUID'][0]) try: user = models.PS1User.objects.get(object_guid=search_guid) user.ldap_user = ldap_user except models.PS1User.DoesNotExist: django_user = models.PS1User(object_guid=search_guid) django_user.ldap_user = ldap_user django_user.save() user = django_user l.unbind_s() except ldap.INVALID_CREDENTIALS: pass return user
def __connect( self ): ''' Connect to the URI in __init__, etc. ''' # If trace_level is set to 1, passwords and other info will be output to stdout ... # don't do this unless you REALLY want to...which, if you do, I'd like to talk to you sometime self.__conn = LockingWrapper( obj = ldap.initialize( self.__uri, trace_level=0 ) ) ldap.set_option( ldap.OPT_DEBUG_LEVEL, self.__debuglevel ) #ldap.set_option( ldap.OPT_NETWORK_TIMEOUT, self.__timeout) self.__conn.set_option( ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3 ) self.__conn.set_option( ldap.OPT_REFERRALS, 0 ) self.__conn.set_option( ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND ) # Die!! #self.__conn.timelimit = self.__timeout #self.__conn.timeout = self.__timeout #self.__conn.network_timeout = self.__timeout #if auth.ldap_tls_cacertfile: # self.__conn.set_option( ldap.OPT_X_TLS_CACERTFILE, local_config['ldap_tls_cacertfile']) #if auth.ldap_tls_cacertdir: # self.__conn.set_option( ldap.OPT_X_TLS_CACERTDIR, local_config['ldap_tls_cacertdir']) #self.__conn.set_option( ldap.OPT_X_SASL_SECPROPS, 'maxssf=0' ) # FIXME: this should probably be in a try/except #self.__conn.bind_s( self.__binddn, self.__bindpw, # self.__bind_type ) self.__conn.simple_bind_s( self.__binddn, self.__bindpw )
def _cursor(self): if self.connection is None: try: logger.debug('Connecting to LDAP at %s with account %s' %(self.settings_dict['NAME'], self.settings_dict['USER'])) if self.settings_dict['CACERT']: logger.debug('Using CACERT: %s' % self.settings_dict['CACERT']) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.settings_dict['CACERT']) self.connection = ldap.initialize(self.settings_dict['NAME']) if self.settings_dict['STARTTLS']: logger.debug('Using STARTTLS') self.connection.start_tls_s() self.connection.simple_bind_s( self.settings_dict['USER'], self.settings_dict['PASSWORD']) except ldap.SERVER_DOWN: logger.error('LDAP server is down') raise ServerDown except ldap.INVALID_CREDENTIALS: logger.error('Invalid credentials') raise InvalidCredentials return DatabaseCursor(self.connection)
def initialize(self): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # XXX this creates option errors, no idea why. keep it around # if needed, seems to work fine without it #ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.certfile) self.ldo = ldap.initialize(self.host) self.ldo.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
def ldap_process(request): """Initiate a ldap login""" config = request.registry.settings urls = splitlines(config['velruse.providers.ldapprovider.urls']) bdn = config['velruse.providers.ldapprovider.basedn'] verified_login = False username = request.POST.get('ldap_username', request.POST.get('username', '')) password = request.POST.get('ldap_password', request.POST.get('password', '')) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) dn = bdn.replace('%LOGIN%', username) data = {} if urls: for url in urls: try: # We have suceed to connect, break the loop con = ldap.initialize(url) bind = con.simple_bind_s(dn, password) verified_login = True items = con.search_s(dn,ldap.SCOPE_SUBTREE) if items: for item in items: if item[0] == dn: data = item[1] break except Exception, e: pass
def conn(self): if not self.check_certificate: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) conn = ldap.initialize(self.conn_string) if self.starttls: try: conn.start_tls_s() except ldap.LDAPError as e: logger.error("can't STARTTLS") if type(e.message) == dict and e.message.has_key("desc"): logger.error(e.message['desc']) else: logger.error(e) conn.unbind() return None try: conn.simple_bind_s(self.bind_dn, self.bind_pw) except ldap.INVALID_CREDENTIALS: logger.info("invalid credentials for bind dn: " + self.bind_dn) conn.unbind() return None except ldap.LDAPError as e: logger.error("LDAP error when binding") if type(e.message) == dict and e.message.has_key('desc'): logger.error(e.message['desc']) else: logger.error(e) conn.unbind() return None return conn
def configure_user(self, user): """ Configures a user after creation and returns the updated user. By default, returns the user unmodified. """ try: ldap.set_option(ldap.OPT_REFERRALS, 0) # DO NOT TURN THIS OFF OR SEARCH WON'T WORK! # initialize l = ldap.initialize(settings.AD_LDAP_URL) # bind binddn = "%s@%s" % (settings.AD_LDAP_USER, settings.AD_NT4_DOMAIN) l.bind_s(binddn, settings.AD_LDAP_PW) # search result = l.search_ext_s(settings.AD_SEARCH_DN, ldap.SCOPE_SUBTREE, "%s=%s" % (settings.AD_LU_ACCOUNT_NAME, user), settings.AD_SEARCH_FIELDS)[0][1] l.unbind_s() # get personal info user.email = result.get(settings.AD_LU_MAIL, [None])[0] user.last_name = result.get(settings.AD_LU_SURNAME, [None])[0] user.first_name = result.get(settings.AD_LU_GIVEN_NAME, [None])[0] except Exception: return None user.is_staff = False user.is_superuser = False user.set_password(None) user.save() return user
def _ldap_connect(self): if self.disable_verify_cert: log.info("Disabling certificate verification") ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) log.debug("Initializing ldap connection: %s" % (self.ldap_url)) self.ldap = ldap.ldapobject.ReconnectLDAPObject(self.ldap_url, retry_max=5, retry_delay=30) self.ldap.set_option(ldap.OPT_REFERRALS, 0) log.debug("LDAP Current OPT_REFERRALS: %s" % (self.ldap.get_option(ldap.OPT_REFERRALS))) self.ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 5) log.debug("LDAP Current OPT_NETWORK_TIMEOUT: %s" % ( self.ldap.get_option(ldap.OPT_NETWORK_TIMEOUT))) try: log.debug("Attempting to authenticate: %s via %s" % (self.ldap_url, self.username)) self.ldap.simple_bind_s("%s" % (self.username), "%s" % (self.password)) log.debug("Authenticated Successfully") except ldap.SERVER_DOWN: log.debug("Can't connect to server: %s" % (self.ldap_url)) log.debug("This can also happen if the server's certificate is invalid") exit(1) except ldap.INVALID_CREDENTIALS: log.debug("I don't have access to this DC: %s" % (self.ldap_url)) exit(1) except ldap.LDAPError, e: log.debug("Unknown Error: %s", e) exit(1)
def search(canonical_name): """ Searches the LDAP server for all Organizational Units (OUs) whose Canonical Name (CN) contains the text argument canonical_name passed into the function. """ ldap.set_option(ldap.OPT_REFERRALS, 0) l = ldap.initialize(settings.LDAP_URL) l.set_option(ldap.OPT_PROTOCOL_VERSION, 3) binddn = '' try: binddn = "%s@%s" % (settings.BIND_USER, settings.NT4_DOMAIN) except AttributeError: binddn = settings.BIND_USER l.simple_bind_s(binddn, settings.BIND_PASSWORD) base = settings.SEARCH_DN scope = ldap.SCOPE_SUBTREE retrieve_attributes = ['cn'] filtered_name = ldap.filter.escape_filter_chars(canonical_name) filter = 'cn=*%s*' % filtered_name results = l.search_s(base, scope, filter, retrieve_attributes) #result_objects = [LDAPSearchResult(result) for result in results] result_objects = [] for result in results: if result[0]: result_objects.append(LDAPSearchResult(result)) return result_objects
def __init__(self, **kwargs): prop_defaults = { "uri": None, "user": None, "password": None, "user_base": None, "group_base": None, "servers_base": None, "ca_certfile": "/etc/ssl/certs/ca-certificates.crt", "default_shell": "/bin/bash", "min_uid": 3000, "max_uid": 1000000, "excluded_uids": [65534] } for (prop, default) in prop_defaults.iteritems(): setattr(self, prop, kwargs.get(prop, default)) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,self.ca_certfile) self.con = ldap.initialize(self.uri) self.con = ldap.ldapobject.ReconnectLDAPObject( self.uri, retry_max=10, retry_delay=5 ) self.con.set_option(ldap.OPT_X_TLS_DEMAND, True) self.con.start_tls_s() self.con.simple_bind_s(self.user, self.password)
def enter_ldap(): global ldap_instance if ldap_instance is None: try: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) ldap_instance = ldap.initialize('ldap://%s' % CONF_MAP['UADM_LDAP_DC']) ldap_instance.set_option(ldap.OPT_REFERRALS, 0) ldap_instance.set_option(ldap.OPT_PROTOCOL_VERSION, 3) ldap_instance.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND) ldap_instance.set_option( ldap.OPT_X_TLS_DEMAND, True ) ldap_instance.set_option( ldap.OPT_DEBUG_LEVEL, 255 ) ldap_instance.start_tls_s() user = DOMAIN_USER if DOMAIN_USER else '' password = DOMAIN_PASS if DOMAIN_PASS else '' if DOMAIN_USER: auth_tokens = ldap.sasl.digest_md5(user, password) ldap_instance.sasl_interactive_bind_s( "", auth_tokens ) else: #try with anonymous login ldap_instance.simple_bind_s() except ldap.LDAPError, e: ldap_instance.unbind() ldap_instance = None raise
def add_ldap_config(self, ldap_config): ldap_url = ldap_config.LDAP_URL.get() if ldap_url is None: LOG.warn("Could not find LDAP URL required for authentication.") return None else: setattr(self._backend.settings, 'SERVER_URI', ldap_config.LDAP_URL.get()) if ldap_url.lower().startswith('ldaps') and ldap_config.USE_START_TLS.get(): LOG.warn("Cannot configure LDAP with SSL and enable STARTTLS.") if ldap_config.SEARCH_BIND_AUTHENTICATION.get(): # New Search/Bind Auth base_dn = ldap_config.BASE_DN.get() user_name_attr = ldap_config.USERS.USER_NAME_ATTR.get() user_filter = ldap_config.USERS.USER_FILTER.get() if not user_filter.startswith('('): user_filter = '(' + user_filter + ')' if ldap_config.BIND_DN.get(): bind_dn = ldap_config.BIND_DN.get() setattr(self._backend.settings, 'BIND_DN', bind_dn) bind_password = ldap_config.BIND_PASSWORD.get() if not bind_password: bind_password = ldap_config.BIND_PASSWORD_SCRIPT.get() setattr(self._backend.settings, 'BIND_PASSWORD', bind_password) if user_filter is None: search_bind_results = LDAPSearch(base_dn, ldap.SCOPE_SUBTREE, "(" + user_name_attr + "=%(user)s)") else: search_bind_results = LDAPSearch(base_dn, ldap.SCOPE_SUBTREE, "(&(" + user_name_attr + "=%(user)s)" + user_filter + ")") setattr(self._backend.settings, 'USER_SEARCH', search_bind_results) else: nt_domain = ldap_config.NT_DOMAIN.get() if nt_domain is None: pattern = ldap_config.LDAP_USERNAME_PATTERN.get() pattern = pattern.replace('<username>', '%(user)s') setattr(self._backend.settings, 'USER_DN_TEMPLATE', pattern) else: # %(user)s is a special string that will get replaced during the authentication process setattr(self._backend.settings, 'USER_DN_TEMPLATE', "%(user)s@" + nt_domain) # Certificate-related config settings if ldap_config.LDAP_CERT.get(): setattr(self._backend.settings, 'START_TLS', ldap_config.USE_START_TLS.get()) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ldap_config.LDAP_CERT.get()) else: setattr(self._backend.settings, 'START_TLS', False) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) if ldap_config.FOLLOW_REFERRALS.get(): ldap.set_option(ldap.OPT_REFERRALS, 1) else: ldap.set_option(ldap.OPT_REFERRALS, 0)
def authenticateUser(session, req, username, password): """authenticate the username/password combination. Only used if config.AUTH_TYPE=='FORM'. This sets session['username'], iff authentication is successful. This should raise an Exception if authentication fails (the caller must make sure to sanitize any error message, since there's no guarantee it won't contain passwords or other sensitive information). """ if password=='': raise Exception("empty password") #the ldap bind does not fail for empty password, so must catch it before import ldap ldap.set_option(ldap.OPT_DEBUG_LEVEL,255) try: try: authenticated = False for host in ('dc2-rc', 'dc3-rc'): try: l = ldap.initialize("ldaps://%s:636/" % host) l.protocol_version = ldap.VERSION3 l.simple_bind_s( core.getStdout("/n/sw/rc/bin/username2ldapatts -a distinguishedName %s" % core.shQuote(username)).strip(), password ) #will raise ldap.INVALID_CREDENTIALS in case of failure authenticated = True break except ldap.SERVER_DOWN, e: msg = "got ldap.SERVER_DOWN for [%s]: %s; will retry other hosts if available" % (host, e) core.log(msg, session, req) continue if not authenticated: raise Exception("cannot contact LDAP server(s)") except ldap.INVALID_CREDENTIALS: raise
def initLDAP(): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) try: l = ldap.initialize(ldapUri) except ldap.LDAPError, e: print e exit(1)
def __init__(self, ldap_config, ldap_url, bind_user=None, bind_password=None, cert_file=None): """ Constructor initializes the LDAP connection """ self.ldap_config = ldap_config if cert_file is not None: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, cert_file) if self.ldap_config.FOLLOW_REFERRALS.get(): ldap.set_option(ldap.OPT_REFERRALS, 1) else: ldap.set_option(ldap.OPT_REFERRALS, 0) if ldap_config.DEBUG.get(): ldap.set_option(ldap.OPT_DEBUG_LEVEL, ldap_config.DEBUG_LEVEL.get()) self.ldap_handle = ldap.initialize(uri=ldap_url, trace_level=ldap_config.TRACE_LEVEL.get()) if bind_user is not None: try: self.ldap_handle.simple_bind_s(bind_user, bind_password) except: msg = "Failed to bind to LDAP server as user %s" % bind_user LOG.exception(msg) raise RuntimeError(msg) else: try: # Do anonymous bind self.ldap_handle.simple_bind_s('','') except: msg = "Failed to bind to LDAP server anonymously" LOG.exception(msg) raise RuntimeError(msg)
def __init__(self, app=web.app, session=session, **settings): # Get LDAP settings. self.basedn = cfg.ldap.get('basedn') self.domainadmin_dn = cfg.ldap.get('domainadmin_dn') # Initialize LDAP connection. try: # Get LDAP URI. uri = cfg.ldap.get('uri', 'ldap://127.0.0.1') # Detect STARTTLS support. if uri.startswith('ldaps://'): starttls = True else: starttls = False # Set necessary option for STARTTLS. if starttls: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Initialize connection. self.conn = ldap.initialize(uri, trace_level=iredutils.LDAP_CONN_TRACE_LEVEL,) # Set LDAP protocol version: LDAP v3. self.conn.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) if starttls: self.conn.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND) except: return False # synchronous bind. self.conn.bind_s(cfg.ldap.get('bind_dn'), cfg.ldap.get('bind_pw'))
def connect(self, no_starttls=False): self.ldapdeleteControl = LDAPControl('1.2.840.113556.1.4.417', criticality=1) self.timeout = 5 use_starttls = 2 if no_starttls: use_starttls = 0 fp = open(self.pw_file, 'r') login_pw = fp.readline() if login_pw[-1] == '\n': login_pw = login_pw[:-1] fp.close() try: self.lo = ldap.initialize(uri="ldap://%s:%s" % (self.host, self.port)) if self.ca_file: ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca_file) if use_starttls: self.lo.start_tls_s() self.lo.simple_bind_s(self.login_dn, login_pw) except: ex = 'LDAP Connection to "%s:%s" as "%s" with password "%s" failed (TLS: %s, Certificate: %s)\n' % (self.host, self.port, self.login_dn, login_pw, not no_starttls, self.ca_file) import traceback raise Exception(ex + traceback.format_exc()) self.lo.set_option(ldap.OPT_REFERRALS, 0)
def open_ldap(url,base,search_flt,page_size=default_page_size): ldap.set_option(ldap.OPT_REFERRALS, 0) l = ldap.initialize(url) l.protocol_version = 3 sasl_auth=ldap.sasl.sasl({},'GSSAPI') try: l.sasl_interactive_bind_s('',sasl_auth) except ldap.LOCAL_ERROR: print "Error: missing credential - Please run kinit" sys.exit() lc = SimplePagedResultsControl( ldap.LDAP_CONTROL_PAGE_OID,True,(page_size,'') ) # Send search request msgid = l.search_ext( base, ldap.SCOPE_SUBTREE, search_flt, serverctrls=[lc] ) return l,lc,msgid
def get_ldap_connection(session, address, force = False): #clear cache clear_ldap_cache() # Get session data ldap_connections_key = address+"__"+session.session_key #try to get LDAP connection from key l = settings.LDAP_CONNECTIONS.get(ldap_connections_key, None) if 'ldap' not in session.keys(): return l elif address not in session['ldap'].keys(): return l elif force or l == None: # get session info data = session['ldap'][address] userDN = data['userDN'] password = data['password'] print "Connecting to LDAP", address server = 'ldaps://%s' % (address) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) l = ldap.initialize(server) #l.start_tls_s() l.simple_bind_s(userDN, password) settings.LDAP_CONNECTIONS[ldap_connections_key] = {'connection':l,'updated_at':datetime.now()} else: print "Get LDAP connection (%s) from cache" % (address) l['updated_at'] = datetime.now(); l = l['connection'] return l
def _bind_ad(self, user_dn=None, passwd=None): user = user_dn or self.bind_dn password = passwd or self.bind_pw if not self.ads.lower().startswith('ldap://') and not self.ads.lower().startswith('ldaps://'): ads = 'ldap://%s' % self.ads else: ads = self.ads try: #ldaps support if ads.lower().startswith('ldaps://'): if self.ignoreunknowncertificate == True: self.log.debug('ignoring unknown certs...') ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) if self.customcacert: self.log.debug('adding custom cacertfile: %s' % self.customcacert) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,self.customcacert) l = ldap.initialize(ads) l.set_option(ldap.OPT_REFERRALS, 0) except: raise TracError('Unable to contact Active Directory >>>%s<<<' % ads) if not user: raise TracError('The bind_dn ini option must be set') if not password: raise TracError('The bind_pw ini option must be set') try: l.simple_bind_s(user, password) except Exception, e: self.log.debug('Unable to bind to Active Directory', exc_info=e) return None
from __future__ import print_function import ldap host = "localhost:1390" print("API info:", ldap.get_option(ldap.OPT_API_INFO)) print("debug level:", ldap.get_option(ldap.OPT_DEBUG_LEVEL)) #print("Setting debug level to 255...") #ldap.set_option(ldap.OPT_DEBUG_LEVEL,255) #print("debug level:",ldap.get_option(ldap.OPT_DEBUG_LEVEL)) print("default size limit:", ldap.get_option(ldap.OPT_SIZELIMIT)) print("Setting default size limit to 10...") ldap.set_option(ldap.OPT_SIZELIMIT, 10) print("default size limit:", ldap.get_option(ldap.OPT_SIZELIMIT)) print("Creating connection to", host, "...") l = ldap.init(host) print("size limit:", l.get_option(ldap.OPT_SIZELIMIT)) print("Setting connection size limit to 20...") l.set_option(ldap.OPT_SIZELIMIT, 20) print("size limit:", l.get_option(ldap.OPT_SIZELIMIT)) #print("Setting time limit to 60 secs...") l.set_option(ldap.OPT_TIMELIMIT, 60) #print("time limit:",l.get_option(ldap.OPT_TIMELIMIT)) print("Binding...") l.simple_bind_s("", "")
except ImportError: LDAP_CONFIGURED = False # LDAP configuration (optional) if LDAP_CONFIGURED: try: import ldap import django_auth_ldap # Prepend LDAPBackend to the default ModelBackend AUTHENTICATION_BACKENDS = [ 'django_auth_ldap.backend.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ] # Optionally disable strict certificate checking if LDAP_IGNORE_CERT_ERRORS: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Enable logging for django_auth_ldap ldap_logger = logging.getLogger('django_auth_ldap') ldap_logger.addHandler(logging.StreamHandler()) ldap_logger.setLevel(logging.DEBUG) except ImportError: raise ImproperlyConfigured( "LDAP authentication has been configured, but django-auth-ldap is not installed. You can remove " "netbox/ldap_config.py to disable LDAP.") # Database configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'}) DATABASES = { 'default': configuration.DATABASE, }
def login(self, user_obj, **kw): username = kw.get('username') password = kw.get('password') # we require non-empty password as ldap bind does a anon (not password # protected) bind if the password is empty and SUCCEEDS! if not password: return ContinueLogin( user_obj, _('Missing password. Please enter user name and password.')) try: try: u = None dn = None server = self.server_uri coding = self.coding logging.debug("Setting misc. ldap options...") ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) # ldap v2 is outdated ldap.set_option(ldap.OPT_REFERRALS, self.referrals) ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout) if hasattr(ldap, 'TLS_AVAIL') and ldap.TLS_AVAIL: for option, value in ( (ldap.OPT_X_TLS_CACERTDIR, self.tls_cacertdir), (ldap.OPT_X_TLS_CACERTFILE, self.tls_cacertfile), (ldap.OPT_X_TLS_CERTFILE, self.tls_certfile), (ldap.OPT_X_TLS_KEYFILE, self.tls_keyfile), (ldap.OPT_X_TLS_REQUIRE_CERT, self.tls_require_cert), (ldap.OPT_X_TLS, self.start_tls), # (ldap.OPT_X_TLS_ALLOW, 1), ): if value is not None: ldap.set_option(option, value) logging.debug("Trying to initialize {0!r}.".format(server)) l = ldap.initialize(server) logging.debug("Connected to LDAP server {0!r}.".format(server)) if self.start_tls and server.startswith('ldap:'): logging.debug( "Trying to start TLS to {0!r}.".format(server)) try: l.start_tls_s() logging.debug("Using TLS to {0!r}.".format(server)) except (ldap.SERVER_DOWN, ldap.CONNECT_ERROR) as err: logging.warning( "Couldn't establish TLS to {0!r} (err: {1!s}).". format(server, err)) raise # you can use %(username)s and %(password)s here to get the stuff entered in the form: binddn = self.bind_dn % locals() bindpw = self.bind_pw % locals() l.simple_bind_s(binddn.encode(coding), bindpw.encode(coding)) logging.debug("Bound with binddn {0!r}".format(binddn)) # you can use %(username)s here to get the stuff entered in the form: filterstr = self.search_filter % locals() logging.debug("Searching {0!r}".format(filterstr)) attrs = [ getattr(self, attr) for attr in [ 'email_attribute', 'displayname_attribute', 'surname_attribute', 'givenname_attribute', ] if getattr(self, attr) is not None ] lusers = l.search_st(self.base_dn, self.scope, filterstr.encode(coding), attrlist=attrs, timeout=self.timeout) # we remove entries with dn == None to get the real result list: lusers = [(dn, ldap_dict) for dn, ldap_dict in lusers if dn is not None] for dn, ldap_dict in lusers: logging.debug("dn:{0!r}".format(dn)) for key, val in ldap_dict.items(): logging.debug(" {0!r}: {1!r}".format(key, val)) result_length = len(lusers) if result_length != 1: if result_length > 1: logging.warning( "Search found more than one ({0}) matches for {1!r}." .format(result_length, filterstr)) if result_length == 0: logging.debug( "Search found no matches for {0!r}.".format( filterstr, )) if self.report_invalid_credentials: return ContinueLogin( user_obj, _("Invalid username or password.")) else: return ContinueLogin(user_obj) dn, ldap_dict = lusers[0] if not self.bind_once: logging.debug( "DN found is {0!r}, trying to bind with pw".format(dn)) l.simple_bind_s(dn, password.encode(coding)) logging.debug( "Bound with dn {0!r} (username: {1!r})".format( dn, username)) if self.email_callback is None: if self.email_attribute: email = ldap_dict.get(self.email_attribute, [''])[0].decode(coding) else: email = None else: email = self.email_callback(ldap_dict) display_name = '' try: display_name = ldap_dict[self.displayname_attribute][0] except (KeyError, IndexError): pass if not display_name: sn = ldap_dict.get(self.surname_attribute, [''])[0] gn = ldap_dict.get(self.givenname_attribute, [''])[0] if sn and gn: display_name = "{0}, {1}".format(sn, gn) elif sn: display_name = sn display_name = display_name.decode(coding) if self.name_callback: username = self.name_callback(ldap_dict) if email: u = user.User(auth_username=username, auth_method=self.name, auth_attribs=( 'name', 'password', 'email', 'mailto_author', ), trusted=self.trusted) u.email = email else: u = user.User(auth_username=username, auth_method=self.name, auth_attribs=( 'name', 'password', 'mailto_author', ), trusted=self.trusted) u.name = username u.display_name = display_name logging.debug( "creating user object with name {0!r} email {1!r} display name {2!r}" .format(username, email, display_name)) except ldap.INVALID_CREDENTIALS as err: logging.debug( "invalid credentials (wrong password?) for dn {0!r} (username: {1!r})" .format(dn, username)) return CancelLogin(_("Invalid username or password.")) if u and self.autocreate: logging.debug( "calling create_or_update to autocreate user {0!r}".format( u.name)) u.create_or_update(True) return ContinueLogin(u) except ldap.SERVER_DOWN as err: # looks like this LDAP server isn't working, so we just try the next # authenticator object in cfg.auth list (there could be some second # ldap authenticator that queries a backup server or any other auth # method). logging.error( "LDAP server {0} failed ({1!s}). " "Trying to authenticate with next auth list entry.".format( server, err)) return ContinueLogin( user_obj, _("LDAP server %(server)s failed.", server=server)) except: logging.exception("caught an exception, traceback follows...") return ContinueLogin(user_obj)
# -*- coding: utf-8 -*- # # last tinkered with by korylprince at gmail.com on 2012-04-5 # import sys import logging try: import ldap import ldap.filter ldap.set_option(ldap.OPT_REFERRALS, 0) except Exception, e: logging.error('missing ldap, try "easy_install python-ldap"') raise e def ldap_auth(server='ldap', port=None, base_dn='ou=users,dc=domain,dc=com', mode='uid', secure=False, cert_path=None, cert_file=None, bind_dn=None, bind_pw=None, filterstr='objectClass=*', username_attrib='uid', custom_scope='subtree', allowed_groups=None, manage_user=False, user_firstname_attrib='cn:1',
def func_get_ldap_connection(): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) conn = ldap.initialize(LDAP_PROVIDER_URL) return conn
def __eval_options(self, section, backend=None): settings = self.__domain settings["domain"] = self.__search_domain settings["emailaddress"] = self.__emailaddress section = self.__find_section(section) if self.has_option(section, "backend"): if backend is None: try: backend = self.get(section, "backend") except NoOptionError: raise Exception("Missing option <backend>") if backend in ("static", "static_append"): for opt in iter(self.options(section)): if opt in ("action", "account_type", "account_name", "account_name_short", "display_name", "server_url", "server_name"): tmp = self.get(section, opt) result = self.__expand_vars(tmp) result = self.__replace_makro(result) settings[opt] = result elif opt == "smtp": service = self.__service(section, "smtp") elif opt == "imap": service = self.__service(section, "imap") elif opt == "pop": service = self.__service(section, "pop") elif opt == "sign_mobileconfig": try: settings[opt] = self.getboolean(section, opt) except: logging.error("%s is not boolean!" % opt) settings[opt] = False elif opt in ("sign_cert", "sign_key"): result = self.get(section, opt) if os.path.exists(result): settings[opt] = result else: logging.error("%s cannot read %s" % (opt, result)) else: pass if opt in ("smtp", "imap", "pop"): if backend == "static_append": if settings.has_key(opt): if self.debug: logging.debug("APPEND %s" % service) settings[opt].append(service) else: if self.debug: logging.debug("APPEND NEW %s" % service) settings[opt] = [service] else: # do not include empty services if len(service) != 0: if self.debug: logging.debug("STATIC %s" % service) service_category = OrderedDict() service_category[opt] = [service] settings.update(service_category) # always follow at the end! if "follow" in self.options(section): tmp = self.get(section, "follow") result = self.__expand_vars(tmp) result = self.__replace_makro(result) self.__eval_options(result) elif backend in ("ldap", "ldap_append"): try: import ldap import ldap.sasl except: raise Exception("python ldap missing") ldap_cfg = dict(host = "ldap://127.0.0.1/", base = "", bindmethod = "simple", binddn = None, bindpw = None, saslmech = None, authzid = "", filter = "(objectClass=*)", result_attrs = [], scope = "sub", usetls = "no", cipher = "TLSv1", reqcert ="never", cert = None, key = None, cacert = None) tls = False sasl = False for opt in iter(self.options(section)): if opt in ("host", "base", "bindmethod", "binddn", "bindpw", "saslmech", "authzid", "filter", "result_attrs", "scope", "usetls", "cipher", "reqcert", "cert", "key", "cacert"): result = self.get(section, opt) if opt in ("host", "result_attrs"): result = self.create_list(result) ldap_cfg[opt] = result # Do we connect with TLS? if ldap_cfg["usetls"].strip().lower() in TRUE: if ldap_cfg["reqcert"] in ("never", "allow", "try", "demand"): rc = ldap_cfg["reqcert"] if rc == "never": reqcert = ldap.OPT_X_TLS_NEVER elif rc == "allow": reqcert = ldap.OPT_X_TLS_ALLOW elif rc == "try": reqcert = ldap.OPT_X_TLS_TRY elif rc == "demand": reqcert = ldap.OPT_X_TLS_DEMAND ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, reqcert) ldap.set_option(ldap.OPT_X_TLS_CIPHER_SUITE, ldap_cfg["cipher"]) if ldap_cfg["cacert"] is not None: ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ldap_cfg["cacert"]) if ldap_cfg["cert"] is not None: ldap.set_option(ldap.OPT_X_TLS_CERTFILE, ldap_cfg["cert"]) if ldap_cfg["key"] is not None: ldap.set_option(ldap.OPT_X_TLS_KEYFILE, ldap_cfg["key"]) tls = True # Are we SASL binding to our servers? if ldap_cfg["bindmethod"] == "sasl": mech = ldap_cfg["saslmech"] if mech is not None: if mech.lower() == "digest-md5": auth_tokens = ldap.sasl.digest_md5( ldap_cfg["binddn"], ldap_cfg["bindpw"]) elif mech.lower() == "cram-md5": auth_tokens = ldap.sasl.cram_md5( ldap_cfg["binddn"], ldap_cfg["bindpw"]) elif mech.lower() == "external": auth_tokens = ldap.sasl.external( ldap_cfg["authzid"]) elif mech.lower() == "gssapi": auth_tokens = ldap.sasl.gssapi(ldap_cfg["authzid"]) sasl = True con = None for server in iter(ldap_cfg["host"]): try: con = ldap.initialize(server) if tls: con.start_tls_s() if sasl: con.sasl_interactive_bind_s("", auth_tokens) else: con.simple_bind_s(ldap_cfg["binddn"], ldap_cfg["bindpw"]) except Exception, e: logging.error("LDAP: %s" % e) continue break if con is not None: if ldap_cfg["scope"] in ("sub", "subtree"): scope = ldap.SCOPE_SUBTREE elif ldap_cfg["scope"] in ("one", "onelevel"): scope = ldap.SCOPE_ONELEVEL elif ldap_cfg["scope"] in ("base", "exact"): scope = ldap.SCOPE_BASE filter = self.__replace_makro(ldap_cfg["filter"]) rid = con.search(ldap_cfg["base"], scope, filter, ldap_cfg["result_attrs"]) raw_res = (None, None) raw_res = con.result(rid, True, 60) if raw_res[0] == None: con.abandon(rid) raise Exception("LDAP server timeout reached") # connection established, we have results self.__vars = dict() # we did not receive data from LDAP if raw_res[1] != []: for entry in raw_res[1]: for key, value in entry[1].items(): # result attributes might be multi values, but # we only accept the first value. self.__vars[key] = unicode(value[0], "utf-8") else: logging.warning("No LDAP result from server!") raise DataNotFoundException try: con.unbind() except ldap.LDAPError, e: pass if backend == "ldap": self.__eval_options(section, backend="static") else: self.__eval_options(section, backend="static_append")
def __init__(self, ldap_config, ldap_url, bind_user=None, bind_password=None, cert_file=None): """ Constructor initializes the LDAP connection """ self.ldap_config = ldap_config self._ldap_url = ldap_url self._username = bind_user self._ldap_cert = cert_file # Certificate-related config settings if ldap_config.LDAP_CERT.get(): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ldap_config.LDAP_CERT.get()) else: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) if self.ldap_config.FOLLOW_REFERRALS.get(): ldap.set_option(ldap.OPT_REFERRALS, 1) else: ldap.set_option(ldap.OPT_REFERRALS, 0) if ldap_config.DEBUG.get(): ldap.set_option(ldap.OPT_DEBUG_LEVEL, ldap_config.DEBUG_LEVEL.get()) self.ldap_handle = ldap.initialize( uri=ldap_url, trace_level=ldap_config.TRACE_LEVEL.get()) if self.ldap_config.USE_START_TLS.get( ) and not ldap_url.lower().startswith('ldaps'): self.ldap_handle.start_tls_s() if bind_user: try: self.ldap_handle.simple_bind_s(bind_user, bind_password) except Exception as e: self.handle_bind_exception(e, bind_user) else: try: # Do anonymous bind self.ldap_handle.simple_bind_s('', '') except Exception as e: self.handle_bind_exception(e)
def auth_user_ldap(self, username, password): """ Method for authenticating user, auth LDAP style. depends on ldap module that is not mandatory requirement for F.A.B. :param username: The username :param password: The password """ if username is None or username == "": return None user = self.find_user(username=username) if user is not None and (not user.is_active()): return None else: try: import ldap except: raise Exception("No ldap library for python.") return None try: if self.auth_ldap_allow_self_signed: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) con = ldap.initialize(self.auth_ldap_server) con.set_option(ldap.OPT_REFERRALS, 0) if self.auth_ldap_use_tls: try: con.start_tls_s() except Exception: log.info( LOGMSG_ERR_SEC_AUTH_LDAP_TLS.format( self.auth_ldap_server)) return None # Authenticate user if not self._bind_ldap(ldap, con, username, password): if user: self.update_user_auth_stat(user, False) log.info(LOGMSG_WAR_SEC_LOGIN_FAILED.format(username)) return None # If user does not exist on the DB and not self user registration, go away if not user and not self.auth_user_registration: return None # User does not exist, create one if self registration. elif not user and self.auth_user_registration: new_user = self._search_ldap(ldap, con, username) if not new_user: log.warning(LOGMSG_WAR_SEC_NOLDAP_OBJ.format(username)) return None ldap_user_info = new_user[0][1] if self.auth_user_registration and user is None: user = self.add_user( username=username, first_name=ldap_user_info.get( self.auth_ldap_firstname_field, [username])[0], last_name=ldap_user_info.get( self.auth_ldap_lastname_field, [username])[0], email=ldap_user_info.get( self.auth_ldap_email_field, [username + '@email.notfound'])[0], role=self.find_role( self.auth_user_registration_role)) self.update_user_auth_stat(user) return user except ldap.LDAPError as e: if type(e.message) == dict and 'desc' in e.message: log.error( LOGMSG_ERR_SEC_AUTH_LDAP.format(e.message['desc'])) return None else: log.error(e) return None
def authenticate(api_handle, username, password): """ Validate an LDAP bind, returning whether the authentication was successful or not. :param api_handle: The api instance to resolve settings. :param username: The username to authenticate. :param password: The password to authenticate. :return: True if the ldap server authentication was a success, otherwise false. """ if not password: return False import ldap server = api_handle.settings().ldap_server basedn = api_handle.settings().ldap_base_dn port = str(api_handle.settings().ldap_port) tls = api_handle.settings().ldap_tls anon_bind = api_handle.settings().ldap_anonymous_bind prefix = api_handle.settings().ldap_search_prefix # Support for LDAP client certificates tls_cacertfile = api_handle.settings().ldap_tls_cacertfile tls_keyfile = api_handle.settings().ldap_tls_keyfile tls_certfile = api_handle.settings().ldap_tls_certfile # allow multiple servers split by a space if server.find(" "): servers = server.split() else: servers = [server] # to get ldap working with Active Directory ldap.set_option(ldap.OPT_REFERRALS, 0) if tls_cacertfile: ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile) if tls_keyfile: ldap.set_option(ldap.OPT_X_TLS_KEYFILE, tls_keyfile) if tls_certfile: ldap.set_option(ldap.OPT_X_TLS_CERTFILE, tls_certfile) uri = "" for server in servers: # form our ldap uri based on connection port if port == '389': uri += 'ldap://' + server elif port == '636': uri += 'ldaps://' + server else: uri += 'ldap://' + "%s:%s" % (server, port) uri += ' ' uri = uri.strip() # connect to LDAP host dir = ldap.initialize(uri) # start_tls if tls is 'on', 'true' or 'yes' and we're not already using old-SSL tls = str(tls).lower() if port != '636': if tls in ["on", "true", "yes", "1"]: try: dir.start_tls_s() except: traceback.print_exc() return False # if we're not allowed to search anonymously, grok the search bind settings and attempt to bind anon_bind = str(anon_bind).lower() if anon_bind not in ["on", "true", "yes", "1"]: searchdn = api_handle.settings().ldap_search_bind_dn searchpw = api_handle.settings().ldap_search_passwd if searchdn == '' or searchpw == '': raise CX("Missing search bind settings") try: dir.simple_bind_s(searchdn, searchpw) except: traceback.print_exc() return False # perform a subtree search in basedn to find the full dn of the user # TODO: what if username is a CN? maybe it goes into the config file as well? filter = prefix + username result = dir.search_s(basedn, ldap.SCOPE_SUBTREE, filter, []) if result: for dn, entry in result: # username _should_ be unique so we should only have one result ignore entry; we don't need it pass else: return False try: # attempt to bind as the user dir.simple_bind_s(dn, password) dir.unbind() return True except: # traceback.print_exc() return False # catch-all return False
def _ldap_auth(kerb_user=None): """ Performs LDAP Authentication and Group Membership Check If Keberos Authentication was successfull this function is used for the additional Group Membership Check. If Kerberos Authentication fails and a Basic Auth Header is preasent in the Request this function is called to to Authenticate using LDAP and additionally Check for Group Membership. Note: LDAP Groups are defined in the configuration file. (config.py) :param kerb_user: Will be None if doing complete Basic Auth will contain users principle if just checking Group membership. :type user principle: str :returns None if auth failed and users principle if successfull :rtype: str or None """ password = None username = None if kerb_user: if _cfg["GROUP_AUTH"]: username = kerb_user.split('@', 1)[0] else: return kerb_user.split('@', 1)[0] elif ("HTTP_AUTHORIZATION" in request.headers.environ and "Basic" in request.environ["HTTP_AUTHORIZATION"]) or \ "BASIC_AUTH" in session: if "BASIC_AUTH" in session: auth = session["BASIC_AUTH"].split(' ', 1) else: auth = request.headers.environ["HTTP_AUTHORIZATION"].split(' ', 1) try: username, password = b64decode((auth[1])).split(":") except Exception as ex: _logger.warn("Bad Request: Basic Auth header decode error") _logger.warn(ex) return None else: return None # Set ldap host ldap_connection = ldap.initialize(_cfg['LDAP_HOST']) # Set up cert, only required by the bind ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, _cfg['LDAP_CERT_PATH']) # set up query string. Used to verify user is in valid groups query = '(&(memberUid=' + username + ')(|' + _cfg[ 'VALID_LDAP_GROUPS'] + "))" # Set up search base base = _cfg['LDAP_SEARCH_BASE'] # Set up search scope search_scope = ldap.SCOPE_SUBTREE # None causes all to be returned retrieve_attributes = None authorized_user = None try: if not kerb_user: _logger.warn(": Could not authorize using kerberos, trying ldap") user = "******" + username + "," + _cfg['LDAP_BIND_BASE'] ldap_connection.start_tls_s() if not ldap_connection.simple_bind_s(user, password): return None authorized_user = username if _cfg['VALID_LDAP_GROUPS'] != "()" and _cfg["GROUP_AUTH"]: # Search ldap to verify that user is in one of the defined valid groups ldap_result_id = ldap_connection.search(base, search_scope, query, retrieve_attributes) rtype, rdata = ldap_connection.result(ldap_result_id, 1) if rdata: authorized_user = username else: func = inspect.stack()[0][3] _logger.warn( "{0} - Bad Request, could not verify users credentials - user not in group " .format(func)) authorized_user = None else: authorized_user = username except Exception as ex: func = inspect.stack()[0][3] _logger.warn( "{0} - Bad Request, could not verifying users credentials ".format( func)) _logger.warn(ex.message) authorized_user = None if authorized_user: return authorized_user else: func = inspect.stack()[0][3] _logger.warn( "{0} - Bad Request, could not verifying users credentials ".format( func)) return None
sys.exit() setup_init = os.path.join(setup_dir, '__init__.py') if not os.path.exists(setup_init): print "setup was not initialized. Please first run Gluu Server upgrader script. Exiting..." sys.exit() from setup.pylib.printVersion import get_war_info from setup.setup import Setup from setup.pylib.Properties import Properties import ldap import ldap.modlist as modlist ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) def check_oxd_server(host, port): conn = httplib.HTTPSConnection(host, port, context=ssl._create_unverified_context()) try: conn.request("GET", "/health-check") result = conn.getresponse() if result.status == 200: text = result.read() data = json.loads(text) if data['status'] == 'running':
def set_option(self, option, value): return ldap.set_option(option, value)
def ldap_auth( server='ldap', port=None, base_dn='ou=users,dc=domain,dc=com', mode='uid', secure=False, self_signed_certificate=None, # See NOTE below cert_path=None, cert_file=None, cacert_path=None, cacert_file=None, key_file=None, bind_dn=None, bind_pw=None, filterstr='objectClass=*', username_attrib='uid', custom_scope='subtree', allowed_groups=None, manage_user=False, user_firstname_attrib='cn:1', user_lastname_attrib='cn:2', user_mail_attrib='mail', manage_groups=False, db=None, group_dn=None, group_name_attrib='cn', group_member_attrib='memberUid', group_filterstr='objectClass=*', tls=False, logging_level='error'): """ to use ldap login with MS Active Directory: from gluon.contrib.login_methods.ldap_auth import ldap_auth auth.settings.login_methods.append(ldap_auth( mode='ad', server='my.domain.controller', base_dn='ou=Users,dc=domain,dc=com')) to use ldap login with Notes Domino: auth.settings.login_methods.append(ldap_auth( mode='domino',server='my.domino.server')) to use ldap login with OpenLDAP: auth.settings.login_methods.append(ldap_auth( server='my.ldap.server', base_dn='ou=Users,dc=domain,dc=com')) to use ldap login with OpenLDAP and subtree search and (optionally) multiple DNs: auth.settings.login_methods.append(ldap_auth( mode='uid_r', server='my.ldap.server', base_dn=['ou=Users,dc=domain,dc=com','ou=Staff,dc=domain,dc=com'])) or (if using CN): auth.settings.login_methods.append(ldap_auth( mode='cn', server='my.ldap.server', base_dn='ou=Users,dc=domain,dc=com')) or you can full customize the search for user: auth.settings.login_methods.append(ldap_auth( mode='custom', server='my.ldap.server', base_dn='ou=Users,dc=domain,dc=com', username_attrib='uid', custom_scope='subtree')) the custom_scope can be: base, onelevel, subtree. If using secure ldaps:// pass secure=True and cert_path="..." If ldap is using GnuTLS then you need cert_file="..." instead cert_path because cert_path isn't implemented in GnuTLS :( To enable TLS, set tls=True: auth.settings.login_methods.append(ldap_auth( server='my.ldap.server', base_dn='ou=Users,dc=domain,dc=com', tls=True)) If you need to bind to the directory with an admin account in order to search it then specify bind_dn & bind_pw to use for this. - currently only implemented for Active Directory If you need to restrict the set of allowed users (e.g. to members of a department) then specify an rfc4515 search filter string. - currently only implemented for mode in ['ad', 'company', 'uid_r'] You can manage user attributes first name, last name, email from ldap: auth.settings.login_methods.append(ldap_auth(...as usual..., manage_user=True, user_firstname_attrib='cn:1', user_lastname_attrib='cn:2', user_mail_attrib='mail' )) Where: manage_user - let web2py handle user data from ldap user_firstname_attrib - the attribute containing the user's first name optionally you can specify parts. Example: cn: "John Smith" - 'cn:1'='John' user_lastname_attrib - the attribute containing the user's last name optionally you can specify parts. Example: cn: "John Smith" - 'cn:2'='Smith' user_mail_attrib - the attribute containing the user's email address If you need group control from ldap to web2py app's database feel free to set: auth.settings.login_methods.append(ldap_auth(...as usual..., manage_groups=True, db=db, group_dn='ou=Groups,dc=domain,dc=com', group_name_attrib='cn', group_member_attrib='memberUid', group_filterstr='objectClass=*' )) Where: manage_group - let web2py handle the groups from ldap db - is the database object (need to have auth_user, auth_group, auth_membership) group_dn - the ldap branch of the groups group_name_attrib - the attribute where the group name is stored group_member_attrib - the attribute containing the group members name group_filterstr - as the filterstr but for group select You can restrict login access to specific groups if you specify: auth.settings.login_methods.append(ldap_auth(...as usual..., allowed_groups=[...], group_dn='ou=Groups,dc=domain,dc=com', group_name_attrib='cn', group_member_attrib='memberUid',#use 'member' for Active Directory group_filterstr='objectClass=*' )) Where: allowed_groups - a list with allowed ldap group names group_dn - the ldap branch of the groups group_name_attrib - the attribute where the group name is stored group_member_attrib - the attribute containing the group members name group_filterstr - as the filterstr but for group select If using Active Directory you must specify bind_dn and bind_pw for allowed_groups unless anonymous bind works. You can set the logging level with the "logging_level" parameter, default is "error" and can be set to error, warning, info, debug. """ if self_signed_certificate: # NOTE : If you have a self-signed SSL Certificate pointing over "port=686" and "secure=True" alone # will not work, you need also to set "self_signed_certificate=True". # Ref1: https://onemoretech.wordpress.com/2015/06/25/connecting-to-ldap-over-self-signed-tls-with-python/ # Ref2: http://bneijt.nl/blog/post/connecting-to-ldaps-with-self-signed-cert-using-python/ ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) logger = logging.getLogger('web2py.auth.ldap_auth') if logging_level == 'error': logger.setLevel(logging.ERROR) elif logging_level == 'warning': logger.setLevel(logging.WARNING) elif logging_level == 'info': logger.setLevel(logging.INFO) elif logging_level == 'debug': logger.setLevel(logging.DEBUG) def ldap_auth_aux(username, password, ldap_server=server, ldap_port=port, ldap_basedn=base_dn, ldap_mode=mode, ldap_binddn=bind_dn, ldap_bindpw=bind_pw, secure=secure, cert_path=cert_path, cert_file=cert_file, cacert_file=cacert_file, key_file=key_file, filterstr=filterstr, username_attrib=username_attrib, custom_scope=custom_scope, manage_user=manage_user, user_firstname_attrib=user_firstname_attrib, user_lastname_attrib=user_lastname_attrib, user_mail_attrib=user_mail_attrib, manage_groups=manage_groups, allowed_groups=allowed_groups, db=db): if password == '': # http://tools.ietf.org/html/rfc4513#section-5.1.2 logger.warning('blank password not allowed') return False logger.debug('mode: [%s] manage_user: [%s] custom_scope: [%s]' ' manage_groups: [%s]' % (str(mode), str(manage_user), str(custom_scope), str(manage_groups))) if manage_user: if user_firstname_attrib.count(':') > 0: (user_firstname_attrib, user_firstname_part) = user_firstname_attrib.split(':', 1) user_firstname_part = (int(user_firstname_part) - 1) else: user_firstname_part = None if user_lastname_attrib.count(':') > 0: (user_lastname_attrib, user_lastname_part) = user_lastname_attrib.split(':', 1) user_lastname_part = (int(user_lastname_part) - 1) else: user_lastname_part = None user_firstname_attrib = ldap.filter.escape_filter_chars( user_firstname_attrib) user_lastname_attrib = ldap.filter.escape_filter_chars( user_lastname_attrib) user_mail_attrib = ldap.filter.escape_filter_chars( user_mail_attrib) try: if allowed_groups: if not is_user_in_allowed_groups(username, password): return False con = init_ldap() if ldap_mode == 'ad': # Microsoft Active Directory if '@' not in username: domain = [] for x in ldap_basedn.split(','): if "DC=" in x.upper(): domain.append(x.split('=')[-1]) username = "******" % (username, '.'.join(domain)) username_bare = username.split("@")[0] con.set_option(ldap.OPT_PROTOCOL_VERSION, 3) # In cases where ForestDnsZones and DomainDnsZones are found, # result will look like the following: # ['ldap://ForestDnsZones.domain.com/DC=ForestDnsZones, # DC=domain,DC=com'] if ldap_binddn: # need to search directory with an admin account 1st con.simple_bind_s(ldap_binddn, ldap_bindpw) else: # credentials should be in the form of [email protected] con.simple_bind_s(username, password) # this will throw an index error if the account is not found # in the ldap_basedn requested_attrs = ['sAMAccountName'] if manage_user: requested_attrs.extend([ user_firstname_attrib, user_lastname_attrib, user_mail_attrib ]) result = con.search_ext_s( ldap_basedn, ldap.SCOPE_SUBTREE, "(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare), filterstr), requested_attrs)[0][1] if not isinstance(result, dict): # result should be a dict in the form # {'sAMAccountName': [username_bare]} logger.warning('User [%s] not found!' % username) return False if ldap_binddn: # We know the user exists & is in the correct OU # so now we just check the password con.simple_bind_s(username, password) username = username_bare if ldap_mode == 'domino': # Notes Domino if "@" in username: username = username.split("@")[0] con.simple_bind_s(username, password) if manage_user: # TODO: sorry I have no clue how to query attrs in domino result = { user_firstname_attrib: username, user_lastname_attrib: None, user_mail_attrib: None } if ldap_mode == 'cn': # OpenLDAP (CN) if ldap_binddn and ldap_bindpw: con.simple_bind_s(ldap_binddn, ldap_bindpw) dn = "cn=" + username + "," + ldap_basedn con.simple_bind_s(dn, password) if manage_user: result = con.search_s( dn, ldap.SCOPE_BASE, "(objectClass=*)", [ user_firstname_attrib, user_lastname_attrib, user_mail_attrib ])[0][1] if ldap_mode == 'uid': # OpenLDAP (UID) if ldap_binddn and ldap_bindpw: con.simple_bind_s(ldap_binddn, ldap_bindpw) dn = "uid=" + username + "," + ldap_basedn dn = con.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, "(uid=%s)" % username, [''])[0][0] else: dn = "uid=" + username + "," + ldap_basedn con.simple_bind_s(dn, password) if manage_user: result = con.search_s( dn, ldap.SCOPE_BASE, "(objectClass=*)", [ user_firstname_attrib, user_lastname_attrib, user_mail_attrib ])[0][1] if ldap_mode == 'company': # no DNs or password needed to search directory dn = "" pw = "" # bind anonymously con.simple_bind_s(dn, pw) # search by e-mail address filter = '(&(mail=%s)(%s))' % ( ldap.filter.escape_filter_chars(username), filterstr) # find the uid attrs = ['uid'] if manage_user: attrs.extend([ user_firstname_attrib, user_lastname_attrib, user_mail_attrib ]) # perform the actual search company_search_result = con.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, filter, attrs) dn = company_search_result[0][0] result = company_search_result[0][1] # perform the real authentication test con.simple_bind_s(dn, password) if ldap_mode == 'uid_r': # OpenLDAP (UID) with subtree search and multiple DNs if isinstance(ldap_basedn, list): basedns = ldap_basedn else: basedns = [ldap_basedn] filter = '(&(uid=%s)(%s))' % ( ldap.filter.escape_filter_chars(username), filterstr) found = False for basedn in basedns: try: result = con.search_s(basedn, ldap.SCOPE_SUBTREE, filter) if result: user_dn = result[0][0] # Check the password con.simple_bind_s(user_dn, password) found = True break except ldap.LDAPError, detail: (exc_type, exc_value) = sys.exc_info()[:2] logger.warning( "ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn, filter, exc_type, exc_value)) if not found: logger.warning('User [%s] not found!' % username) return False result = result[0][1] if ldap_mode == 'custom': # OpenLDAP (username_attrs) with subtree search and # multiple DNs if isinstance(ldap_basedn, list): basedns = ldap_basedn else: basedns = [ldap_basedn] filter = '(&(%s=%s)(%s))' % ( username_attrib, ldap.filter.escape_filter_chars(username), filterstr) if custom_scope == 'subtree': ldap_scope = ldap.SCOPE_SUBTREE elif custom_scope == 'base': ldap_scope = ldap.SCOPE_BASE elif custom_scope == 'onelevel': ldap_scope = ldap.SCOPE_ONELEVEL found = False for basedn in basedns: try: result = con.search_s(basedn, ldap_scope, filter) if result: user_dn = result[0][0] # Check the password con.simple_bind_s(user_dn, password) found = True break except ldap.LDAPError, detail: (exc_type, exc_value) = sys.exc_info()[:2] logger.warning( "ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn, filter, exc_type, exc_value)) if not found: logger.warning('User [%s] not found!' % username) return False result = result[0][1] if manage_user: logger.info('[%s] Manage user data' % str(username)) try: if user_firstname_part is not None: store_user_firstname = result[user_firstname_attrib][ 0].split(' ', 1)[user_firstname_part] else: store_user_firstname = result[user_firstname_attrib][0] except KeyError, e: store_user_firstname = None try: if user_lastname_part is not None: store_user_lastname = result[user_lastname_attrib][ 0].split(' ', 1)[user_lastname_part] else: store_user_lastname = result[user_lastname_attrib][0] except KeyError, e: store_user_lastname = None
def __init__(self, url, page_size, alias_dereferencing=None, use_tls=False, tls_cacertfile=None, tls_cacertdir=None, tls_req_cert='demand'): LOG.debug(_("LDAP init: url=%s"), url) LOG.debug( _('LDAP init: use_tls=%(use_tls)s\n' 'tls_cacertfile=%(tls_cacertfile)s\n' 'tls_cacertdir=%(tls_cacertdir)s\n' 'tls_req_cert=%(tls_req_cert)s\n' 'tls_avail=%(tls_avail)s\n') % { 'use_tls': use_tls, 'tls_cacertfile': tls_cacertfile, 'tls_cacertdir': tls_cacertdir, 'tls_req_cert': tls_req_cert, 'tls_avail': ldap.TLS_AVAIL }) #NOTE(topol) #for extra debugging uncomment the following line #ldap.set_option(ldap.OPT_DEBUG_LEVEL, 4095) using_ldaps = url.lower().startswith("ldaps") if use_tls and using_ldaps: raise AssertionError(_('Invalid TLS / LDAPS combination')) if use_tls: if not ldap.TLS_AVAIL: raise ValueError( _('Invalid LDAP TLS_AVAIL option: %s. TLS' 'not available') % ldap.TLS_AVAIL) if tls_cacertfile: #NOTE(topol) #python ldap TLS does not verify CACERTFILE or CACERTDIR #so we add some extra simple sanity check verification #Also, setting these values globally (i.e. on the ldap object) #works but these values are ignored when setting them on the #connection if not os.path.isfile(tls_cacertfile): raise IOError( _("tls_cacertfile %s not found " "or is not a file") % tls_cacertfile) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile) elif tls_cacertdir: #NOTE(topol) #python ldap TLS does not verify CACERTFILE or CACERTDIR #so we add some extra simple sanity check verification #Also, setting these values globally (i.e. on the ldap object) #works but these values are ignored when setting them on the #connection if not os.path.isdir(tls_cacertdir): raise IOError( _("tls_cacertdir %s not found " "or is not a directory") % tls_cacertdir) ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, tls_cacertdir) if tls_req_cert in LDAP_TLS_CERTS.values(): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_cert) else: LOG.debug(_("LDAP TLS: invalid TLS_REQUIRE_CERT Option=%s"), tls_req_cert) self.conn = ldap.initialize(url) self.conn.protocol_version = ldap.VERSION3 if alias_dereferencing is not None: self.conn.set_option(ldap.OPT_DEREF, alias_dereferencing) self.page_size = page_size if use_tls: self.conn.start_tls_s()
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." ) # FixMe: get new url 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.info( "ldap.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 __init__(self, ldap_config, who=None, cred=None): """ Initialize an ldap connection object and bind to the configured LDAP server. None if initialization failed. """ ldap_server = ldap_config.get('connection_url') if ldap_server is None: LOG.error('Server address is missing from the configuration') self.connection = None return referrals = ldap_config.get('referrals', False) ldap.set_option(ldap.OPT_REFERRALS, 1 if referrals else 0) deref = ldap_config.get('deref', ldap.DEREF_ALWAYS) if deref == 'never': deref = ldap.DEREF_NEVER else: deref = ldap.DEREF_ALWAYS ldap.set_option(ldap.OPT_DEREF, deref) ldap.protocol_version = ldap.VERSION3 # Verify certificate in LDAPS connections tls_require_cert = ldap_config.get('tls_require_cert', '') if tls_require_cert.lower() == 'never': LOG.debug("Insecure LDAPS connection because of " "tls_require_cert=='never'") ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) self.connection = ldap.initialize(ldap_server, bytes_mode=False) LOG.debug('Binding to LDAP server with user: %s', who if who else '') res = None with ldap_error_handler(): if who is None or cred is None: LOG.debug("Anonymous bind with no credentials.") res = self.connection.simple_bind_s() LOG.debug(res) else: LOG.debug("Binding with credential: %s", who) res = self.connection.simple_bind_s(who, cred) whoami = self.connection.whoami_s() LOG.debug(res) LOG.debug(whoami) # mail.python.org/pipermail/python-ldap/2012q4/003180.html if whoami is None: # If LDAP server allows anonymous binds, simple bind # does not throw an exception when the password is # empty and does the binding as anonymous. # This is an expected behaviour as per LDAP RFC. # However, if the bind is successful but no # authentication has been done, it is still to be # considered an error from the user's perspective. LOG.debug("Anonymous bind succeeded but no valid " "password was given.") raise ldap.INVALID_CREDENTIALS() if not res: LOG.debug("Server bind failed.") if self.connection is not None: self.connection.unbind() self.connection = None
def authenticate(self, username=None, password=None): # Check if ldap server is set if settings.AUTH_LDAP_SERVER_URI is None: self.logger.error('AUTH_LDAP_SERVER_URI not defined in settings!') raise Exception("AUTH_LDAP_SERVER_URI not defined in settings!") self.logger.info('Authenticate user %s in AD/LDAP %s' % (username, settings.AUTH_LDAP_SERVER_URI)) # Check if authentication should trust all AD certificates if settings.AUTH_LDAP_TRUST_ALL_CERTIFICATES: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) ldap_connection = ldap.initialize(settings.AUTH_LDAP_SERVER_URI) # https://stackoverflow.com/questions/18793040/python-ldap-not-able-to-bind-successfully ldap_connection.set_option(ldap.OPT_REFERRALS, 0) # Check if domain is already at the end of the username try: if str(username).lower().endswith( str(settings.AUTH_LDAP_USER_DOMAIN).lower()): username_ldap_bind = username else: username_ldap_bind = "%s@%s" % (username, settings.AUTH_LDAP_USER_DOMAIN) self.logger.debug( 'Domain %s is not part of the given username %s, add it to bind to ldap: %s' % (settings.AUTH_LDAP_USER_DOMAIN, username, username_ldap_bind)) except Exception as ex: self.logger.warn( 'AUTH_LDAP_USER_DOMAIN not defined in django settings. Do not append domain to username for ldap authentication' ) username_ldap_bind = username # Bind to ldap ############## try: self.__ldap_bind(ldap_connection=ldap_connection, username=username_ldap_bind, password=password) except Exception as ex: self.logger.error( 'Could not bind to ldap (%s) as user %s. User therefore not authenticated.' % (settings.AUTH_LDAP_SERVER_URI, username_ldap_bind)) self.logger.info('Bind exception message: %s' % ex.message) self.logger.debug(ex) return None # Check if AUTH_LDAP_USER_SEARCH is a list if not isinstance( settings.AUTH_LDAP_USER_SEARCH, (list, tuple)): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for AUTH_LDAP_USER_SEARCH is not a list (%s), convert it to a list.' % type(settings.AUTH_LDAP_USER_SEARCH)) settings.AUTH_LDAP_USER_SEARCH = ( settings.AUTH_LDAP_USER_SEARCH, ) # trailing comma: https://wiki.python.org/moin/TupleSyntax # Get Ldap User Object from ldap_base ldap_user_fields = None base_dn = None for ldap_base in settings.AUTH_LDAP_USER_SEARCH: ldap_user_fields = self.__get_user_from_ldap(ldap_connection, username, ldap_base=ldap_base) if ldap_user_fields is None: self.logger.info( 'Could not get ldap user with username %s in base_dn %s.' % (username, ldap_base)) else: self.logger.debug('User %s from ldap in base_dn %s received.' % (username, ldap_base)) base_dn = ldap_base break if ldap_user_fields is None: self.logger.error( 'Could not get ldap user with username %s in any of the configured AUTH_LDAP_USER_SEARCH. User therefore not authorized!' % username) return None try: ldap_username = ldap_user_fields[ settings.AUTH_LDAP_USER_ATTR_MAP['username']][0] self.logger.debug('Username of %s in ldap: %s' % (username, ldap_username)) except NameError as ne: self.logger.warn( 'Could not get username from ldap fields for user %s: %s' % (username, ne.message)) self.logger.debug( 'Probably AUTH_LDAP_USER_ATTR_MAP["username"] in settings not defined, use normal username %s as ldap_username.' % username) ldap_username = username # Django username, may have a prefix (AUTH_LDAP_USER_PREFIX) compared to login try: username_django = '%s%s' % (settings.AUTH_LDAP_USER_PREFIX, ldap_username) except NameError: username_django = ldap_username self.logger.debug('Username of %s in django: %s' % (ldap_username, username_django)) # Get fields for django user from ldap ###################################### # first_name try: first_name = ldap_user_fields[ settings.AUTH_LDAP_USER_ATTR_MAP['first_name']][0] except Exception as ex: self.logger.warn( 'Could not get first_name from ldap fields (several reasons: ldap field not set, AUTH_LDAP_USER_ATTR_MAP for first_name): %s' % ex.message) first_name = None # last_name try: last_name = ldap_user_fields[ settings.AUTH_LDAP_USER_ATTR_MAP['last_name']][0] except Exception as ex: self.logger.warn( 'Could not get last_name from ldap fields (several reasons: ldap field not set, AUTH_LDAP_USER_ATTR_MAP for last_name): %s' % ex.message) last_name = None # Email try: email = ldap_user_fields[ settings.AUTH_LDAP_USER_ATTR_MAP['email']][0] except Exception as ex: self.logger.warn( 'Could not get last_name from ldap fields (several reasons: ldap field not set, AUTH_LDAP_USER_ATTR_MAP for email): %s' % ex.message) email = None # Get/Create django user ######################## django_user = self.__get_or_create_django_user(username_django, first_name=first_name, last_name=last_name, email=email) # Reset staff und superuser fields at login django_user.is_staff = False django_user.is_superuser = False # User Profile (level: GA/RW/RO/SO) ################################### user_profile = None # GA = Global Admin #------------------ user_profile_groups = None try: # Check if setting exist user_profile_groups = settings.AUTH_LDAP_USER_PROFILE['GA'] except Exception as ex: self.logger.warn( 'Could not get ldap group(s) of user profile GA in setting AUTH_LDAP_USER_PROFILE.' ) if user_profile_groups is not None: if not isinstance( user_profile_groups, (list, tuple)): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for user profile "GA" is not a list (%s), convert it to a list.' % type(user_profile_groups)) user_profile_groups = ( user_profile_groups, ) # trailing comma: https://wiki.python.org/moin/TupleSyntax for group in user_profile_groups: if self.__is_user_member_of_ldap_group( ldap_connection=ldap_connection, username=ldap_username, group_dn=group, ldap_base=base_dn): self.logger.debug('User %s is member of GA group %s' % (ldap_username, group)) self.__set_userprofile(username_django, 'GA') user_profile = 'GA' self.logger.debug( 'Set django user %s field "is_staff" to True.') django_user.is_staff = True django_user.save() self.logger.debug( 'User profile to "GA" = Global Admin set. Do not check for other profiles anymore.' ) break if user_profile is None: self.logger.debug('User %s is not part of any GA group.' % ldap_username) else: self.logger.debug( 'No ldap group for user profile "GA" defined in settings.') # RW = Read & Write #------------------ user_profile_groups = None # temporary variable with ldap groups try: # Check if setting exist user_profile_groups = settings.AUTH_LDAP_USER_PROFILE['RW'] except Exception as ex: self.logger.warn( 'Could not get ldap group(s) of user profile RW in setting AUTH_LDAP_USER_PROFILE.' ) if user_profile_groups is not None and user_profile is None: if not isinstance( user_profile_groups, (list, tuple)): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for user profile "RW" is not a list (%s), convert it to a list.' % type(user_profile_groups)) user_profile_groups = ( user_profile_groups, ) # trailing comma: https://wiki.python.org/moin/TupleSyntax for group in user_profile_groups: if self.__is_user_member_of_ldap_group( ldap_connection=ldap_connection, username=ldap_username, group_dn=group, ldap_base=base_dn): self.logger.debug('User %s is member of RW group %s' % (ldap_username, group)) self.__set_userprofile(username_django, 'RW') user_profile = 'RW' self.logger.debug( 'User profile to "RW" = "Read Write" set. Do not check for other profiles anymore.' ) break if user_profile is None: self.logger.debug('User %s is not part of any RW group.' % ldap_username) else: self.logger.debug( 'No ldap group for user profile "RW" defined in settings OR user profile already set to GA.' ) # RO = Read Only #--------------- user_profile_groups = None # temporary variable with ldap groups try: # Check if setting exist user_profile_groups = settings.AUTH_LDAP_USER_PROFILE['RO'] except Exception as ex: self.logger.warn( 'Could not get ldap group(s) of user profile RO in setting AUTH_LDAP_USER_PROFILE.' ) if user_profile_groups is not None and user_profile is None: if not isinstance( user_profile_groups, (list, tuple)): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for user profile "RO" is not a list (%s), convert it to a list.' % type(user_profile_groups)) user_profile_groups = ( user_profile_groups, ) # trailing comma: https://wiki.python.org/moin/TupleSyntax for group in user_profile_groups: if self.__is_user_member_of_ldap_group( ldap_connection=ldap_connection, username=ldap_username, group_dn=group, ldap_base=base_dn): self.logger.debug('User %s is member of RO group %s' % (ldap_username, group)) self.__set_userprofile(username_django, 'RO') user_profile = 'RO' self.logger.debug( 'User profile to "RO" = "Read Only" set. Do not check for other profiles anymore.' ) break if user_profile is None: self.logger.debug('User %s is not part of any RO group.' % ldap_username) else: self.logger.debug( 'No ldap group for user profile "RO" defined in settings OR user profile already set to GA or RW.' ) # SO = Stats Only (not implemented (yet?) in SAL) #------------------------------------------------ user_profile_groups = None # temporary variable with ldap groups try: # Check if setting exist user_profile_groups = settings.AUTH_LDAP_USER_PROFILE['SO'] except Exception as ex: self.logger.warn( 'Could not get ldap group(s) of user profile SO in setting AUTH_LDAP_USER_PROFILE.' ) if user_profile_groups is not None and user_profile is None: if not isinstance( user_profile_groups, (list, tuple)): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for user profile "SO" is not a list (%s), convert it to a list.' % type(user_profile_groups)) user_profile_groups = ( user_profile_groups, ) # trailing comma: https://wiki.python.org/moin/TupleSyntax for group in user_profile_groups: if self.__is_user_member_of_ldap_group( ldap_connection=ldap_connection, username=ldap_username, group_dn=group, ldap_base=base_dn): self.logger.debug('User %s is member of SO group %s' % (ldap_username, group)) self.__set_userprofile(username_django, 'SO') user_profile = 'SO' self.logger.debug( 'User profile to "SO" = "Stats Only" set. Do not check for other profiles anymore.' ) break if user_profile is None: self.logger.debug('User %s is not part of any SO group.') else: self.logger.debug( 'No ldap group for user profile "SO" defined in settings OR user profile already set to GA, RW or RO.' ) # If the user does not exist in any of the given AUTH_LDAP_USER_PROFILE groups, set to default UserProfile level if user_profile is None: self.logger.warn( 'User %s authenticated in AD/LDAP, but not part of any configured GA/RW/RO/SO group. Set to %s.' % (django_user, UserProfile._meta.get_field('level').get_default())) self.__set_userprofile( username_django, '%s' % UserProfile._meta.get_field('level').get_default()) user_profile = UserProfile._meta.get_field('level').get_default() # Business Units ################ # remove from all existing Business units, before assigne to new business units. self.logger.debug( 'Remove all business units of %s, assign the configured ones afterwards.' % username_django) for business_unit in self.__get_business_units( username=username_django): self.logger.debug('Remove business unit "%s" from user %s.' % (business_unit, username_django)) self.__remove_user_from_business_unit(username_django, business_unit) # assign Business units self.logger.debug('Get all existing business units.') all_business_units = self.__get_business_units() user_business_units = [] # business units of user. business_units_settings = None # Configured Business units in the settings try: business_units_settings = settings.AUTH_LDAP_USER_TO_BUSINESS_UNIT.keys( ) except Exception as ex: self.logger.debug( 'AUTH_LDAP_USER_TO_BUSINESS_UNIT not configured in settings as dictionary.' ) if business_units_settings is not None and user_profile != 'GA': # GA (Global Admin does not need assigned business units) for business_unit in business_units_settings: # Handle all business units for key #ALL_BU if business_unit == '#ALL_BU': # Special case: users in the group #ALL_BU get access to all Business units. self.logger.debug( 'Check if user %s has access to all business units ("%s").' % (ldap_username, business_unit)) if not isinstance( settings. AUTH_LDAP_USER_TO_BUSINESS_UNIT[business_unit], (list, tuple) ): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for business unit "%s" is not a list, convert it to a list.' % business_unit) # trailing comma: https://wiki.python.org/moin/TupleSyntax settings.AUTH_LDAP_USER_TO_BUSINESS_UNIT[ business_unit] = ( settings. AUTH_LDAP_USER_TO_BUSINESS_UNIT[business_unit], ) for group in settings.AUTH_LDAP_USER_TO_BUSINESS_UNIT[ business_unit]: # Loop over groups self.logger.debug( 'Check if user %s is in ldap group %s.' % (ldap_username, group)) if self.__is_user_member_of_ldap_group( ldap_connection=ldap_connection, username=ldap_username, group_dn=group, ldap_base=base_dn): self.logger.debug( 'User %s is member of group %s, assign user to all existing business units!' % (ldap_username, group)) for one_of_all_business_units in all_business_units: self.logger.debug( 'Assign business unit %s to user %s with access to all existing business units.' % (one_of_all_business_units, username_django)) self.__add_user_to_business_unit( username_django, one_of_all_business_units ) # Assign user to business unit user_business_units.append( one_of_all_business_units) break else: self.logger.debug( 'User %s is NOT member of group %s.' % (ldap_username, group)) # Check if business unit is an existing one elif business_unit in all_business_units: if not isinstance( settings. AUTH_LDAP_USER_TO_BUSINESS_UNIT[business_unit], (list, tuple) ): # Check if it is a list, otherwise convert to list self.logger.debug( 'Given setting for business unit "%s" is not a list, convert it to a list.' % business_unit) # trailing comma: https://wiki.python.org/moin/TupleSyntax settings.AUTH_LDAP_USER_TO_BUSINESS_UNIT[ business_unit] = ( settings. AUTH_LDAP_USER_TO_BUSINESS_UNIT[business_unit], ) for group in settings.AUTH_LDAP_USER_TO_BUSINESS_UNIT[ business_unit]: # Loop over groups self.logger.debug( 'Check if user %s is in ldap group %s.' % (ldap_username, group)) if self.__is_user_member_of_ldap_group( ldap_connection=ldap_connection, username=ldap_username, group_dn=group, ldap_base=base_dn): self.logger.debug( 'User %s is member of group %s, assign user to business unit %s' % (ldap_username, group, business_unit)) self.__add_user_to_business_unit( username_django, business_unit) # Assign user to business unit user_business_units.append(business_unit) break else: self.logger.debug( 'User %s is NOT member of group %s.' % (ldap_username, group)) else: self.logger.warn( 'Business unit in settings (AUTH_LDAP_USER_TO_BUSINESS_UNIT) %s does not exist in existing SAL business units (%s)' % (business_unit, ''.join(all_business_units))) elif user_profile == 'GA': self.logger.debug( 'User %s has user profile GA (Global Admin), therefore not necessary to assign business units to the user.' % username_django) elif business_units_settings is None: self.logger.debug( 'AUTH_LDAP_USER_TO_BUSINESS_UNIT not correct configured in settings, therefore not possible to assign business units to user %s.' % username_django) self.logger.info( 'Everything fine! Found user with username "%s" in ldap. User has user profile "%s" and access to following business units: %s' % (username, user_profile, ', '.join(user_business_units))) django_user.save() return django_user
def ipacheckldap(self, thost, trealm, ca_cert_path=None): """ Given a host and kerberos realm verify that it is an IPA LDAP server hosting the realm. Returns a list [errno, host, realm] or an empty list on error. Errno is an error number: 0 means all ok 1 means we could not check the info in LDAP (may happend when anonymous binds are disabled) 2 means the server is certainly not an IPA server """ lrealms = [] i = 0 #now verify the server is really an IPA server try: ldap_url = "ldap://" + format_netloc(thost, 389) root_logger.debug("Init LDAP connection with: %s", ldap_url) lh = ldap.initialize(ldap_url) if ca_cert_path: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ca_cert_path) lh.set_option(ldap.OPT_X_TLS_DEMAND, True) lh.start_tls_s() lh.set_option(ldap.OPT_PROTOCOL_VERSION, 3) lh.simple_bind_s("", "") # get IPA base DN root_logger.debug("Search LDAP server for IPA base DN") basedn = get_ipa_basedn(lh) if basedn is None: root_logger.debug("The server is not an IPA server") return [NOT_IPA_SERVER] self.basedn = basedn self.basedn_source = 'From IPA server %s' % ldap_url #search and return known realms root_logger.debug( "Search for (objectClass=krbRealmContainer) in %s (sub)", self.basedn) lret = lh.search_s(str(DN(('cn', 'kerberos'), self.basedn)), ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)") if not lret: #something very wrong return [REALM_NOT_FOUND] for lres in lret: root_logger.debug("Found: %s", lres[0]) for lattr in lres[1]: if lattr.lower() == "cn": lrealms.append(lres[1][lattr][0]) if trealm: for r in lrealms: if trealm == r: return [0, thost, trealm] # must match or something is very wrong return [REALM_NOT_FOUND] else: if len(lrealms) != 1: #which one? we can't attach to a multi-realm server without DNS working return [REALM_NOT_FOUND] else: return [0, thost, lrealms[0]] #we shouldn't get here return [UNKNOWN_ERROR] except LDAPError, err: if isinstance(err, ldap.TIMEOUT): root_logger.debug("LDAP Error: timeout") return [NO_LDAP_SERVER] if isinstance(err, ldap.SERVER_DOWN): root_logger.debug("LDAP Error: server down") return [NO_LDAP_SERVER] if isinstance(err, ldap.INAPPROPRIATE_AUTH): root_logger.debug("LDAP Error: Anonymous access not allowed") return [NO_ACCESS_TO_LDAP] # We should only get UNWILLING_TO_PERFORM if the remote LDAP server # has minssf > 0 and we have attempted a non-TLS connection. if ca_cert_path is None and isinstance(err, ldap.UNWILLING_TO_PERFORM): root_logger.debug( "LDAP server returned UNWILLING_TO_PERFORM. This likely means that minssf is enabled" ) return [NO_TLS_LDAP] root_logger.error( "LDAP Error: %s: %s" % (err.args[0]['desc'], err.args[0].get('info', ''))) return [UNKNOWN_ERROR]
def authenticate(self, name, pw, certlist, certhash, strong, current=None): """ This function is called to authenticate a user """ # Search for the user in the database FALL_THROUGH = -2 AUTH_REFUSED = -1 # SuperUser is a special login. if name == "SuperUser": debug("Forced fall through for SuperUser") return (FALL_THROUGH, None, None) # Otherwise, let's check the LDAP server. uid = None if cfg.ldap.use_start_tls: # try StartTLS: global options debug( "use_start_tls is set, setting global option TLS_REQCERT = never" ) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) ldap_trace = 0 # Change to 1 for more verbose trace ldap_conn = ldap.initialize(cfg.ldap.ldap_uri, ldap_trace) if cfg.ldap.use_start_tls: # try StartTLS: connection specific options debug( "use_start_tls is set, setting connection options X_TLS_*") ldap_conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3) ldap_conn.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND) ldap_conn.set_option(ldap.OPT_X_TLS_DEMAND, True) try: ldap_conn.start_tls_s() except Exception as e: warning("could not initiate StartTLS, e = " + str(e)) return (AUTH_REFUSED, None, None) if cfg.ldap.bind_dn: # Bind the functional account to search the directory. bind_dn = cfg.ldap.bind_dn bind_pass = cfg.ldap.bind_pass try: debug("try to connect to ldap (bind_dn will be used)") ldap_conn.bind_s(bind_dn, bind_pass) except ldap.INVALID_CREDENTIALS: ldap_conn.unbind() warning("Invalid credentials for bind_dn=" + bind_dn) return (AUTH_REFUSED, None, None) elif cfg.ldap.discover_dn: # Use anonymous bind to discover the DN try: ldap_conn.bind_s() except ldap.INVALID_CREDENTIALS: ldap_conn.unbind() warning("Failed anomymous bind for discovering DN") return (AUTH_REFUSED, None, None) else: # Prevent anonymous authentication. if not pw: warning("No password supplied for user " + name) return (AUTH_REFUSED, None, None) # Bind the user account to search the directory. bind_dn = "%s=%s,%s" % (cfg.ldap.username_attr, name, cfg.ldap.users_dn) bind_pass = pw try: ldap_conn.bind_s(bind_dn, bind_pass) except ldap.INVALID_CREDENTIALS: ldap_conn.unbind() warning("User " + name + " failed with invalid credentials") return (AUTH_REFUSED, None, None) # Search for the user. res = ldap_conn.search_s( cfg.ldap.users_dn, ldap.SCOPE_SUBTREE, "(%s=%s)" % (cfg.ldap.username_attr, name), [cfg.ldap.number_attr, cfg.ldap.display_attr], ) if len(res) == 0: warning("User " + name + " not found") if cfg.user.reject_on_miss: return (AUTH_REFUSED, None, None) else: return (FALL_THROUGH, None, None) match = res[ 0] # Only interested in the first result, as there should only be one match # Parse the user information. uid = self.getMumbleID(match[1][cfg.ldap.number_attr][0]) displayName = match[1][cfg.ldap.display_attr][0].decode("UTF-8") user_dn = match[0] debug("User match found, display '" + displayName + "' with UID " + repr(uid)) # Optionally check groups. if cfg.ldap.group_cn != "": debug("Checking group membership for " + name) # Search for user in group res = ldap_conn.search_s( cfg.ldap.group_cn, ldap.SCOPE_SUBTREE, "(%s=%s)" % (cfg.ldap.group_attr, user_dn), [cfg.ldap.number_attr, cfg.ldap.display_attr], ) # Check if the user is a member of the group if len(res) < 1: debug("User " + name + " failed with no group membership") return (AUTH_REFUSED, None, None) # Second bind to test user credentials if using bind_dn or discover_dn. if cfg.ldap.bind_dn or cfg.ldap.discover_dn: # Prevent anonymous authentication. if not pw: warning("No password supplied for user " + name) return (AUTH_REFUSED, None, None) bind_dn = user_dn bind_pass = pw try: ldap_conn.bind_s(bind_dn, bind_pass) except ldap.INVALID_CREDENTIALS: ldap_conn.unbind() warning("User " + name + " failed with wrong password") return (AUTH_REFUSED, None, None) # Unbind and close connection. ldap_conn.unbind() # If we get here, the login is correct. # Add the user/id combo to cache, then accept: self.name_uid_cache[displayName] = uid debug("Login accepted for " + name) return (uid + cfg.user.id_offset, displayName, [])
def _connect(self): """Initialize an ldap client""" ldap_client = ldap.initialize(self.uri) ldap.set_option(ldap.OPT_REFERRALS, 0) ldap.set_option(ldap.OPT_TIMEOUT, self.timeout) if self.starttls == 'on': ldap.set_option(ldap.OPT_X_TLS_DEMAND, True) else: ldap.set_option(ldap.OPT_X_TLS_DEMAND, False) # set the CA file if declared and if necessary if self.ca and self.checkcert == 'on': # check if the CA file actually exists if os.path.isfile(self.ca): ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca) else: raise CaFileDontExist(self.ca) if self.checkcert == 'off': # this is dark magic # remove any of these two lines and it doesn't work ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) ldap_client.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) else: # this is even darker magic ldap_client.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) # it doesn't make sense to set it to never # (== don't check certifate) # but it only works with this option... # ... and it checks the certificat # (I've lost my sanity over this) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) if self.starttls == 'on': try: ldap_client.start_tls_s() except Exception as e: self._exception_handler(e) return ldap_client
def login(): # Allow LDAP server to use a self signed certificate if current_app.config['LDAP_ALLOW_SELF_SIGNED_CERT']: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) # Retrieve required fields from client request try: login = request.json.get('username', None) or request.json['email'] password = request.json['password'] except KeyError: raise ApiError("must supply 'username' and 'password'", 401) if '\\' in login: domain, username = login.split('\\') email = '' email_verified = False else: username, domain = login.split('@') email = login email_verified = True # Validate LDAP domain if domain not in current_app.config['LDAP_DOMAINS']: raise ApiError('unauthorized domain', 403) userdn = current_app.config['LDAP_DOMAINS'][domain] % username # Attempt LDAP AUTH try: trace_level = 2 if current_app.debug else 0 ldap_connection = ldap.initialize(current_app.config['LDAP_URL'], trace_level=trace_level) ldap_connection.simple_bind_s(userdn, password) except ldap.INVALID_CREDENTIALS: raise ApiError('invalid username or password', 401) except Exception as e: raise ApiError(str(e), 500) # Get email address from LDAP if not email_verified: try: ldap_result = ldap_connection.search_s(userdn, ldap.SCOPE_SUBTREE, '(objectClass=*)', ['mail']) email = ldap_result[0][1]['mail'][0].decode(sys.stdout.encoding) email_verified = True except: email = '{}@{}'.format(username, domain) # Create user if not yet there user = User.find_by_username(username=login) if not user: user = User(name=username, login=login, password='', email=email, roles=[], text='LDAP user', email_verified=email_verified) try: user = user.create() except Exception as e: ApiError(str(e), 500) # Assign customers & update last login time groups = list() try: groups_filters = current_app.config.get('LDAP_DOMAINS_GROUP', {}) base_dns = current_app.config.get('LDAP_DOMAINS_BASEDN', {}) if domain in groups_filters and domain in base_dns: resultID = ldap_connection.search( base_dns[domain], ldap.SCOPE_SUBTREE, groups_filters[domain].format(username=username, email=email, userdn=userdn), ['cn']) resultTypes, results = ldap_connection.result(resultID) for _dn, attributes in results: groups.append(attributes['cn'][0].decode('utf-8')) except ldap.LDAPError as e: raise ApiError(str(e), 500) # Check user is active if user.status != 'active': raise ApiError('User {} not active'.format(login), 403) user.update_last_login() scopes = Permission.lookup(login=login, roles=user.roles + groups) customers = get_customers(login=login, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='basic-ldap-login', message='user login via LDAP', user=login, customers=customers, scopes=scopes, resource_id=user.id, type='user', request=request) # Generate token token = create_token(user_id=user.id, name=user.name, login=user.email, provider='ldap', customers=customers, scopes=scopes, roles=user.roles, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
LDAP_ENABLED = os.getenv('DBAAS_LDAP_ENABLED', '0') if LDAP_ENABLED == "1": LDAP_ENABLED = True else: LDAP_ENABLED = False LDAP_CERTDIR = os.getenv('DBAAS_LDAP_CERTDIR', '') LDAP_CACERTFILE = os.getenv('DBAAS_LDAP_CACERTFILE', '') LDAP_CERTFILE = os.getenv('DBAAS_LDAP_CERTFILE', '') LDAP_KEYFILE = os.getenv('DBAAS_LDAP_KEYFILE', '') if LDAP_ENABLED: import ldap from django_auth_ldap.config import LDAPSearch, GroupOfNamesType ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, LDAP_CERTDIR + LDAP_CACERTFILE) ldap.set_option(ldap.OPT_X_TLS_CERTFILE, LDAP_CERTDIR + LDAP_CERTFILE) ldap.set_option(ldap.OPT_X_TLS_KEYFILE, LDAP_CERTDIR + LDAP_KEYFILE) # Baseline configuration. AUTH_LDAP_SERVER_URI = os.getenv('AUTH_LDAP_SERVER_URI', '') AUTH_LDAP_BIND_DN = os.getenv('AUTH_LDAP_BIND_DN', '') AUTH_LDAP_BIND_PASSWORD = os.getenv('AUTH_LDAP_BIND_PASSWORD', '') AUTH_LDAP_USER_SEARCH_STR = os.getenv('AUTH_LDAP_USER_SEARCH', '') AUTH_LDAP_USER_SEARCH = LDAPSearch( AUTH_LDAP_USER_SEARCH_STR, ldap.SCOPE_SUBTREE, "(&(uid=%(user)s)(!(nsaccountlock=TRUE)))") AUTH_LDAP_GROUP_SEARCH_STR = os.getenv('AUTH_LDAP_GROUP_SEARCH', '') AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP_SEARCH_STR, ldap.SCOPE_SUBTREE,
def login(): try: login = request.json.get('username') or request.json['email'] password = request.json['password'] except KeyError: raise ApiError("must supply 'username' and 'password'", 401) if not password: raise ApiError('password not allowed to be empty', 401) try: if '\\' in login: domain, username = login.split('\\') else: username, domain = login.split('@') except ValueError: if current_app.config['LDAP_DEFAULT_DOMAIN']: username = login domain = current_app.config['LDAP_DEFAULT_DOMAIN'] else: raise ApiError('expected username with domain', 401) # Validate LDAP domain if (domain not in current_app.config['ALLOWED_EMAIL_DOMAINS'] and domain not in current_app.config['LDAP_DOMAINS']): raise ApiError('unauthorized domain', 403) # LDAP certificate settings if current_app.config['LDAP_CACERT']: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, current_app.config['LDAP_CACERT']) # Allow LDAP server to use a self-signed certificate if current_app.config['LDAP_ALLOW_SELF_SIGNED_CERT']: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) # Set LDAP Timeout: if current_app.config['LDAP_QUERY_TIMEOUT_SECONDS']: ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, current_app.config['LDAP_QUERY_TIMEOUT_SECONDS']) # Initialise ldap connection try: trace_level = 2 if current_app.debug else 0 # XXX - do not set in production environments ldap_connection = ldap.initialize(current_app.config['LDAP_URL'], trace_level=trace_level) except Exception as e: raise ApiError(str(e), 500) # bind user credentials ldap_bind_username = current_app.config['LDAP_BIND_USERNAME'] ldap_bind_password = current_app.config['LDAP_BIND_PASSWORD'] if ldap_bind_username: try: ldap_connection.simple_bind_s(ldap_bind_username, ldap_bind_password) except ldap.INVALID_CREDENTIALS: raise ApiError('invalid ldap bind credentials', 500) # Set default base DN for user and group search base_dn = current_app.config['LDAP_BASEDN'] # If user search filter exist # Search the user using the provided User Search filter for the current domain # If one user is found # Set the DN as the one found # Set email retreived from AD # If more than one user is found # Except: Search query is bad defined # Else # Set the DN as the one found in LDAP_DOMAINS variable user_filter = current_app.config['LDAP_USER_FILTER'] user_base_dn = current_app.config['LDAP_USER_BASEDN'] user_attrs = [ current_app.config['LDAP_USER_NAME_ATTR'], current_app.config['LDAP_USER_EMAIL_ATTR'] ] if user_filter: result = [ r for r in ldap_connection.search_s(base=user_base_dn or base_dn, scope=ldap.SCOPE_SUBTREE, filterstr=user_filter.format( username=username), attrlist=user_attrs) if None not in r ] if len(result) > 1: raise ApiError( 'invalid search query for domain "{}"'.format(domain), 500) elif len(result) == 0: raise ApiError('invalid username or password', 401) user_dn = result[0][0] name = result[0][1][ current_app.config['LDAP_USER_NAME_ATTR']][0].decode( 'utf-8', 'ignore') email = result[0][1][ current_app.config['LDAP_USER_EMAIL_ATTR']][0].decode( 'utf-8', 'ignore') email_verified = bool(email) else: if '%' in current_app.config['LDAP_DOMAINS'][domain]: user_dn = current_app.config['LDAP_DOMAINS'][domain] % username else: user_dn = current_app.config['LDAP_DOMAINS'][domain].format( username) name = username email = '{}@{}'.format(username, domain) email_verified = False # Authenticate user logging in try: ldap_connection.simple_bind_s(user_dn, password) except ldap.INVALID_CREDENTIALS: raise ApiError('invalid username or password', 401) login = email or username user = User.find_by_username(username=login) if not user: user = User(name=name, login=login, password='', email=email, roles=current_app.config['USER_ROLES'], text='LDAP user', email_verified=email_verified) user = user.create() else: user.update(login=login, email=email, email_verified=email_verified) if ldap_bind_username: try: ldap_connection.simple_bind_s(ldap_bind_username, ldap_bind_password) except ldap.INVALID_CREDENTIALS: raise ApiError('invalid ldap bind credentials', 500) # Assign customers & update last login time group_filter = current_app.config['LDAP_GROUP_FILTER'] group_base_dn = current_app.config['LDAP_GROUP_BASEDN'] groups = list() if group_filter: result = ldap_connection.search_s( base=group_base_dn or base_dn, scope=ldap.SCOPE_SUBTREE, filterstr=group_filter.format(username=username, email=email, userdn=user_dn), attrlist=[current_app.config['LDAP_GROUP_NAME_ATTR']]) for group_dn, group_attrs in result: if current_app.config['LDAP_GROUP_NAME_ATTR'] in group_attrs.keys( ): groups.extend([ g.decode('utf-8', 'ignore') for g in group_attrs[ current_app.config['LDAP_GROUP_NAME_ATTR']] ]) else: groups.append(group_dn) # Check user is active if user.status != 'active': raise ApiError('User {} not active'.format(login), 403) if not_authorized('ALLOWED_LDAP_GROUPS', groups): raise ApiError('User {} is not authorized'.format(login), 403) user.update_last_login() scopes = Permission.lookup(login=login, roles=user.roles + groups) customers = get_customers(login=login, groups=[user.domain] + groups) auth_audit_trail.send(current_app._get_current_object(), event='basic-ldap-login', message='user login via LDAP', user=login, customers=customers, scopes=scopes, roles=user.roles, groups=groups, resource_id=user.id, type='user', request=request) # Generate token token = create_token(user_id=user.id, name=user.name, login=user.email, provider='ldap', customers=customers, scopes=scopes, roles=user.roles, groups=groups, email=user.email, email_verified=user.email_verified) return jsonify(token=token.tokenize)
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
def __init__(self, config): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) self._config = config self._conn = None
def POST(self): # Get username, password. i = web.input(_unicode=False) username = web.safestr(i.get('username', '').strip()).lower() password = i.get('password', '').strip() save_pass = web.safestr(i.get('save_pass', 'no').strip()) if not iredutils.is_email(username): raise web.seeother('/login?msg=INVALID_USERNAME') if not password: raise web.seeother('/login?msg=EMPTY_PASSWORD') # Get LDAP URI. uri = settings.ldap_uri # Verify bind_dn & bind_pw. try: # Detect STARTTLS support. if uri.startswith('ldaps://'): starttls = True else: starttls = False # Set necessary option for STARTTLS. if starttls: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Initialize connection. conn = ldap.initialize(uri) # Set LDAP protocol version: LDAP v3. conn.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) if starttls: conn.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND) # synchronous bind. conn.bind_s(settings.ldap_bind_dn, settings.ldap_bind_password) conn.unbind_s() except (ldap.INVALID_CREDENTIALS): raise web.seeother('/login?msg=vmailadmin_INVALID_CREDENTIALS') except Exception as e: raise web.seeother('/login?msg=%s' % web.safestr(e)) # Check whether it's a mail user dn_user = ldaputils.convert_keyword_to_dn(username, accountType='user') qr_user_auth = auth.Auth(uri=uri, dn=dn_user, password=password) qr_admin_auth = (False, 'INVALID_CREDENTIALS') if not qr_user_auth[0]: # Verify admin account under 'o=domainAdmins'. dn_admin = ldaputils.convert_keyword_to_dn(username, accountType='admin') qr_admin_auth = auth.Auth(uri=uri, dn=dn_admin, password=password) if not qr_admin_auth[0]: session['failed_times'] += 1 web.logger(msg="Login failed.", admin=username, event='login', loglevel='error') raise web.seeother('/login?msg=INVALID_CREDENTIALS') if qr_admin_auth[0] or qr_user_auth[0]: session['username'] = username session['logged'] = True # Read preferred language from LDAP if qr_admin_auth[0] is True: adminLib = adminlib.Admin() adminProfile = adminLib.profile( username, attributes=['preferredLanguage']) if adminProfile[0] is True: dn, entry = adminProfile[1][0] lang = entry.get('preferredLanguage', [settings.default_language])[0] session['lang'] = lang if qr_user_auth[0] is True: session['isMailUser'] = True web.config.session_parameters['cookie_name'] = 'iRedAdmin-Pro' # Session expire when client ip was changed. web.config.session_parameters['ignore_change_ip'] = False # Don't ignore session expiration. web.config.session_parameters['ignore_expiry'] = False if save_pass == 'yes': # Session timeout (in seconds). web.config.session_parameters['timeout'] = 86400 # 24 hours else: # Expire session when browser closed. web.config.session_parameters['timeout'] = 600 # 10 minutes web.logger( msg="Login success", event='login', ) # Save selected language selected_language = str(i.get('lang', '')).strip() if selected_language != web.ctx.lang and \ selected_language in languages.get_language_maps(): session['lang'] = selected_language raise web.seeother('/dashboard/checknew') else: session['failed_times'] += 1 web.logger( msg="Login failed.", admin=username, event='login', loglevel='error', ) raise web.seeother('/login?msg=%s' % qr_admin_auth[1])
def _open(self): """ We can only intialize a single host. In this case, we iterate through a list of hosts until we get one that works and then use that to set our LDAP handle. SASL GSSAPI bind only succeeds when DNS reverse lookup zone is correctly populated. Fall through to simple bind if this fails. """ res = None if self._isopen: return True if self.hosts: saved_simple_error = None saved_gssapi_error = None for server in self.hosts: try: self._handle = pyldap.initialize(server) except Exception as e: self.logger.debug( f'Failed to initialize ldap connection to [{server}]: ({e}). Moving to next server.' ) continue res = None pyldap.protocol_version = pyldap.VERSION3 pyldap.set_option(pyldap.OPT_REFERRALS, 0) pyldap.set_option(pyldap.OPT_NETWORK_TIMEOUT, self.ldap['dns_timeout']) if SSL(self.ldap['ssl']) != SSL.NOSSL: if self.ldap['certificate']: pyldap.set_option( pyldap.OPT_X_TLS_CERTFILE, f"/etc/certificates/{self.ldap['cert_name']}.crt") pyldap.set_option( pyldap.OPT_X_TLS_KEYFILE, f"/etc/certificates/{self.ldap['cert_name']}.key") pyldap.set_option(pyldap.OPT_X_TLS_CACERTFILE, '/etc/ssl/truenas_cacerts.pem') if self.ldap['validate_certificates']: pyldap.set_option(pyldap.OPT_X_TLS_REQUIRE_CERT, pyldap.OPT_X_TLS_DEMAND) else: pyldap.set_option(pyldap.OPT_X_TLS_REQUIRE_CERT, pyldap.OPT_X_TLS_ALLOW) try: pyldap.set_option(pyldap.OPT_X_TLS_NEWCTX, 0) except Exception: self.logger.warning( 'Failed to initialize new TLS context.', exc_info=True) if SSL(self.ldap['ssl']) == SSL.USESTARTTLS: try: self._handle.start_tls_s() except pyldap.LDAPError as e: self.logger.debug( 'Encountered error initializing start_tls: %s', e) saved_simple_error = e continue if self.ldap['anonbind']: try: res = self._handle.simple_bind_s() break except Exception as e: saved_simple_error = e self.logger.debug('Anonymous bind failed: %s' % e) continue if self.ldap['certificate']: try: res = self._handle.sasl_non_interactive_bind_s( 'EXTERNAL') if self.ad['verbose_logging']: self.logger.debug( 'Successfully bound to [%s] using client certificate.', server) break except Exception as e: saved_simple_error = e self.logger.debug('SASL EXTERNAL bind failed.', exc_info=True) continue if self.ldap['kerberos_principal']: try: self._handle.set_option(pyldap.OPT_X_SASL_NOCANON, 1) self._handle.sasl_gssapi_bind_s() res = True break except Exception as e: saved_gssapi_error = e self.logger.debug( f'SASL GSSAPI bind failed: {e}. Attempting simple bind' ) try: res = self._handle.simple_bind_s(self.ldap['binddn'], self.ldap['bindpw']) break except Exception as e: self.logger.debug( f'Failed to bind to [{server}] using [{self.ldap["binddn"]}]: {e}' ) saved_simple_error = e continue if res: self._isopen = True elif saved_gssapi_error: self._convert_exception(saved_gssapi_error) elif saved_simple_error: self._convert_exception(saved_simple_error) return (self._isopen is True)
def get_user_info(self, username, password): """ get user info from ADS to a dictionary """ try: userInfo = { 'username' : username, 'password' : password, } # prepare LDAP connection ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,settings.AD_CERT_FILE) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_NEVER) #This required to avoid CN mismatches ldap.set_option(ldap.OPT_REFERRALS,0) # DO NOT TURN THIS OFF OR SEARCH WON'T WORK! # initialize self.debug_write('ldap.initialize...') l = ldap.initialize(settings.AD_LDAP_URL) l.set_option(ldap.OPT_PROTOCOL_VERSION, 3) # bind binddn = "%s@%s" % (username,settings.AD_NT4_DOMAIN) self.debug_write('ldap.bind %s' % binddn) l.bind_s(binddn,password) # search self.debug_write('search...') result = l.search_ext_s(settings.AD_SEARCH_DN,ldap.SCOPE_SUBTREE,"sAMAccountName=%s" % username,settings.AD_SEARCH_FIELDS)[0][1] self.debug_write("results in %s" % result) # Validate that they are a member of review board group if result.has_key('memberOf'): membership = result['memberOf'] else: self.debug_write('AD user has no group memberships') return None # user ADS Groups isAdmin, isValid, idGroup = self.check_group(membership) if not isValid: return None userInfo['isAdmin'] = isAdmin userInfo['idGroup'] = idGroup self.debug_write(idGroup) # get user info from ADS # get email if result.has_key('mail'): mail = result['mail'][0] else: mail = "" userInfo['mail'] = mail self.debug_write("mail=%s" % mail) # get surname if result.has_key('sn'): last_name = result['sn'][0] else: last_name = None userInfo['last_name'] = last_name self.debug_write("last_name=%s" % last_name) # get display name if result.has_key('givenName'): first_name = result['givenName'][0] else: first_name = None userInfo['first_name'] = first_name self.debug_write("first_name=%s" % first_name) # LDAP unbind l.unbind_s() return userInfo except Exception, e: self.debug_write("exception caught!") self.debug_write(e) return None
query = Q_GET_BORRABLES + ' AND ' + Q_BETWEEN_DATES if DEBUG: print "get_list_by_date Query:", query cursor.execute(query) userList = cursor.fetchall() return userList def testPyad(): rows = getListByDate('2008-02-01') for usuario in rows: user = pyad.from_cn(usuario) print type(user) print user raw_input("Pulse para continuar ...") print len(rows) try: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, 0) lcon = ldap.initialize(LDAP_SERVER) lcon.simple_bind_s(BIND_DN, BIND_PASS) except ldap.LDAPError, e: print e user = lcon.search_s(USER_BASE, ldap.SCOPE_SUBTREE, "cn=i02s*") for dn, entry in user: print 'Processing', repr(dn) print entry #handle_ldap_entry(entry)
import time import ldap import ldap.modlist as modlist import secrets import base64 from flask import abort HTTP_NOTFOUND = 404 #BASE_MEMBERS = 'OU=Test,OU=GroupsOU,DC=ps,DC=protospace,DC=ca' # testing BASE_MEMBERS = 'OU=MembersOU,DC=ps,DC=protospace,DC=ca' # prod ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, './ProtospaceAD.cer') def init_ldap(): ldap_conn = ldap.initialize('ldaps://ldap.ps.protospace.ca:636') ldap_conn.set_option(ldap.OPT_REFERRALS, 0) ldap_conn.set_option(ldap.OPT_PROTOCOL_VERSION, 3) ldap_conn.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND) ldap_conn.set_option(ldap.OPT_X_TLS_DEMAND, True) ldap_conn.set_option(ldap.OPT_DEBUG_LEVEL, 255) return ldap_conn def find_user(username): ''' Search for a user by sAMAccountname '''