Exemple #1
0
class BaseLDAPServer(protocol.Protocol):
    debug = False

    def __init__(self):
        self.buffer = ''
        self.connected = None

    berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
        inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
            fallback=pureldap.LDAPBERDecoderContext(
                fallback=pureber.BERDecoderContext()),
            inherit=pureldap.LDAPBERDecoderContext(
                fallback=pureber.BERDecoderContext())))

    def dataReceived(self, recd):
        self.buffer += recd
        while 1:
            try:
                o, bytes = pureber.berDecodeObject(self.berdecoder,
                                                   self.buffer)
            except pureber.BERExceptionInsufficientData:
                o, bytes = None, 0
            self.buffer = self.buffer[bytes:]
            if o is None:
                break
            self.handle(o)

    def connectionMade(self):
        """TCP connection has opened"""
        self.connected = 1

    def connectionLost(self, reason=protocol.connectionDone):
        """Called when TCP connection has been lost"""
        self.connected = 0

    def queue(self, id, op):
        if not self.connected:
            raise LDAPServerConnectionLostException()
        msg = pureldap.LDAPMessage(op, id=id)
        if self.debug:
            log.msg('S->C %s' % repr(msg), debug=True)
        self.transport.write(str(msg))

    def unsolicitedNotification(self, msg):
        log.msg("Got unsolicited notification: %s" % repr(msg))

    def checkControls(self, controls):
        if controls is not None:
            for controlType, criticality, controlValue in controls:
                if criticality:
                    raise ldaperrors.LDAPUnavailableCriticalExtension(
                        'Unknown control %s' % controlType)

    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 _cbLDAPError(self, reason, name):
        reason.trap(ldaperrors.LDAPException)
        return self._callErrorHandler(name=name,
                                      resultCode=reason.value.resultCode,
                                      errorMessage=reason.value.message)

    def _cbHandle(self, response, id):
        if response is not None:
            self.queue(id, response)

    def failDefault(self, resultCode, errorMessage):
        return pureldap.LDAPExtendedResponse(
            resultCode=resultCode,
            responseName='1.3.6.1.4.1.1466.20036',
            errorMessage=errorMessage)

    def _callErrorHandler(self, name, resultCode, errorMessage):
        errh = getattr(self, 'fail_' + name, self.failDefault)
        return errh(resultCode=resultCode, errorMessage=errorMessage)

    def _cbOtherError(self, reason, name):
        return self._callErrorHandler(
            name=name,
            resultCode=ldaperrors.LDAPProtocolError.resultCode,
            errorMessage=reason.getErrorMessage())

    def handle(self, msg):
        assert isinstance(msg.value, pureldap.LDAPProtocolRequest)
        if self.debug:
            log.msg('S<-C %s' % repr(msg), debug=True)

        if msg.id == 0:
            self.unsolicitedNotification(msg.value)
        else:
            name = msg.value.__class__.__name__
            handler = getattr(self, 'handle_' + name, self.handleUnknown)
            d = defer.maybeDeferred(
                handler, msg.value, msg.controls,
                lambda response: self._cbHandle(response, msg.id))
            d.addErrback(self._cbLDAPError, name)
            d.addErrback(defer.logError)
            d.addErrback(self._cbOtherError, name)
            d.addCallback(self._cbHandle, msg.id)
