mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-16 06:22:59 +00:00
Merge branch 'rbac' into rbac-group-roles to fix CircleCI test
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
FROM python:3.6.3-alpine3.6
|
||||
|
||||
ARG JUPYTERHUB_VERSION=0.8.1
|
||||
|
||||
RUN pip3 install --no-cache jupyterhub==${JUPYTERHUB_VERSION}
|
||||
FROM alpine:3.13
|
||||
ENV LANG=en_US.UTF-8
|
||||
RUN apk add --no-cache \
|
||||
python3 \
|
||||
py3-pip \
|
||||
py3-ruamel.yaml \
|
||||
py3-cryptography \
|
||||
py3-sqlalchemy
|
||||
|
||||
ARG JUPYTERHUB_VERSION=1.3.0
|
||||
RUN pip3 install --no-cache jupyterhub==${JUPYTERHUB_VERSION}
|
||||
|
||||
USER nobody
|
||||
CMD ["jupyterhub"]
|
||||
|
@@ -13,8 +13,8 @@ from oauthlib import oauth2
|
||||
from tornado import web
|
||||
|
||||
from .. import orm
|
||||
from .. import scopes
|
||||
from ..user import User
|
||||
from ..utils import compare_token
|
||||
from ..utils import token_authenticated
|
||||
from .base import APIHandler
|
||||
from .base import BaseHandler
|
||||
@@ -23,12 +23,24 @@ from .base import BaseHandler
|
||||
class TokenAPIHandler(APIHandler):
|
||||
@token_authenticated
|
||||
def get(self, token):
|
||||
# FIXME: deprecate this API for oauth token resolution, in favor of using /api/user
|
||||
# TODO: require specific scope for this deprecated API, applied to oauth client secrets only?
|
||||
self.log.warning(
|
||||
"/authorizations/token/:token endpoint is deprecated in JupyterHub 2.0. Use /api/user"
|
||||
)
|
||||
orm_token = orm.APIToken.find(self.db, token)
|
||||
if orm_token is None:
|
||||
orm_token = orm.OAuthAccessToken.find(self.db, token)
|
||||
if orm_token is None:
|
||||
raise web.HTTPError(404)
|
||||
|
||||
owner = orm_token.user or orm_token.service
|
||||
if owner:
|
||||
# having a token means we should be able to read the owner's model
|
||||
# (this is the only thing this handler is for)
|
||||
self.raw_scopes.update(scopes.identify_scopes(owner))
|
||||
self.parsed_scopes = scopes.parse_scopes(self.raw_scopes)
|
||||
|
||||
# record activity whenever we see a token
|
||||
now = orm_token.last_activity = datetime.utcnow()
|
||||
if orm_token.user:
|
||||
|
@@ -185,3 +185,25 @@ def needs_scope(*scopes):
|
||||
return _auth_func
|
||||
|
||||
return scope_decorator
|
||||
|
||||
|
||||
def identify_scopes(obj):
|
||||
"""Return 'identify' scopes for an orm object
|
||||
|
||||
Arguments:
|
||||
obj: orm.User or orm.Service
|
||||
|
||||
Returns:
|
||||
scopes (set): set of scopes needed for 'identify' endpoints
|
||||
"""
|
||||
if isinstance(obj, orm.User):
|
||||
return {
|
||||
f"read:users:{field}!user={obj.name}"
|
||||
for field in {"name", "admin", "groups"}
|
||||
}
|
||||
elif isinstance(obj, orm.Service):
|
||||
return {
|
||||
f"read:services:{field}!service={obj.name}" for field in {"name", "admin"}
|
||||
}
|
||||
else:
|
||||
raise TypeError(f"Expected orm.User or orm.Service, got {obj!r}")
|
||||
|
@@ -85,6 +85,8 @@ class MockAPIHandler:
|
||||
def __init__(self):
|
||||
self.raw_scopes = {'users'}
|
||||
self.parsed_scopes = {}
|
||||
self.request = mock.Mock(spec=HTTPServerRequest)
|
||||
self.request.path = '/path'
|
||||
|
||||
@needs_scope('users')
|
||||
def user_thing(self, user_name):
|
||||
@@ -169,7 +171,6 @@ class MockAPIHandler:
|
||||
def test_scope_method_access(scopes, method, arguments, is_allowed):
|
||||
obj = MockAPIHandler()
|
||||
obj.current_user = mock.Mock(name=arguments[0])
|
||||
obj.request = mock.Mock(spec=HTTPServerRequest)
|
||||
obj.raw_scopes = set(scopes)
|
||||
obj.parsed_scopes = parse_scopes(obj.raw_scopes)
|
||||
api_call = getattr(obj, method)
|
||||
@@ -183,7 +184,6 @@ def test_scope_method_access(scopes, method, arguments, is_allowed):
|
||||
def test_double_scoped_method_succeeds():
|
||||
obj = MockAPIHandler()
|
||||
obj.current_user = mock.Mock(name='lucille')
|
||||
obj.request = mock.Mock(spec=HTTPServerRequest)
|
||||
obj.raw_scopes = {'users', 'read:services'}
|
||||
obj.parsed_scopes = parse_scopes(obj.raw_scopes)
|
||||
assert obj.secret_thing()
|
||||
@@ -192,7 +192,6 @@ def test_double_scoped_method_succeeds():
|
||||
def test_double_scoped_method_denials():
|
||||
obj = MockAPIHandler()
|
||||
obj.current_user = mock.Mock(name='lucille2')
|
||||
obj.request = mock.Mock(spec=HTTPServerRequest)
|
||||
obj.raw_scopes = {'users', 'read:groups'}
|
||||
obj.parsed_scopes = parse_scopes(obj.raw_scopes)
|
||||
with pytest.raises(web.HTTPError):
|
||||
|
Reference in New Issue
Block a user