def digest_auth(qop=None, user="******", passwd="passwd"): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ("auth", "auth-int"): qop = None if not request.headers.get("Authorization"): response = app.make_response("") response.status_code = 401 # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H( b"".join( [ getattr(request, "remote_addr", u"").encode("ascii"), b":", str(time.time()).encode("ascii"), b":", os.urandom(10), ] ) ) opaque = H(os.urandom(10)) auth = WWWAuthenticate("digest") auth.set_digest( "*****@*****.**", nonce, opaque=opaque, qop=("auth", "auth-int") if qop is None else (qop,) ) response.headers["WWW-Authenticate"] = auth.to_header() response.headers["Set-Cookie"] = "fake=fake_value" return response elif not (check_digest_auth(user, passwd) and request.headers.get("Cookie")): return status_code(401) return jsonify(authenticated=True, user=user)
def digest_auth(qop=None, user='******', passwd='passwd'): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ('auth', 'auth-int'): qop = None if 'Authorization' not in request.headers or \ not check_digest_auth(user, passwd) or \ not 'Cookie' in request.headers: response = app.make_response('') response.status_code = 401 # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H(b''.join([ getattr(request,'remote_addr',u'').encode('ascii'), b':', str(time.time()).encode('ascii'), b':', os.urandom(10) ])) opaque = H(os.urandom(10)) auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, )) response.headers['WWW-Authenticate'] = auth.to_header() response.headers['Set-Cookie'] = 'fake=fake_value' return response return jsonify(authenticated=True, user=user)
def handle_unauthorized(): authenticate = WWWAuthenticate() authenticate.set_basic('AdminLDAP Login') response = make_response(error_response( u'Authentifizierung erforderlich',401)) response.headers['WWW-Authenticate'] = authenticate.to_header() return response
def digest_auth(qop=None, user='******', passwd='passwd', algorithm='MD5'): """Prompts the user for authorization using HTTP Digest auth""" if algorithm not in ('MD5', 'SHA-256'): algorithm = 'MD5' if qop not in ('auth', 'auth-int'): qop = None if 'Authorization' not in request.headers or \ not check_digest_auth(user, passwd) or \ 'Cookie' not in request.headers: response = app.make_response('') response.status_code = 401 # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H( b''.join([ getattr(request, 'remote_addr', u'').encode('ascii'), b':', str(time.time()).encode('ascii'), b':', os.urandom(10) ]), "MD5") opaque = H(os.urandom(10), "MD5") auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, ), algorithm=algorithm) response.headers['WWW-Authenticate'] = auth.to_header() response.headers['Set-Cookie'] = 'fake=fake_value' return response return jsonify(authenticated=True, user=user)
def parse_www_authenticate_header(value, on_update = None): if not value: return WWWAuthenticate(on_update=on_update) try: auth_type, auth_info = value.split(None, 1) auth_type = auth_type.lower() except (ValueError, AttributeError): return WWWAuthenticate(value.strip().lower(), on_update=on_update) return WWWAuthenticate(auth_type, parse_dict_header(auth_info), on_update)
def digest_auth(qop=None, user='******', passwd='passwd', checkCookie=True): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ('auth', 'auth-int'): qop = None try: remoteAddr = request.remote_addr or u'' authInHeaders = 'Authorization' in request.headers digestCheck = authInHeaders and request.headers.get( 'Authorization').startswith('Digest ') authCheck = authInHeaders and digestCheck and check_digest_auth( user, passwd) if not all([authInHeaders, digestCheck, authCheck]): # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H(b':'.join([ remoteAddr.encode('ascii'), str(time.time()).encode('ascii'), os.urandom(10) ])) opaque = H(os.urandom(10)) response = app.make_response( jsonify(authenticated=False, user=user, authInHeaders=authInHeaders, digestCheck=digestCheck, authCheck=authCheck, headers=dict(request.headers))) response.status_code = 401 auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, )) response.headers['WWW-Authenticate'] = auth.to_header() if checkCookie is True: response.headers['Set-Cookie'] = 'auth=%s' % remoteAddr return response elif checkCookie is True and request.cookies.get('auth') != remoteAddr: # check for auth challange cookie per https://github.com/Runscope/httpbin/issues/124 response = app.make_response( 'Missing the cookie set in the 401 response. ' 'This client seems broken. To bypass this check use the digest-auth-nocookie route.' ) response.status_code = 403 return response except Exception as e: response = app.make_response('Error: %s' % str(e)) response.status_code = 500 return response return jsonify(authenticated=True, user=user)
def __init__(self, error=None, status=401, headers=None): www_auth_header = WWWAuthenticate(auth_type="Bearer") www_auth_header["realm"] = "api.districtr.org" if error is not None: www_auth_header["error"] = error if headers is None: headers = dict() headers["WWW-Authenticate"] = www_auth_header.to_header() super().__init__(None, status, headers)
def parse_www_authenticate_header(value, on_update=None): """Parse an HTTP WWW-Authenticate header into a :class:`WWWAuthenticate` object. :param value: a WWW-Authenticate header to parse. :param on_update: an optional callable that is called every time a value on the :class:`WWWAuthenticate` object is changed. :return: a :class:`WWWAuthenticate` object. """ if not value: return WWWAuthenticate(on_update=on_update) try: auth_type, auth_info = value.split(None, 1) auth_type = auth_type.lower() except (ValueError, AttributeError): return WWWAuthenticate(value.lower(), on_update=on_update) return WWWAuthenticate(auth_type, parse_dict_header(auth_info), on_update)
def digest_auth(qop=None, user='******', passwd='passwd', checkCookie=True): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ('auth', 'auth-int'): qop = None try: remoteAddr = request.remote_addr or u'' authInHeaders = 'Authorization' in request.headers digestCheck = authInHeaders and request.headers.get('Authorization').startswith('Digest ') authCheck = authInHeaders and digestCheck and check_digest_auth(user, passwd) if not all([authInHeaders, digestCheck, authCheck]): # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H(b':'.join([ remoteAddr.encode('ascii'), str(time.time()).encode('ascii'), os.urandom(10) ])) opaque = H(os.urandom(10)) response = app.make_response(jsonify( authenticated=False, user=user, authInHeaders=authInHeaders, digestCheck=digestCheck, authCheck=authCheck, headers=dict(request.headers))) response.status_code = 401 auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, )) response.headers['WWW-Authenticate'] = auth.to_header() if checkCookie is True: response.headers['Set-Cookie'] = 'auth=%s' % remoteAddr return response elif checkCookie is True and request.cookies.get('auth') != remoteAddr: # check for auth challange cookie per https://github.com/Runscope/httpbin/issues/124 response = app.make_response('Missing the cookie set in the 401 response. ' 'This client seems broken. To bypass this check use the digest-auth-nocookie route.') response.status_code = 403 return response except Exception as e: response = app.make_response('Error: %s' % str(e)) response.status_code = 500 return response return jsonify(authenticated=True, user=user)
def test_unauthorized_www_authenticate(): basic = WWWAuthenticate() basic.set_basic("test") digest = WWWAuthenticate() digest.set_digest("test", "test") exc = exceptions.Unauthorized(www_authenticate=basic) h = dict(exc.get_headers({})) assert h["WWW-Authenticate"] == str(basic) exc = exceptions.Unauthorized(www_authenticate=[digest, basic]) h = dict(exc.get_headers({})) assert h["WWW-Authenticate"] == ", ".join((str(digest), str(basic)))
def digest_auth(qop=None, user="******", passwd="passwd"): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ("auth", "auth-int"): qop = None if not request.headers.get("Authorization"): response = app.make_response("") response.status_code = 401 nonce = H("%s:%d:%s" % (request.remote_addr, time.time(), os.urandom(10))) opaque = H(os.urandom(10)) auth = WWWAuthenticate("digest") auth.set_digest( "*****@*****.**", nonce, opaque=opaque, qop=("auth", "auth-int") if qop is None else (qop,) ) response.headers["WWW-Authenticate"] = auth.to_header() return response elif not check_digest_auth(user, passwd): return status_code(401) return jsonify(authenticated=True, user=user)
def digest_auth(qop=None, user='******', passwd='passwd'): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ('auth', 'auth-int'): qop = None if not request.headers.get('Authorization'): response = app.make_response('') response.status_code = 401 nonce = H("%s:%d:%s" % (request.remote_addr, time.time(), os.urandom(10))) opaque = H(os.urandom(10)) auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, )) response.headers['WWW-Authenticate'] = auth.to_header() return response elif not check_digest_auth(user, passwd): return status_code(403) return jsonify(authenticated=True, user=user)
def digest_auth(qop=None, user='******', passwd='passwd'): """Prompts the user for authorization using HTTP Digest auth""" if qop not in ('auth', 'auth-int'): qop = None if not request.headers.get('Authorization'): response = app.make_response('') response.status_code = 401 nonce = H("%s:%d:%s" % (request.remote_addr, time.time(), os.urandom(10))) opaque = H(os.urandom(10)) auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, )) response.headers['WWW-Authenticate'] = auth.to_header() return response elif not check_digest_auth(user, passwd): return status_code(403) return dict(authenticated=True, user=user)
def digest_challenge_response(app, qop, algorithm, stale=False): response = app.make_response('') response.status_code = 401 # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H( b''.join([ getattr(request, 'remote_addr', u'').encode('ascii'), b':', str(time.time()).encode('ascii'), b':', os.urandom(10) ]), "MD5") opaque = H(os.urandom(10), "MD5") auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop, ), algorithm=algorithm) auth.stale = stale response.headers['WWW-Authenticate'] = auth.to_header() return response
def digest_challenge_response(app, qop, algorithm, stale = False): response = app.make_response('') response.status_code = 401 # RFC2616 Section4.2: HTTP headers are ASCII. That means # request.remote_addr was originally ASCII, so I should be able to # encode it back to ascii. Also, RFC2617 says about nonces: "The # contents of the nonce are implementation dependent" nonce = H(b''.join([ getattr(request, 'remote_addr', u'').encode('ascii'), b':', str(time.time()).encode('ascii'), b':', os.urandom(10) ]), algorithm) opaque = H(os.urandom(10), algorithm) auth = WWWAuthenticate("digest") auth.set_digest('*****@*****.**', nonce, opaque=opaque, qop=('auth', 'auth-int') if qop is None else (qop,), algorithm=algorithm) auth.stale = stale response.headers['WWW-Authenticate'] = auth.to_header() return response
def test_unauthorized_www_authenticate(): basic = WWWAuthenticate() basic.set_basic("test") digest = WWWAuthenticate() digest.set_digest("test", "test") exc = exceptions.Unauthorized(www_authenticate=basic) h = Headers(exc.get_headers({})) assert h["WWW-Authenticate"] == str(basic) exc = exceptions.Unauthorized(www_authenticate=[digest, basic]) h = Headers(exc.get_headers({})) assert h.get_all("WWW-Authenticate") == [str(digest), str(basic)] exc = exceptions.Unauthorized() h = Headers(exc.get_headers({})) assert "WWW-Authenticate" not in h
def test_unauthorized_www_authenticate(): basic = WWWAuthenticate() basic.set_basic("test") digest = WWWAuthenticate() digest.set_digest("test", "test") exc = exceptions.Unauthorized(www_authenticate=basic) h = dict(exc.get_headers({})) assert h['WWW-Authenticate'] == str(basic) exc = exceptions.Unauthorized(www_authenticate=[digest, basic]) h = dict(exc.get_headers({})) assert h['WWW-Authenticate'] == ', '.join((str(digest), str(basic)))
""" Exceptions for the API. """ import inspect import logging import werkzeug.exceptions from flask import jsonify from typing import Any from werkzeug.exceptions import Unauthorized from werkzeug.datastructures import WWWAuthenticate from .utils import export LOG = logging.getLogger(__name__) WWW_AUTHENTICATE = WWWAuthenticate("basic", {"realm": "api"}) @export class AuthenticationRequired(Unauthorized): """ A specialized :class:`werkzeug.exceptions.Unauthorized` with a preset ``WWW-Authenticate`` header. """ def get_headers(self, *args, **kwargs): """ Unconditionally adds a statically defined ``WWW-Authenticate`` header using :const:`WWW_AUTHENTICATE`. This will be rendered unnecessary when the latest dev version of werkzeug is released, as it has another mechanism for passing through the header value.
def unauthorized(): auth = WWWAuthenticate() auth.set_basic() abort(401, www_authenticate=auth)
def _create_unauthorized(description, realm=DEFAULT_REALM): www_authenticate = WWWAuthenticate() www_authenticate.set_basic(realm=realm) return Unauthorized(description=description, www_authenticate=www_authenticate.to_header())
def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]: raise Unauthorized("Foo < Bar", www_authenticate=WWWAuthenticate("Test"))
def on_update(www_auth: WWWAuthenticate) -> None: if not www_auth and "www-authenticate" in self.headers: del self.headers["www-authenticate"] elif www_auth: self.headers["WWW-Authenticate"] = www_auth.to_header()
def get_basic_auth(realm=None): basic_auth = WWWAuthenticate() basic_auth.set_basic(realm=realm or 'Authentication required') return basic_auth.to_header()