def test_cookie_no_request(self): from webob.cookies import CookieProfile cookie = CookieProfile("uns") with pytest.raises(ValueError): cookie.get_value()
class CookieCSRFStoragePolicy(object): """ An alternative CSRF implementation that stores its information in unauthenticated cookies, known as the 'Double Submit Cookie' method in the `OWASP CSRF guidelines <https://www.owasp.org/index.php/ Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet# Double_Submit_Cookie>`_. This gives some additional flexibility with regards to scaling as the tokens can be generated and verified by a front-end server. .. versionadded:: 1.9 .. versionchanged: 1.10 Added the ``samesite`` option and made the default ``'Lax'``. """ _token_factory = staticmethod(lambda: text_(uuid.uuid4().hex)) def __init__(self, cookie_name='csrf_token', secure=False, httponly=False, domain=None, max_age=None, path='/', samesite='Lax'): serializer = SimpleSerializer() self.cookie_profile = CookieProfile( cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=httponly, path=path, domains=[domain], serializer=serializer, samesite=samesite, ) self.cookie_name = cookie_name def new_csrf_token(self, request): """ Sets a new CSRF token into the request and returns it. """ token = self._token_factory() request.cookies[self.cookie_name] = token def set_cookie(request, response): self.cookie_profile.set_cookies( response, token, ) request.add_response_callback(set_cookie) return token def get_csrf_token(self, request): """ Returns the currently active CSRF token by checking the cookies sent with the current request.""" bound_cookies = self.cookie_profile.bind(request) token = bound_cookies.get_value() if not token: token = self.new_csrf_token(request) return token def check_csrf_token(self, request, supplied_token): """ Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ( bytes_(expected_token), bytes_(supplied_token))
def __init__(self, cookie_name='csrf_token', secure=False, httponly=False, domain=None, max_age=None, path='/'): serializer = _SimpleSerializer() self.cookie_profile = CookieProfile(cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=httponly, path=path, domains=[domain], serializer=serializer) self.cookie_name = cookie_name
def __init__(self, secret, cookie_name='auth_tkt', secure=False, include_ip=False, timeout=None, reissue_time=None, max_age=None, http_only=False, path="/", wild_domain=True, hashalg='md5', parent_domain=False, domain=None): serializer = _SimpleSerializer() self.cookie_profile = CookieProfile(cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=http_only, path=path, serializer=serializer) self.secret = secret self.cookie_name = cookie_name self.secure = secure self.include_ip = include_ip self.timeout = timeout self.reissue_time = reissue_time self.max_age = max_age self.wild_domain = wild_domain self.parent_domain = parent_domain self.domain = domain self.hashalg = hashalg
def __init__( self, private_key, public_key=None, algorithm="HS512", leeway=0, expiration=None, default_claims=None, http_header="Authorization", auth_type="JWT", callback=None, json_encoder=None, audience=None, cookie_name=None, https_only=True, reissue_time=None, cookie_path=None, ): super(JWTCookieAuthenticationPolicy, self).__init__( private_key, public_key, algorithm, leeway, expiration, default_claims, http_header, auth_type, callback, json_encoder, audience, ) self.https_only = asbool(https_only) self.cookie_name = cookie_name or "Authorization" self.max_age = self.expiration and self.expiration.total_seconds() if reissue_time and isinstance(reissue_time, datetime.timedelta): reissue_time = reissue_time.total_seconds() self.reissue_time = reissue_time self.cookie_profile = CookieProfile( cookie_name=self.cookie_name, secure=self.https_only, max_age=self.max_age, httponly=True, path=cookie_path, )
def makeOne(self, secret='seekrit', salt='salty', name='uns', **kw): if 'request' in kw: request = kw['request'] del kw['request'] else: request = self.makeOneRequest() from webob.cookies import SignedCookieProfile as CookieProfile return CookieProfile(secret, salt, name, **kw)(request)
def makeOne(self, name='uns', **kw): if 'request' in kw: request = kw['request'] del kw['request'] else: request = self.makeOneRequest() from webob.cookies import CookieProfile return CookieProfile(name, **kw)(request)
def makeOne(self, secret="seekrit", salt="salty", name="uns", **kw): if "request" in kw: request = kw["request"] del kw["request"] else: request = self.makeOneRequest() from webob.cookies import SignedCookieProfile as CookieProfile return CookieProfile(secret, salt, name, **kw)(request)
def makeOne(self, name="uns", **kw): if "request" in kw: request = kw["request"] del kw["request"] else: request = self.makeOneRequest() from webob.cookies import CookieProfile return CookieProfile(name, **kw)(request)
def __init__( self, secret, cookie_name='auth_tkt', secure=False, include_ip=False, timeout=None, reissue_time=None, max_age=None, http_only=False, path="/", wild_domain=True, hashalg=None, parent_domain=False, domain=None, samesite='Lax', ): if hashalg is None: hashalg = 'md5' warnings.warn( 'The default "hashalg" is "md5" and will change to "sha512" ' 'in Pyramid 2.0. To preserve the current behavior, ' 'explicitly pass hashalg="md5".', DeprecationWarning, stacklevel=1, ) serializer = SimpleSerializer() self.cookie_profile = CookieProfile( cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=http_only, path=path, serializer=serializer, samesite=samesite, ) self.secret = secret self.cookie_name = cookie_name self.secure = secure self.include_ip = include_ip self.timeout = timeout if timeout is None else int(timeout) self.reissue_time = (reissue_time if reissue_time is None else int(reissue_time)) self.max_age = max_age if max_age is None else int(max_age) self.wild_domain = wild_domain self.parent_domain = parent_domain self.domain = domain self.hashalg = hashalg
def __init__(self, cookie_name='csrf_token', secure=False, httponly=False, domain=None, max_age=None, path='/', samesite='Lax'): serializer = SimpleSerializer() self.cookie_profile = CookieProfile( cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=httponly, path=path, domains=[domain], serializer=serializer, samesite=samesite, ) self.cookie_name = cookie_name
def __init__( self, application_name, header_key=None, cookie_key=None): self.application_name = application_name self.header_key = header_key self.cookie_key = cookie_key if self.cookie_key: self.cookie_profile = CookieProfile( cookie_name=self.cookie_key, path='/', serializer=SimpleSerializer()) if not self.header_key and not self.cookie_key: raise ValueError('Please define a key for authentication validation. `header_key` or `cookie_key`')
def __init__( self, secret, cookie_name='auth_tkt', secure=False, include_ip=False, timeout=None, reissue_time=None, max_age=None, http_only=False, path="/", wild_domain=True, hashalg='md5', parent_domain=False, domain=None, samesite='Lax', ): serializer = SimpleSerializer() self.cookie_profile = CookieProfile( cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=http_only, path=path, serializer=serializer, samesite=samesite, ) self.secret = secret self.cookie_name = cookie_name self.secure = secure self.include_ip = include_ip self.timeout = timeout if timeout is None else int(timeout) self.reissue_time = (reissue_time if reissue_time is None else int(reissue_time)) self.max_age = max_age if max_age is None else int(max_age) self.wild_domain = wild_domain self.parent_domain = parent_domain self.domain = domain self.hashalg = hashalg
class CookieCSRFStoragePolicy(object): """ An alternative CSRF implementation that stores its information in unauthenticated cookies, known as the 'Double Submit Cookie' method in the `OWASP CSRF guidelines <https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie>`_. This gives some additional flexibility with regards to scaling as the tokens can be generated and verified by a front-end server. .. versionadded:: 1.9 .. versionchanged: 1.10 Added the ``samesite`` option and made the default ``'Lax'``. """ _token_factory = staticmethod(lambda: text_(uuid.uuid4().hex)) def __init__( self, cookie_name='csrf_token', secure=False, httponly=False, domain=None, max_age=None, path='/', samesite='Lax', ): self.cookie_profile = CookieProfile( cookie_name=cookie_name, secure=secure, max_age=max_age, httponly=httponly, path=path, domains=[domain], serializer=SimpleSerializer(), samesite=samesite, ) self.cookie_name = cookie_name def new_csrf_token(self, request): """ Sets a new CSRF token into the request and returns it. """ token = self._token_factory() request.cookies[self.cookie_name] = token def set_cookie(request, response): self.cookie_profile.set_cookies(response, token) request.add_response_callback(set_cookie) return token def get_csrf_token(self, request): """ Returns the currently active CSRF token by checking the cookies sent with the current request.""" bound_cookies = self.cookie_profile.bind(request) token = bound_cookies.get_value() if not token: token = self.new_csrf_token(request) return token def check_csrf_token(self, request, supplied_token): """ Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ(bytes_(expected_token), bytes_(supplied_token))
def test_cookie_no_request(self): from webob.cookies import CookieProfile cookie = CookieProfile('uns') self.assertRaises(ValueError, cookie.get_value)
class ApplicationHeaderAuthenticationPolicy(object): def __init__( self, application_name, header_key=None, cookie_key=None): self.application_name = application_name self.header_key = header_key self.cookie_key = cookie_key if self.cookie_key: self.cookie_profile = CookieProfile( cookie_name=self.cookie_key, path='/', serializer=SimpleSerializer()) if not self.header_key and not self.cookie_key: raise ValueError('Please define a key for authentication validation. `header_key` or `cookie_key`') def get_authenticated_session(self, request): have_cache = hasattr(request, 'session_cache') if have_cache and 'authenticated' in request.session_cache: return request.session_cache['authenticated'] authenticated = None authorization_string = self.unauthenticated_userid(request) if authorization_string: authorization_info = authorization_string.split('-', 1) authorization_type = authorization_info[0].lower() if (len(authorization_info) == 2 and authorization_info[1] and authorization_type in ('token', 'apikey')): authenticated = ( getattr(request.applications, self.application_name) .get_authorization(authorization_type, authorization_info[1])) if authenticated and not isinstance(authenticated, AuthenticatedSession): session_type = authorization_type == 'token' and 'user' or authorization_type authenticated = AuthenticatedSession(session_type, authenticated) if have_cache: request.session_cache['authenticated'] = authenticated return authenticated def authenticated_userid(self, request): return self.get_authenticated_session(request) def unauthenticated_userid(self, request): if self.header_key: userid = request.headers.get(self.header_key) if userid: return userid if self.cookie_key: userid = request.cookies.get(self.cookie_key) if userid: return userid def effective_principals(self, request): authenticated = self.get_authenticated_session(request) if not authenticated: return [Everyone, NotAuthenticated] else: return authenticated.get_principals() def remember(self, request, token): if self.cookie_key: return self.cookie_profile.get_headers('Token-%s' % token) else: return [] def forget(self, request): if self.cookie_key: return self.cookie_profile.get_headers(None) else: return []
def get_profile(self, realm): if realm not in self._cache: self._cache[realm] = CookieProfile(self.prefix + realm, max_age=self.max_age) return self._cache.get(realm)
def __init__( self, private_key, public_key=None, algorithm="HS512", leeway=0, expiration=None, default_claims=None, http_header="Authorization", auth_type="JWT", callback=None, json_encoder=None, audience=None, cookie_name=None, https_only=True, samesite=None, reissue_time=None, cookie_path=None, accept_header=False, header_first=False, reissue_callback=None, ): super(JWTCookieAuthenticationPolicy, self).__init__( private_key, public_key, algorithm, leeway, expiration, default_claims, http_header, auth_type, callback, json_encoder, audience, ) self.https_only = asbool(https_only) self.samesite = samesite self.cookie_name = cookie_name or "Authorization" self.max_age = self.expiration and self.expiration.total_seconds() if reissue_time and isinstance(reissue_time, datetime.timedelta): reissue_time = reissue_time.total_seconds() self.reissue_time = int( reissue_time) if reissue_time is not None else None self.accept_header = asbool(accept_header) self.header_first = asbool(header_first) def _default_reissue_callback(request, principal, **claims): return self.create_token(principal, self.expiration, self.audience, **claims) self.reissue_callback = reissue_callback or _default_reissue_callback self.cookie_profile = CookieProfile( cookie_name=self.cookie_name, secure=self.https_only, samesite=self.samesite, max_age=self.max_age, httponly=True, path=cookie_path, )
class JWTCookieAuthenticationPolicy(JWTAuthenticationPolicy): def __init__( self, private_key, public_key=None, algorithm="HS512", leeway=0, expiration=None, default_claims=None, http_header="Authorization", auth_type="JWT", callback=None, json_encoder=None, audience=None, cookie_name=None, https_only=True, samesite=None, reissue_time=None, cookie_path=None, accept_header=False, header_first=False, reissue_callback=None, ): super(JWTCookieAuthenticationPolicy, self).__init__( private_key, public_key, algorithm, leeway, expiration, default_claims, http_header, auth_type, callback, json_encoder, audience, ) self.https_only = asbool(https_only) self.samesite = samesite self.cookie_name = cookie_name or "Authorization" self.max_age = self.expiration and self.expiration.total_seconds() if reissue_time and isinstance(reissue_time, datetime.timedelta): reissue_time = reissue_time.total_seconds() self.reissue_time = int( reissue_time) if reissue_time is not None else None self.accept_header = asbool(accept_header) self.header_first = asbool(header_first) def _default_reissue_callback(request, principal, **claims): return self.create_token(principal, self.expiration, self.audience, **claims) self.reissue_callback = reissue_callback or _default_reissue_callback self.cookie_profile = CookieProfile( cookie_name=self.cookie_name, secure=self.https_only, samesite=self.samesite, max_age=self.max_age, httponly=True, path=cookie_path, ) @staticmethod def make_from(policy, **kwargs): if not isinstance(policy, JWTAuthenticationPolicy): pol_type = policy.__class__.__name__ raise ValueError("Invalid policy type %s" % pol_type) return JWTCookieAuthenticationPolicy( private_key=policy.private_key, public_key=policy.public_key, algorithm=policy.algorithm, leeway=policy.leeway, expiration=policy.expiration, default_claims=policy.default_claims, http_header=policy.http_header, auth_type=policy.auth_type, callback=policy.callback, json_encoder=policy.json_encoder, audience=policy.audience, **kwargs) def _get_cookies(self, request, value, max_age=None, domains=None): profile = self.cookie_profile(request) if domains is None: domains = [request.domain] kw = {"domains": domains} if max_age is not None: kw["max_age"] = max_age headers = profile.get_headers(value, **kw) return headers def remember(self, request, token, **kw): if hasattr(request, "_jwt_cookie_reissued") and request._jwt_cookie_reissued: request._jwt_cookie_reissue_revoked = True return self._get_cookies(request, token, self.max_age, domains=kw.get("domains")) def forget(self, request): request._jwt_cookie_reissue_revoked = True return self._get_cookies(request, None) def get_token(self, request): if self.accept_header: token = super().get_token(request) if token and self.header_first: return token profile = self.cookie_profile.bind(request) cookie = profile.get_value() if not cookie and self.accept_header: return token # if we handle reissue at this early stage we avoid reissuing cookies # on requests that used header authentication if (cookie and self.reissue_time is not None and not hasattr(request, "_jwt_cookie_reissued")): claims = self._internal_jwt_claims(request, cookie) if claims: self._handle_reissue(request, claims) return cookie # store claims in request to avoid decoding twice in reissue_callback def _internal_jwt_claims(self, request, token): if not hasattr(request, "_internal_jwt_claims"): request._internal_jwt_claims = self.jwt_decode(request, token) return request._internal_jwt_claims # redefined get_claims to use internally stored claims def get_claims(self, request): token = self.get_token(request) if not token: return {} return self._internal_jwt_claims(request, token) def _handle_reissue(self, request, claims): if not request or not claims: raise ValueError( "Cannot handle JWT reissue: insufficient arguments") if "iat" not in claims: raise ReissueError("Token claim's is missing IAT") if "sub" not in claims: raise ReissueError("Token claim's is missing SUB") # avoid getting called again from reissue_callback via get_token() or get_claims() request._jwt_cookie_reissued = False token_dt = claims["iat"] principal = claims["sub"] now = time.time() if now < token_dt + self.reissue_time: # Token not yet eligible for reissuing return try: token = self.reissue_callback(request, principal, **claims) except Exception as e: raise ReissueError("Callback raised exception") from e def reissue_jwt_cookie(request, response): if not hasattr(request, "_jwt_cookie_reissue_revoked"): for k, v in headers: response.headerlist.append((k, v)) if token: headers = self.remember(request, token) request.add_response_callback(reissue_jwt_cookie) request._jwt_cookie_reissued = True
class JWTCookieAuthenticationPolicy(JWTAuthenticationPolicy): def __init__( self, private_key, public_key=None, algorithm="HS512", leeway=0, expiration=None, default_claims=None, http_header="Authorization", auth_type="JWT", callback=None, json_encoder=None, audience=None, cookie_name=None, https_only=True, reissue_time=None, cookie_path=None, ): super(JWTCookieAuthenticationPolicy, self).__init__( private_key, public_key, algorithm, leeway, expiration, default_claims, http_header, auth_type, callback, json_encoder, audience, ) self.https_only = https_only self.cookie_name = cookie_name or "Authorization" self.max_age = self.expiration and self.expiration.total_seconds() if reissue_time and isinstance(reissue_time, datetime.timedelta): reissue_time = reissue_time.total_seconds() self.reissue_time = reissue_time serializer = _SimpleSerializer() self.cookie_profile = CookieProfile( cookie_name=self.cookie_name, secure=self.https_only, max_age=self.max_age, httponly=True, path=cookie_path, serializer=serializer ) @staticmethod def make_from(policy, **kwargs): if not isinstance(policy, JWTAuthenticationPolicy): pol_type = policy.__class__.__name__ raise ValueError("Invalid policy type %s" % pol_type) return JWTCookieAuthenticationPolicy( private_key=policy.private_key, public_key=policy.public_key, algorithm=policy.algorithm, leeway=policy.leeway, expiration=policy.expiration, default_claims=policy.default_claims, http_header=policy.http_header, auth_type=policy.auth_type, callback=policy.callback, json_encoder=policy.json_encoder, audience=policy.audience, **kwargs ) def _get_cookies(self, request, value, max_age=None, domains=None): profile = self.cookie_profile(request) if domains is None: domains = [request.domain] kw = {"domains": domains} if max_age is not None: kw["max_age"] = max_age headers = profile.get_headers(value, **kw) return headers def remember(self, request, principal, **kw): token = self.create_token(principal, self.expiration, self.audience, **kw) if hasattr(request, "_jwt_cookie_reissued"): request._jwt_cookie_reissue_revoked = True domains = kw.get("domains") return self._get_cookies(request, token, self.max_age, domains=domains) def forget(self, request): request._jwt_cookie_reissue_revoked = True return self._get_cookies(request, None) def get_claims(self, request): profile = self.cookie_profile.bind(request) cookie = profile.get_value() reissue = self.reissue_time is not None if cookie is None: return {} claims = self.jwt_decode(request, cookie) if reissue and not hasattr(request, "_jwt_cookie_reissued"): self._handle_reissue(request, claims) return claims def _handle_reissue(self, request, claims): if not request or not claims: raise ValueError("Cannot handle JWT reissue: insufficient arguments") if "iat" not in claims: raise ReissueError("Token claim's is missing IAT") if "sub" not in claims: raise ReissueError("Token claim's is missing SUB") token_dt = claims["iat"] principal = claims["sub"] now = time.time() if now < token_dt + self.reissue_time: # Token not yet eligible for reissuing return extra_claims = dict( filter(lambda item: item[0] not in self.jwt_std_claims, claims.items()) ) headers = self.remember(request, principal, **extra_claims) def reissue_jwt_cookie(request, response): if not hasattr(request, "_jwt_cookie_reissue_revoked"): for k, v in headers: response.headerlist.append((k, v)) request.add_response_callback(reissue_jwt_cookie) request._jwt_cookie_reissued = True
def test_cookie_no_request(self): from webob.cookies import CookieProfile cookie = CookieProfile('uns') with pytest.raises(ValueError): cookie.get_value()