Ejemplo n.º 1
0
    def decode(self, response, request):
        """
        Do the default behavior but then strip out any 'qop' from the credential fields
        if no qop was specified.
        """

        """
        Decode the given response and attempt to generate a
        L{DigestedCredentials} from it.

        @type response: C{str}
        @param response: A string of comma seperated key=value pairs

        @type request: L{txweb2.server.Request}
        @param request: the request being processed

        @return: L{DigestedCredentials}

        @raise: L{error.LoginFailed} if the response does not contain a
            username, a nonce, an opaque, or if the opaque is invalid.
        """

        response = ' '.join(response.splitlines())

        try:
            parts = split(tokenize((response,), foldCase=False), Token(","))

            auth = {}

            for (k, v) in [parseKeyValue(p) for p in parts]:
                auth[k.strip()] = v.strip()
        except ValueError:
            raise error.LoginFailed('Invalid response.')

        username = auth.get('username')
        if not username:
            raise error.LoginFailed('Invalid response, no username given.')

        if 'nonce' not in auth:
            raise error.LoginFailed('Invalid response, no nonce given.')

        # Now verify the nonce/cnonce values for this client
        result = (yield self._validate(auth, request))
        if result:
            if hasattr(request, "originalMethod"):
                originalMethod = request.originalMethod
            else:
                originalMethod = None

            credentials = DigestedCredentials(username,
                                              originalMethod or request.method,
                                              self._real.authenticationRealm,
                                              auth)

            if not self.qop and 'qop' in credentials.fields:
                del credentials.fields['qop']

            returnValue(credentials)
        else:
            raise error.LoginFailed('Invalid nonce/cnonce values')
Ejemplo n.º 2
0
    def decode(self, response, request):

        creds = response.split(":", 1)
        if len(creds) != 2:
            raise error.LoginFailed("Invalid credentials")

        accessKey, encodedMAC = creds
        try:
            mac = binascii.a2b_base64(encodedMAC)
        except binascii.Error:
            raise error.LoginFailed("Invalid credentials")

        contentType = request.getHeader('content-type') or ""

        date = request.getHeader('date') or ""
        self.checkDate(date)

        calculatedContentMD5 = self.readBodyHash(request) or ""
        headerContentMD5 = request.getHeader('content-md5') or ""

        if headerContentMD5 and headerContentMD5 != calculatedContentMD5:
            raise error.LoginFailed("Invalid body md5")

        return AuthHMACCredentials(
            accessKey=accessKey,
            mac=mac,
            httpVerb=request.method,
            contentType=contentType,
            contentMD5=calculatedContentMD5,
            date=date,
            requestURI=request.uri,
        )
Ejemplo n.º 3
0
 def checkDate(self, date):
     if not date and self.max_request_time_delta is not None:
         raise error.LoginFailed("Missing mandatory 'date' header")
     t2 = stringToDatetime(date)
     t1 = time.time()
     if self.max_request_time_delta is not None and abs(t1 - t2) > self.max_request_time_delta:
         raise error.LoginFailed("Request 'date' too old")
Ejemplo n.º 4
0
    def decode(self, response, request):  # @UnusedVariable
        try:
            creds = (response + '===').decode('base64')
        except:
            raise error.LoginFailed('Invalid credentials')

        creds = creds.split(':', 1)
        if len(creds) == 2:
            c = BasicKerberosCredentials(creds[0], creds[1], self.service, self.realm)
            return succeed(c)
        raise error.LoginFailed('Invalid credentials')
Ejemplo n.º 5
0
    def decode(self, response, request):
        try:
            creds = (response + '===').decode('base64')
        except:
            raise error.LoginFailed('Invalid credentials')

        creds = creds.split(':', 1)
        if len(creds) == 2:
            return credentials.UsernamePassword(*creds)
        else:
            raise error.LoginFailed('Invalid credentials')
Ejemplo n.º 6
0
    def decode(self, response, request):
        try:
            creds = binascii.a2b_base64(response + b'===')
        except binascii.Error:
            raise error.LoginFailed('Invalid credentials')

        creds = creds.split(b':', 1)
        if len(creds) == 2:
            return UsernamePassword(*creds)
        else:
            raise error.LoginFailed('Invalid credentials')
Ejemplo n.º 7
0
def decode(self, response, request):
    try:
        creds = (response + '===').decode('base64')
    except Exception:
        raise error.LoginFailed('Invalid credentials')

    creds = creds.split(':', 1)
    if len(creds) == 2:
        creds = BasicCredentials(creds[0], creds[1], self.realm)  # our change
        return creds
    else:
        raise error.LoginFailed('Invalid credentials')
