Skip to content

Commit

Permalink
Upgrade to Pyramid 2.0
Browse files Browse the repository at this point in the history
Bumps [pyramid](https://github.com/Pylons/pyramid) from 1.10.5 to 2.0.
- [Release notes](https://github.com/Pylons/pyramid/releases)
- [Changelog](https://github.com/Pylons/pyramid/blob/2.0/CHANGES.rst)
- [Commits](Pylons/pyramid@1.10.5...2.0)

Co-authored-by: dependabot[bot] <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
  • Loading branch information
2 people authored and seanh committed Apr 6, 2021
1 parent 1c64af8 commit c054c7f
Show file tree
Hide file tree
Showing 21 changed files with 448 additions and 413 deletions.
5 changes: 2 additions & 3 deletions checkmate/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pyramid_tm
from pyramid.session import SignedCookieSessionFactory

from checkmate.auth import AuthenticationPolicy, AuthorizationPolicy
from checkmate.security import SecurityPolicy

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -143,8 +143,7 @@ def _configure_auth(self, config):
)
config.set_session_factory(session_factory)

config.set_authentication_policy(AuthenticationPolicy())
config.set_authorization_policy(AuthorizationPolicy())
config.set_security_policy(SecurityPolicy())


def create_app(_=None, celery_worker=False, **settings): # pragma: no cover
Expand Down
152 changes: 0 additions & 152 deletions checkmate/auth.py

This file was deleted.

1 change: 0 additions & 1 deletion checkmate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Data and domain models."""

from checkmate.models.auth import Permissions, Principals
from checkmate.models.blocked_for import BlockedFor
from checkmate.models.db.allow_rule import AllowRule
from checkmate.models.db.custom_rule import CustomRule
Expand Down
27 changes: 0 additions & 27 deletions checkmate/models/auth.py

This file was deleted.

122 changes: 122 additions & 0 deletions checkmate/security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from enum import Enum
from typing import List, NamedTuple

from pyramid.authentication import (
SessionAuthenticationHelper,
extract_http_basic_credentials,
)
from pyramid.security import Allowed, Denied


class Permissions(Enum):
ADMIN = "admin"
CHECK_URL = "check_url"
ADD_TO_ALLOW_LIST = "add_to_allow_list"


class Identity(NamedTuple):
userid: str
permissions: List[str]


class CascadingSecurityPolicy:
def __init__(self, subpolicies):
self._subpolicies = subpolicies

def identity(self, request):
return self._effective_subpolicy(request).identity(request)

def authenticated_userid(self, request):
return self._effective_subpolicy(request).authenticated_userid(request)

def permits(self, request, context, permission):
return self._effective_subpolicy(request).permits(request, context, permission)

def forget(self, request, **kwargs):
return self._effective_subpolicy(request).forget(request, **kwargs)

def remember(self, request, userid, iface, **kwargs):
return self._get_specific_policy(iface).remember(request, userid, **kwargs)

def _effective_subpolicy(self, request):
for policy in self._subpolicies:
if policy.authenticated_userid(request):
return policy

return self._subpolicies[-1]

def _get_specific_policy(self, iface):
for policy in self._subpolicies:
if isinstance(policy, iface):
return policy

raise KeyError(
f"Could not find a policy matching the requested interface: {iface}"
)


class SecurityPolicy(CascadingSecurityPolicy):
def __init__(self):
super().__init__(
subpolicies=[HTTPBasicAuthSecurityPolicy(), GoogleSecurityPolicy()]
)


class GoogleSecurityPolicy:
def __init__(self):
self._session_authentication_helper = SessionAuthenticationHelper()

def identity(self, request):
userid = self.authenticated_userid(request)

if userid and userid.endswith("@hypothes.is"):
return Identity(
userid, permissions=[Permissions.ADMIN, Permissions.ADD_TO_ALLOW_LIST]
)

return Identity("", [])

def authenticated_userid(self, request):
return self._session_authentication_helper.authenticated_userid(request)

def permits(self, request, _context, permission):
if permission in self.identity(request).permissions:
return Allowed("allowed")

return Denied("denied")

def remember(self, request, userid, **kwargs):
return self._session_authentication_helper.remember(request, userid, **kwargs)

def forget(self, request, **kwargs):
return self._session_authentication_helper.forget(request, **kwargs)


class HTTPBasicAuthSecurityPolicy:
def identity(self, request):
userid = self.authenticated_userid(request)

if userid:
return Identity(userid, permissions=[Permissions.CHECK_URL])

return Identity("", [])

def authenticated_userid(self, request): # pylint:disable=no-self-use
credentials = extract_http_basic_credentials(request)

if credentials:
return request.registry.settings["api_keys"].get(credentials.username)

return None

def permits(self, request, _context, permission):
if permission in self.identity(request).permissions:
return Allowed("allowed")

return Denied("denied")

def remember(self, request, userid, **kwargs):
pass

def forget(self, request, **kwargs):
pass
6 changes: 3 additions & 3 deletions checkmate/templates/admin/pages.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
{% endif %}
<br>

<h2>Effective Principals</h2>
<code>{{ request.effective_principals }}</code>
<h2>Permissions</h2>
<code>{{ request.identity.permissions }}</code>

<h2>Session</h2>
<code>{{ request.session }}</code>
Expand All @@ -25,4 +25,4 @@
<code>tox -qe dev --run-command "python bin/add_to_allow_list.py --session={{ session }} --route={{ request.route_url('add_to_allow_list') }}"</code>

<hr>
<a href="{{ request.route_url("logout") }}">Logout</a>
<a href="{{ request.route_url("logout") }}">Logout</a>
3 changes: 2 additions & 1 deletion checkmate/views/api/check_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from pyramid.view import view_config

from checkmate.exceptions import BadURLParameter, MalformedURL
from checkmate.models import BlockedFor, Permissions, Reason
from checkmate.models import BlockedFor, Reason
from checkmate.security import Permissions
from checkmate.services import SecureLinkService, URLCheckerService


Expand Down
8 changes: 4 additions & 4 deletions checkmate/views/ui/admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from http.cookies import SimpleCookie

from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config, view_defaults
from pyramid.view import forbidden_view_config, view_config, view_defaults

from checkmate.models import Principals
from checkmate.security import Permissions


@view_defaults(route_name="admin_pages", request_method="GET")
Expand All @@ -13,15 +13,15 @@ def __init__(self, request):

@view_config(
renderer="checkmate:templates/admin/pages.html.jinja2",
effective_principals=[Principals.STAFF],
permission=Permissions.ADMIN,
)
def get(self):
cookie = SimpleCookie()
cookie.load(self.request.headers["Cookie"])

return {"session": cookie["session"].value}

@view_config()
@forbidden_view_config()
def logged_out(self):
return HTTPFound(location=self.request.route_url("login"))

Expand Down
Loading

0 comments on commit c054c7f

Please sign in to comment.