def _get_challenge_params(self, request, params=None, nonce=None):
     """Generate a fresh set of challenge parameters."""
     # Parse the parameters from the incoming request.
     # We're only looking for username, so don't bother validating
     # any other parameters that may be present.
     if params is None:
         params = parse_authz_header(request)
         if params is None:
             return {}
     # If they didn't provide the username, they get a blank challenge.
     # This is the first request in the handshake.
     username = params.get("username")
     if username is None:
         return {}
     # If they did provide the username, then they need to know the
     # salt, server-side key, etc.  This is the second request.
     (algorithm, salt, verifier) = self._get_verifier(username)
     if verifier is None:
         return {}
     new_params = {}
     new_params["algorithm"] = algorithm
     new_params["salt"] = salt
     # Generate new nonce if needed
     if nonce is None:
         nonce = self.nonce_manager.generate_nonce(request)
     new_params["nonce"] = nonce
     # Calculate the corresponding server public key.
     privkey = self._get_privkey(nonce)
     pubkey = calculate_server_pubkey(params, privkey, verifier)
     new_params["skey"] = b64encode(int_to_bytes(pubkey))
     # That'll do it.
     return new_params
def calculate_request_hmac(request, params=None, **kwds):
    """Calculate the expected HMAC for the given request.

    This function calculates the HMAC of the given request, using parameters
    from the request or from the optional "params" dict.  For client-side
    calculation you must provide "privkey" and "password" as keyword args;
    for server-side calculation you must provide "privkey" and "verifier".
    """
    if params is None:
        params = parse_authz_header(request)
    hashmod = ALGORITHMS[params.get("algorithm", DEFAULT_ALGORITHM)][3]
    secret = int_to_bytes(calculate_shared_secret(params, **kwds))
    hasher = hmac.new(secret, "", hashmod)
    # The hash covers: ckey, skey, nonce, nc, method, uri, headers.
    # They must all be as they will appear on the wire, i.e. SRP integers
    # in b64 encoding, other bytestrings in hex.
    hasher.update(params["ckey"])
    hasher.update(":")
    hasher.update(params["skey"])
    hasher.update(":")
    hasher.update(params["nonce"])
    hasher.update(":")
    hasher.update(params["nc"])
    hasher.update(":")
    hasher.update(request.method)
    hasher.update(":")
    hasher.update(params["uri"])
    hasher.update(":")
    hasher.update(request.environ.get("HTTP_CONTENT_TYPE", ""))
    hasher.update(":")
    hasher.update(request.environ.get("HTTP_CONTENT_LENGTH", ""))
    hasher.update(":")
    hasher.update(request.environ.get("HTTP_CONTENT_MD5", ""))
    # The output is also as on the wire, i.e. hex format.
    return hasher.hexdigest()
def calculate_request_hmac(request, params=None, **kwds):
    """Calculate the expected HMAC for the given request.

    This function calculates the HMAC of the given request, using parameters
    from the request or from the optional "params" dict.  For client-side
    calculation you must provide "privkey" and "password" as keyword args;
    for server-side calculation you must provide "privkey" and "verifier".
    """
    if params is None:
        params = parse_authz_header(request)
    hashmod = ALGORITHMS[params.get("algorithm", DEFAULT_ALGORITHM)][3]
    secret = int_to_bytes(calculate_shared_secret(params, **kwds))
    hasher = hmac.new(secret, "", hashmod)
    # The hash covers: ckey, skey, nonce, nc, method, uri, headers.
    # They must all be as they will appear on the wire, i.e. SRP integers
    # in b64 encoding, other bytestrings in hex.
    hasher.update(params["ckey"])
    hasher.update(":")
    hasher.update(params["skey"])
    hasher.update(":")
    hasher.update(params["nonce"])
    hasher.update(":")
    hasher.update(params["nc"])
    hasher.update(":")
    hasher.update(request.method)
    hasher.update(":")
    hasher.update(params["uri"])
    hasher.update(":")
    hasher.update(request.environ.get("HTTP_CONTENT_TYPE", ""))
    hasher.update(":")
    hasher.update(request.environ.get("HTTP_CONTENT_LENGTH", ""))
    hasher.update(":")
    hasher.update(request.environ.get("HTTP_CONTENT_MD5", ""))
    # The output is also as on the wire, i.e. hex format.
    return hasher.hexdigest()
 def _get_challenge_params(self, request, params=None, nonce=None):
     """Generate a fresh set of challenge parameters."""
     # Parse the parameters from the incoming request.
     # We're only looking for username, so don't bother validating
     # any other parameters that may be present.
     if params is None:
         params = parse_authz_header(request)
         if params is None:
             return {}
     # If they didn't provide the username, they get a blank challenge.
     # This is the first request in the handshake.
     username = params.get("username")
     if username is None:
         return {}
     # If they did provide the username, then they need to know the
     # salt, server-side key, etc.  This is the second request.
     (algorithm, salt, verifier) = self._get_verifier(username)
     if verifier is None:
         return {}
     new_params = {}
     new_params["algorithm"] = algorithm
     new_params["salt"] = salt
     # Generate new nonce if needed
     if nonce is None:
         nonce = self.nonce_manager.generate_nonce(request)
     new_params["nonce"] = nonce
     # Calculate the corresponding server public key.
     privkey = self._get_privkey(nonce)
     pubkey = calculate_server_pubkey(params, privkey, verifier)
     new_params["skey"] = b64encode(int_to_bytes(pubkey))
     # That'll do it.
     return new_params
def get_challenge(policy, request, username):
    """Get a new srp-hmac-auth challenge from the policy."""
    set_authz_header(request, dict(username=username))
    for name, value in policy.forget(request):
        if name == "WWW-Authenticate":
            req = make_request(HTTP_AUTHORIZATION=value)
            return parse_authz_header(req)
    raise ValueError("policy didn't issue a challenge")