Ejemplo n.º 8
0
    def decode(self, response, request):
        """
        Parse the base64-encoded, colon-separated username and password into a
        L{credentials.UsernamePassword} instance.
        """
        try:
            creds = binascii.a2b_base64(response + '===')
        except binascii.Error:
            raise error.LoginFailed('Invalid credentials')

        creds = creds.split(':', 1)
        if len(creds) == 2:
            return credentials.UsernamePassword(*creds)
        else:
            raise error.LoginFailed('Invalid credentials')
Ejemplo n.º 9
0
    def decode(self, response, method, host):
        """
        Decode the given response and attempt to generate a
        L{DigestedCredentials} from it.

        @type response: C{str}
        @param response: A string of comma seperated key=value pairs

        @type method: C{str}
        @param method: The action requested to which this response is addressed
        (GET, POST, INVITE, OPTIONS, etc).

        @type host: C{str}
        @param host: The address the request was sent from.

        @raise error.LoginFailed: If the response does not contain a username,
            a nonce, an opaque, or if the opaque is invalid.

        @return: L{DigestedCredentials}
        """
        def unq(s):
            if s[0] == s[-1] == '"':
                return s[1:-1]
            return s
        response = ' '.join(response.splitlines())
        parts = response.split(',')

        auth = {}

        for (k, v) in [p.split('=', 1) for p in parts]:
            auth[k.strip()] = unq(v.strip())

        username = auth.get('username')
        if not username:
            raise error.LoginFailed('Invalid response, no username given.')

        if 'opaque' not in auth:
            raise error.LoginFailed('Invalid response, no opaque given.')

        if 'nonce' not in auth:
            raise error.LoginFailed('Invalid response, no nonce given.')

        # Now verify the nonce/opaque values for this client
        if self._verifyOpaque(auth.get('opaque'), auth.get('nonce'), host):
            return DigestedCredentials(username,
                                       method,
                                       self.authenticationRealm,
                                       auth)
Ejemplo n.º 10
0
 def requestAvatarId(self, credentials):
     try:
         pydas.login(email=credentials.username, password=credentials.password, application='Midasftp Server', url=self.url)
     except pydas.exceptions.PydasException as detail:
         print "Caught PydasException: ", detail
         return defer.fail(error.LoginFailed("Invalid email or password"))
     return defer.succeed((credentials.username, pydas, self.url))
Ejemplo n.º 11
0
    def decode(self, response, request):
        """
        Decode the credentials for basic auth.

        @see L{ICredentialFactory.decode}
        """
        try:
            creds = (response + '===').decode('base64')
        except:
            raise error.LoginFailed('Invalid credentials')

        creds = creds.split(':', 1)
        if len(creds) == 2:
            return succeed(credentials.UsernamePassword(*creds))
        else:
            return fail(error.LoginFailed('Invalid credentials'))
Ejemplo n.º 12
0
    def decode(self, response, request):
        """
        Decode the given response and attempt to generate a
        L{DigestedCredentials} from it.

        @type response: C{str}
        @param response: A string of comma seperated key=value pairs

        @type request: L{twisted.web2.server.Request}
        @param request: the request being processed

        @return: L{DigestedCredentials}

        @raise: L{error.LoginFailed} if the response does not contain a
            username, a nonce, an opaque, or if the opaque is invalid.
        """
        def unq(s):
            if s[0] == s[-1] == '"':
                return s[1:-1]
            return s
        response = ' '.join(response.splitlines())
        parts = response.split(',')

        auth = {}

        for (k, v) in [p.split('=', 1) for p in parts]:
            auth[k.strip()] = unq(v.strip())

        username = auth.get('username')
        if not username:
            raise error.LoginFailed('Invalid response, no username given.')

        if 'opaque' not in auth:
            raise error.LoginFailed('Invalid response, no opaque given.')

        if 'nonce' not in auth:
            raise error.LoginFailed('Invalid response, no nonce given.')

        # Now verify the nonce/opaque values for this client
        if self.verifyOpaque(auth.get('opaque'),
                             auth.get('nonce'),
                             request.remoteAddr.host):

            return DigestedCredentials(username,
                                       request.method,
                                       self.realm,
                                       auth)
Ejemplo n.º 13
0
    def _verifyOpaque(self, opaque, nonce, clientip):
        """
        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.
        """
        # First split the digest from the key
        opaqueParts = opaque.split(b'-')
        if len(opaqueParts) != 2:
            raise error.LoginFailed('Invalid response, invalid opaque value')

        if not clientip:
            clientip = b''
        elif isinstance(clientip, unicode):
            clientip = clientip.encode('ascii')

        # Verify the key
        key = base64.b64decode(opaqueParts[1])
        keyParts = key.split(b',')

        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')

        # Verify the digest
        digest = hexlify(md5(key + self.privateKey).digest())
        if digest != opaqueParts[0]:
            raise error.LoginFailed('Invalid response, invalid opaque value')

        return True