class KnownValues(unittest.TestCase):
    knownValues=( # class, args, kwargs, expected_result

        (pureldap.LDAPModifyRequest,
         [],
         { "object": 'cn=foo, dc=example, dc=com',
           "modification": [
                      pureber.BERSequence([
                        pureber.BEREnumerated(0),
                        pureber.BERSequence([
                          pureldap.LDAPAttributeDescription('bar'),
                          pureber.BERSet([
                            pureldap.LDAPString('a'),
                            pureldap.LDAPString('b'),
                            ]),
                          ]),
                        ]),
                      ],
           },
         None,
         [0x66, 50]
         + ([0x04, 0x1a] + l(b"cn=foo, dc=example, dc=com")
            + [0x30, 20]
            + ([0x30, 18]
               + ([0x0a, 0x01, 0x00]
                  + [0x30, 13]
                  + ([0x04, len(b"bar")] + l(b"bar")
                     + [0x31, 0x06]
                     + ([0x04, len(b"a")] + l(b"a")
                        + [0x04, len(b"b")] + l(b"b"))))))
            ),

        (pureldap.LDAPModifyRequest,
         [],
         { "object": 'cn=foo, dc=example, dc=com',
           "modification": [
                      pureber.BERSequence([
                        pureber.BEREnumerated(1),
                        pureber.BERSequence([
                          pureber.BEROctetString('bar'),
                          pureber.BERSet([]),
                          ]),
                        ]),
                      ],
           },
         None,
         [0x66, 0x2c]
         + ([0x04, 0x1a] + l(b"cn=foo, dc=example, dc=com")
            + [0x30, 0x0e]
            + ([0x30, 0x0c]
               + ([0x0a, 0x01, 0x01]
                  + [0x30, 0x07]
                  + ([0x04, 0x03] + l(b"bar")
                     + [0x31, 0x00]))))
        ),

        (pureldap.LDAPFilter_not,
         [],
         { "value": pureldap.LDAPFilter_present("foo"),
           },
         pureldap.LDAPBERDecoderContext_Filter(fallback=pureber.BERDecoderContext()),
         [0xa2, 0x05]
         + [0x87]
         + [len(b"foo")]
         + l(b"foo")),

        (pureldap.LDAPFilter_or,
         [],
         { "value": [pureldap.LDAPFilter_equalityMatch(
        attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
        assertionValue=pureldap.LDAPAssertionValue(value='foo')),
                     pureldap.LDAPFilter_equalityMatch(
        attributeDesc=pureldap.LDAPAttributeDescription(value='uid'),
        assertionValue=pureldap.LDAPAssertionValue(value='foo')),
                     ]
           },
         pureldap.LDAPBERDecoderContext_Filter(fallback=pureber.BERDecoderContext()),
         [0xa1, 23]
         + [0xa3, 9]
         + [0x04] + [len(b"cn")] + l(b"cn")
         + [0x04] + [len(b"foo")] + l(b"foo")
         + [0xa3, 10]
         + [0x04] + [len(b"uid")] + l(b"uid")
         + [0x04] + [len(b"foo")] + l(b"foo"),
         ),

        (pureldap.LDAPFilter_and,
         [],
         { "value": [pureldap.LDAPFilter_equalityMatch(
        attributeDesc=pureldap.LDAPAttributeDescription(value='cn'),
        assertionValue=pureldap.LDAPAssertionValue(value='foo')),
                     pureldap.LDAPFilter_equalityMatch(
        attributeDesc=pureldap.LDAPAttributeDescription(value='uid'),
        assertionValue=pureldap.LDAPAssertionValue(value='foo')),
                     ]
           },
         pureldap.LDAPBERDecoderContext_Filter(fallback=pureber.BERDecoderContext()),
         [0xa0, 23]
         + [0xa3, 9]
         + [0x04] + [len(b"cn")] + l(b"cn")
         + [0x04] + [len(b"foo")] + l(b"foo")
         + [0xa3, 10]
         + [0x04] + [len(b"uid")] + l(b"uid")
         + [0x04] + [len(b"foo")] + l(b"foo"),
         ),

        (pureldap.LDAPModifyDNRequest,
         [],
         {'entry': 'cn=foo,dc=example,dc=com',
          'newrdn': 'uid=bar',
          'deleteoldrdn': 0,
          },
         None,
         [0x6c, 0x26]
         + [0x04]
         + [len(b"cn=foo,dc=example,dc=com")]
         + l(b"cn=foo,dc=example,dc=com")
         + [0x04]
         + [len(b"uid=bar")]
         + l(b"uid=bar")
         + [0x01, 0x01, 0x00]),

        (pureldap.LDAPModifyDNRequest,
         [],
         {'entry': 'cn=aoue,dc=example,dc=com',
          'newrdn': 'uid=aoue',
          'deleteoldrdn': 0,
          'newSuperior': 'ou=People,dc=example,dc=com',
          },
         None,
         [0x6c, 69]
         + [0x04]
         + [len(b"cn=aoue,dc=example,dc=com")]
         + l(b"cn=aoue,dc=example,dc=com")
         + [0x04]
         + [len(b"uid=aoue")]
         + l(b"uid=aoue")
         + [0x01, 0x01, 0x00]
         + [0x80]
         + [len(b"ou=People,dc=example,dc=com")]
         + l(b"ou=People,dc=example,dc=com")),

        (pureldap.LDAPSearchRequest,
         [],
         {'baseObject': 'dc=yoja,dc=example,dc=com',
          },
         None,
         [0x63, 57]
         + [0x04]
         + [len(b'dc=yoja,dc=example,dc=com')]
         + l(b'dc=yoja,dc=example,dc=com')
         # scope
         + [0x0a, 1, 2]
         # derefAliases
         + [0x0a, 1, 0]
         # sizeLimit
         + [0x02, 1, 0]
         # timeLimit
         + [0x02, 1, 0]
         # typesOnly
         + [0x01, 1, 0]
         # filter
         + [135, 11] + l(b'objectClass')
         # attributes
         + [48, 0]
         ),

        (pureldap.LDAPUnbindRequest,
         [],
         {},
         None,
         [0x42, 0x00]
        ),

        (pureldap.LDAPSearchResultDone,
         [],
         {'resultCode': 0,
          },
         None,
         [0x65, 0x07]
         # resultCode
         + [0x0a, 0x01, 0x00]
         # matchedDN
         + [0x04]
         + [len(b'')]
         + l(b'')
         # errorMessage
         + [0x04]
         + [len(b'')]
         + l(b'')
         # referral, TODO
         + []
        ),

        (pureldap.LDAPSearchResultDone,
         [],
         {'resultCode': 0,
          'matchedDN': 'dc=foo,dc=example,dc=com',
          },
         None,
         [0x65, 31]
         # resultCode
         + [0x0a, 0x01, 0x00]
         # matchedDN
         + [0x04]
         + [len(b'dc=foo,dc=example,dc=com')]
         + l(b'dc=foo,dc=example,dc=com')
         # errorMessage
         + [0x04]
         + [len(b'')]
         + l(b'')
         # referral, TODO
         + []
        ),

        (pureldap.LDAPSearchResultDone,
         [],
         {'resultCode': 0,
          'matchedDN': 'dc=foo,dc=example,dc=com',
          'errorMessage': 'the foobar was fubar',
          },
         None,
         [0x65, 51]
         # resultCode
         + [0x0a, 0x01, 0x00]
         # matchedDN
         + [0x04]
         + [len(b'dc=foo,dc=example,dc=com')]
         + l(b'dc=foo,dc=example,dc=com')
         # errorMessage
         + [0x04]
         + [len(b'the foobar was fubar')]
         + l(b'the foobar was fubar',)
         # referral, TODO
         + []
        ),

        (pureldap.LDAPSearchResultDone,
         [],
         {'resultCode': 0,
          'errorMessage': 'the foobar was fubar',
          },
         None,
         [0x65, 27]
         # resultCode
         + [0x0a, 0x01, 0x00]
         # matchedDN
         + [0x04]
         + [len(b'')]
         + l(b'')
         # errorMessage
         + [0x04]
         + [len(b'the foobar was fubar')]
         + l(b'the foobar was fubar',)
         # referral, TODO
         + []
        ),

        (pureldap.LDAPMessage,
         [],
         {'id': 42,
          'value': pureldap.LDAPBindRequest(),
          },
         pureldap.LDAPBERDecoderContext_TopLevel(
        inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
        fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
        inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()))),
         [0x30, 12]
         # id
         + [0x02, 0x01, 42]
         # value
         + l(pureldap.LDAPBindRequest().toWire())
         ),

        (pureldap.LDAPControl,
         [],
         {'controlType': '1.2.3.4',
          },
         None,
         [0x30, 9]
         # controlType
         + [0x04, 7]
         + l(b"1.2.3.4")
         ),

        (pureldap.LDAPControl,
         [],
         {'controlType': '1.2.3.4',
          'criticality': True,
          },
         None,
         [0x30, 12]
         # controlType
         + [0x04, 7]
         + l(b"1.2.3.4")
         # criticality
         + [0x01, 1, 0xFF]
         ),

        (pureldap.LDAPControl,
         [],
         {'controlType': '1.2.3.4',
          'criticality': True,
          'controlValue': 'silly',
          },
         None,
         [0x30, 19]
         # controlType
         + [0x04, 7]
         + l(b"1.2.3.4")
         # criticality
         + [0x01, 1, 0xFF]
         # controlValue
         + [0x04, len(b"silly")]
         + l(b"silly")
         ),

        (pureldap.LDAPMessage,
         [],
         {'id': 42,
          'value': pureldap.LDAPBindRequest(),
          'controls': [ ('1.2.3.4', None, None),
                        ('2.3.4.5', False),
                        ('3.4.5.6', True, b'\x00\x01\x02\xFF'),
                        ('4.5.6.7', None, b'\x00\x01\x02\xFF'),
                        ],
          },
         pureldap.LDAPBERDecoderContext_TopLevel(
        inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
        fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
        inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()))),
         [0x30, 76]
         # id
         + [0x02, 0x01, 42]
         # value
         + l(pureldap.LDAPBindRequest().toWire())
         # controls
         + l(pureldap.LDAPControls(value=[
        pureldap.LDAPControl(controlType='1.2.3.4'),
        pureldap.LDAPControl(controlType='2.3.4.5',
                             criticality=False),
        pureldap.LDAPControl(controlType='3.4.5.6',
                             criticality=True,
                             controlValue=b'\x00\x01\x02\xFF'),
        pureldap.LDAPControl(controlType='4.5.6.7',
                             criticality=None,
                             controlValue=b'\x00\x01\x02\xFF'),
        ]).toWire()),
         ),

        (pureldap.LDAPFilter_equalityMatch,
         [],
         {'attributeDesc': pureldap.LDAPAttributeDescription('cn'),
          'assertionValue': pureldap.LDAPAssertionValue('foo'),
          },
         pureldap.LDAPBERDecoderContext_Filter(
        fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
        inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),

         [0xa3, 9]
         + ([0x04, 2] + l(b'cn')
            + [0x04, 3] + l(b'foo'))
         ),

        (pureldap.LDAPFilter_or,
         [[pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
                                             assertionValue=pureldap.LDAPAssertionValue('foo')),
           pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('uid'),
                                             assertionValue=pureldap.LDAPAssertionValue('foo')),
           pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('mail'),
                                             assertionValue=pureldap.LDAPAssertionValue('foo')),
           pureldap.LDAPFilter_substrings(type='mail', substrings=[pureldap.LDAPFilter_substrings_initial('foo@')]),
           ]],
         {},
         pureldap.LDAPBERDecoderContext_Filter(
        fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
        inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),

         [0xA1, 52]
         + ([0xa3, 9]
            + ([0x04, 2] + l(b'cn')
               + [0x04, 3] + l(b'foo'))
            + [0xa3, 10]
            + ([0x04, 3] + l(b'uid')
               + [0x04, 3] + l(b'foo'))
            + [0xa3, 11]
               + ([0x04, 4] + l(b'mail')
                  + [0x04, 3] + l(b'foo'))
            + [0xa4, 14]
            + ([0x04, 4] + l(b'mail')
               + [0x30, 6]
               + ([0x80, 4] + l(b'foo@'))))
         ),

        (pureldap.LDAPSearchRequest,
         [],
         {'baseObject': 'dc=example,dc=com',
          'scope': pureldap.LDAP_SCOPE_wholeSubtree,
          'derefAliases': pureldap.LDAP_DEREF_neverDerefAliases,
          'sizeLimit': 1,
          'timeLimit': 0,
          'typesOnly': False,
          'filter': pureldap.LDAPFilter_or([
        pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
                                          assertionValue=pureldap.LDAPAssertionValue('foo')),
        pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('uid'),
                                          assertionValue=pureldap.LDAPAssertionValue('foo')),
        pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('mail'),
                                          assertionValue=pureldap.LDAPAssertionValue('foo')),
        pureldap.LDAPFilter_substrings(type='mail', substrings=[pureldap.LDAPFilter_substrings_initial('foo@')]),
        ]),
          'attributes': [''],
        },
         pureldap.LDAPBERDecoderContext_LDAPMessage(
        fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
        inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),

         [0x63, 92]
         + ([0x04, 17] + l(b'dc=example,dc=com')
            + [0x0a, 1, 0x02]
            + [0x0a, 1, 0x00]
            + [0x02, 1, 0x01]
            + [0x02, 1, 0x00]
            + [0x01, 1, 0x00]
            + [0xA1, 52]
            + ([0xa3, 9]
               + ([0x04, 2] + l(b'cn')
                  + [0x04, 3] + l(b'foo'))
               + [0xa3, 10]
               + ([0x04, 3] + l(b'uid')
                  + [0x04, 3] + l(b'foo'))
               + [0xa3, 11]
               + ([0x04, 4] + l(b'mail')
                  + [0x04, 3] + l(b'foo'))
               + [0xa4, 14]
               + ([0x04, 4] + l(b'mail')
                  + [0x30, 6]
                  + ([0x80, 4] + l(b'foo@'))))
            + [0x30, 2]
            + ([0x04, 0])
            )
         ),

        (pureldap.LDAPMessage,
         [],
         {'id': 1,
          'value': pureldap.LDAPSearchRequest(
        baseObject='dc=example,dc=com',
        scope=pureldap.LDAP_SCOPE_wholeSubtree,
        derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
        sizeLimit=1,
        timeLimit=0,
        typesOnly=False,
        filter=pureldap.LDAPFilter_or([
        pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('cn'),
                                          assertionValue=pureldap.LDAPAssertionValue('foo')),
        pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('uid'),
                                          assertionValue=pureldap.LDAPAssertionValue('foo')),
        pureldap.LDAPFilter_equalityMatch(attributeDesc=pureldap.LDAPAttributeDescription('mail'),
                                          assertionValue=pureldap.LDAPAssertionValue('foo')),
        pureldap.LDAPFilter_substrings(type='mail', substrings=[pureldap.LDAPFilter_substrings_initial('foo@')]),
        ]),
        attributes=[''],
        ),
          },
         pureldap.LDAPBERDecoderContext_TopLevel(
        inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
        fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
        inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()))),

         [0x30, 97]
         # id
         + [0x02, 1, 1]
         # value
         + [0x63, 92]
         + ([0x04, 17] + l(b'dc=example,dc=com')
            + [0x0a, 1, 0x02]
            + [0x0a, 1, 0x00]
            + [0x02, 1, 0x01]
            + [0x02, 1, 0x00]
            + [0x01, 1, 0x00]
            + [0xA1, 52]
            + ([0xa3, 9]
               + ([0x04, 2] + l(b'cn')
                  + [0x04, 3] + l(b'foo'))
               + [0xa3, 10]
               + ([0x04, 3] + l(b'uid')
                  + [0x04, 3] + l(b'foo'))
               + [0xa3, 11]
               + ([0x04, 4] + l(b'mail')
                  + [0x04, 3] + l(b'foo'))
               + [0xa4, 14]
               + ([0x04, 4] + l(b'mail')
                  + [0x30, 6]
                  + ([0x80, 4] + l(b'foo@'))))
            + [0x30, 2]
            + ([0x04, 0])
            )
         ),

        (pureldap.LDAPExtendedRequest,
         [],
         {'requestName': '42.42.42',
          'requestValue': 'foo',
          },
         None,
         [0x40|0x20|23, 1+1+8+1+1+3]
         + ([0x80|0]
            + [len(b'42.42.42')]
            + l(b'42.42.42'))
         + ([0x80|1]
            + [len(b'foo')]
            + l(b'foo'))
         ),

        (pureldap.LDAPExtendedRequest,
         [],
         {'requestName': '42.42.42',
          'requestValue': None,
          },
         None,
         [0x40|0x20|23, 1+1+8]
         + ([0x80|0]
            + [len(b'42.42.42')]
            + l(b'42.42.42'))
         ),

        (pureldap.LDAPExtendedResponse,
         [],
         {'resultCode': 49,
          'matchedDN': 'foo',
          'errorMessage': 'bar',
          'responseName': None,
          'response': None,
          },
         None,
         [0x40|0x20|24, 3+2+3+2+3,
          0x0a, 1, 49,
          0x04, len(b'foo')] + l(b'foo') + [
          0x04, len(b'bar')] + l(b'bar'),
         ),

        (pureldap.LDAPExtendedResponse,
         [],
         {'resultCode': 49,
          'matchedDN': 'foo',
          'errorMessage': 'bar',
          'responseName': '1.2.3.4.5.6.7.8.9',
          'response': 'baz',
          },
         None,
         [0x40|0x20|24, 3+2+3+2+3+2+len('1.2.3.4.5.6.7.8.9')+2+3,
          0x0a, 1, 49,
          0x04, len(b'foo')] + l(b'foo') + [
          0x04, len(b'bar')] + l(b'bar') + [
          0x8a, len(b'1.2.3.4.5.6.7.8.9')] + l(b'1.2.3.4.5.6.7.8.9') + [
          0x8b, len(b'baz')] + l(b'baz'),
         ),

        (pureldap.LDAPAbandonRequest,
         [],
         {'id': 3},
         None,
         [0x40|0x10, 0x01, 3]
         ),

        (pureldap.LDAPBindRequest,
         [],
         {'auth': ('PLAIN', 'test'),
          'sasl': True},
         pureldap.LDAPBERDecoderContext(
                fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
                inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())),
         l(pureldap.LDAPBindRequest(auth=('PLAIN', 'test'), sasl=True).toWire())
         )
        )

    def testToLDAP(self):
        """LDAPClass(...).toWire() should give known result with known input"""
        for klass, args, kwargs, decoder, encoded in self.knownValues:
            result = klass(*args, **kwargs)
            result = result.toWire()
            result = l(result)

            message = (
                "Class %s(*%r, **%r) doesn't encode properly: "
                "%r != %r" % (
                    klass.__name__, args, kwargs, result, encoded))
            self.assertEqual(encoded, result, message)

    def testFromLDAP(self):
        """LDAPClass(encoded="...") should give known result with known input"""
        for klass, args, kwargs, decoder, encoded in self.knownValues:
            if decoder is None:
                decoder = pureldap.LDAPBERDecoderContext(
                    fallback=pureber.BERDecoderContext())
            m=s(*encoded)
            result, bytes = pureber.berDecodeObject(decoder, m)
            self.assertEqual(bytes, len(m))

            shouldBe = klass(*args, **kwargs)
            assert result.toWire() == shouldBe.toWire(), \
                   "Class %s(*%s, **%s) doesn't decode properly: " \
                   "%s != %s" % (klass.__name__,
                                 repr(args), repr(kwargs),
                                 repr(result), repr(shouldBe))

    def testPartial(self):
        """LDAPClass(encoded="...") with too short input should throw BERExceptionInsufficientData"""
        for klass, args, kwargs, decoder, encoded in self.knownValues:
            if decoder is None:
                decoder = pureldap.LDAPBERDecoderContext(
                    fallback=pureber.BERDecoderContext())
            for i in six.moves.range(1, len(encoded)):
                m=s(*encoded)[:i]
                self.assertRaises(pureber.BERExceptionInsufficientData,
                                  pureber.berDecodeObject,
                                  decoder, m)
            self.assertEqual((None, 0), pureber.berDecodeObject(decoder, ''))
