def cb_(result): if result: return pureldap.LDAPExtendedResponse( resultCode=ldaperrors.Success.resultCode, responseName=self.extendedRequest_LDAPPasswordModifyRequest.oid) else: raise ldaperrors.LDAPOperationsError('Internal error.')
def handleUnknown(self, request, controls, callback): log.msg('Unknown request: %r' % request) msg = pureldap.LDAPExtendedResponse( resultCode=ldaperrors.LDAPProtocolError.resultCode, responseName='1.3.6.1.4.1.1466.20036', errorMessage='Unknown request') return msg
def handle_LDAPExtendedRequest( self, request: LDAPExtendedRequest, controls: pureldap.LDAPControl, reply_fn: Callable[..., None], ) -> Any: # Handle STARTTLS locally; proxy everything else. if request.requestName != pureldap.LDAPStartTLSRequest.oid: return self.handleUnknown(request, controls, reply_fn) if not self.sslctx: raise ldaperrors.LDAPProtocolError( STARTTLS_NOT_SUPPORTED_ERROR_MESSAGE) self.checkControls(controls) # assert can ignore controls, then do so try: # Send reply indicating TLS negotiation should start. msg = pureldap.LDAPExtendedResponse( resultCode=ldaperrors.Success.resultCode, responseName=pureldap.LDAPStartTLSRequest.oid, ) reply_fn(msg) # Start TLS negotiation! self.transport.startTLS(self.sslctx, self.factory) except ldaperrors.LDAPException: raise except Exception: raise ldaperrors.LDAPUnwillingToPerform()
def eb(fail, oid): fail.trap(ldaperrors.LDAPException) return pureldap.LDAPExtendedResponse( resultCode=fail.value.resultCode, errorMessage=fail.value.message, responseName=oid, )
def test_extendedRequest_unknown(self): self.server.dataReceived( pureldap.LDAPMessage(pureldap.LDAPExtendedRequest( requestName='42.42.42', requestValue='foo'), id=2).toWire()) self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage(pureldap.LDAPExtendedResponse( resultCode=ldaperrors.LDAPProtocolError.resultCode, errorMessage='Unknown extended request: 42.42.42'), id=2).toWire())
def test_passwordModify_notBound(self): self.server.dataReceived( pureldap.LDAPMessage(pureldap.LDAPPasswordModifyRequest( userIdentity='cn=thingie,ou=stuff,dc=example,dc=com', newPasswd='hushhush'), id=2).toWire()) self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage(pureldap.LDAPExtendedResponse( resultCode=ldaperrors.LDAPStrongAuthRequired.resultCode, responseName=pureldap.LDAPPasswordModifyRequest.oid), id=2).toWire())
def test_passwordModify_someoneElse(self): commits = observeCommits(self.thingie) # first bind to some entry userPassword = b"{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8=" # secret self.thingie["userPassword"] = [userPassword] self.server.dataReceived( pureldap.LDAPMessage( pureldap.LDAPBindRequest( dn="cn=thingie,ou=stuff,dc=example,dc=com", auth=b"secret"), id=4, ).toWire()) self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage( pureldap.LDAPBindResponse( resultCode=0, matchedDN="cn=thingie,ou=stuff,dc=example,dc=com"), id=4, ).toWire(), ) self.server.transport.clear() observer = testing.EventLoggingObserver.createWithCleanup(self, log) self.server.dataReceived( pureldap.LDAPMessage( pureldap.LDAPPasswordModifyRequest( userIdentity="cn=another,ou=stuff,dc=example,dc=com", newPasswd="hushhush", ), id=2, ).toWire()) self.assertEqual( observer[0]["log_text"], "User cn=thingie,ou=stuff,dc=example,dc=com " "tried to change password of " "b'cn=another,ou=stuff,dc=example,dc=com'", ) self.assertListEqual(commits, [], "Server committed data.") self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage( pureldap.LDAPExtendedResponse( resultCode=ldaperrors.LDAPInsufficientAccessRights. resultCode, responseName=pureldap.LDAPPasswordModifyRequest.oid, ), id=2, ).toWire(), ) self.assertSequenceEqual( self.thingie.get("userPassword", []), [userPassword], )
def extendedRequest_LDAPPasswordModifyRequest(self, data, reply): if not isinstance(data, pureber.BERSequence): raise ldaperrors.LDAPProtocolError('Extended request PasswordModify expected a BERSequence.') userIdentity = None oldPasswd = None newPasswd = None for value in data: if isinstance(value, pureldap.LDAPPasswordModifyRequest_userIdentity): if userIdentity is not None: raise ldaperrors.LDAPProtocolError( 'Extended request PasswordModify received userIdentity twice.') userIdentity = value.value elif isinstance(value, pureldap.LDAPPasswordModifyRequest_oldPasswd): if oldPasswd is not None: raise ldaperrors.LDAPProtocolError('Extended request PasswordModify received oldPasswd twice.') oldPasswd = value.value elif isinstance(value, pureldap.LDAPPasswordModifyRequest_newPasswd): if newPasswd is not None: raise ldaperrors.LDAPProtocolError('Extended request PasswordModify received newPasswd twice.') newPasswd = value.value else: raise ldaperrors.LDAPProtocolError('Extended request PasswordModify received unexpected item.') if self.boundUser is None: raise ldaperrors.LDAPStrongAuthRequired() if (userIdentity is not None and userIdentity != self.boundUser.dn): #TODO this hardcodes ACL log.msg('User %(actor)s tried to change password of %(target)s' % { 'actor': str(self.boundUser.dn), 'target': str(userIdentity), }) raise ldaperrors.LDAPInsufficientAccessRights() if (oldPasswd is not None or newPasswd is None): raise ldaperrors.LDAPOperationsError('Password does not support this case.') self.boundUser.setPassword(newPasswd) return pureldap.LDAPExtendedResponse(resultCode=ldaperrors.Success.resultCode, responseName=self.extendedRequest_LDAPPasswordModifyRequest.oid) # TODO if userIdentity is None: userIdentity = str(self.boundUser.dn) raise NotImplementedError('VALUE %r' % value)
def test_passwordModify_simple(self): data = {'committed': False} def onCommit_(result, info): info['committed'] = result return result wrapCommit(self.thingie, onCommit_, data) # first bind to some entry self.thingie['userPassword'] = ['{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8='] # "secret" self.server.dataReceived( pureldap.LDAPMessage( pureldap.LDAPBindRequest( dn='cn=thingie,ou=stuff,dc=example,dc=com', auth=b'secret'), id=4).toWire()) self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage( pureldap.LDAPBindResponse( resultCode=0, matchedDN='cn=thingie,ou=stuff,dc=example,dc=com'), id=4).toWire()) self.server.transport.clear() self.server.dataReceived( pureldap.LDAPMessage( pureldap.LDAPPasswordModifyRequest( userIdentity='cn=thingie,ou=stuff,dc=example,dc=com', newPasswd='hushhush'), id=2).toWire()) self.assertEqual(data['committed'], True, "Server never committed data.") self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage( pureldap.LDAPExtendedResponse( resultCode=ldaperrors.Success.resultCode, responseName=pureldap.LDAPPasswordModifyRequest.oid), id=2).toWire()) # tree changed secrets = self.thingie.get('userPassword', []) self.assertEqual(len(secrets), 1) for secret in secrets: self.assertEqual(secret[:len(b'{SSHA}')], b'{SSHA}') # DUO EDIT @mbishop # Nominal change to remove deprecation warning # raw = base64.decodestring(secret[len(b'{SSHA}'):]) raw = base64.decodebytes(secret[len(b'{SSHA}'):]) # END EDIT salt = raw[20:] self.assertEqual(entry.sshaDigest(b'hushhush', salt), secret)
def test_passwordModify_simple(self): commits = observeCommits(self.thingie) # first bind to some entry self.thingie["userPassword"] = [ "{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8=" ] # "secret" self.server.dataReceived( pureldap.LDAPMessage( pureldap.LDAPBindRequest( dn="cn=thingie,ou=stuff,dc=example,dc=com", auth=b"secret"), id=4, ).toWire()) self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage( pureldap.LDAPBindResponse( resultCode=0, matchedDN="cn=thingie,ou=stuff,dc=example,dc=com"), id=4, ).toWire(), ) self.server.transport.clear() self.server.dataReceived( pureldap.LDAPMessage( pureldap.LDAPPasswordModifyRequest( userIdentity="cn=thingie,ou=stuff,dc=example,dc=com", newPasswd="hushhush", ), id=2, ).toWire()) self.assertListEqual(commits, [True], "Server never committed data.") self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage( pureldap.LDAPExtendedResponse( resultCode=ldaperrors.Success.resultCode, responseName=pureldap.LDAPPasswordModifyRequest.oid, ), id=2, ).toWire(), ) # tree changed secrets = self.thingie.get("userPassword", []) self.assertEqual(len(secrets), 1) for secret in secrets: self.assertEqual(secret[:len(b"{SSHA}")], b"{SSHA}") raw = base64.decodebytes(secret[len(b"{SSHA}"):]) salt = raw[20:] self.assertEqual(entry.sshaDigest(b"hushhush", salt), secret)
def test_unknownRequest(self): # make server miss one of the handle_* attributes # without having to modify the LDAPServer class class MockServer(ldapserver.LDAPServer): handle_LDAPBindRequest = property() self.server.__class__ = MockServer self.server.dataReceived( pureldap.LDAPMessage(pureldap.LDAPBindRequest(), id=2).toWire()) self.assertEqual( self.server.transport.value(), pureldap.LDAPMessage(pureldap.LDAPExtendedResponse( resultCode=ldaperrors.LDAPProtocolError.resultCode, responseName='1.3.6.1.4.1.1466.20036', errorMessage='Unknown request'), id=2).toWire())
def test_passwordModify_simple(self): # first bind to some entry self.thingie['userPassword'] = [ '{SSHA}yVLLj62rFf3kDAbzwEU0zYAVvbWrze8=' ] # "secret" self.server.dataReceived( str( pureldap.LDAPMessage(pureldap.LDAPBindRequest( dn='cn=thingie,ou=stuff,dc=example,dc=com', auth='secret'), id=4))) self.assertEquals( self.server.transport.value(), str( pureldap.LDAPMessage(pureldap.LDAPBindResponse( resultCode=0, matchedDN='cn=thingie,ou=stuff,dc=example,dc=com'), id=4))) self.server.transport.clear() self.server.dataReceived( str( pureldap.LDAPMessage(pureldap.LDAPPasswordModifyRequest( userIdentity='cn=thingie,ou=stuff,dc=example,dc=com', newPasswd='hushhush'), id=2))) self.assertEquals( self.server.transport.value(), str( pureldap.LDAPMessage(pureldap.LDAPExtendedResponse( resultCode=ldaperrors.Success.resultCode, responseName=pureldap.LDAPPasswordModifyRequest.oid), id=2)), ) # tree changed secrets = self.thingie.get('userPassword', []) self.assertEquals(len(secrets), 1) for secret in secrets: self.assertEquals(secret[:len('{SSHA}')], '{SSHA}') raw = base64.decodestring(secret[len('{SSHA}'):]) salt = raw[20:] self.assertEquals(entry.sshaDigest('hushhush', salt), secret)
def failDefault(self, resultCode, errorMessage): return pureldap.LDAPExtendedResponse( resultCode=resultCode, responseName='1.3.6.1.4.1.1466.20036', errorMessage=errorMessage)