Ejemplo n.º 14
0
    def decode(self, base64data, request):

        # Init GSSAPI first - we won't specify the service now as we need to accept a target
        # name that is case-insenstive as some clients will use "http" instead of "HTTP"
        try:
            _ignore_result, context = kerberos.authGSSServerInit("")
        except kerberos.GSSError, ex:
            self.log.error("authGSSServerInit: {ex0}({ex1})", ex0=ex[0][0], ex1=ex[1][0])
            raise error.LoginFailed('Authentication System Failure: %s(%s)' % (ex[0][0], ex[1][0],))
Ejemplo n.º 15
0
    def decode(self, response, method, host):
        """
        Decode the given response and attempt to generate a
        L{DigestedCredentials} from it.

        @type response: L{bytes}
        @param response: A string of comma separated key=value pairs

        @type method: L{bytes}
        @param method: The action requested to which this response is addressed
            (GET, POST, INVITE, OPTIONS, etc).

        @type host: L{bytes}
        @param host: The address the request was sent from.

        @raise error.LoginFailed: If the response does not contain a username,
            a nonce, an opaque, or if the opaque is invalid.

        @return: L{DigestedCredentials}
        """
        response = b' '.join(response.splitlines())
        parts = self._parseparts.findall(response)
        auth = {}
        for (key, bare, quoted) in parts:
            value = (quoted or bare).strip()
            auth[nativeString(key.strip())] = value

        username = auth.get('username')
        if not username:
            raise error.LoginFailed('Invalid response, no username given.')

        if 'opaque' not in auth:
            raise error.LoginFailed('Invalid response, no opaque given.')

        if 'nonce' not in auth:
            raise error.LoginFailed('Invalid response, no nonce given.')

        # Now verify the nonce/opaque values for this client
        if self._verifyOpaque(auth.get('opaque'), auth.get('nonce'), host):
            return DigestedCredentials(username,
                                       method,
                                       self.authenticationRealm,
                                       auth)
Ejemplo n.º 16
0
    def _validate(self, auth, request):
        """
        Check that the parameters in the response represent a valid set of credentials that
        may be being re-used.

        @param auth:        the response parameters.
        @type auth:         C{dict}
        @param request:     the request being processed.
        @type request:      L{txweb2.server.Request}

        @return:            C{True} if validated.
        @raise LoginFailed: if validation fails.
        """

        nonce = auth.get('nonce')
        nonce_count = auth.get('nc')

        # First check we have this nonce
        result = (yield self.db.get(nonce))
        if result is None:
            raise error.LoginFailed('Invalid nonce value: %s' % (nonce,))
        db_nonce_count, db_timestamp = result

        # cnonce and nonce-count MUST be present if qop is present
        if auth.get('qop') is not None:
            if auth.get('cnonce') is None:
                yield self._invalidate(nonce)
                raise error.LoginFailed('cnonce is required when qop is specified')
            if nonce_count is None:
                yield self._invalidate(nonce)
                raise error.LoginFailed('nonce-count is required when qop is specified')

            # Next check the nonce-count is one greater than the previous one and update it in the DB
            try:
                nonce_count = int(nonce_count, 16)
            except ValueError:
                yield self._invalidate(nonce)
                raise error.LoginFailed('nonce-count is not a valid hex string: %s' % (auth.get('nonce-count'),))
            if nonce_count != db_nonce_count + 1:
                yield self._invalidate(nonce)
                raise error.LoginFailed('nonce-count value out of sequence: %s should be one more than %s' % (nonce_count, db_nonce_count,))
            yield self.db.set(nonce, (nonce_count, db_timestamp))
        else:
            # When not using qop the stored nonce-count must always be zero.
            # i.e. we can't allow a qop auth then a non-qop auth with the same nonce
            if db_nonce_count != 0:
                yield self._invalidate(nonce)
                raise error.LoginFailed('nonce-count was sent with this nonce: %s' % (nonce,))

        # Now check timestamp
        if db_timestamp + DigestCredentialFactory.CHALLENGE_LIFETIME_SECS <= time.time():
            yield self._invalidate(nonce)
            if request.remoteAddr:
                request.remoteAddr.stale = True
            raise error.LoginFailed('Digest credentials expired')

        returnValue(True)