Exemple #3
0
class LDAPServer(BaseLDAPServer):
    """An LDAP server"""
    boundUser = None

    fail_LDAPBindRequest = pureldap.LDAPBindResponse

    def handle_LDAPBindRequest(self, request, controls, reply):
        if request.version != 3:
            raise ldaperrors.LDAPProtocolError('Version %u not supported' %
                                               request.version)

        self.checkControls(controls)

        if request.dn == '':
            # anonymous bind
            self.boundUser = None
            return pureldap.LDAPBindResponse(resultCode=0)
        else:
            dn = distinguishedname.DistinguishedName(request.dn)
            root = interfaces.IConnectedLDAPEntry(self.factory)
            d = root.lookup(dn)

            def _noEntry(fail):
                fail.trap(ldaperrors.LDAPNoSuchObject)
                return None

            d.addErrback(_noEntry)

            def _gotEntry(entry, auth):
                if entry is None:
                    raise ldaperrors.LDAPInvalidCredentials

                d = entry.bind(auth)

                def _cb(entry):
                    self.boundUser = entry
                    msg = pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.Success.resultCode,
                        matchedDN=str(entry.dn))
                    return msg

                d.addCallback(_cb)
                return d

            d.addCallback(_gotEntry, request.auth)

            return d

    def handle_LDAPUnbindRequest(self, request, controls, reply):
        # explicitly do not check unsupported critical controls -- we
        # have no way to return an error, anyway.
        self.transport.loseConnection()

    def getRootDSE(self, request, reply):
        root = interfaces.IConnectedLDAPEntry(self.factory)
        reply(
            pureldap.LDAPSearchResultEntry(
                objectName='',
                attributes=[
                    ('supportedLDAPVersion', ['3']),
                    ('namingContexts', [str(root.dn)]),
                    ('supportedExtension', [
                        pureldap.LDAPPasswordModifyRequest.oid,
                    ]),
                ],
            ))
        return pureldap.LDAPSearchResultDone(
            resultCode=ldaperrors.Success.resultCode)

    def _cbSearchGotBase(self, base, dn, request, reply):
        def _sendEntryToClient(entry):
            reply(
                pureldap.LDAPSearchResultEntry(
                    objectName=str(entry.dn),
                    attributes=entry.items(),
                ))

        d = base.search(filterObject=request.filter,
                        attributes=request.attributes,
                        scope=request.scope,
                        derefAliases=request.derefAliases,
                        sizeLimit=request.sizeLimit,
                        timeLimit=request.timeLimit,
                        typesOnly=request.typesOnly,
                        callback=_sendEntryToClient)

        def _done(_):
            return pureldap.LDAPSearchResultDone(
                resultCode=ldaperrors.Success.resultCode)

        d.addCallback(_done)
        return d

    def _cbSearchLDAPError(self, reason):
        reason.trap(ldaperrors.LDAPException)
        return pureldap.LDAPSearchResultDone(
            resultCode=reason.value.resultCode)

    def _cbSearchOtherError(self, reason):
        return pureldap.LDAPSearchResultDone(
            resultCode=ldaperrors.other, errorMessage=reason.getErrorMessage())

    fail_LDAPSearchRequest = pureldap.LDAPSearchResultDone

    def handle_LDAPSearchRequest(self, request, controls, reply):
        self.checkControls(controls)

        if (request.baseObject == ''
                and request.scope == pureldap.LDAP_SCOPE_baseObject and
                request.filter == pureldap.LDAPFilter_present('objectClass')):
            return self.getRootDSE(request, reply)
        dn = distinguishedname.DistinguishedName(request.baseObject)
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(dn)
        d.addCallback(self._cbSearchGotBase, dn, request, reply)
        d.addErrback(self._cbSearchLDAPError)
        d.addErrback(defer.logError)
        d.addErrback(self._cbSearchOtherError)
        return d

    fail_LDAPDelRequest = pureldap.LDAPDelResponse

    def handle_LDAPDelRequest(self, request, controls, reply):
        self.checkControls(controls)

        dn = distinguishedname.DistinguishedName(request.value)
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(dn)

        def _gotEntry(entry):
            d = entry.delete()
            return d

        def _report(entry):
            return pureldap.LDAPDelResponse(resultCode=0)

        d.addCallback(_gotEntry)
        d.addCallback(_report)
        return d

    fail_LDAPAddRequest = pureldap.LDAPAddResponse

    def handle_LDAPAddRequest(self, request, controls, reply):
        self.checkControls(controls)

        attributes = {}
        for name, vals in request.attributes:
            attributes.setdefault(name.value, set())
            attributes[name.value].update([x.value for x in vals])
        dn = distinguishedname.DistinguishedName(request.entry)
        rdn = str(dn.split()[0])
        parent = dn.up()
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(parent)

        def _gotEntry(parent):
            d = parent.addChild(rdn, attributes)
            return d

        def _report(entry):
            return pureldap.LDAPAddResponse(resultCode=0)

        d.addCallback(_gotEntry)
        d.addCallback(_report)
        return d

    fail_LDAPModifyDNRequest = pureldap.LDAPModifyDNResponse

    def handle_LDAPModifyDNRequest(self, request, controls, reply):
        self.checkControls(controls)
        dn = distinguishedname.DistinguishedName(request.entry)
        newrdn = distinguishedname.RelativeDistinguishedName(request.newrdn)
        deleteoldrdn = bool(request.deleteoldrdn)
        if not deleteoldrdn:
            raise ldaperrors.LDAPUnwillingToPerform(
                "Cannot handle preserving old RDN yet.")
        newSuperior = request.newSuperior
        if newSuperior is None:
            newSuperior = dn.up()
        else:
            newSuperior = distinguishedname.DistinguishedName(newSuperior)
        newdn = distinguishedname.DistinguishedName(listOfRDNs=(newrdn, ) +
                                                    newSuperior.split())
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(dn)

        def _gotEntry(entry):
            d = entry.move(newdn)
            return d

        def _report(entry):
            return pureldap.LDAPModifyDNResponse(resultCode=0)

        d.addCallback(_gotEntry)
        d.addCallback(_report)
        return d

    fail_LDAPModifyRequest = pureldap.LDAPModifyResponse

    def handle_LDAPModifyRequest(self, request, controls, reply):
        self.checkControls(controls)

        root = interfaces.IConnectedLDAPEntry(self.factory)
        mod = delta.ModifyOp.fromLDAP(request)
        d = mod.patch(root)

        def _patched(entry):
            return entry.commit()

        def _report(entry):
            return pureldap.LDAPModifyResponse(resultCode=0)

        d.addCallback(_patched)
        d.addCallback(_report)
        return d

    fail_LDAPExtendedRequest = pureldap.LDAPExtendedResponse

    def handle_LDAPExtendedRequest(self, request, controls, reply):
        self.checkControls(controls)

        for handler in [
                getattr(self, attr) for attr in dir(self)
                if attr.startswith('extendedRequest_')
        ]:
            if getattr(handler, 'oid', None) == request.requestName:
                berdecoder = getattr(handler, 'berdecoder', None)

                if berdecoder is None:
                    values = [request.requestValue]
                else:
                    values = pureber.berDecodeMultiple(request.requestValue,
                                                       berdecoder)

                d = defer.maybeDeferred(handler, *values, **{'reply': reply})

                def eb(fail, oid):
                    fail.trap(ldaperrors.LDAPException)
                    return pureldap.LDAPExtendedResponse(
                        resultCode=fail.value.resultCode,
                        errorMessage=fail.value.message,
                        responseName=oid,
                    )

                d.addErrback(eb, request.requestName)
                return d

        raise ldaperrors.LDAPProtocolError('Unknown extended request: %s' %
                                           request.requestName)

    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):
            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)
        d = self.boundUser.commit()

        def cb_(result):
            if result:
                return pureldap.LDAPExtendedResponse(
                    resultCode=ldaperrors.Success.resultCode,
                    responseName=self.
                    extendedRequest_LDAPPasswordModifyRequest.oid)
            else:
                raise ldaperrors.LDAPOperationsError('Internal error.')

        d.addCallback(cb_)
        return d

    extendedRequest_LDAPPasswordModifyRequest.oid = pureldap.LDAPPasswordModifyRequest.oid
    extendedRequest_LDAPPasswordModifyRequest.berdecoder = (
        pureber.BERDecoderContext(
            inherit=pureldap.LDAPBERDecoderContext_LDAPPasswordModifyRequest(
                inherit=pureber.BERDecoderContext())))
