def _cbDeleteDone(self, msg): assert isinstance(msg, pureldap.LDAPResult) if not isinstance(msg, pureldap.LDAPDelResponse): raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.matchedDN == "" return self
def _cbDeleteDone(self, msg): assert isinstance(msg, pureldap.LDAPResult) if not isinstance(msg, pureldap.LDAPDelResponse): raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self._assertMatchedDN(msg.matchedDN) return self
def perform_bind_ntlm( client, username, password, domain, workstation, ntlm_version, peercert: X509 = None, ): """ Perform bind using custom NTLM mechanism. Will return different value based on ntlm_version. NTLMv2 using session key for future sign and seal. We do not support NTLMv1 with sign and seal on purpose. :returns NTLMv1 : None NTLMv2 : session key for sign and seal """ sign_seal_enable = client._ntlm_sign_seal_enable(ntlm_version) ntlm_negotiate_msg = ntlm.create_negotiate_msg( sign_seal=sign_seal_enable) op = pureldap.LDAPBindRequest(auth=("GSS-SPNEGO", ntlm_negotiate_msg), sasl=True) response = yield client.send(op) if response.resultCode != ldaperrors.LDAPSaslBindInProgress.resultCode: raise ldaperrors.get(response.resultCode, response.errorMessage) ntlm_challenge_msg = response.serverSaslCreds.value ntlm_authenticate = ntlm.create_ntlm_auth( ntlm_negotiate_msg, ntlm_challenge_msg, username, password, domain, workstation, ntlm_version, sign_seal=sign_seal_enable, peercert=peercert, ) op = pureldap.LDAPBindRequest( auth=("GSS-SPNEGO", ntlm_authenticate.get_encoded_msg()), sasl=True) response = yield client.send(op) if response.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(response.resultCode, response.errorMessage) if ntlm_version == 2 and isinstance(ntlm_authenticate, ntlm.NTLMv2Auth): defer.returnValue(ntlm_authenticate.session_key)
def _cbSearchMsg(self, msg, controls, d, callback, complete, sizeLimitIsNonFatal): if isinstance(msg, pureldap.LDAPSearchResultDone): assert msg.referral is None # TODO e = ldaperrors.get(msg.resultCode, msg.errorMessage) if not isinstance(e, ldaperrors.Success): try: raise e except ldaperrors.LDAPSizeLimitExceeded: if sizeLimitIsNonFatal: pass except Exception: d.errback(Failure()) return True # search ended successfully self._assertMatchedDN(msg.matchedDN) d.callback(controls) return True elif isinstance(msg, pureldap.LDAPSearchResultEntry): self._cbSearchEntry(callback, msg.objectName, msg.attributes, complete=complete) return False elif isinstance(msg, pureldap.LDAPSearchResultReference): return False else: raise ldaperrors.LDAPProtocolError("bad search response: %r" % msg)
def test_get_existing_exception(self): """Getting existing LDAPException subclass""" exception = ldaperrors.get(49, 'Error message') self.assertEqual(exception.__class__, ldaperrors.LDAPInvalidCredentials) self.assertEqual(exception.resultCode, 49) self.assertEqual(exception.name, b'invalidCredentials') self.assertEqual(exception.message, 'Error message')
def _cbSetPassword_ExtendedOperation(self, msg): assert isinstance(msg, pureldap.LDAPExtendedResponse) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self._assertMatchedDN(msg.matchedDN) return self
def _cbSetPassword_ExtendedOperation(self, msg): assert isinstance(msg, pureldap.LDAPExtendedResponse) assert msg.referral is None #TODO if msg.resultCode!=ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.matchedDN=='' return self
def _cbStartTLS(self, msg, ctx): assert isinstance(msg, pureldap.LDAPExtendedResponse) assert msg.referral is None #TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self.transport.startTLS(ctx) return self
def test_get_existing_exception(self): """Getting existing LDAPException subclass""" exception = ldaperrors.get(49, "Error message") self.assertEqual(exception.__class__, ldaperrors.LDAPInvalidCredentials) self.assertEqual(exception.resultCode, 49) self.assertEqual(exception.name, b"invalidCredentials") self.assertEqual(exception.message, "Error message")
def _cbStartTLS(self, msg, ctx): assert isinstance(msg, pureldap.LDAPExtendedResponse) assert msg.referral is None #TODO if msg.resultCode!=ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self.transport.startTLS(ctx) return self
def _cbMoveDone(self, msg, newDN): assert isinstance(msg, pureldap.LDAPModifyDNResponse) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self._assertMatchedDN(msg.matchedDN) self.dn = newDN return self
def _cbAddDone(self, msg, dn): assert isinstance(msg, pureldap.LDAPAddResponse), "LDAPRequest response was not an LDAPAddResponse: %r" % msg assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.matchedDN == "" e = self.__class__(dn=dn, client=self.client) return e
def _cbMoveDone(self, msg, newDN): assert isinstance(msg, pureldap.LDAPModifyDNResponse) assert msg.referral is None #TODO if msg.resultCode!=ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.matchedDN=='' self.dn = newDN return self
def _cbAddDone(self, msg, dn): assert isinstance(msg, pureldap.LDAPAddResponse), \ "LDAPRequest response was not an LDAPAddResponse: %r" % msg assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self._assertMatchedDN(msg.matchedDN) e = self.__class__(dn=dn, client=self.client) return e
def _commit_success(self, msg): assert isinstance(msg, pureldap.LDAPModifyResponse) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) self._assertMatchedDN(msg.matchedDN) self._remoteData = entry.EditableLDAPEntry(self.dn, self) self._journal = [] return self
def _commit_success(self, msg): assert isinstance(msg, pureldap.LDAPModifyResponse) assert msg.referral is None #TODO if msg.resultCode!=ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) assert msg.matchedDN=='' self._remoteData = entry.EditableLDAPEntry(self.dn, self) self._journal=[] return self
def _cbSearchMsg(self, msg, d, callback, complete, sizeLimitIsNonFatal): if isinstance(msg, pureldap.LDAPSearchResultDone): assert msg.referral is None #TODO e = ldaperrors.get(msg.resultCode, msg.errorMessage) if not isinstance(e, ldaperrors.Success): try: raise e except ldaperrors.LDAPSizeLimitExceeded, e: if sizeLimitIsNonFatal: pass except: d.errback(Failure())
def _cbStartTLS(self, msg, ctx): assert isinstance(msg, pureldap.LDAPExtendedResponse) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) if (msg.responseName is not None) and \ (msg.responseName != pureldap.LDAPStartTLSResponse.oid): raise LDAPStartTLSInvalidResponseName(msg.responseName) self.transport.startTLS(ctx) return self
def perform_bind_ntlm(self, dn, username, password, domain, workstation, ntlm_version): ntlm_negotiate_msg = ntlm.create_negotiate_msg() op = pureldap.LDAPBindRequest(dn=dn, auth=('GSS-SPNEGO', ntlm_negotiate_msg), sasl=True) response = yield self.send(op) if response.resultCode != ldaperrors.LDAPSaslBindInProgress.resultCode: raise ldaperrors.get(response.resultCode, response.errorMessage) ntlm_challenge_msg = response.serverSaslCreds.value ntlm_authenticate_msg = ntlm.create_authenticate_msg( ntlm_negotiate_msg, ntlm_challenge_msg, username, password, domain, workstation, ntlm_version) op = pureldap.LDAPBindRequest(dn=dn, auth=('GSS-SPNEGO', ntlm_authenticate_msg), sasl=True) response = yield self.send(op) if response.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(response.resultCode, response.errorMessage)
def _send_sspi_bind(self, current_buffer): # format request and send it op = pureldap.LDAPBindRequest( auth=("GSS-SPNEGO", current_buffer[0].Buffer), sasl="True", ) response = yield self.send(op) # If we got something other than a success or challenge back from # the bind, an LDAP error occurred. Halt immediately. if response.resultCode not in [ ldaperrors.Success.resultCode, ldaperrors.LDAPSaslBindInProgress.resultCode, ]: raise ldaperrors.get(response.resultCode, response.errorMessage) return response
def handle_msg(value, controls, d): try: if isinstance(value, pureldap.LDAPSearchResultDone): e = ldaperrors.get(value.resultCode, value.errorMessage) if isinstance(e, (ldaperrors.Success, ldaperrors.LDAPSizeLimitExceeded)): cookie = get_cookie(controls) d.callback((None, cookie)) else: d.callback((e, None)) elif isinstance(value, pureldap.LDAPSearchResultEntry): # Always send DN. Overwrite DN from attribute set, if any. obj = { "distinguishedname": [escape_bytes(value.objectName)] } for k, vs in value.attributes: # Smash attribute name case. k = k.decode().lower() # Server may not honor attributes (e.g. # SearchByTreeWalkingMixin). if attributes and k.encode() not in attributes: continue # Covert value to list and encode for JSON. vs = [escape_bytes(v) for v in vs] obj[k] = vs # Refuse to return certain attributes even if all # attributes were requested. obj.pop("userpassword", None) res.append(obj) except Exception: log.failure("Unexpected error handling message") finally: return isinstance(value, ( pureldap.LDAPBindResponse, pureldap.LDAPSearchResultDone, ))
def perform_bind_plain(self, dn, password): op = pureldap.LDAPBindRequest(dn=dn, auth=password, sasl=False) response = yield self.send(op) if response.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(response.resultCode, response.errorMessage)
def test_get_success(self): """Getting OK message""" success = ldaperrors.get(0, 'Some message') self.assertEqual(success.__class__, ldaperrors.Success) self.assertEqual(success.resultCode, 0) self.assertEqual(success.name, b'success')
def _handle_bind_msg(self, msg): assert isinstance(msg, pureldap.LDAPBindResponse) assert msg.referral is None # TODO if msg.resultCode != ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) return self
def test_get_nonexisting_exception(self): """Getting non-existing LDAP error""" exception = ldaperrors.get(55, "Error message") self.assertEqual(exception.__class__, ldaperrors.LDAPUnknownError) self.assertEqual(exception.code, 55) self.assertEqual(exception.message, "Error message")
def test_get_nonexisting_exception(self): """Getting non-existing LDAP error""" exception = ldaperrors.get(55, 'Error message') self.assertEqual(exception.__class__, ldaperrors.LDAPUnknownError) self.assertEqual(exception.code, 55) self.assertEqual(exception.message, 'Error message')
def test_get_success(self): """Getting OK message""" success = ldaperrors.get(0, "Some message") self.assertEqual(success.__class__, ldaperrors.Success) self.assertEqual(success.resultCode, 0) self.assertEqual(success.name, b"success")
def _handle_bind_msg(self, msg): assert isinstance(msg, pureldap.LDAPBindResponse) assert msg.referral is None #TODO if msg.resultCode!=ldaperrors.Success.resultCode: raise ldaperrors.get(msg.resultCode, msg.errorMessage) return self
def perform_bind_sspi(self, dn: str, username: str, password: str, domain: str, permit_implicit: bool, targetspn=None): """Perform bind using native windows SSPI mechanism. If no username, password, or domain is provided, then we'll attempt to use the authproxy's existing process credentials to perform the bind. If targetspn is provided (and valid), then theoretically we might use kerberos instead of NTLM Returns: No return value from this function. Finishing without raising an exception means the bind succeeded Raises: LDAPUnwillingToPerform: If SSPI auth is not supported SSPIError: If the SSPI negotiation fails """ if sspi is None: msg = 'The SSPI bind type is only supported on Windows.' log.err(msg) raise ldaperrors.LDAPUnwillingToPerform(msg) auth_info: Optional[Tuple[str, str, str]] = (username, domain, password) # omitting 'domain' from this if statement; that way we can # specify ntlm_domain in config and have it apply to user # auth, but not automatically trip us into using configured, # rather than implicit, service account creds if not (username or password): if permit_implicit: auth_info = None else: # even passing a tuple of empty values still appears # to trigger the implicit-auth mechanism, so we need # to be explicit msg = 'Implicit authentication forbidden for this request.' log.err(msg) raise ldaperrors.LDAPUnwillingToPerform(msg) # SSPI negotiation can request some application-level # encryption/authentication, but AD apparently throws a fit if # you leave this on when using SSL/TLS (and expects you to # actually somehow sign all your LDAP requests otherwise) scflags = ISC_REQ_NO_INTEGRITY # these return codes mean we need to continue the handshake sspi_continue = set([ sspicon.SEC_I_CONTINUE_NEEDED, sspicon.SEC_I_COMPLETE_AND_CONTINUE ]) # any return code not in this set should be considered an error sspi_ok = sspi_continue.union( [sspicon.SEC_E_OK, sspicon.SEC_I_COMPLETE_NEEDED]) ca = self._create_sspi_authenticator(auth_info, targetspn, scflags) data = None # This negotiation is made up of challenge and response messages. # We will continue responding to challenges until a success or # failure case is hit while True: # get the next step in the handshake err, out_buf = ca.authorize(data) if err not in sspi_ok: raise SSPIError('SSPI negotiation failed', err) response = yield self._send_sspi_bind(dn, out_buf) if response.resultCode == ldaperrors.LDAPSaslBindInProgress.resultCode: data = self._recalculate_buffer_data(ca, response) elif response.resultCode == ldaperrors.Success.resultCode: break else: raise ldaperrors.get(response.resultCode, response.errorMessage) # if SSPI said we're done, but ldap response doesn't # agree, that's weird if err not in sspi_continue: raise SSPIError('SSPI negotiation should\'ve finished by now', err)