Ejemplo n.º 17
0
    def decode(self, response, request):
        def unq(s):
            if s[0] == s[-1] == '"':
                return s[1:-1]
            return s

        response = ' '.join(response.splitlines())
        parts = response.split(',')
        auth = dict([(k.strip(), unq(v.strip()))
                     for (k, v) in [p.split('=', 1) for p in parts]])

        username = auth.get('username')
        if not username:
            raise error.LoginFailed('Invalid response, no username given')

        if auth.get('opaque') not in self.outstanding:
            raise error.LoginFailed('Invalid response, opaque not outstanding')

        del self.outstanding[auth['opaque']]

        return DigestedCredentials(username, request.method, self.realm, auth)
Ejemplo n.º 18
0
    def decode(self, response, request):
        """
        Decode the credentials for basic auth.

        @see L{ICredentialFactory.decode}
        """
        try:
            creds = credentials.UsernamePassword(response, '')
        except:
            raise error.LoginFailed('Invalid credentials')

        return succeed(creds)
Ejemplo n.º 19
0
    def decode(self, response, method, host):
        response = ' '.join(response.splitlines())

        # split comma separated parameters, don't split quoted strings, remove
        # quotes
        quoted = False
        parts = []
        p = ""
        for c in response:
            if c == '"':
                quoted = not quoted
            elif not quoted and c == ',':
                parts.append(p)
                p = ""
            else:
                p += c
        if p:
            parts.append(p)

        auth = {}

        for (k, v) in [p.split('=', 1) for p in parts]:
            auth[k.strip()] = v.strip()

        username = auth.get('username')
        if not username:
            raise error.LoginFailed("invalid response, no user name given")

        if 'opaque' not in auth:
            raise error.LoginFailed("invalid response, no opaque given")

        if 'nonce' not in auth:
            raise error.LoginFailed("invalid response, no nonce given.")

        # Now verify the nonce/opaque values for this client
        if self._verifyOpaque(auth.get('opaque'), auth.get('nonce'), host):
            return credentials.DigestedCredentials(username, method,
                                                   self.authenticationRealm,
                                                   auth)
Ejemplo n.º 20
0
    def verifyOpaque(self, opaque, nonce, clientip):
        """
        Given the opaque and nonce from the request, as well as the clientip
        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

        @return: C{True} if the opaque was successfully verified.

        @raise error.LoginFailed: if C{opaque} could not be parsed or
            contained the wrong values.
        """

        # First split the digest from the key
        opaqueParts = opaque.split('-')
        if len(opaqueParts) != 2:
            raise error.LoginFailed('Invalid response, invalid opaque value')

        # Verify the key
        key = opaqueParts[1].decode('base64')
        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')

        if (int(self._getTime()) - int(keyParts[2]) >
            DigestCredentialFactory.CHALLENGE_LIFETIME_SECS):

            raise error.LoginFailed(
                'Invalid response, incompatible opaque/nonce too old')

        # Verify the digest
        digest = md5(key + self.privateKey).hexdigest()
        if digest != opaqueParts[0]:
            raise error.LoginFailed('Invalid response, invalid opaque value')

        return True
Ejemplo n.º 21
0
 def _ebAuthenticate(self, failure, credentials, deferred):
     deferred.errback(error.LoginFailed(failure))
Ejemplo n.º 22
0
    def decode(self, response, request):
        key, token = response.split('=', 1)
        if key == 'auth':
            return KontalkToken(token, True)

        raise error.LoginFailed('Invalid token')
Ejemplo n.º 23
0
 def _ebAuthenticate(self, message, credentials, deferred):
     deferred.errback(credError.LoginFailed(message))
Ejemplo n.º 24
0
 def _ebAuthenticate(self, message, credentials, deferred):
     """
     The database lookup failed for some reason.
     """
     deferred.errback(error.LoginFailed(message))
Ejemplo n.º 25
0
        # We currently do not support cross-realm authentication, so we
        # must verify that the realm we got exactly matches the one we expect.
        if realmname != self.realm:
            username = principal

        # Close the context
        try:
            kerberos.authGSSServerClean(context)
        except kerberos.GSSError, ex:
            self.log.error("authGSSServerClean: %s" % (
                ex[0][0],
                ex[1][0],
            ))
            raise error.LoginFailed('Authentication System Failure %s(%s)' % (
                ex[0][0],
                ex[1][0],
            ))

        # If we successfully decoded and verified the Kerberos credentials we need to add the Kerberos
        # response data to the outgoing request

        wwwauth = '%s %s' % (self.scheme, response)

        def responseFilterAddWWWAuthenticate(request,
                                             response):  # @UnusedVariable
            if response.code != responsecode.UNAUTHORIZED:
                response.headers.addRawHeader('www-authenticate', wwwauth)
            return response

        responseFilterAddWWWAuthenticate.handleErrors = True