Exemple #4
0
class LDAPClient(protocol.Protocol):
    """An LDAP client"""
    debug = False

    def __init__(self):
        self.onwire = {}
        self.buffer = b''
        self.connected = None

    berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
        inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
            fallback=pureldap.LDAPBERDecoderContext(
                fallback=pureber.BERDecoderContext()),
            inherit=pureldap.LDAPBERDecoderContext(
                fallback=pureber.BERDecoderContext())))

    def dataReceived(self, recd):
        self.buffer += recd
        while 1:
            try:
                o, bytes = pureber.berDecodeObject(self.berdecoder,
                                                   self.buffer)
            except pureber.BERExceptionInsufficientData:
                o, bytes = None, 0
            self.buffer = self.buffer[bytes:]
            if not o:
                break
            self.handle(o)

    def connectionMade(self):
        """TCP connection has opened"""
        self.connected = 1

    def connectionLost(self, reason=protocol.connectionDone):
        """Called when TCP connection has been lost"""
        self.connected = 0
        # notify handlers of operations in flight
        while self.onwire:
            k, v = self.onwire.popitem()
            d, _, _, _, _ = v
            d.errback(reason)

    def _send(self, op, controls=None):
        if not self.connected:
            raise LDAPClientConnectionLostException()
        msg = pureldap.LDAPMessage(op, controls=controls)
        if self.debug:
            log.msg('C->S %s' % repr(msg))
        assert msg.id not in self.onwire
        return msg

    def send(self, op, controls=None):
        """
        Send an LDAP operation to the server.
        @param op: the operation to send
        @type op: LDAPProtocolRequest
        @param controls: Any controls to be included in the request.
        @type controls: LDAPControls
        @return: the response from server
        @rtype: Deferred LDAPProtocolResponse
        """
        msg = self._send(op, controls=controls)
        assert op.needs_answer
        d = defer.Deferred()
        self.onwire[msg.id] = (d, False, None, None, None)
        self.transport.write(msg.toWire())
        return d

    def send_multiResponse(self, op, handler, *args, **kwargs):
        """
        Send an LDAP operation to the server, expecting one or more
        responses.

        If `handler` is provided, it will receive a LDAP response as
        its first argument. The Deferred returned by this function will
        never fire.

        If `handler` is not provided, the Deferred returned by this
        function will fire with the final LDAP response.

        @param op: the operation to send
        @type op: LDAPProtocolRequest
        @param handler: a callable that will be called for each
        response. It should return a boolean, whether this was the
        final response.
        @param args: positional arguments to pass to handler
        @param kwargs: keyword arguments to pass to handler
        @return: the result from the first handler as a deferred that
        completes when the first response has been received
        @rtype: Deferred LDAPProtocolResponse
        """
        msg = self._send(op)
        assert op.needs_answer
        d = defer.Deferred()
        self.onwire[msg.id] = (d, False, handler, args, kwargs)
        self.transport.write(msg.toWire())
        return d

    def send_multiResponse_ex(self,
                              op,
                              controls=None,
                              handler=None,
                              *args,
                              **kwargs):
        """
        Send an LDAP operation to the server, expecting one or more
        responses.

        If `handler` is provided, it will receive a LDAP response *and*
        response controls as its first 2 arguments. The Deferred returned
        by this function will never fire.

        If `handler` is not provided, the Deferred returned by this
        function will fire with a tuple of the first LDAP response
        and any associated response controls.

        @param op: the operation to send
        @type op: LDAPProtocolRequest
        @param controls: LDAP controls to send with the message.
        @type controls: LDAPControls
        @param handler: a callable that will be called for each
        response. It should return a boolean, whether this was the
        final response.
        @param args: positional arguments to pass to handler
        @param kwargs: keyword arguments to pass to handler
        @return: the result from the last handler as a deferred that
        completes when the last response has been received
        @rtype: Deferred LDAPProtocolResponse
        """
        msg = self._send(op, controls=controls)
        assert op.needs_answer
        d = defer.Deferred()
        self.onwire[msg.id] = (d, True, handler, args, kwargs)
        self.transport.write(msg.toWire())
        return d

    def send_noResponse(self, op, controls=None):
        """
        Send an LDAP operation to the server, with no response
        expected.

        @param op: the operation to send
        @type op: LDAPProtocolRequest
        """
        msg = self._send(op, controls=controls)
        assert not op.needs_answer
        self.transport.write(msg.toWire())

    def unsolicitedNotification(self, msg):
        log.msg("Got unsolicited notification: %s" % repr(msg))

    def handle(self, msg):
        assert isinstance(msg.value, pureldap.LDAPProtocolResponse)
        if self.debug:
            log.msg('C<-S %s' % repr(msg))

        if msg.id == 0:
            self.unsolicitedNotification(msg.value)
        else:
            d, return_controls, handler, args, kwargs = self.onwire[msg.id]

            if handler is None:
                assert (args is None) or (args == ())
                assert (kwargs is None) or (kwargs == {})
                if return_controls:
                    d.callback((msg.value, msg.controls))
                else:
                    d.callback(msg.value)
                del self.onwire[msg.id]
            else:
                assert args is not None
                assert kwargs is not None
                # Return true to mark request as fully handled
                if return_controls:
                    if handler(msg.value, msg.controls, *args, **kwargs):
                        del self.onwire[msg.id]
                else:
                    if handler(msg.value, *args, **kwargs):
                        del self.onwire[msg.id]

    def bind(self, dn='', auth=''):
        """
        @depreciated: Use e.bind(auth).

        @todo: Remove this method when there are no callers.
        """
        if not self.connected:
            raise LDAPClientConnectionLostException()
        else:
            r = pureldap.LDAPBindRequest(dn=dn, auth=auth)
            d = self.send(r)
            d.addCallback(self._handle_bind_msg)
        return d

    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 (msg.matchedDN, msg.serverSaslCreds)

    def unbind(self):
        if not self.connected:
            raise Exception(
                "Not connected (TODO)")  # TODO make this a real object
        r = pureldap.LDAPUnbindRequest()
        self.send_noResponse(r)
        self.transport.loseConnection()

    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 startTLS(self, ctx=None):
        """
        Start Transport Layer Security.

        It is the callers responsibility to make sure other things
        are not happening at the same time.

        @todo: server hostname check, see rfc2830 section 3.6.
        @return: a deferred that will complete when the TLS handshake is
        complete.
        """
        if ctx is None:
            ctx = ssl.ClientContextFactory()
        # we always delay by one event loop iteration to make
        # sure the previous handler has exited and self.onwire
        # has been cleaned up
        d = defer.Deferred()
        d.addCallback(self._startTLS)
        reactor.callLater(0, d.callback, ctx)
        return d

    def _startTLS(self, ctx):
        if not self.connected:
            raise LDAPClientConnectionLostException()
        elif self.onwire:
            raise LDAPStartTLSBusyError(self.onwire)
        else:
            op = pureldap.LDAPStartTLSRequest()
            d = self.send(op)
            d.addCallback(self._cbStartTLS, ctx)
            return d
