Esempio n. 1
0
    def test_cookie_no_request(self):
        from webob.cookies import CookieProfile

        cookie = CookieProfile("uns")

        with pytest.raises(ValueError):
            cookie.get_value()
Esempio n. 2
0
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))
Esempio n. 3
0
 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
Esempio n. 5
0
    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,
        )
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    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)
Esempio n. 9
0
    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)
Esempio n. 10
0
    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
Esempio n. 11
0
 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
Esempio n. 12
0
    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`')
Esempio n. 13
0
    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
Esempio n. 14
0
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))
Esempio n. 15
0
    def test_cookie_no_request(self):
        from webob.cookies import CookieProfile
        cookie = CookieProfile('uns')

        self.assertRaises(ValueError, cookie.get_value)
Esempio n. 16
0
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 []
Esempio n. 17
0
 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)
Esempio n. 18
0
    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,
        )
Esempio n. 19
0
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
Esempio n. 20
0
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
Esempio n. 21
0
    def test_cookie_no_request(self):
        from webob.cookies import CookieProfile
        cookie = CookieProfile('uns')

        with pytest.raises(ValueError):
            cookie.get_value()