def get_challenge(policy, request, username):
    """Get a new srp-hmac-auth challenge from the policy."""
    set_authz_header(request, dict(username=username))
    for name, value in policy.forget(request):
        if name == "WWW-Authenticate":
            req = make_request(HTTP_AUTHORIZATION=value)
            return parse_authz_header(req)
    raise ValueError("policy didn't issue a challenge")
    def _get_unvalidated_auth_params(self, request):
        """Extract srp-hmac-auth parameters from the request.

        This method extracts srp-hmac-auth parameters from the Authorization
        header and returns them as a dict.  If they are missing then None
        is returned.
        """
        try:
            params = parse_authz_header(request)
        except ValueError:
            params = None
        if params is None:
            return None
        if params["scheme"].lower() != "srp-hmac":
            return None
        return params
    def _get_unvalidated_auth_params(self, request):
        """Extract srp-hmac-auth parameters from the request.

        This method extracts srp-hmac-auth parameters from the Authorization
        header and returns them as a dict.  If they are missing then None
        is returned.
        """
        try:
            params = parse_authz_header(request)
        except ValueError:
            params = None
        if params is None:
            return None
        if params["scheme"].lower() != "srp-hmac":
            return None
        return params
def validate_uri(request, params=None):
    """Validate that the digest URI matches the request environment.

    This is a helper function to check that srp-hmac-auth is being applied
    to the correct URI.  It matches the given request environment against
    the URI specified in the srp-hmac auth parameters, returning True if
    they are equiavlent and False otherwise.
    """
    if params is None:
        params = parse_authz_header(request)
    uri = params["uri"]
    req_uri = wsgiref.util.request_uri(request.environ)
    if uri != req_uri:
        p_req_uri = urlparse(req_uri)
        if not p_req_uri.query:
            if uri != p_req_uri.path:
                return False
        else:
            if uri != "%s?%s" % (p_req_uri.path, p_req_uri.query):
                return False
    return True
def validate_uri(request, params=None):
    """Validate that the digest URI matches the request environment.

    This is a helper function to check that srp-hmac-auth is being applied
    to the correct URI.  It matches the given request environment against
    the URI specified in the srp-hmac auth parameters, returning True if
    they are equiavlent and False otherwise.
    """
    if params is None:
        params = parse_authz_header(request)
    uri = params["uri"]
    req_uri = wsgiref.util.request_uri(request.environ)
    if uri != req_uri:
        p_req_uri = urlparse(req_uri)
        if not p_req_uri.query:
            if uri != p_req_uri.path:
                return False
        else:
            if uri != "%s?%s" % (p_req_uri.path, p_req_uri.query):
                return False
    return True
def validate_nonce(nonce_manager, request, params=None):
    """Validate that the auth parameters contain a fresh nonce.

    This is a helper function to check that the provided srp-hmac-auth
    credentials contain a valid, up-to-date nonce.  It calls various
    methods on the provided NonceManager object in order to query and
    update the state of the nonce database.

    Returns True if the nonce is valid, False otherwise.
    """
    if params is None:
        params = parse_authz_header(request)
    # Check that the nonce itself is valid.
    nonce = params["nonce"]
    if not nonce_manager.is_valid_nonce(nonce, request):
        return False
    # Check that the nonce-count is valid.
    # RFC-2617 says the nonce-count must be an 8-char-long hex number.
    # We convert to an integer since they take less memory than strings.
    # We enforce the length limit strictly since flooding the server with
    # many large nonce-counts could cause a DOS via memory exhaustion.
    nc_new = params.get("nc", None)
    if nc_new is not None:
        try:
            nc_new = int(nc_new[:8], 16)
        except ValueError:
            return False
    # Check that the the nonce-count is strictly increasing.
    nc_old = nonce_manager.get_nonce_count(nonce)
    if nc_old is not None:
        if nc_new is None or nc_new <= nc_old:
            return False
    if nc_new is not None:
        nonce_manager.set_nonce_count(nonce, nc_new)
    # Looks good!
    return True
def validate_nonce(nonce_manager, request, params=None):
    """Validate that the auth parameters contain a fresh nonce.

    This is a helper function to check that the provided srp-hmac-auth
    credentials contain a valid, up-to-date nonce.  It calls various
    methods on the provided NonceManager object in order to query and
    update the state of the nonce database.

    Returns True if the nonce is valid, False otherwise.
    """
    if params is None:
        params = parse_authz_header(request)
    # Check that the nonce itself is valid.
    nonce = params["nonce"]
    if not nonce_manager.is_valid_nonce(nonce, request):
        return False
    # Check that the nonce-count is valid.
    # RFC-2617 says the nonce-count must be an 8-char-long hex number.
    # We convert to an integer since they take less memory than strings.
    # We enforce the length limit strictly since flooding the server with
    # many large nonce-counts could cause a DOS via memory exhaustion.
    nc_new = params.get("nc", None)
    if nc_new is not None:
        try:
            nc_new = int(nc_new[:8], 16)
        except ValueError:
            return False
    # Check that the the nonce-count is strictly increasing.
    nc_old = nonce_manager.get_nonce_count(nonce)
    if nc_old is not None:
        if nc_new is None or nc_new <= nc_old:
            return False
    if nc_new is not None:
        nonce_manager.set_nonce_count(nonce, nc_new)
    # Looks good!
    return True
def parse_authz_value(authz):
    environ = {"HTTP_AUTHORIZATION": authz}
    req = DummyRequest(environ=environ)
    return parse_authz_header(req)