Exemple #5
0
class ServiceBindingProxy(unittest.TestCase):
    berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
        inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
            fallback=pureldap.LDAPBERDecoderContext(
                fallback=pureber.BERDecoderContext()),
            inherit=pureldap.LDAPBERDecoderContext(
                fallback=pureber.BERDecoderContext())))

    def createServer(self, services, fallback=None, responses=[]):
        server = testutil.createServer(
            lambda config: svcbindproxy.ServiceBindingProxy(
                config=config,
                services=services,
                fallback=fallback,
            ),
            baseDN='dc=example,dc=com',
            *responses)
        server.now = '20050213140302Z'
        server.timestamp = lambda: server.now
        return server

    def test_bind_noMatchingServicesFound_noFallback(self):
        server = self.createServer(
            services=[
                'svc1',
                'svc2',
                'svc3',
            ],
            fallback=False,
            responses=[
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
            ])
        server.dataReceived(
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindRequest(
                    dn='cn=jack,dc=example,dc=com', auth='s3krit'),
                                     id=4)))
        reactor.iterate()  #TODO
        client = server.client

        client.assertSent(
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc1)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc2)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc3)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
        )
        self.assertEqual(
            server.transport.value(),
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindResponse(
                    resultCode=ldaperrors.LDAPInvalidCredentials.resultCode),
                                     id=4)))

    def test_bind_noMatchingServicesFound_fallback_success(self):
        server = self.createServer(
            services=[
                'svc1',
                'svc2',
                'svc3',
            ],
            fallback=True,
            responses=[
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.Success.resultCode)
                ],
            ])
        server.dataReceived(
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindRequest(
                    dn='cn=jack,dc=example,dc=com', auth='s3krit'),
                                     id=4)))
        reactor.iterate()  #TODO
        client = server.client

        client.assertSent(
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc1)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc2)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc3)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com',
                                     auth='s3krit'))
        self.assertEqual(
            server.transport.value(),
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindResponse(
                    resultCode=ldaperrors.Success.resultCode),
                                     id=4)))

    def test_bind_noMatchingServicesFound_fallback_badAuth(self):
        server = self.createServer(
            services=[
                'svc1',
                'svc2',
                'svc3',
            ],
            fallback=True,
            responses=[
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.LDAPInvalidCredentials.resultCode
                    ),
                ],
            ])
        server.dataReceived(
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindRequest(
                    dn='cn=jack,dc=example,dc=com', auth='wrong-s3krit'),
                                     id=4)))
        reactor.iterate()  #TODO
        client = server.client

        client.assertSent(
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc1)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc2)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc3)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(dn='cn=jack,dc=example,dc=com',
                                     auth='wrong-s3krit'))
        self.assertEqual(
            server.transport.value(),
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindResponse(
                    resultCode=ldaperrors.LDAPInvalidCredentials.resultCode),
                                     id=4)))

    def test_bind_match_success(self):
        server = self.createServer(
            services=[
                'svc1',
                'svc2',
                'svc3',
            ],
            fallback=True,
            responses=[

                # svc1
                [
                    pureldap.LDAPSearchResultEntry(
                        r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                        attributes=[]),
                    pureldap.LDAPSearchResultDone(
                        ldaperrors.Success.resultCode)
                ],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.Success.resultCode)
                ],
            ])

        server.dataReceived(
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindRequest(
                    dn='cn=jack,dc=example,dc=com', auth='secret'),
                                     id=4)))
        reactor.iterate()  #TODO
        client = server.client

        client.assertSent(
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc1)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(
                dn=
                r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                auth='secret'),
        )
        self.assertEqual(
            server.transport.value(),
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindResponse(
                    resultCode=ldaperrors.Success.resultCode,
                    matchedDN='cn=jack,dc=example,dc=com'),
                                     id=4)))

    def test_bind_match_success_later(self):
        server = self.createServer(
            services=[
                'svc1',
                'svc2',
                'svc3',
            ],
            fallback=True,
            responses=[

                # svc1
                [
                    pureldap.LDAPSearchResultEntry(
                        r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                        attributes=[]),
                    pureldap.LDAPSearchResultDone(
                        ldaperrors.Success.resultCode)
                ],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.LDAPInvalidCredentials.resultCode
                    )
                ],

                # svc2
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],

                # svc3
                [
                    pureldap.LDAPSearchResultEntry(
                        r'cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                        attributes=[]),
                    pureldap.LDAPSearchResultDone(
                        ldaperrors.Success.resultCode)
                ],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.Success.resultCode)
                ],
            ])

        server.dataReceived(
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindRequest(
                    dn='cn=jack,dc=example,dc=com', auth='secret'),
                                     id=4)))
        reactor.iterate()  #TODO
        client = server.client

        client.assertSent(
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc1)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(
                dn=
                r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                auth='secret'),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc2)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc3)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(
                dn=
                'cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                auth='secret'),
        )
        self.assertEqual(
            server.transport.value(),
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindResponse(
                    resultCode=ldaperrors.Success.resultCode,
                    matchedDN='cn=jack,dc=example,dc=com'),
                                     id=4)))

    def test_bind_match_badAuth(self):
        server = self.createServer(
            services=[
                'svc1',
                'svc2',
                'svc3',
            ],
            fallback=True,
            responses=[

                # svc1
                [
                    pureldap.LDAPSearchResultEntry(
                        r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                        attributes=[]),
                    pureldap.LDAPSearchResultDone(
                        ldaperrors.Success.resultCode)
                ],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.LDAPInvalidCredentials.resultCode
                    )
                ],

                # svc2
                [pureldap.LDAPSearchResultDone(ldaperrors.Success.resultCode)],

                # svc3
                [
                    pureldap.LDAPSearchResultEntry(
                        r'cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                        attributes=[]),
                    pureldap.LDAPSearchResultDone(
                        ldaperrors.Success.resultCode)
                ],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.LDAPInvalidCredentials.resultCode
                    )
                ],
                [
                    pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.LDAPInvalidCredentials.resultCode
                    )
                ],
            ])

        server.dataReceived(
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindRequest(
                    dn='cn=jack,dc=example,dc=com', auth='wrong-s3krit'),
                                     id=4)))
        reactor.iterate()  #TODO
        client = server.client

        client.assertSent(
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc1)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(
                dn=
                r'cn=svc1+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                auth='wrong-s3krit'),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc2)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPSearchRequest(
                baseObject='dc=example,dc=com',
                derefAliases=0,
                sizeLimit=0,
                timeLimit=0,
                typesOnly=0,
                filter=ldapfilter.parseFilter(
                    '(&' + '(objectClass=serviceSecurityObject)' +
                    '(owner=cn=jack,dc=example,dc=com)' + '(cn=svc3)' +
                    ('(|(!(validFrom=*))(validFrom<=%s))' % server.now) +
                    ('(|(!(validUntil=*))(validUntil>=%s))' % server.now) +
                    ')'),
                attributes=('1.1', )),
            pureldap.LDAPBindRequest(
                dn=
                'cn=svc3+owner=cn\=jack\,dc\=example\,dc\=com,dc=example,dc=com',
                auth='wrong-s3krit'),
            pureldap.LDAPBindRequest(version=3,
                                     dn='cn=jack,dc=example,dc=com',
                                     auth='wrong-s3krit'),
        )
        self.assertEqual(
            server.transport.value(),
            str(
                pureldap.LDAPMessage(pureldap.LDAPBindResponse(
                    resultCode=ldaperrors.LDAPInvalidCredentials.resultCode),
                                     id=4)))
