'Given the opaque and nonce from the request, as well as the client IP
that made the request, verify that the opaque was generated by us.
And that it\'s not too old.
@param opaque: The opaque value from the Digest response
@param nonce: The nonce value from the Digest response
@param clientip: The remote IP address of the client making the request
or L{None} if the request was submitted over a channel where this
does not make sense.
@return: C{True} if the opaque was successfully verified.
@raise error.LoginFailed: if C{opaque} could not be parsed or
contained the wrong values.'

def _verifyOpaque(self, opaque, nonce, clientip):

    opaqueParts = opaque.split('-')
    if (len(opaqueParts) != 2):
        raise error.LoginFailed('Invalid    response,    invalid    opaque    value')
    if (not clientip):
        clientip = ''
    elif isinstance(clientip, unicode):
        clientip = clientip.encode('ascii')
    key = base64.b64decode(opaqueParts[1])
    keyParts = key.split(',')
    if (len(keyParts) != 3):
        raise error.LoginFailed('Invalid    response,    invalid    opaque    value')
    if (keyParts[0] != nonce):
        raise error.LoginFailed('Invalid    response,    incompatible    opaque/nonce    values')
    if (keyParts[1] != clientip):
        raise error.LoginFailed('Invalid    response,    incompatible    opaque/client    values')
    try:
        when = int(keyParts[2])
    except ValueError:
        raise error.LoginFailed('Invalid    response,    invalid    opaque/time    values')
    if ((int(self._getTime()) - when) > DigestCredentialFactory.CHALLENGE_LIFETIME_SECS):
        raise error.LoginFailed('Invalid    response,    incompatible    opaque/nonce    too    old')
    digest = hexlify(md5((key + self.privateKey)).digest())
    if (digest != opaqueParts[0]):
        raise error.LoginFailed('Invalid    response,    invalid    opaque    value')
    return True