Exemple #6
0
 def testPartialBERNullEncodings(self):
     """BERNull(encoded="...") with too short input should throw BERExceptionInsufficientData"""
     m=str(pureber.BERNull())
     assert len(m)==2
     self.assertRaises(pureber.BERExceptionInsufficientData, pureber.berDecodeObject, pureber.BERDecoderContext(), m[:1])
     self.assertEquals((None, 0), pureber.berDecodeObject(pureber.BERDecoderContext(), ''))
Exemple #7
0
class LDAPServer(BaseLDAPServer):
    """An LDAP server"""

    boundUser = None

    fail_LDAPBindRequest = pureldap.LDAPBindResponse

    def handle_LDAPBindRequest(self, request, controls, reply):
        if request.version != 3:
            raise ldaperrors.LDAPProtocolError("Version %u not supported" %
                                               request.version)

        self.checkControls(controls)

        if request.dn == b"":
            # anonymous bind
            self.boundUser = None
            return pureldap.LDAPBindResponse(resultCode=0)
        else:
            dn = distinguishedname.DistinguishedName(request.dn)
            root = interfaces.IConnectedLDAPEntry(self.factory)
            d = root.lookup(dn)

            def _noEntry(fail):
                fail.trap(ldaperrors.LDAPNoSuchObject)
                return None

            d.addErrback(_noEntry)

            def _gotEntry(entry, auth):
                if entry is None:
                    raise ldaperrors.LDAPInvalidCredentials()

                d = entry.bind(auth)

                def _cb(entry):
                    self.boundUser = entry
                    msg = pureldap.LDAPBindResponse(
                        resultCode=ldaperrors.Success.resultCode,
                        matchedDN=entry.dn.getText(),
                    )
                    return msg

                d.addCallback(_cb)
                return d

            d.addCallback(_gotEntry, request.auth)

            return d

    def handle_LDAPUnbindRequest(self, request, controls, reply):
        # explicitly do not check unsupported critical controls -- we
        # have no way to return an error, anyway.
        self.transport.loseConnection()

    def getRootDSE(self, request, reply):
        root = interfaces.IConnectedLDAPEntry(self.factory)
        reply(
            pureldap.LDAPSearchResultEntry(
                objectName="",
                attributes=[
                    ("supportedLDAPVersion", ["3"]),
                    ("namingContexts", [root.dn.getText()]),
                    (
                        "supportedExtension",
                        [
                            pureldap.LDAPPasswordModifyRequest.oid,
                        ],
                    ),
                ],
            ))
        return pureldap.LDAPSearchResultDone(
            resultCode=ldaperrors.Success.resultCode)

    fail_LDAPCompareRequest = pureldap.LDAPCompareResponse

    def handle_LDAPCompareRequest(self, request, controls, reply):
        def _cbCompareGotBase(base, ava, reply):
            def _done(result_list):
                if result_list:
                    resultCode = ldaperrors.LDAPCompareTrue.resultCode
                else:
                    resultCode = ldaperrors.LDAPCompareFalse.resultCode
                return pureldap.LDAPCompareResponse(resultCode)

            # base.search only works with Filter Objects, and not with
            # AttributeValueAssertion objects. Here we convert the AVA to an
            # equivalent Filter so we can re-use the existing search
            # functionality we require.
            search_filter = pureldap.LDAPFilter_equalityMatch(
                attributeDesc=ava.attributeDesc,
                assertionValue=ava.assertionValue)

            d = base.search(
                filterObject=search_filter,
                scope=pureldap.LDAP_SCOPE_baseObject,
                derefAliases=pureldap.LDAP_DEREF_neverDerefAliases,
            )

            d.addCallback(_done)

            return d

        def _cbCompareLDAPError(reason):
            reason.trap(ldaperrors.LDAPException)
            return pureldap.LDAPCompareResponse(
                resultCode=reason.value.resultCode)

        def _cbCompareOtherError(reason):
            return pureldap.LDAPCompareResponse(
                resultCode=ldaperrors.other,
                errorMessage=reason.getErrorMessage())

        self.checkControls(controls)
        dn = distinguishedname.DistinguishedName(request.entry)
        root = interfaces.IConnectedLDAPEntry(self.factory)

        d = root.lookup(dn)
        d.addCallback(_cbCompareGotBase, request.ava, reply)
        d.addErrback(_cbCompareLDAPError)
        d.addErrback(defer.logError)
        d.addErrback(_cbCompareOtherError)
        return d

    def _cbSearchGotBase(self, base, dn, request, reply):
        def _sendEntryToClient(entry):
            requested_attribs = request.attributes
            if len(requested_attribs) > 0 and b"*" not in requested_attribs:
                filtered_attribs = [(k, entry.get(k))
                                    for k in requested_attribs if k in entry]
            else:
                filtered_attribs = entry.items()
            reply(
                pureldap.LDAPSearchResultEntry(
                    objectName=entry.dn.getText(),
                    attributes=filtered_attribs,
                ))

        d = base.search(
            filterObject=request.filter,
            attributes=request.attributes,
            scope=request.scope,
            derefAliases=request.derefAliases,
            sizeLimit=request.sizeLimit,
            timeLimit=request.timeLimit,
            typesOnly=request.typesOnly,
            callback=_sendEntryToClient,
        )

        def _done(_):
            return pureldap.LDAPSearchResultDone(
                resultCode=ldaperrors.Success.resultCode)

        d.addCallback(_done)
        return d

    def _cbSearchLDAPError(self, reason):
        reason.trap(ldaperrors.LDAPException)
        return pureldap.LDAPSearchResultDone(
            resultCode=reason.value.resultCode)

    def _cbSearchOtherError(self, reason):
        return pureldap.LDAPSearchResultDone(
            resultCode=ldaperrors.other, errorMessage=reason.getErrorMessage())

    fail_LDAPSearchRequest = pureldap.LDAPSearchResultDone

    def handle_LDAPSearchRequest(self, request, controls, reply):
        self.checkControls(controls)

        if (request.baseObject == b""
                and request.scope == pureldap.LDAP_SCOPE_baseObject and
                request.filter == pureldap.LDAPFilter_present("objectClass")):
            return self.getRootDSE(request, reply)
        dn = distinguishedname.DistinguishedName(request.baseObject)
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(dn)
        d.addCallback(self._cbSearchGotBase, dn, request, reply)
        d.addErrback(self._cbSearchLDAPError)
        d.addErrback(defer.logError)
        d.addErrback(self._cbSearchOtherError)
        return d

    fail_LDAPDelRequest = pureldap.LDAPDelResponse

    def handle_LDAPDelRequest(self, request, controls, reply):
        self.checkControls(controls)

        dn = distinguishedname.DistinguishedName(request.value)
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(dn)

        def _gotEntry(entry):
            d = entry.delete()
            return d

        def _report(entry):
            return pureldap.LDAPDelResponse(resultCode=0)

        d.addCallback(_gotEntry)
        d.addCallback(_report)
        return d

    fail_LDAPAddRequest = pureldap.LDAPAddResponse

    def handle_LDAPAddRequest(self, request, controls, reply):
        self.checkControls(controls)

        attributes = {}
        for name, vals in request.attributes:
            attributes.setdefault(name.value, set())
            attributes[name.value].update([x.value for x in vals])
        dn = distinguishedname.DistinguishedName(request.entry)
        rdn = dn.split()[0].getText()
        parent = dn.up()
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(parent)

        def _gotEntry(parent):
            d = parent.addChild(rdn, attributes)
            return d

        def _report(entry):
            return pureldap.LDAPAddResponse(resultCode=0)

        d.addCallback(_gotEntry)
        d.addCallback(_report)
        return d

    fail_LDAPModifyDNRequest = pureldap.LDAPModifyDNResponse

    def handle_LDAPModifyDNRequest(self, request, controls, reply):
        self.checkControls(controls)
        dn = distinguishedname.DistinguishedName(request.entry)
        newrdn = distinguishedname.RelativeDistinguishedName(request.newrdn)
        deleteoldrdn = bool(request.deleteoldrdn)
        if not deleteoldrdn:
            raise ldaperrors.LDAPUnwillingToPerform(
                "Cannot handle preserving old RDN yet.")
        newSuperior = request.newSuperior
        if newSuperior is None:
            newSuperior = dn.up()
        else:
            newSuperior = distinguishedname.DistinguishedName(newSuperior)
        newdn = distinguishedname.DistinguishedName(listOfRDNs=(newrdn, ) +
                                                    newSuperior.split())
        root = interfaces.IConnectedLDAPEntry(self.factory)
        d = root.lookup(dn)

        def _gotEntry(entry):
            d = entry.move(newdn)
            return d

        def _report(entry):
            return pureldap.LDAPModifyDNResponse(resultCode=0)

        d.addCallback(_gotEntry)
        d.addCallback(_report)
        return d

    fail_LDAPModifyRequest = pureldap.LDAPModifyResponse

    def handle_LDAPModifyRequest(self, request, controls, reply):
        self.checkControls(controls)

        root = interfaces.IConnectedLDAPEntry(self.factory)
        mod = delta.ModifyOp.fromLDAP(request)
        d = mod.patch(root)

        def _patched(entry):
            return entry.commit()

        def _report(entry):
            return pureldap.LDAPModifyResponse(resultCode=0)

        d.addCallback(_patched)
        d.addCallback(_report)
        return d

    fail_LDAPExtendedRequest = pureldap.LDAPExtendedResponse

    def handle_LDAPExtendedRequest(self, request, controls, reply):
        self.checkControls(controls)

        for handler in [
                getattr(self, attr) for attr in dir(self)
                if attr.startswith("extendedRequest_")
        ]:
            if getattr(handler, "oid", None) == request.requestName:
                berdecoder = getattr(handler, "berdecoder", None)

                if berdecoder is None:
                    values = [request.requestValue]
                else:
                    values = pureber.berDecodeMultiple(request.requestValue,
                                                       berdecoder)

                d = defer.maybeDeferred(handler, *values, **{"reply": reply})

                def eb(fail, oid):
                    fail.trap(ldaperrors.LDAPException)
                    return pureldap.LDAPExtendedResponse(
                        resultCode=fail.value.resultCode,
                        errorMessage=fail.value.message,
                        responseName=oid,
                    )

                d.addErrback(eb, request.requestName)
                return d

        raise ldaperrors.LDAPProtocolError(b"Unknown extended request: %s" %
                                           request.requestName)

    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:
            log.msg("User {actor} tried to change password of {target}".format(
                actor=self.boundUser.dn.getText(),
                target=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)
        d = self.boundUser.commit()

        def cb_(result):
            if result:
                return pureldap.LDAPExtendedResponse(
                    resultCode=ldaperrors.Success.resultCode,
                    responseName=self.
                    extendedRequest_LDAPPasswordModifyRequest.oid,
                )
            else:
                raise ldaperrors.LDAPOperationsError("Internal error.")

        d.addCallback(cb_)
        return d

    extendedRequest_LDAPPasswordModifyRequest.oid = (
        pureldap.LDAPPasswordModifyRequest.oid)
    extendedRequest_LDAPPasswordModifyRequest.berdecoder = pureber.BERDecoderContext(
        inherit=pureldap.LDAPBERDecoderContext_LDAPPasswordModifyRequest(
            inherit=pureber.BERDecoderContext()))