From 14ed3124143f5c2c445a0721fa51e07b78f4d9ef Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Mon, 7 Sep 2020 16:44:18 +0200 Subject: [PATCH 001/270] adding security definition (with scopes) for oauth --- docs/rest-api.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 09d0ed99..3c05639e 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -13,6 +13,36 @@ securityDefinitions: type: apiKey name: Authorization in: header + oauth2: + type: oauth2 + flow: accessCode + authorizationUrl: 'https://localhost:8000/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? + tokenUrl: 'https://localhost:8000/hub/api/oauth2/token' + scopes: + all: Everything a user can do + read:all: Read-only access to everything a user can read + users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers + read:users: Read-only access to the above + read:users:username: Read-only access to a single user's model + read:users:names: Read-only access to users' names + read:users:groups: Read-only access to users' groups + read:users:activity: Read-only access to users' activity + read:users:activity:groupname: Read-only access to specific group's users' activity + read:users:servers: Read-only access to users' servers + users:activity:username: Update a user's activity + users:servers: Grants access to start/stop any server + users:servers:servername: Limits the above to a specific server + users:tokens: Grants access to users' token (includes create/revoke a token) + read:users:tokens: Identify a user from a token + admin:users: Grants access to creating/removing users + admin:users:servers: Grants access to create/remove users' servers + groups: Add/remove users from any group + groups:groupname: Add/remove users from a specific group only + read:groups: Read-only access to groups + admin:groups: Grants access to create/delete groups + read:services: Read-only access to services + proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy + shutdown: Grants access to shutdown the Hub security: - token: [] basePath: /hub/api From eac2e75fe4aef87251652172edc84005d547e3a4 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 9 Sep 2020 10:38:00 +0200 Subject: [PATCH 002/270] adding scopes on operational level for API endpoints --- docs/rest-api.yml | 109 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 3c05639e..2b860365 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -43,8 +43,10 @@ securityDefinitions: read:services: Read-only access to services proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy shutdown: Grants access to shutdown the Hub -security: +security: # global security, do we want to keep the only the apiKey (token: []), change to only oauth2 (with scope all) or have both as changed here (either can be used)? - token: [] + - oauth2: + - all basePath: /hub/api produces: - application/json @@ -109,6 +111,10 @@ paths: /users: get: summary: List users + security: + - oauth2: + - users + - read:users responses: '200': description: The Hub's user list @@ -118,6 +124,9 @@ paths: $ref: '#/definitions/User' post: summary: Create multiple users + security: + - oauth2: + - admin:users parameters: - name: body in: body @@ -144,6 +153,11 @@ paths: /users/{name}: get: summary: Get a user by name + security: + - oauth2: + - users + - read:users + - read:users:username parameters: - name: name description: username @@ -157,6 +171,9 @@ paths: $ref: '#/definitions/User' post: summary: Create a single user + security: + - oauth2: + - admin:users parameters: - name: name description: username @@ -171,6 +188,9 @@ paths: patch: summary: Modify a user description: Change a user's name or admin status + security: + - oauth2: + - users parameters: - name: name description: username @@ -197,6 +217,9 @@ paths: $ref: '#/definitions/User' delete: summary: Delete a user + security: + - oauth2: + - admin:users parameters: - name: name description: username @@ -214,6 +237,10 @@ paths: Notify the Hub of activity by the user, e.g. accessing a service or (more likely) actively using a server. + security: + - oauth2: + - users + - users:activity:username parameters: - name: name description: username @@ -266,6 +293,10 @@ paths: /users/{name}/server: post: summary: Start a user's single-user notebook server + security: + - oauth2: + - users + - users:servers parameters: - name: name description: username @@ -292,6 +323,10 @@ paths: description: The user's notebook server has not yet started, but has been requested delete: summary: Stop a user's server + security: + - oauth2: + - users + - users:servers parameters: - name: name description: username @@ -306,6 +341,11 @@ paths: /users/{name}/servers/{server_name}: post: summary: Start a user's single-user named-server notebook server + security: + - oauth2: + - users + - users:servers + - users:servers:servername parameters: - name: name description: username @@ -337,6 +377,11 @@ paths: description: The user's notebook named-server has not yet started, but has been requested delete: summary: Stop a user's named-server + security: + - oauth2: + - users + - users:servers + - users:servers:servername parameters: - name: name description: username @@ -374,6 +419,9 @@ paths: type: string get: summary: List tokens for the user + security: + - oauth2: + - users:tokens responses: '200': description: The list of tokens @@ -387,6 +435,9 @@ paths: description: No such user post: summary: Create a new token for the user + security: + - oauth2: + - users:tokens parameters: - name: token_params in: body @@ -420,6 +471,9 @@ paths: type: string get: summary: Get the model for a token by id + security: + - oauth2: + - users:tokens responses: '200': description: The info for the new token @@ -427,12 +481,19 @@ paths: $ref: '#/definitions/Token' delete: summary: Delete (revoke) a token by id + security: + - oauth2: + - users:tokens responses: '204': description: The token has been deleted /user: get: summary: Return authenticated user's model + security: + - oauth2: + - all + - read:all responses: '200': description: The authenticated user's model is returned. @@ -441,6 +502,10 @@ paths: /groups: get: summary: List groups + security: + - oauth2: + - groups + - read:groups responses: '200': description: The list of groups @@ -451,6 +516,11 @@ paths: /groups/{name}: get: summary: Get a group by name + security: + - oauth2: + - groups + - groups:groupname + - read:groups parameters: - name: name description: group name @@ -464,6 +534,9 @@ paths: $ref: '#/definitions/Group' post: summary: Create a group + security: + - oauth2: + - admin:groups parameters: - name: name description: group name @@ -477,6 +550,9 @@ paths: $ref: '#/definitions/Group' delete: summary: Delete a group + security: + - oauth2: + - admin:groups parameters: - name: name description: group name @@ -489,6 +565,10 @@ paths: /groups/{name}/users: post: summary: Add users to a group + security: + - oauth2: + - groups + - groups:groupname parameters: - name: name description: group name @@ -514,6 +594,10 @@ paths: $ref: '#/definitions/Group' delete: summary: Remove users from a group + security: + - oauth2: + - groups + - groups:groupname parameters: - name: name description: group name @@ -538,6 +622,9 @@ paths: /services: get: summary: List services + security: + - oauth2: + - read:services responses: '200': description: The service list @@ -548,6 +635,9 @@ paths: /services/{name}: get: summary: Get a service by name + security: + - oauth2: + - read:services parameters: - name: name description: service name @@ -563,6 +653,9 @@ paths: get: summary: Get the proxy's routing table description: A convenience alias for getting the routing table directly from the proxy + security: + - oauth2: + - proxy responses: '200': description: Routing table @@ -571,12 +664,18 @@ paths: description: configurable-http-proxy routing table (see configurable-http-proxy docs for details) post: summary: Force the Hub to sync with the proxy + security: + - oauth2: + - proxy responses: '200': description: Success patch: summary: Notify the Hub about a new proxy description: Notifies the Hub of a new proxy to use. + security: + - oauth2: + - proxy parameters: - name: body in: body @@ -609,6 +708,9 @@ paths: in the JSON request body. Logging in via this method is only available when the active Authenticator accepts passwords (e.g. not OAuth). + security: + - oauth2: + - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope parameters: - name: credentials in: body @@ -633,6 +735,7 @@ paths: /authorizations/token/{token}: get: summary: Identify a user or service from an API token + # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path @@ -663,6 +766,7 @@ paths: $ref: '#/definitions/User' '404': description: A user is not found. + deprecated: true # minrk: let’s not add a scope for this, let’s remove it /oauth2/authorize: get: summary: 'OAuth 2.0 authorize endpoint' @@ -744,6 +848,9 @@ paths: /shutdown: post: summary: Shutdown the Hub + security: + - oauth2: + - shutdown parameters: - name: body in: body From f1940c7c6107843e914e3b93301d9c0b8c0d10e1 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 9 Sep 2020 15:12:06 +0200 Subject: [PATCH 003/270] added read:all scope (whoami) to GET /authorizations/token/{token} --- docs/rest-api.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 2b860365..cc78f5d3 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -20,7 +20,7 @@ securityDefinitions: tokenUrl: 'https://localhost:8000/hub/api/oauth2/token' scopes: all: Everything a user can do - read:all: Read-only access to everything a user can read + read:all: Read-only access to everything a user can read (also whoami handler) users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers read:users: Read-only access to the above read:users:username: Read-only access to a single user's model @@ -735,7 +735,9 @@ paths: /authorizations/token/{token}: get: summary: Identify a user or service from an API token - # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? + security: + - oauth2: + - read:all # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path From 3d7e4458fc7a7a1022e1c16635b249f0cbde32b0 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 11 Sep 2020 11:07:03 +0200 Subject: [PATCH 004/270] correction of scope for GET /authorizations/token/{token} --- docs/rest-api.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index cc78f5d3..0ad94edf 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -737,7 +737,7 @@ paths: summary: Identify a user or service from an API token security: - oauth2: - - read:all # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? + - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path From a220899bf955c0cb0e516a99993c958249bf9d89 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 8 Oct 2020 13:49:04 +0200 Subject: [PATCH 005/270] fix for scope names in rest-api.yml --- docs/rest-api.yml | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 0ad94edf..beb5e181 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -16,34 +16,34 @@ securityDefinitions: oauth2: type: oauth2 flow: accessCode - authorizationUrl: 'https://localhost:8000/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? - tokenUrl: 'https://localhost:8000/hub/api/oauth2/token' + authorizationUrl: '/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? + tokenUrl: '/hub/api/oauth2/token' scopes: all: Everything a user can do read:all: Read-only access to everything a user can read (also whoami handler) users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers read:users: Read-only access to the above - read:users:username: Read-only access to a single user's model + read:users!user=username: Read-only access to a single user's model read:users:names: Read-only access to users' names read:users:groups: Read-only access to users' groups read:users:activity: Read-only access to users' activity - read:users:activity:groupname: Read-only access to specific group's users' activity + read:users:activity!group=groupname: Read-only access to specific group's users' activity read:users:servers: Read-only access to users' servers - users:activity:username: Update a user's activity + users:activity!user=username: Update a user's activity users:servers: Grants access to start/stop any server - users:servers:servername: Limits the above to a specific server + users:servers!server=servername: Limits the above to a specific server users:tokens: Grants access to users' token (includes create/revoke a token) read:users:tokens: Identify a user from a token admin:users: Grants access to creating/removing users admin:users:servers: Grants access to create/remove users' servers groups: Add/remove users from any group - groups:groupname: Add/remove users from a specific group only + groups!group=groupname: Add/remove users from a specific group only read:groups: Read-only access to groups admin:groups: Grants access to create/delete groups read:services: Read-only access to services proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy shutdown: Grants access to shutdown the Hub -security: # global security, do we want to keep the only the apiKey (token: []), change to only oauth2 (with scope all) or have both as changed here (either can be used)? +security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope all) or have both (either can be used)? - token: [] - oauth2: - all @@ -157,7 +157,7 @@ paths: - oauth2: - users - read:users - - read:users:username + - read:users!user=username parameters: - name: name description: username @@ -240,7 +240,7 @@ paths: security: - oauth2: - users - - users:activity:username + - users:activity!user=username parameters: - name: name description: username @@ -345,7 +345,7 @@ paths: - oauth2: - users - users:servers - - users:servers:servername + - users:servers!server=servername parameters: - name: name description: username @@ -381,7 +381,7 @@ paths: - oauth2: - users - users:servers - - users:servers:servername + - users:servers!server=servername parameters: - name: name description: username @@ -519,7 +519,7 @@ paths: security: - oauth2: - groups - - groups:groupname + - groups!group=groupname - read:groups parameters: - name: name @@ -568,7 +568,7 @@ paths: security: - oauth2: - groups - - groups:groupname + - groups!group=groupname parameters: - name: name description: group name @@ -597,7 +597,7 @@ paths: security: - oauth2: - groups - - groups:groupname + - groups!group=groupname parameters: - name: name description: group name @@ -886,6 +886,11 @@ definitions: admin: type: boolean description: Whether the user is an admin + roles: + type: array + description: The names of roles this user has + items: + type: string groups: type: array description: The names of groups where this user is a member From b6fa3532010d685623fb10863e16726e786ad984 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 19 Oct 2020 13:09:26 +0200 Subject: [PATCH 006/270] Implemented scope-based access in API handlers --- jupyterhub/apihandlers/groups.py | 38 ++++++++++------ jupyterhub/apihandlers/hub.py | 5 ++- jupyterhub/apihandlers/proxy.py | 7 +-- jupyterhub/apihandlers/services.py | 5 ++- jupyterhub/apihandlers/users.py | 69 +++++++++++++++++++----------- jupyterhub/utils.py | 18 +++++++- 6 files changed, 97 insertions(+), 45 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index e6b439ba..a6cfeb8f 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -7,6 +7,7 @@ from tornado import web from .. import orm from ..utils import admin_only +from ..utils import needs_scope from .base import APIHandler @@ -34,13 +35,16 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @admin_only - def get(self): + @needs_scope('read:groups') + def get(self, subset=None): """List groups""" - data = [self.group_model(g) for g in self.db.query(orm.Group)] + groups = self.db.query(orm.Group) + if subset is not None: + groups = groups.filter(orm.Group.name.in_(subset)) + data = [self.group_model(g) for g in groups] self.write(json.dumps(data)) - @admin_only + @needs_scope('admin:groups') async def post(self): """POST creates Multiple groups """ model = self.get_json_body() @@ -73,12 +77,14 @@ class GroupListAPIHandler(_GroupAPIHandler): class GroupAPIHandler(_GroupAPIHandler): """View and modify groups by name""" - @admin_only - def get(self, name): + @needs_scope('read:groups') + def get(self, name, subset=None): + if subset is not None and name not in subset: + raise web.HTTPError(403, "No read access to group {}".format(name)) group = self.find_group(name) self.write(json.dumps(self.group_model(group))) - @admin_only + @needs_scope('admin:groups') async def post(self, name): """POST creates a group by name""" model = self.get_json_body() @@ -104,9 +110,11 @@ class GroupAPIHandler(_GroupAPIHandler): self.write(json.dumps(self.group_model(group))) self.set_status(201) - @admin_only - def delete(self, name): + @needs_scope('admin:groups') + def delete(self, name, subset=None): """Delete a group by name""" + if subset is not None and name not in subset: + raise web.HTTPError(403, "No write access to group {}".format(name)) group = self.find_group(name) self.log.info("Deleting group %s", name) self.db.delete(group) @@ -117,9 +125,11 @@ class GroupAPIHandler(_GroupAPIHandler): class GroupUsersAPIHandler(_GroupAPIHandler): """Modify a group's user list""" - @admin_only - def post(self, name): + @needs_scope('groups') + def post(self, name, subset=None): """POST adds users to a group""" + if subset is not None and name not in subset: + raise web.HTTPError(403, "No access to add users to group {}".format(name)) group = self.find_group(name) data = self.get_json_body() self._check_group_model(data) @@ -135,9 +145,11 @@ class GroupUsersAPIHandler(_GroupAPIHandler): self.db.commit() self.write(json.dumps(self.group_model(group))) - @admin_only - async def delete(self, name): + @needs_scope('groups') + async def delete(self, name, subset=None): """DELETE removes users from a group""" + if subset is not None and name not in subset: + raise web.HTTPError(403, "No access to add users to group {}".format(name)) group = self.find_group(name) data = self.get_json_body() self._check_group_model(data) diff --git a/jupyterhub/apihandlers/hub.py b/jupyterhub/apihandlers/hub.py index 155ddf92..77eec918 100644 --- a/jupyterhub/apihandlers/hub.py +++ b/jupyterhub/apihandlers/hub.py @@ -9,11 +9,12 @@ from tornado.ioloop import IOLoop from .._version import __version__ from ..utils import admin_only +from ..utils import needs_scope from .base import APIHandler class ShutdownAPIHandler(APIHandler): - @admin_only + @needs_scope('shutdown') def post(self): """POST /api/shutdown triggers a clean shutdown @@ -65,7 +66,7 @@ class RootAPIHandler(APIHandler): class InfoAPIHandler(APIHandler): - @admin_only + @needs_scope('admin') # Todo: Probably too strict def get(self): """GET /api/info returns detailed info about the Hub and its API. diff --git a/jupyterhub/apihandlers/proxy.py b/jupyterhub/apihandlers/proxy.py index 0a43583b..81430879 100644 --- a/jupyterhub/apihandlers/proxy.py +++ b/jupyterhub/apihandlers/proxy.py @@ -6,11 +6,12 @@ import json from tornado import web from ..utils import admin_only +from ..utils import needs_scope from .base import APIHandler class ProxyAPIHandler(APIHandler): - @admin_only + @needs_scope('proxy') async def get(self): """GET /api/proxy fetches the routing table @@ -20,7 +21,7 @@ class ProxyAPIHandler(APIHandler): routes = await self.proxy.get_all_routes() self.write(json.dumps(routes)) - @admin_only + @needs_scope('proxy') async def post(self): """POST checks the proxy to ensure that it's up to date. @@ -29,7 +30,7 @@ class ProxyAPIHandler(APIHandler): """ await self.proxy.check_routes(self.users, self.services) - @admin_only + @needs_scope('proxy') async def patch(self): """PATCH updates the location of the proxy diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 3d1f7bcc..b0310350 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -10,6 +10,7 @@ from tornado import web from .. import orm from ..utils import admin_only +from ..utils import needs_scope from .base import APIHandler @@ -28,7 +29,7 @@ def service_model(service): class ServiceListAPIHandler(APIHandler): - @admin_only + @needs_scope('read:services') def get(self): data = {name: service_model(service) for name, service in self.services.items()} self.write(json.dumps(data)) @@ -56,7 +57,7 @@ def admin_or_self(method): class ServiceAPIHandler(APIHandler): - @admin_or_self + @needs_scope('read:services') def get(self, name): service = self.services[name] self.write(json.dumps(service_model(service))) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 44c829ff..e73be2eb 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -14,10 +14,10 @@ from tornado.iostream import StreamClosedError from .. import orm from ..user import User -from ..utils import admin_only from ..utils import isoformat from ..utils import iterate_until from ..utils import maybe_future +from ..utils import needs_scope from ..utils import url_path_join from .base import APIHandler @@ -28,6 +28,7 @@ class SelfAPIHandler(APIHandler): Based on the authentication info. Acts as a 'whoami' for auth tokens. """ + @needs_scope('read:users') async def get(self): user = self.current_user if user is None: @@ -39,15 +40,19 @@ class SelfAPIHandler(APIHandler): class UserListAPIHandler(APIHandler): - @admin_only - def get(self): + @needs_scope('read:users') + def get(self, subset=None): + users = self.db.query(orm.User) + if subset is not None: + users = users.filter( + User.name.in_(subset) + ) # Should result in only one db query data = [ - self.user_model(u, include_servers=True, include_state=True) - for u in self.db.query(orm.User) + self.user_model(u, include_servers=True, include_state=True) for u in users ] self.write(json.dumps(data)) - @admin_only + @needs_scope('users') async def post(self): data = self.get_json_body() if not data or not isinstance(data, dict) or not data.get('usernames'): @@ -122,9 +127,13 @@ def admin_or_self(method): class UserAPIHandler(APIHandler): - @admin_or_self - async def get(self, name): + @needs_scope('read:users') + async def get(self, name, subset=None): user = self.find_user(name) + if subset is not None: + if user not in subset: + raise web.HTTPError(403, "No access to users") + model = self.user_model( user, include_servers=True, include_state=self.current_user.admin ) @@ -137,7 +146,7 @@ class UserAPIHandler(APIHandler): model['auth_state'] = await user.get_auth_state() self.write(json.dumps(model)) - @admin_only + @needs_scope('admin:users') async def post(self, name): data = self.get_json_body() user = self.find_user(name) @@ -162,7 +171,7 @@ class UserAPIHandler(APIHandler): self.write(json.dumps(self.user_model(user))) self.set_status(201) - @admin_only + @needs_scope('admin:users') async def delete(self, name): user = self.find_user(name) if user is None: @@ -187,7 +196,7 @@ class UserAPIHandler(APIHandler): self.set_status(204) - @admin_only + @needs_scope('admin:users') async def patch(self, name): user = self.find_user(name) if user is None: @@ -215,7 +224,7 @@ class UserAPIHandler(APIHandler): class UserTokenListAPIHandler(APIHandler): """API endpoint for listing/creating tokens""" - @admin_or_self + @needs_scope('users:tokens') def get(self, name): """Get tokens for a given user""" user = self.find_user(name) @@ -249,6 +258,7 @@ class UserTokenListAPIHandler(APIHandler): oauth_tokens.append(self.token_model(token)) self.write(json.dumps({'api_tokens': api_tokens, 'oauth_tokens': oauth_tokens})) + @needs_scope('users:tokens') async def post(self, name): body = self.get_json_body() or {} if not isinstance(body, dict): @@ -313,6 +323,7 @@ class UserTokenListAPIHandler(APIHandler): class UserTokenAPIHandler(APIHandler): """API endpoint for retrieving/deleting individual tokens""" + @needs_scope('read:users:tokens') def find_token_by_id(self, user, token_id): """Find a token object by token-id key @@ -320,7 +331,7 @@ class UserTokenAPIHandler(APIHandler): (e.g. wrong owner, invalid key format, etc.) """ not_found = "No such token %s for user %s" % (token_id, user.name) - prefix, id = token_id[0], token_id[1:] + prefix, id_ = token_id[0], token_id[1:] if prefix == 'a': Token = orm.APIToken elif prefix == 'o': @@ -328,16 +339,16 @@ class UserTokenAPIHandler(APIHandler): else: raise web.HTTPError(404, not_found) try: - id = int(id) + id_ = int(id_) except ValueError: raise web.HTTPError(404, not_found) - orm_token = self.db.query(Token).filter(Token.id == id).first() + orm_token = self.db.query(Token).filter(Token.id == id_).first() if orm_token is None or orm_token.user is not user.orm_user: raise web.HTTPError(404, "Token not found %s", orm_token) return orm_token - @admin_or_self + @needs_scope('read:users:tokens') def get(self, name, token_id): """""" user = self.find_user(name) @@ -346,7 +357,7 @@ class UserTokenAPIHandler(APIHandler): token = self.find_token_by_id(user, token_id) self.write(json.dumps(self.token_model(token))) - @admin_or_self + @needs_scope('users:tokens') def delete(self, name, token_id): """Delete a token""" user = self.find_user(name) @@ -371,12 +382,17 @@ class UserTokenAPIHandler(APIHandler): class UserServerAPIHandler(APIHandler): """Start and stop single-user servers""" - @admin_or_self - async def post(self, name, server_name=''): + @needs_scope('user:servers') + async def post(self, name, server_name='', subset=None): user = self.find_user(name) if server_name: if not self.allow_named_servers: raise web.HTTPError(400, "Named servers are not enabled.") + if subset is not None: + if server_name not in subset: + raise web.HTTPError( + 403, "No access to create {}".format(server_name) + ) if ( self.named_server_limit_per_user > 0 and server_name not in user.orm_spawners @@ -416,7 +432,7 @@ class UserServerAPIHandler(APIHandler): self.set_header('Content-Type', 'text/plain') self.set_status(status) - @admin_or_self + @needs_scope('user:servers') async def delete(self, name, server_name=''): user = self.find_user(name) options = self.get_json_body() @@ -479,7 +495,7 @@ class UserAdminAccessAPIHandler(APIHandler): This handler sets the necessary cookie for an admin to login to a single-user server. """ - @admin_only + @needs_scope('users:servers') def post(self, name): self.log.warning( "Deprecated in JupyterHub 0.8." @@ -535,11 +551,16 @@ class SpawnProgressAPIHandler(APIHandler): await asyncio.wait([self._finish_future], timeout=self.keepalive_interval) - @admin_or_self - async def get(self, username, server_name=''): + @needs_scope('read:users:servers') + async def get(self, username, server_name='', subset=None): self.set_header('Cache-Control', 'no-cache') if server_name is None: server_name = '' + if subset is not None: + if server_name not in subset: + raise web.HTTPError( + 403, "No read access to server {}".format(server_name) + ) user = self.find_user(username) if user is None: # no such user @@ -678,7 +699,7 @@ class ActivityAPIHandler(APIHandler): ) return servers - @admin_or_self + @needs_scope('users') def post(self, username): user = self.find_user(username) if user is None: diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index e3f0a0e6..424c48a7 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -8,6 +8,7 @@ import hashlib import inspect import os import random +import re import socket import ssl import sys @@ -247,9 +248,10 @@ def auth_decorator(check_auth): def decorator(method): def decorated(self, *args, **kwargs): - check_auth(self) + check_auth(self, **kwargs) return method(self, *args, **kwargs) + # Perhaps replace with functools.wrap decorated.__name__ = method.__name__ decorated.__doc__ = method.__doc__ return decorated @@ -296,6 +298,20 @@ def metrics_authentication(self): raise web.HTTPError(403) +@auth_decorator +def needs_scope(self, scope, **kwargs): + """Decorator to restrict access to users or services with the required scope""" + if scope not in self.current_scopes: + # Check if access is not restricted to user/server/group + match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") + subscopes = filter(lambda s: re.search(match_string, s), self.current_scopes) + subset = [subscope.split('=')[1] for subscope in subscopes] + if not subset: + raise web.HTTPError(403, "Action is not authorized with current scopes") + else: + kwargs['subset'] = subset + + # Token utilities From ff38a9e383619cc1f8e44a58904d351b033637b2 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Mon, 7 Sep 2020 16:44:18 +0200 Subject: [PATCH 007/270] scope schema definitions for rest-api --- docs/rest-api.yml | 141 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 1 deletion(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 09d0ed99..028c895e 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -13,8 +13,40 @@ securityDefinitions: type: apiKey name: Authorization in: header -security: + oauth2: + type: oauth2 + flow: accessCode + authorizationUrl: 'https://localhost:8000/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? + tokenUrl: 'https://localhost:8000/hub/api/oauth2/token' + scopes: + all: Everything a user can do + read:all: Read-only access to everything a user can read (also whoami handler) + users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers + read:users: Read-only access to the above + read:users:username: Read-only access to a single user's model + read:users:names: Read-only access to users' names + read:users:groups: Read-only access to users' groups + read:users:activity: Read-only access to users' activity + read:users:activity:groupname: Read-only access to specific group's users' activity + read:users:servers: Read-only access to users' servers + users:activity:username: Update a user's activity + users:servers: Grants access to start/stop any server + users:servers:servername: Limits the above to a specific server + users:tokens: Grants access to users' token (includes create/revoke a token) + read:users:tokens: Identify a user from a token + admin:users: Grants access to creating/removing users + admin:users:servers: Grants access to create/remove users' servers + groups: Add/remove users from any group + groups:groupname: Add/remove users from a specific group only + read:groups: Read-only access to groups + admin:groups: Grants access to create/delete groups + read:services: Read-only access to services + proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy + shutdown: Grants access to shutdown the Hub +security: # global security, do we want to keep the only the apiKey (token: []), change to only oauth2 (with scope all) or have both as changed here (either can be used)? - token: [] + - oauth2: + - all basePath: /hub/api produces: - application/json @@ -79,6 +111,10 @@ paths: /users: get: summary: List users + security: + - oauth2: + - users + - read:users responses: '200': description: The Hub's user list @@ -88,6 +124,9 @@ paths: $ref: '#/definitions/User' post: summary: Create multiple users + security: + - oauth2: + - admin:users parameters: - name: body in: body @@ -114,6 +153,11 @@ paths: /users/{name}: get: summary: Get a user by name + security: + - oauth2: + - users + - read:users + - read:users:username parameters: - name: name description: username @@ -127,6 +171,9 @@ paths: $ref: '#/definitions/User' post: summary: Create a single user + security: + - oauth2: + - admin:users parameters: - name: name description: username @@ -141,6 +188,9 @@ paths: patch: summary: Modify a user description: Change a user's name or admin status + security: + - oauth2: + - users parameters: - name: name description: username @@ -167,6 +217,9 @@ paths: $ref: '#/definitions/User' delete: summary: Delete a user + security: + - oauth2: + - admin:users parameters: - name: name description: username @@ -184,6 +237,10 @@ paths: Notify the Hub of activity by the user, e.g. accessing a service or (more likely) actively using a server. + security: + - oauth2: + - users + - users:activity:username parameters: - name: name description: username @@ -236,6 +293,10 @@ paths: /users/{name}/server: post: summary: Start a user's single-user notebook server + security: + - oauth2: + - users + - users:servers parameters: - name: name description: username @@ -262,6 +323,10 @@ paths: description: The user's notebook server has not yet started, but has been requested delete: summary: Stop a user's server + security: + - oauth2: + - users + - users:servers parameters: - name: name description: username @@ -276,6 +341,11 @@ paths: /users/{name}/servers/{server_name}: post: summary: Start a user's single-user named-server notebook server + security: + - oauth2: + - users + - users:servers + - users:servers:servername parameters: - name: name description: username @@ -307,6 +377,11 @@ paths: description: The user's notebook named-server has not yet started, but has been requested delete: summary: Stop a user's named-server + security: + - oauth2: + - users + - users:servers + - users:servers:servername parameters: - name: name description: username @@ -344,6 +419,9 @@ paths: type: string get: summary: List tokens for the user + security: + - oauth2: + - users:tokens responses: '200': description: The list of tokens @@ -357,6 +435,9 @@ paths: description: No such user post: summary: Create a new token for the user + security: + - oauth2: + - users:tokens parameters: - name: token_params in: body @@ -390,6 +471,9 @@ paths: type: string get: summary: Get the model for a token by id + security: + - oauth2: + - users:tokens responses: '200': description: The info for the new token @@ -397,12 +481,19 @@ paths: $ref: '#/definitions/Token' delete: summary: Delete (revoke) a token by id + security: + - oauth2: + - users:tokens responses: '204': description: The token has been deleted /user: get: summary: Return authenticated user's model + security: + - oauth2: + - all + - read:all responses: '200': description: The authenticated user's model is returned. @@ -411,6 +502,10 @@ paths: /groups: get: summary: List groups + security: + - oauth2: + - groups + - read:groups responses: '200': description: The list of groups @@ -421,6 +516,11 @@ paths: /groups/{name}: get: summary: Get a group by name + security: + - oauth2: + - groups + - groups:groupname + - read:groups parameters: - name: name description: group name @@ -434,6 +534,9 @@ paths: $ref: '#/definitions/Group' post: summary: Create a group + security: + - oauth2: + - admin:groups parameters: - name: name description: group name @@ -447,6 +550,9 @@ paths: $ref: '#/definitions/Group' delete: summary: Delete a group + security: + - oauth2: + - admin:groups parameters: - name: name description: group name @@ -459,6 +565,10 @@ paths: /groups/{name}/users: post: summary: Add users to a group + security: + - oauth2: + - groups + - groups:groupname parameters: - name: name description: group name @@ -484,6 +594,10 @@ paths: $ref: '#/definitions/Group' delete: summary: Remove users from a group + security: + - oauth2: + - groups + - groups:groupname parameters: - name: name description: group name @@ -508,6 +622,9 @@ paths: /services: get: summary: List services + security: + - oauth2: + - read:services responses: '200': description: The service list @@ -518,6 +635,9 @@ paths: /services/{name}: get: summary: Get a service by name + security: + - oauth2: + - read:services parameters: - name: name description: service name @@ -533,6 +653,9 @@ paths: get: summary: Get the proxy's routing table description: A convenience alias for getting the routing table directly from the proxy + security: + - oauth2: + - proxy responses: '200': description: Routing table @@ -541,12 +664,18 @@ paths: description: configurable-http-proxy routing table (see configurable-http-proxy docs for details) post: summary: Force the Hub to sync with the proxy + security: + - oauth2: + - proxy responses: '200': description: Success patch: summary: Notify the Hub about a new proxy description: Notifies the Hub of a new proxy to use. + security: + - oauth2: + - proxy parameters: - name: body in: body @@ -579,6 +708,9 @@ paths: in the JSON request body. Logging in via this method is only available when the active Authenticator accepts passwords (e.g. not OAuth). + security: + - oauth2: + - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope parameters: - name: credentials in: body @@ -603,6 +735,9 @@ paths: /authorizations/token/{token}: get: summary: Identify a user or service from an API token + security: + - oauth2: + - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path @@ -633,6 +768,7 @@ paths: $ref: '#/definitions/User' '404': description: A user is not found. + # deprecated: true # minrk: let’s not add a scope for this, let’s remove it /oauth2/authorize: get: summary: 'OAuth 2.0 authorize endpoint' @@ -714,6 +850,9 @@ paths: /shutdown: post: summary: Shutdown the Hub + security: + - oauth2: + - shutdown parameters: - name: body in: body From f1ed74bae10c17a69772e6289ab163c654ee62f4 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 24 Sep 2020 14:05:15 +0200 Subject: [PATCH 008/270] creating roles module --- .circleci/config.yml | 46 ---------- docs/rest-api.yml | 37 ++++---- docs/source/changelog.md | 147 +++++++++++++++++++++++++++++++- jupyterhub/_version.py | 4 +- jupyterhub/apihandlers/base.py | 1 + jupyterhub/apihandlers/users.py | 9 +- jupyterhub/app.py | 57 ++++++++++++- jupyterhub/dbutil.py | 2 +- jupyterhub/orm.py | 55 ++++++++++++ jupyterhub/roles.py | 127 +++++++++++++++++++++++++++ jupyterhub/tests/mocking.py | 6 +- jupyterhub/tests/populate_db.py | 3 + jupyterhub/tests/test_api.py | 37 +++++++- jupyterhub/tests/test_orm.py | 6 +- jupyterhub/tests/test_roles.py | 135 +++++++++++++++++++++++++++++ jupyterhub/traitlets.py | 9 +- jupyterhub/utils.py | 3 +- pytest.ini | 1 + 18 files changed, 607 insertions(+), 78 deletions(-) create mode 100644 jupyterhub/roles.py create mode 100644 jupyterhub/tests/test_roles.py diff --git a/.circleci/config.yml b/.circleci/config.yml index fb744df7..2f4a568a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,51 +24,6 @@ jobs: command: | docker run --rm -it -v $PWD/dockerfiles:/io jupyterhub/jupyterhub python3 /io/test.py - docs: - # This is the base environment that Circle will use - docker: - - image: circleci/python:3.6-stretch - steps: - # Get our data and merge with upstream - - run: sudo apt-get update - - checkout - # Update our path - - run: echo "export PATH=~/.local/bin:$PATH" >> $BASH_ENV - # Restore cached files to speed things up - - restore_cache: - keys: - - cache-pip - # Install the packages needed to build our documentation - - run: - name: Install NodeJS - command: | - # From https://github.com/nodesource/distributions/blob/master/README.md#debinstall - curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash - - sudo apt-get install -y nodejs - - - run: - name: Install dependencies - command: | - python3 -m pip install --user -r dev-requirements.txt - python3 -m pip install --user -r docs/requirements.txt - sudo npm install -g configurable-http-proxy - sudo python3 -m pip install --editable . - - # Cache some files for a speedup in subsequent builds - - save_cache: - key: cache-pip - paths: - - ~/.cache/pip - # Build the docs - - run: - name: Build docs to store - command: | - cd docs - make html - # Tell Circle to store the documentation output in a folder that we can access later - - store_artifacts: - path: docs/build/html/ - destination: html # Tell CircleCI to use this workflow when it builds the site workflows: @@ -76,4 +31,3 @@ workflows: default: jobs: - build - - docs diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 028c895e..beb5e181 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -16,34 +16,34 @@ securityDefinitions: oauth2: type: oauth2 flow: accessCode - authorizationUrl: 'https://localhost:8000/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? - tokenUrl: 'https://localhost:8000/hub/api/oauth2/token' + authorizationUrl: '/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? + tokenUrl: '/hub/api/oauth2/token' scopes: all: Everything a user can do read:all: Read-only access to everything a user can read (also whoami handler) users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers read:users: Read-only access to the above - read:users:username: Read-only access to a single user's model + read:users!user=username: Read-only access to a single user's model read:users:names: Read-only access to users' names read:users:groups: Read-only access to users' groups read:users:activity: Read-only access to users' activity - read:users:activity:groupname: Read-only access to specific group's users' activity + read:users:activity!group=groupname: Read-only access to specific group's users' activity read:users:servers: Read-only access to users' servers - users:activity:username: Update a user's activity + users:activity!user=username: Update a user's activity users:servers: Grants access to start/stop any server - users:servers:servername: Limits the above to a specific server + users:servers!server=servername: Limits the above to a specific server users:tokens: Grants access to users' token (includes create/revoke a token) read:users:tokens: Identify a user from a token admin:users: Grants access to creating/removing users admin:users:servers: Grants access to create/remove users' servers groups: Add/remove users from any group - groups:groupname: Add/remove users from a specific group only + groups!group=groupname: Add/remove users from a specific group only read:groups: Read-only access to groups admin:groups: Grants access to create/delete groups read:services: Read-only access to services proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy shutdown: Grants access to shutdown the Hub -security: # global security, do we want to keep the only the apiKey (token: []), change to only oauth2 (with scope all) or have both as changed here (either can be used)? +security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope all) or have both (either can be used)? - token: [] - oauth2: - all @@ -157,7 +157,7 @@ paths: - oauth2: - users - read:users - - read:users:username + - read:users!user=username parameters: - name: name description: username @@ -240,7 +240,7 @@ paths: security: - oauth2: - users - - users:activity:username + - users:activity!user=username parameters: - name: name description: username @@ -345,7 +345,7 @@ paths: - oauth2: - users - users:servers - - users:servers:servername + - users:servers!server=servername parameters: - name: name description: username @@ -381,7 +381,7 @@ paths: - oauth2: - users - users:servers - - users:servers:servername + - users:servers!server=servername parameters: - name: name description: username @@ -519,7 +519,7 @@ paths: security: - oauth2: - groups - - groups:groupname + - groups!group=groupname - read:groups parameters: - name: name @@ -568,7 +568,7 @@ paths: security: - oauth2: - groups - - groups:groupname + - groups!group=groupname parameters: - name: name description: group name @@ -597,7 +597,7 @@ paths: security: - oauth2: - groups - - groups:groupname + - groups!group=groupname parameters: - name: name description: group name @@ -768,7 +768,7 @@ paths: $ref: '#/definitions/User' '404': description: A user is not found. - # deprecated: true # minrk: let’s not add a scope for this, let’s remove it + deprecated: true # minrk: let’s not add a scope for this, let’s remove it /oauth2/authorize: get: summary: 'OAuth 2.0 authorize endpoint' @@ -886,6 +886,11 @@ definitions: admin: type: boolean description: Whether the user is an admin + roles: + type: array + description: The names of roles this user has + items: + type: string groups: type: array description: The names of groups where this user is a member diff --git a/docs/source/changelog.md b/docs/source/changelog.md index 6eb740e7..d5f12850 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -7,6 +7,152 @@ command line for details. ## [Unreleased] +## 1.2 + +### 1.2.0b1 + +JupyterHub 1.2 is an incremental release with lots of small improvements. +It is unlikely that users will have to change much to upgrade, +but lots of new things are possible and/or better! + +There are no database schema changes requiring migration from 1.1 to 1.2. + +Highlights: + +- Deprecate black/whitelist configuration fields in favor of more inclusive blocked/allowed language +- More configuration of page templates and service display +- Pagination of the admin page improving performance with large numbers of users +- Improved control of user redirect with +- Support for [jupyter-server](https://jupyter-server.readthedocs.io/en/latest/)-based single-user servers, such as [Voilà](https://voila-gallery.org) and latest JupyterLab. +- Lots more improvements to documentation, HTML pages, and customizations + + + + + +([full changelog](https://github.com/jupyterhub/jupyterhub/compare/1.1.0...1.2.0b1)) + + +#### Enhancements made +* Control service display [#3160](https://github.com/jupyterhub/jupyterhub/pull/3160) ([@rcthomas](https://github.com/rcthomas)) +* Add a footer block + wrap the admin footer in this block [#3136](https://github.com/jupyterhub/jupyterhub/pull/3136) ([@pabepadu](https://github.com/pabepadu)) +* Allow JupyterHub.default_url to be a callable [#3133](https://github.com/jupyterhub/jupyterhub/pull/3133) ([@danlester](https://github.com/danlester)) +* Allow head requests for the health endpoint [#3131](https://github.com/jupyterhub/jupyterhub/pull/3131) ([@rkevin-arch](https://github.com/rkevin-arch)) +* Hide hamburger button menu in mobile/responsive mode and fix other minor issues [#3103](https://github.com/jupyterhub/jupyterhub/pull/3103) ([@kinow](https://github.com/kinow)) +* build jupyterhub/jupyterhub-demo image on docker hub [#3083](https://github.com/jupyterhub/jupyterhub/pull/3083) ([@minrk](https://github.com/minrk)) +* Add JupyterHub Demo docker image [#3059](https://github.com/jupyterhub/jupyterhub/pull/3059) ([@GeorgianaElena](https://github.com/GeorgianaElena)) +* Warn if both bind_url and ip/port/base_url are set [#3057](https://github.com/jupyterhub/jupyterhub/pull/3057) ([@GeorgianaElena](https://github.com/GeorgianaElena)) +* UI Feedback on Submit [#3028](https://github.com/jupyterhub/jupyterhub/pull/3028) ([@possiblyMikeB](https://github.com/possiblyMikeB)) +* Support kubespawner running on a IPv6 only cluster [#3020](https://github.com/jupyterhub/jupyterhub/pull/3020) ([@stv0g](https://github.com/stv0g)) +* Spawn with options passed in query arguments to /spawn [#3013](https://github.com/jupyterhub/jupyterhub/pull/3013) ([@twalcari](https://github.com/twalcari)) +* SpawnHandler POST with user form options displays the spawn-pending page [#2978](https://github.com/jupyterhub/jupyterhub/pull/2978) ([@danlester](https://github.com/danlester)) +* Start named servers by pressing the Enter key [#2960](https://github.com/jupyterhub/jupyterhub/pull/2960) ([@jtpio](https://github.com/jtpio)) +* Keep the URL fragments after spawning an application [#2952](https://github.com/jupyterhub/jupyterhub/pull/2952) ([@kinow](https://github.com/kinow)) +* Allow implicit spawn via javascript redirect [#2941](https://github.com/jupyterhub/jupyterhub/pull/2941) ([@minrk](https://github.com/minrk)) +* make init_spawners check O(running servers) not O(total users) [#2936](https://github.com/jupyterhub/jupyterhub/pull/2936) ([@minrk](https://github.com/minrk)) +* Add favicon to the base page template [#2930](https://github.com/jupyterhub/jupyterhub/pull/2930) ([@JohnPaton](https://github.com/JohnPaton)) +* Adding pagination in the admin panel [#2929](https://github.com/jupyterhub/jupyterhub/pull/2929) ([@cbjuan](https://github.com/cbjuan)) +* Generate prometheus metrics docs [#2891](https://github.com/jupyterhub/jupyterhub/pull/2891) ([@rajat404](https://github.com/rajat404)) +* Add support for Jupyter Server [#2601](https://github.com/jupyterhub/jupyterhub/pull/2601) ([@yuvipanda](https://github.com/yuvipanda)) + +#### Bugs fixed +* avoid specifying default_value=None in Command traits [#3208](https://github.com/jupyterhub/jupyterhub/pull/3208) ([@minrk](https://github.com/minrk)) +* Prevent OverflowErrors in exponential_backoff() [#3204](https://github.com/jupyterhub/jupyterhub/pull/3204) ([@kreuzert](https://github.com/kreuzert)) +* update prometheus metrics for server spawn when it fails with exception [#3150](https://github.com/jupyterhub/jupyterhub/pull/3150) ([@yhal-nesi](https://github.com/yhal-nesi)) +* jupyterhub/utils: Load system default CA certificates in make_ssl_context [#3140](https://github.com/jupyterhub/jupyterhub/pull/3140) ([@chancez](https://github.com/chancez)) +* admin page sorts on spawner last_activity instead of user last_activity [#3137](https://github.com/jupyterhub/jupyterhub/pull/3137) ([@lydian](https://github.com/lydian)) +* Fix the services dropdown on the admin page [#3132](https://github.com/jupyterhub/jupyterhub/pull/3132) ([@pabepadu](https://github.com/pabepadu)) +* Don't log a warning when slow_spawn_timeout is disabled [#3127](https://github.com/jupyterhub/jupyterhub/pull/3127) ([@mriedem](https://github.com/mriedem)) +* app.py: Work around incompatibility between Tornado 6 and asyncio proactor event loop in python 3.8 on Windows [#3123](https://github.com/jupyterhub/jupyterhub/pull/3123) ([@alexweav](https://github.com/alexweav)) +* jupyterhub/user: clear spawner state after post_stop_hook [#3121](https://github.com/jupyterhub/jupyterhub/pull/3121) ([@rkdarst](https://github.com/rkdarst)) +* fix for stopping named server deleting default server and tests [#3109](https://github.com/jupyterhub/jupyterhub/pull/3109) ([@kxiao-fn](https://github.com/kxiao-fn)) +* Hide hamburger button menu in mobile/responsive mode and fix other minor issues [#3103](https://github.com/jupyterhub/jupyterhub/pull/3103) ([@kinow](https://github.com/kinow)) +* Rename Authenticator.white/blacklist to allowed/blocked [#3090](https://github.com/jupyterhub/jupyterhub/pull/3090) ([@minrk](https://github.com/minrk)) +* Include the query string parameters when redirecting to a new URL [#3089](https://github.com/jupyterhub/jupyterhub/pull/3089) ([@kinow](https://github.com/kinow)) +* Make `delete_invalid_users` configurable [#3087](https://github.com/jupyterhub/jupyterhub/pull/3087) ([@fcollonval](https://github.com/fcollonval)) +* Ensure client dependencies build before wheel [#3082](https://github.com/jupyterhub/jupyterhub/pull/3082) ([@diurnalist](https://github.com/diurnalist)) +* make Spawner.environment config highest priority [#3081](https://github.com/jupyterhub/jupyterhub/pull/3081) ([@minrk](https://github.com/minrk)) +* Changing start my server button link to spawn url once server is stopped [#3042](https://github.com/jupyterhub/jupyterhub/pull/3042) ([@rabsr](https://github.com/rabsr)) +* Fix CSS on admin page version listing [#3035](https://github.com/jupyterhub/jupyterhub/pull/3035) ([@vilhelmen](https://github.com/vilhelmen)) +* Fix user_row endblock in admin template [#3015](https://github.com/jupyterhub/jupyterhub/pull/3015) ([@jtpio](https://github.com/jtpio)) +* Fix --generate-config bug when specifying a filename [#2907](https://github.com/jupyterhub/jupyterhub/pull/2907) ([@consideRatio](https://github.com/consideRatio)) +* Handle the protocol when ssl is enabled and log the right URL [#2773](https://github.com/jupyterhub/jupyterhub/pull/2773) ([@kinow](https://github.com/kinow)) + +#### Maintenance and upkeep improvements +* stop building docs on circleci [#3209](https://github.com/jupyterhub/jupyterhub/pull/3209) ([@minrk](https://github.com/minrk)) +* Upgraded Jquery dep [#3174](https://github.com/jupyterhub/jupyterhub/pull/3174) ([@AngelOnFira](https://github.com/AngelOnFira)) +* Don't allow 'python:3.8 + master dependencies' to fail [#3157](https://github.com/jupyterhub/jupyterhub/pull/3157) ([@manics](https://github.com/manics)) +* Update Dockerfile to ubuntu:focal (Python 3.8) [#3156](https://github.com/jupyterhub/jupyterhub/pull/3156) ([@manics](https://github.com/manics)) +* Simplify code of the health check handler [#3149](https://github.com/jupyterhub/jupyterhub/pull/3149) ([@betatim](https://github.com/betatim)) +* Get error description from error key vs error_description key [#3147](https://github.com/jupyterhub/jupyterhub/pull/3147) ([@jgwerner](https://github.com/jgwerner)) +* Implement singleuser with mixins [#3128](https://github.com/jupyterhub/jupyterhub/pull/3128) ([@minrk](https://github.com/minrk)) +* only build tagged versions on docker tags [#3118](https://github.com/jupyterhub/jupyterhub/pull/3118) ([@minrk](https://github.com/minrk)) +* Log slow_stop_timeout when hit like slow_spawn_timeout [#3111](https://github.com/jupyterhub/jupyterhub/pull/3111) ([@mriedem](https://github.com/mriedem)) +* loosen jupyter-telemetry pin [#3102](https://github.com/jupyterhub/jupyterhub/pull/3102) ([@minrk](https://github.com/minrk)) +* Remove old context-less print statement [#3100](https://github.com/jupyterhub/jupyterhub/pull/3100) ([@mriedem](https://github.com/mriedem)) +* Allow `python:3.8 + master dependencies` to fail [#3079](https://github.com/jupyterhub/jupyterhub/pull/3079) ([@manics](https://github.com/manics)) +* Test with some master dependencies. [#3076](https://github.com/jupyterhub/jupyterhub/pull/3076) ([@Carreau](https://github.com/Carreau)) +* synchronize implementation of expiring values [#3072](https://github.com/jupyterhub/jupyterhub/pull/3072) ([@minrk](https://github.com/minrk)) +* More consistent behavior for UserDict.get and `key in UserDict` [#3071](https://github.com/jupyterhub/jupyterhub/pull/3071) ([@minrk](https://github.com/minrk)) +* pin jupyter_telemetry dependency [#3067](https://github.com/jupyterhub/jupyterhub/pull/3067) ([@Zsailer](https://github.com/Zsailer)) +* Use the issue templates from the central repo [#3056](https://github.com/jupyterhub/jupyterhub/pull/3056) ([@GeorgianaElena](https://github.com/GeorgianaElena)) +* Update links to the black GitHub repository [#3054](https://github.com/jupyterhub/jupyterhub/pull/3054) ([@jtpio](https://github.com/jtpio)) +* Log successful /health requests as debug level [#3047](https://github.com/jupyterhub/jupyterhub/pull/3047) ([@consideRatio](https://github.com/consideRatio)) +* Fix broken test due to BeautifulSoup 4.9.0 behavior change [#3025](https://github.com/jupyterhub/jupyterhub/pull/3025) ([@twalcari](https://github.com/twalcari)) +* Remove unused imports [#3019](https://github.com/jupyterhub/jupyterhub/pull/3019) ([@stv0g](https://github.com/stv0g)) +* Use pip instead of conda for building the docs on RTD [#3010](https://github.com/jupyterhub/jupyterhub/pull/3010) ([@GeorgianaElena](https://github.com/GeorgianaElena)) +* Avoid redundant logging of jupyterhub version mismatches [#2971](https://github.com/jupyterhub/jupyterhub/pull/2971) ([@mriedem](https://github.com/mriedem)) +* Add .vscode to gitignore [#2959](https://github.com/jupyterhub/jupyterhub/pull/2959) ([@jtpio](https://github.com/jtpio)) +* preserve auth type when logging obfuscated auth header [#2953](https://github.com/jupyterhub/jupyterhub/pull/2953) ([@minrk](https://github.com/minrk)) +* make spawner:server relationship explicitly one to one [#2944](https://github.com/jupyterhub/jupyterhub/pull/2944) ([@minrk](https://github.com/minrk)) +* Add what we need with some margin to Dockerfile's build stage [#2905](https://github.com/jupyterhub/jupyterhub/pull/2905) ([@consideRatio](https://github.com/consideRatio)) +* bump reorder-imports hook [#2899](https://github.com/jupyterhub/jupyterhub/pull/2899) ([@minrk](https://github.com/minrk)) + +#### Documentation improvements +* [docs] Remove duplicate line in changelog for 1.1.0 [#3207](https://github.com/jupyterhub/jupyterhub/pull/3207) ([@kinow](https://github.com/kinow)) +* Add SELinux configuration for nginx [#3185](https://github.com/jupyterhub/jupyterhub/pull/3185) ([@rainwoodman](https://github.com/rainwoodman)) +* Mention the PAM pitfall on fedora. [#3184](https://github.com/jupyterhub/jupyterhub/pull/3184) ([@rainwoodman](https://github.com/rainwoodman)) +* Added extra documentation for endpoint /users/{name}/servers/{server_name}. [#3159](https://github.com/jupyterhub/jupyterhub/pull/3159) ([@synchronizing](https://github.com/synchronizing)) +* docs: please docs linter (move_cert docstring) [#3151](https://github.com/jupyterhub/jupyterhub/pull/3151) ([@consideRatio](https://github.com/consideRatio)) +* Needed NoEsacpe (NE) option for apache [#3143](https://github.com/jupyterhub/jupyterhub/pull/3143) ([@basvandervlies](https://github.com/basvandervlies)) +* Document external service api_tokens better [#3142](https://github.com/jupyterhub/jupyterhub/pull/3142) ([@snickell](https://github.com/snickell)) +* Remove idle culler example [#3114](https://github.com/jupyterhub/jupyterhub/pull/3114) ([@yuvipanda](https://github.com/yuvipanda)) +* docs: unsqueeze logo, remove unused CSS and templates [#3107](https://github.com/jupyterhub/jupyterhub/pull/3107) ([@consideRatio](https://github.com/consideRatio)) +* Update version in docs/rest-api.yaml [#3104](https://github.com/jupyterhub/jupyterhub/pull/3104) ([@cmd-ntrf](https://github.com/cmd-ntrf)) +* Replace zonca/remotespawner with NERSC/sshspawner [#3086](https://github.com/jupyterhub/jupyterhub/pull/3086) ([@manics](https://github.com/manics)) +* Remove already done named servers from roadmap [#3084](https://github.com/jupyterhub/jupyterhub/pull/3084) ([@elgalu](https://github.com/elgalu)) +* proxy settings might cause authentication errors [#3078](https://github.com/jupyterhub/jupyterhub/pull/3078) ([@gatoniel](https://github.com/gatoniel)) +* Add Configuration Reference section to docs [#3077](https://github.com/jupyterhub/jupyterhub/pull/3077) ([@kinow](https://github.com/kinow)) +* document upgrading from api_tokens to services config [#3055](https://github.com/jupyterhub/jupyterhub/pull/3055) ([@minrk](https://github.com/minrk)) +* [Docs] Disable proxy_buffering when using nginx reverse proxy [#3048](https://github.com/jupyterhub/jupyterhub/pull/3048) ([@mhwasil](https://github.com/mhwasil)) +* docs: add proxy_http_version 1.1 [#3046](https://github.com/jupyterhub/jupyterhub/pull/3046) ([@ceocoder](https://github.com/ceocoder)) +* #1018 PAM added in prerequisites [#3040](https://github.com/jupyterhub/jupyterhub/pull/3040) ([@romainx](https://github.com/romainx)) +* Fix use of auxiliary verb on index.rst [#3022](https://github.com/jupyterhub/jupyterhub/pull/3022) ([@joshmeek](https://github.com/joshmeek)) +* Fix docs CI test failure: duplicate object description [#3021](https://github.com/jupyterhub/jupyterhub/pull/3021) ([@rkdarst](https://github.com/rkdarst)) +* Update issue templates [#3001](https://github.com/jupyterhub/jupyterhub/pull/3001) ([@GeorgianaElena](https://github.com/GeorgianaElena)) +* fix wrong name on firewall [#2997](https://github.com/jupyterhub/jupyterhub/pull/2997) ([@thuvh](https://github.com/thuvh)) +* updating docs theme [#2995](https://github.com/jupyterhub/jupyterhub/pull/2995) ([@choldgraf](https://github.com/choldgraf)) +* Update contributor docs [#2972](https://github.com/jupyterhub/jupyterhub/pull/2972) ([@mriedem](https://github.com/mriedem)) +* Server.user_options rest-api documented [#2966](https://github.com/jupyterhub/jupyterhub/pull/2966) ([@mriedem](https://github.com/mriedem)) +* Pin sphinx theme [#2956](https://github.com/jupyterhub/jupyterhub/pull/2956) ([@manics](https://github.com/manics)) +* [doc] Fix couple typos in the documentation [#2951](https://github.com/jupyterhub/jupyterhub/pull/2951) ([@kinow](https://github.com/kinow)) +* Docs: Fixed grammar on landing page [#2950](https://github.com/jupyterhub/jupyterhub/pull/2950) ([@alexdriedger](https://github.com/alexdriedger)) +* add general faq [#2946](https://github.com/jupyterhub/jupyterhub/pull/2946) ([@minrk](https://github.com/minrk)) +* docs: use metachannel for faster environment solve [#2943](https://github.com/jupyterhub/jupyterhub/pull/2943) ([@minrk](https://github.com/minrk)) +* update docs environments [#2942](https://github.com/jupyterhub/jupyterhub/pull/2942) ([@minrk](https://github.com/minrk)) +* [doc] Add more docs about Cookies used for authentication in JupyterHub [#2940](https://github.com/jupyterhub/jupyterhub/pull/2940) ([@kinow](https://github.com/kinow)) +* [doc] Use fixed commit plus line number in github link [#2939](https://github.com/jupyterhub/jupyterhub/pull/2939) ([@kinow](https://github.com/kinow)) +* [doc] Fix link to SSL encryption from troubleshooting page [#2938](https://github.com/jupyterhub/jupyterhub/pull/2938) ([@kinow](https://github.com/kinow)) +* rest api: fix schema for remove parameter in rest api [#2917](https://github.com/jupyterhub/jupyterhub/pull/2917) ([@minrk](https://github.com/minrk)) +* Add troubleshooting topics [#2914](https://github.com/jupyterhub/jupyterhub/pull/2914) ([@jgwerner](https://github.com/jgwerner)) +* Several fixes to the doc [#2904](https://github.com/jupyterhub/jupyterhub/pull/2904) ([@reneluria](https://github.com/reneluria)) +* fix: 'Non-ASCII character '\xc3' [#2901](https://github.com/jupyterhub/jupyterhub/pull/2901) ([@jgwerner](https://github.com/jgwerner)) +* Generate prometheus metrics docs [#2891](https://github.com/jupyterhub/jupyterhub/pull/2891) ([@rajat404](https://github.com/rajat404)) + +#### Contributors to this release +([GitHub contributors page for this release](https://github.com/jupyterhub/jupyterhub/graphs/contributors?from=2020-01-17&to=2020-10-15&type=c)) + +[@1kastner](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3A1kastner+updated%3A2020-01-17..2020-10-15&type=Issues) | [@alexdriedger](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aalexdriedger+updated%3A2020-01-17..2020-10-15&type=Issues) | [@alexweav](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aalexweav+updated%3A2020-01-17..2020-10-15&type=Issues) | [@Analect](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AAnalect+updated%3A2020-01-17..2020-10-15&type=Issues) | [@analytically](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aanalytically+updated%3A2020-01-17..2020-10-15&type=Issues) | [@AngelOnFira](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AAngelOnFira+updated%3A2020-01-17..2020-10-15&type=Issues) | [@barrachri](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Abarrachri+updated%3A2020-01-17..2020-10-15&type=Issues) | [@basvandervlies](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Abasvandervlies+updated%3A2020-01-17..2020-10-15&type=Issues) | [@betatim](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Abetatim+updated%3A2020-01-17..2020-10-15&type=Issues) | [@bigbosst](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Abigbosst+updated%3A2020-01-17..2020-10-15&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ablink1073+updated%3A2020-01-17..2020-10-15&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3ACarreau+updated%3A2020-01-17..2020-10-15&type=Issues) | [@cbjuan](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Acbjuan+updated%3A2020-01-17..2020-10-15&type=Issues) | [@ceocoder](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aceocoder+updated%3A2020-01-17..2020-10-15&type=Issues) | [@chancez](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Achancez+updated%3A2020-01-17..2020-10-15&type=Issues) | [@choldgraf](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Acholdgraf+updated%3A2020-01-17..2020-10-15&type=Issues) | [@Chrisjw42](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AChrisjw42+updated%3A2020-01-17..2020-10-15&type=Issues) | [@cmd-ntrf](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Acmd-ntrf+updated%3A2020-01-17..2020-10-15&type=Issues) | [@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AconsideRatio+updated%3A2020-01-17..2020-10-15&type=Issues) | [@danlester](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Adanlester+updated%3A2020-01-17..2020-10-15&type=Issues) | [@diurnalist](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Adiurnalist+updated%3A2020-01-17..2020-10-15&type=Issues) | [@Dmitry1987](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3ADmitry1987+updated%3A2020-01-17..2020-10-15&type=Issues) | [@dylex](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Adylex+updated%3A2020-01-17..2020-10-15&type=Issues) | [@echarles](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aecharles+updated%3A2020-01-17..2020-10-15&type=Issues) | [@elgalu](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aelgalu+updated%3A2020-01-17..2020-10-15&type=Issues) | [@fcollonval](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Afcollonval+updated%3A2020-01-17..2020-10-15&type=Issues) | [@gatoniel](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Agatoniel+updated%3A2020-01-17..2020-10-15&type=Issues) | [@GeorgianaElena](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AGeorgianaElena+updated%3A2020-01-17..2020-10-15&type=Issues) | [@jgwerner](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ajgwerner+updated%3A2020-01-17..2020-10-15&type=Issues) | [@JohnPaton](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AJohnPaton+updated%3A2020-01-17..2020-10-15&type=Issues) | [@joshmeek](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ajoshmeek+updated%3A2020-01-17..2020-10-15&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ajtpio+updated%3A2020-01-17..2020-10-15&type=Issues) | [@kinow](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Akinow+updated%3A2020-01-17..2020-10-15&type=Issues) | [@kreuzert](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Akreuzert+updated%3A2020-01-17..2020-10-15&type=Issues) | [@kxiao-fn](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Akxiao-fn+updated%3A2020-01-17..2020-10-15&type=Issues) | [@lesiano](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Alesiano+updated%3A2020-01-17..2020-10-15&type=Issues) | [@lydian](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Alydian+updated%3A2020-01-17..2020-10-15&type=Issues) | [@mabbasi90](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amabbasi90+updated%3A2020-01-17..2020-10-15&type=Issues) | [@maluhoss](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amaluhoss+updated%3A2020-01-17..2020-10-15&type=Issues) | [@manics](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amanics+updated%3A2020-01-17..2020-10-15&type=Issues) | [@matteoipri](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amatteoipri+updated%3A2020-01-17..2020-10-15&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ameeseeksmachine+updated%3A2020-01-17..2020-10-15&type=Issues) | [@mhwasil](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amhwasil+updated%3A2020-01-17..2020-10-15&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aminrk+updated%3A2020-01-17..2020-10-15&type=Issues) | [@mriedem](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amriedem+updated%3A2020-01-17..2020-10-15&type=Issues) | [@nscozzaro](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Anscozzaro+updated%3A2020-01-17..2020-10-15&type=Issues) | [@pabepadu](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Apabepadu+updated%3A2020-01-17..2020-10-15&type=Issues) | [@possiblyMikeB](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3ApossiblyMikeB+updated%3A2020-01-17..2020-10-15&type=Issues) | [@psyvision](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Apsyvision+updated%3A2020-01-17..2020-10-15&type=Issues) | [@rabsr](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Arabsr+updated%3A2020-01-17..2020-10-15&type=Issues) | [@rainwoodman](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Arainwoodman+updated%3A2020-01-17..2020-10-15&type=Issues) | [@rajat404](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Arajat404+updated%3A2020-01-17..2020-10-15&type=Issues) | [@rcthomas](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Arcthomas+updated%3A2020-01-17..2020-10-15&type=Issues) | [@reneluria](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Areneluria+updated%3A2020-01-17..2020-10-15&type=Issues) | [@rkdarst](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Arkdarst+updated%3A2020-01-17..2020-10-15&type=Issues) | [@rkevin-arch](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Arkevin-arch+updated%3A2020-01-17..2020-10-15&type=Issues) | [@romainx](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aromainx+updated%3A2020-01-17..2020-10-15&type=Issues) | [@ryanlovett](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aryanlovett+updated%3A2020-01-17..2020-10-15&type=Issues) | [@ryogesh](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aryogesh+updated%3A2020-01-17..2020-10-15&type=Issues) | [@sdague](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asdague+updated%3A2020-01-17..2020-10-15&type=Issues) | [@snickell](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asnickell+updated%3A2020-01-17..2020-10-15&type=Issues) | [@SonakshiGrover](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3ASonakshiGrover+updated%3A2020-01-17..2020-10-15&type=Issues) | [@steinad](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asteinad+updated%3A2020-01-17..2020-10-15&type=Issues) | [@stephen-a2z](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Astephen-a2z+updated%3A2020-01-17..2020-10-15&type=Issues) | [@stevegore](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Astevegore+updated%3A2020-01-17..2020-10-15&type=Issues) | [@stv0g](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Astv0g+updated%3A2020-01-17..2020-10-15&type=Issues) | [@subgero](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asubgero+updated%3A2020-01-17..2020-10-15&type=Issues) | [@sudi007](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asudi007+updated%3A2020-01-17..2020-10-15&type=Issues) | [@summerswallow](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asummerswallow+updated%3A2020-01-17..2020-10-15&type=Issues) | [@support](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asupport+updated%3A2020-01-17..2020-10-15&type=Issues) | [@synchronizing](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asynchronizing+updated%3A2020-01-17..2020-10-15&type=Issues) | [@thuvh](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Athuvh+updated%3A2020-01-17..2020-10-15&type=Issues) | [@tritemio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Atritemio+updated%3A2020-01-17..2020-10-15&type=Issues) | [@twalcari](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Atwalcari+updated%3A2020-01-17..2020-10-15&type=Issues) | [@vchandvankar](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Avchandvankar+updated%3A2020-01-17..2020-10-15&type=Issues) | [@vilhelmen](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Avilhelmen+updated%3A2020-01-17..2020-10-15&type=Issues) | [@vlizanae](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Avlizanae+updated%3A2020-01-17..2020-10-15&type=Issues) | [@weimin](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aweimin+updated%3A2020-01-17..2020-10-15&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Awelcome+updated%3A2020-01-17..2020-10-15&type=Issues) | [@willingc](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Awillingc+updated%3A2020-01-17..2020-10-15&type=Issues) | [@yhal-nesi](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ayhal-nesi+updated%3A2020-01-17..2020-10-15&type=Issues) | [@ynnelson](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aynnelson+updated%3A2020-01-17..2020-10-15&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ayuvipanda+updated%3A2020-01-17..2020-10-15&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AZsailer+updated%3A2020-01-17..2020-10-15&type=Issues) ## 1.1 @@ -43,7 +189,6 @@ Thanks to everyone who has contributed to this release! - Add prometheus metric to measure hub startup time [#2799](https://github.com/jupyterhub/jupyterhub/pull/2799) ([@rajat404](https://github.com/rajat404)) - Add Spawner.auth_state_hook [#2555](https://github.com/jupyterhub/jupyterhub/pull/2555) ([@rcthomas](https://github.com/rcthomas)) - Link services from jupyterhub pages [#2763](https://github.com/jupyterhub/jupyterhub/pull/2763) ([@rcthomas](https://github.com/rcthomas)) -- Add Spawner.auth_state_hook [#2555](https://github.com/jupyterhub/jupyterhub/pull/2555) ([@rcthomas](https://github.com/rcthomas)) - `JupyterHub.user_redirect_hook` is added to allow admins to customize /user-redirect/ behavior [#2790](https://github.com/jupyterhub/jupyterhub/pull/2790) ([@yuvipanda](https://github.com/yuvipanda)) - Add prometheus metric to measure hub startup time [#2799](https://github.com/jupyterhub/jupyterhub/pull/2799) ([@rajat404](https://github.com/rajat404)) - Add prometheus metric to measure proxy route poll times [#2798](https://github.com/jupyterhub/jupyterhub/pull/2798) ([@rajat404](https://github.com/rajat404)) diff --git a/jupyterhub/_version.py b/jupyterhub/_version.py index f3376877..3f64fe6f 100644 --- a/jupyterhub/_version.py +++ b/jupyterhub/_version.py @@ -6,8 +6,8 @@ version_info = ( 1, 2, 0, - # "", # release (b1, rc1, or "" for final or dev) - "dev", # dev or nothing for beta/rc/stable releases + "b1", # release (b1, rc1, or "" for final or dev) + # "dev", # dev or nothing for beta/rc/stable releases ) # pep 440 version: no dot before beta/rc, but before .dev diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index d59cfb12..8ebc15d4 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -190,6 +190,7 @@ class APIHandler(BaseHandler): 'kind': 'user', 'name': user.name, 'admin': user.admin, + 'roles': [r.name for r in user.roles], 'groups': [g.name for g in user.groups], 'server': user.url if user.running else None, 'pending': None, diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 44c829ff..8398de6d 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -13,6 +13,7 @@ from tornado import web from tornado.iostream import StreamClosedError from .. import orm +from .. import roles from ..user import User from ..utils import admin_only from ..utils import isoformat @@ -87,7 +88,8 @@ class UserListAPIHandler(APIHandler): user = self.user_from_username(name) if admin: user.admin = True - self.db.commit() + roles.DefaultRoles.add_default_role(self.db, user) + self.db.commit() try: await maybe_future(self.authenticator.add_user(user)) except Exception as e: @@ -149,7 +151,8 @@ class UserAPIHandler(APIHandler): self._check_user_model(data) if 'admin' in data: user.admin = data['admin'] - self.db.commit() + roles.DefaultRoles.add_default_role(self.db, user) + self.db.commit() try: await maybe_future(self.authenticator.add_user(user)) @@ -205,6 +208,8 @@ class UserAPIHandler(APIHandler): if key == 'auth_state': await user.save_auth_state(value) else: + if key == 'admin' and value != user.admin: + roles.DefaultRoles.change_admin(self.db, user=user, admin=value) setattr(user, key, value) self.db.commit() user_ = self.user_model(user) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 9b11fef0..f72f899e 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -73,6 +73,7 @@ from .services.service import Service from . import crypto from . import dbutil, orm +from . import roles from .user import UserDict from .oauth.provider import make_provider from ._data import DATA_FILES_PATH @@ -311,6 +312,28 @@ class JupyterHub(Application): """, ).tag(config=True) + load_roles = List( + Dict(), + help="""List of predefined role dictionaries to load at startup. + + For instance:: + + roles = [ + { + 'name': 'teacher', + 'description': 'Access users information, servers and groups without create/delete privileges', + 'scopes': ['users', 'groups'], + 'users': ['cyclops', 'wolverine'] + } + ] + + See all the available scopes in the JupyterHub REST API documentation. + + The default roles are in roles.py. + + """, + ).tag(config=True) + config_file = Unicode('jupyterhub_config.py', help="The config file to load").tag( config=True ) @@ -1692,6 +1715,7 @@ class JupyterHub(Application): for name in admin_users: # ensure anyone specified as admin in config is admin in db + # and gets admin role user = orm.User.find(db, name) if user is None: user = orm.User(name=name, admin=True) @@ -1699,7 +1723,6 @@ class JupyterHub(Application): db.add(user) else: user.admin = True - # the admin_users config variable will never be used after this point. # only the database values will be referenced. @@ -1798,6 +1821,37 @@ class JupyterHub(Application): group.users.append(user) db.commit() + async def init_roles(self): + """Load default and predefined roles into the database""" + db = self.db + # load default roles + roles.DefaultRoles.load_to_database(db) + + # load predefined roles from config file + for predef_role in self.load_roles: + role = roles.add_predef_role(db, predef_role) + # handle users + for username in predef_role['users']: + username = self.authenticator.normalize_username(username) + if not ( + await maybe_future(self.authenticator.check_allowed(username, None)) + ): + raise ValueError( + "Username %r is not in Authenticator.allowed_users" % username + ) + user = orm.User.find(db, name=username) + if user is None: + if not self.authenticator.validate_username(username): + raise ValueError("Role username %r is not valid" % username) + user = orm.User(name=username) + db.add(user) + roles.add_user(db, user=user, role=role) + + # make sure every existing user has a default user or admin role + for user in db.query(orm.User): + roles.DefaultRoles.add_default_role(db, user) + db.commit() + async def _add_tokens(self, token_dict, kind): """Add tokens for users or services to the database""" if kind == 'user': @@ -2376,6 +2430,7 @@ class JupyterHub(Application): self.init_oauth() await self.init_users() await self.init_groups() + await self.init_roles() self.init_services() await self.init_api_tokens() self.init_tornado_settings() diff --git a/jupyterhub/dbutil.py b/jupyterhub/dbutil.py index 703de8f4..e3fc7850 100644 --- a/jupyterhub/dbutil.py +++ b/jupyterhub/dbutil.py @@ -139,7 +139,7 @@ def upgrade_if_needed(db_url, backup=True, log=None): def shell(args=None): - """Start an IPython shell hooked up to the jupyerhub database""" + """Start an IPython shell hooked up to the jupyterhub database""" from .app import JupyterHub hub = JupyterHub() diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index cc96ca88..1a518bf0 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -90,6 +90,26 @@ class JSONDict(TypeDecorator): return value +class JSONList(JSONDict): + """Represents an immutable structure as a json-encoded string (to be used for list type columns). + + Usage:: + + JSONList(JSONDict) + + """ + + def process_bind_param(self, value, dialect): + if isinstance(value, list) and value is not None: + value = json.dumps(value) + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = json.loads(value) + return value + + Base = declarative_base() Base.log = app_log @@ -113,6 +133,41 @@ class Server(Base): return "" % (self.ip, self.port) +# user:role many:many mapping table +user_role_map = Table( + 'user_role_map', + Base.metadata, + Column('user_id', ForeignKey('users.id', ondelete='CASCADE'), primary_key=True), + Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), +) + + +class Role(Base): + """User Roles""" + + __tablename__ = 'roles' + id = Column(Integer, primary_key=True, autoincrement=True) + name = Column(Unicode(255), unique=True) + description = Column(Unicode(1023)) + scopes = Column(JSONList) + users = relationship('User', secondary='user_role_map', backref='roles') + + def __repr__(self): + return "<%s %s (%s) - scopes: %s>" % ( + self.__class__.__name__, + self.name, + self.description, + self.scopes, + ) + + @classmethod + def find(cls, db, name): + """Find a role by name. + Returns None if not found. + """ + return db.query(cls).filter(cls.name == name).first() + + # user:group many:many mapping table user_group_map = Table( 'user_group_map', diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py new file mode 100644 index 00000000..ac5180e2 --- /dev/null +++ b/jupyterhub/roles.py @@ -0,0 +1,127 @@ +"""Roles utils""" +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. +from .orm import Role + + +# define default roles +class DefaultRoles: + + user = Role(name='user', description='Everything the user can do', scopes=['all']) + admin = Role( + name='admin', + description='Admin privileges (currently can do everything)', + scopes=[ + 'all', + 'users', + 'users:tokens', + 'admin:users', + 'admin:users:servers', + 'groups', + 'admin:groups', + 'read:services', + 'proxy', + 'shutdown', + ], + ) + server = Role( + name='server', + description='Post activity only', + scopes=['users:activity!user=username'], + ) + roles = (user, admin, server) + + def __init__(cls, roles=roles): + cls.roles = roles + + @classmethod + def get_user_role(cls, db): + return Role.find(db, name=cls.user.name) + + @classmethod + def get_admin_role(cls, db): + return Role.find(db, name=cls.admin.name) + + @classmethod + def get_server_role(cls, db): + return Role.find(db, name=cls.server.name) + + @classmethod + def load_to_database(cls, db): + for role in cls.roles: + db_role = Role.find(db, name=role.name) + if db_role is None: + new_role = Role( + name=role.name, description=role.description, scopes=role.scopes, + ) + db.add(new_role) + db.commit() + + @classmethod + def add_default_role(cls, db, user): + role = None + if user.admin and cls.admin not in user.roles: + role = cls.get_admin_role(db) + if not user.admin and cls.user not in user.roles: + role = cls.get_user_role(db) + if role is not None: + add_user(db, user, role) + db.commit() + + @classmethod + def change_admin(cls, db, user, admin): + user_role = cls.get_user_role(db) + admin_role = cls.get_admin_role(db) + if admin: + if user_role in user.roles: + remove_user(db, user, user_role) + add_user(db, user, admin_role) + else: + if admin_role in user.roles: + remove_user(db, user, admin_role) + add_user(db, user, user_role) + db.commit() + + +def add_user(db, user, role): + if role is not None and role not in user.roles: + user.roles.append(role) + db.commit() + + +def remove_user(db, user, role): + if role is not None and role in user.roles: + user.roles.remove(role) + db.commit() + + +def add_predef_role(db, predef_role): + """ + Returns either the role to write into db or updated role if already in db + """ + role = Role.find(db, predef_role['name']) + # if a new role, add to db, if existing, rewrite its attributes apart from the name + if role is None: + role = Role( + name=predef_role['name'], + description=predef_role['description'], + scopes=predef_role['scopes'], + ) + db.add(role) + db.commit() + else: + # check if it's not one of the default roles + if not any(d.name == predef_role['name'] for d in DefaultRoles.roles): + # if description and scopes specified, rewrite the old ones + if 'description' in predef_role.keys(): + role.description = predef_role['description'] + if 'scopes' in predef_role.keys(): + role.scopes = predef_role['scopes'] + # FIXME - for now deletes old users and writes new ones + role.users = [] + else: + raise ValueError( + "The role %r is a default role that cannot be overwritten, use a different role name" + % predef_role['name'] + ) + return role diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 47b38f87..d7fddf8b 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -44,6 +44,7 @@ from traitlets import default from traitlets import Dict from .. import orm +from .. import roles from ..app import JupyterHub from ..auth import PAMAuthenticator from ..objects import Server @@ -318,6 +319,8 @@ class MockHub(JupyterHub): self.db.delete(user) for group in self.db.query(orm.Group): self.db.delete(group) + for role in self.db.query(orm.Role): + self.db.delete(role) self.db.commit() @gen.coroutine @@ -333,6 +336,7 @@ class MockHub(JupyterHub): user = self.db.query(orm.User).filter(orm.User.name == 'user').first() if user is None: user = orm.User(name='user') + roles.DefaultRoles.add_default_role(self.db, user=user) self.db.add(user) self.db.commit() @@ -403,7 +407,7 @@ class StubSingleUserSpawner(MockSpawner): - authenticated, so we are testing auth - always available (i.e. in base ServerApp and NotebookApp """ - return "/api/spec.yaml" + return "/api/status" _thread = None diff --git a/jupyterhub/tests/populate_db.py b/jupyterhub/tests/populate_db.py index 2b5c6007..fd8cb9a1 100644 --- a/jupyterhub/tests/populate_db.py +++ b/jupyterhub/tests/populate_db.py @@ -10,6 +10,9 @@ from datetime import datetime import jupyterhub from jupyterhub import orm +# FIXME - for later versions of jupyterhub add code to test Roles +# from jupyterhub.orm import Role + def populate_db(url): """Populate a jupyterhub database""" diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index fa6a20d1..dab18512 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -17,6 +17,7 @@ from tornado import gen import jupyterhub from .. import orm +from .. import roles from ..utils import url_path_join as ujoin from ..utils import utcnow from .mocking import public_host @@ -66,9 +67,10 @@ async def test_auth_api(app): async def test_referer_check(app): url = ujoin(public_host(app), app.hub.base_url) host = urlparse(url).netloc + # add admin user user = find_user(app.db, 'admin') if user is None: - user = add_user(app.db, name='admin', admin=True) + user = add_user(app.db, name='admin', admin=True, roles=['admin']) cookies = await app.login_user('admin') r = await api_request( @@ -152,6 +154,7 @@ def fill_user(model): """ model.setdefault('server', None) model.setdefault('kind', 'user') + model.setdefault('roles', []) model.setdefault('groups', []) model.setdefault('admin', False) model.setdefault('server', None) @@ -166,6 +169,7 @@ TIMESTAMP = normalize_timestamp(datetime.now().isoformat() + 'Z') @mark.user +@mark.role async def test_get_users(app): db = app.db r = await api_request(app, 'users') @@ -174,8 +178,10 @@ async def test_get_users(app): users = sorted(r.json(), key=lambda d: d['name']) users = [normalize_user(u) for u in users] assert users == [ - fill_user({'name': 'admin', 'admin': True}), - fill_user({'name': 'user', 'admin': False, 'last_activity': None}), + fill_user({'name': 'admin', 'admin': True, 'roles': ['admin']}), + fill_user( + {'name': 'user', 'admin': False, 'roles': ['user'], 'last_activity': None} + ), ] r = await api_request(app, 'users', headers=auth_header(db, 'user')) @@ -216,6 +222,7 @@ async def test_get_self(app): @mark.user +@mark.role async def test_add_user(app): db = app.db name = 'newuser' @@ -225,16 +232,20 @@ async def test_add_user(app): assert user is not None assert user.name == name assert not user.admin + # assert newuser has default 'user' role + assert roles.DefaultRoles.get_user_role(db=db) in user.roles + assert roles.DefaultRoles.get_admin_role(db=db) not in user.roles @mark.user +@mark.role async def test_get_user(app): name = 'user' r = await api_request(app, 'users', name) assert r.status_code == 200 user = normalize_user(r.json()) - assert user == fill_user({'name': name, 'auth_state': None}) + assert user == fill_user({'name': name, 'roles': ['user'], 'auth_state': None}) @mark.user @@ -262,6 +273,7 @@ async def test_add_multi_user_invalid(app): @mark.user +@mark.role async def test_add_multi_user(app): db = app.db names = ['a', 'b'] @@ -278,6 +290,9 @@ async def test_add_multi_user(app): assert user is not None assert user.name == name assert not user.admin + # assert default 'user' role added + assert roles.DefaultRoles.get_user_role(db=db) in user.roles + assert roles.DefaultRoles.get_admin_role(db=db) not in user.roles # try to create the same users again r = await api_request( @@ -298,6 +313,7 @@ async def test_add_multi_user(app): @mark.user +@mark.role async def test_add_multi_user_admin(app): db = app.db names = ['c', 'd'] @@ -317,6 +333,8 @@ async def test_add_multi_user_admin(app): assert user is not None assert user.name == name assert user.admin + assert roles.DefaultRoles.get_user_role(db=db) not in user.roles + assert roles.DefaultRoles.get_admin_role(db=db) in user.roles @mark.user @@ -342,6 +360,7 @@ async def test_add_user_duplicate(app): @mark.user +@mark.role async def test_add_admin(app): db = app.db name = 'newadmin' @@ -350,9 +369,13 @@ async def test_add_admin(app): ) assert r.status_code == 201 user = find_user(db, name) + user_role = orm.Role.find(db, 'user') assert user is not None assert user.name == name assert user.admin + # assert newadmin has default 'admin' role + assert roles.DefaultRoles.get_user_role(db=db) not in user.roles + assert roles.DefaultRoles.get_admin_role(db=db) in user.roles @mark.user @@ -364,6 +387,7 @@ async def test_delete_user(app): @mark.user +@mark.role async def test_make_admin(app): db = app.db name = 'admin2' @@ -373,15 +397,20 @@ async def test_make_admin(app): assert user is not None assert user.name == name assert not user.admin + assert roles.DefaultRoles.get_user_role(db=db) in user.roles + assert roles.DefaultRoles.get_admin_role(db=db) not in user.roles r = await api_request( app, 'users', name, method='patch', data=json.dumps({'admin': True}) ) + assert r.status_code == 200 user = find_user(db, name) assert user is not None assert user.name == name assert user.admin + assert roles.DefaultRoles.get_user_role(db=db) not in user.roles + assert roles.DefaultRoles.get_admin_role(db=db) in user.roles @mark.user diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index 0c125c5a..4b6c12ae 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -245,10 +245,12 @@ def test_groups(db): db.commit() assert group.users == [] assert user.groups == [] + group.users.append(user) db.commit() assert group.users == [user] assert user.groups == [group] + db.delete(user) db.commit() assert group.users == [] @@ -460,7 +462,7 @@ def test_group_delete_cascade(db): assert group2 in user2.groups # now start deleting - # 1. remove group via user.groups + # 1. remove group via user.group user1.groups.remove(group2) db.commit() assert user1 not in group2.users @@ -480,6 +482,7 @@ def test_group_delete_cascade(db): # 4. delete user object db.delete(user1) + db.delete(user2) db.commit() assert user1 not in group1.users @@ -557,3 +560,4 @@ def test_expiring_oauth_code(app, user): assert orm_code in db.query(orm.OAuthCode) orm.OAuthCode.purge_expired(db) assert orm_code not in db.query(orm.OAuthCode) + diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py new file mode 100644 index 00000000..5c3c0689 --- /dev/null +++ b/jupyterhub/tests/test_roles.py @@ -0,0 +1,135 @@ +"""Test roles""" +# import pytest +from pytest import mark + +from .. import orm +from ..roles import DefaultRoles +from .mocking import MockHub + + +@mark.role +def test_roles(db): + """Test orm roles setup""" + user = orm.User(name='falafel') + db.add(user) + role = orm.Role(name='default') + db.add(role) + db.commit() + assert role.users == [] + assert user.roles == [] + + role.users.append(user) + db.commit() + assert role.users == [user] + assert user.roles == [role] + + db.delete(user) + db.commit() + assert role.users == [] + db.delete(role) + + +@mark.role +def test_role_delete_cascade(db): + """Orm roles cascade""" + user1 = orm.User(name='user1') + user2 = orm.User(name='user2') + role1 = orm.Role(name='role1') + role2 = orm.Role(name='role2') + db.add(user1) + db.add(user2) + db.add(role1) + db.add(role2) + db.commit() + # add user to role via user.roles + user1.roles.append(role1) + db.commit() + assert user1 in role1.users + assert role1 in user1.roles + + # add user to role via roles.users + role1.users.append(user2) + db.commit() + assert user2 in role1.users + assert role1 in user2.roles + + # fill role2 and check role1 again + role2.users.append(user1) + role2.users.append(user2) + db.commit() + assert user1 in role1.users + assert user2 in role1.users + assert user1 in role2.users + assert user2 in role2.users + assert role1 in user1.roles + assert role1 in user2.roles + assert role2 in user1.roles + assert role2 in user2.roles + + # now start deleting + # 1. remove role via user.roles + user1.roles.remove(role2) + db.commit() + assert user1 not in role2.users + assert role2 not in user1.roles + + # 2. remove user via role.users + role1.users.remove(user2) + db.commit() + assert user2 not in role1.users + assert role1 not in user2.roles + + # 3. delete role object + db.delete(role2) + db.commit() + assert role2 not in user1.roles + assert role2 not in user2.roles + + # 4. delete user object + db.delete(user1) + db.delete(user2) + db.commit() + assert user1 not in role1.users + + +@mark.role +async def test_load_roles(tmpdir, request): + """Test loading default and predefined roles in app.py""" + to_load = [ + { + 'name': 'teacher', + 'description': 'Access users information, servers and groups without create/delete privileges', + 'scopes': ['users', 'groups'], + 'users': ['cyclops', 'gandalf'], + } + ] + kwargs = {'load_roles': to_load} + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + # keep the users and groups from test_load_groups + hub = MockHub(test_clean_db=False, **kwargs) + hub.init_db() + await hub.init_users() + await hub.init_roles() + db = hub.db + # test default roles loaded to database + assert DefaultRoles.get_user_role(db) is not None + assert DefaultRoles.get_admin_role(db) is not None + assert DefaultRoles.get_server_role(db) is not None + # test if every existing user has a correct default role + for user in db.query(orm.User): + assert len(user.roles) == len(set(user.roles)) + if user.admin: + assert DefaultRoles.get_admin_role(db) in user.roles + assert DefaultRoles.get_user_role(db) not in user.roles + else: + assert DefaultRoles.get_user_role(db) in user.roles + assert DefaultRoles.get_admin_role(db) not in user.roles + # test if predefined roles loaded and assigned + teacher_role = orm.Role.find(db, name='teacher') + assert teacher_role is not None + gandalf_user = orm.User.find(db, name='gandalf') + assert teacher_role in gandalf_user.roles + cyclops_user = orm.User.find(db, name='cyclops') + assert teacher_role in cyclops_user.roles diff --git a/jupyterhub/traitlets.py b/jupyterhub/traitlets.py index af3cd7fa..0cc616a9 100644 --- a/jupyterhub/traitlets.py +++ b/jupyterhub/traitlets.py @@ -9,6 +9,7 @@ from traitlets import List from traitlets import TraitError from traitlets import TraitType from traitlets import Type +from traitlets import Undefined from traitlets import Unicode @@ -27,11 +28,15 @@ class Command(List): but allows it to be specified as a single string. """ - def __init__(self, default_value=None, **kwargs): + def __init__(self, default_value=Undefined, **kwargs): kwargs.setdefault('minlen', 1) if isinstance(default_value, str): default_value = [default_value] - super().__init__(Unicode(), default_value, **kwargs) + if default_value is not Undefined and ( + not (default_value is None and not kwargs.get("allow_none", False)) + ): + kwargs["default_value"] = default_value + super().__init__(Unicode(), **kwargs) def validate(self, obj, value): if isinstance(value, str): diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index e3f0a0e6..73235914 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -173,7 +173,8 @@ async def exponential_backoff( # this prevents overloading any single tornado loop iteration with # too many things dt = min(max_wait, remaining, random.uniform(0, start_wait * scale)) - scale *= scale_factor + if dt < max_wait: + scale *= scale_factor await gen.sleep(dt) raise TimeoutError(fail_message) diff --git a/pytest.ini b/pytest.ini index dff95321..4b499de6 100644 --- a/pytest.ini +++ b/pytest.ini @@ -13,3 +13,4 @@ markers = services: mark as a services test user: mark as a test for a user slow: mark a test as slow + role: mark as a test for roles From ced80f9e6bb1edfc0e9de9d104d25c3020c2b93b Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 20 Oct 2020 08:11:42 +0200 Subject: [PATCH 009/270] removing rest-api.yml changes --- docs/rest-api.yml | 146 +--------------------------------------------- 1 file changed, 1 insertion(+), 145 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index beb5e181..09d0ed99 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -13,40 +13,8 @@ securityDefinitions: type: apiKey name: Authorization in: header - oauth2: - type: oauth2 - flow: accessCode - authorizationUrl: '/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? - tokenUrl: '/hub/api/oauth2/token' - scopes: - all: Everything a user can do - read:all: Read-only access to everything a user can read (also whoami handler) - users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers - read:users: Read-only access to the above - read:users!user=username: Read-only access to a single user's model - read:users:names: Read-only access to users' names - read:users:groups: Read-only access to users' groups - read:users:activity: Read-only access to users' activity - read:users:activity!group=groupname: Read-only access to specific group's users' activity - read:users:servers: Read-only access to users' servers - users:activity!user=username: Update a user's activity - users:servers: Grants access to start/stop any server - users:servers!server=servername: Limits the above to a specific server - users:tokens: Grants access to users' token (includes create/revoke a token) - read:users:tokens: Identify a user from a token - admin:users: Grants access to creating/removing users - admin:users:servers: Grants access to create/remove users' servers - groups: Add/remove users from any group - groups!group=groupname: Add/remove users from a specific group only - read:groups: Read-only access to groups - admin:groups: Grants access to create/delete groups - read:services: Read-only access to services - proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy - shutdown: Grants access to shutdown the Hub -security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope all) or have both (either can be used)? +security: - token: [] - - oauth2: - - all basePath: /hub/api produces: - application/json @@ -111,10 +79,6 @@ paths: /users: get: summary: List users - security: - - oauth2: - - users - - read:users responses: '200': description: The Hub's user list @@ -124,9 +88,6 @@ paths: $ref: '#/definitions/User' post: summary: Create multiple users - security: - - oauth2: - - admin:users parameters: - name: body in: body @@ -153,11 +114,6 @@ paths: /users/{name}: get: summary: Get a user by name - security: - - oauth2: - - users - - read:users - - read:users!user=username parameters: - name: name description: username @@ -171,9 +127,6 @@ paths: $ref: '#/definitions/User' post: summary: Create a single user - security: - - oauth2: - - admin:users parameters: - name: name description: username @@ -188,9 +141,6 @@ paths: patch: summary: Modify a user description: Change a user's name or admin status - security: - - oauth2: - - users parameters: - name: name description: username @@ -217,9 +167,6 @@ paths: $ref: '#/definitions/User' delete: summary: Delete a user - security: - - oauth2: - - admin:users parameters: - name: name description: username @@ -237,10 +184,6 @@ paths: Notify the Hub of activity by the user, e.g. accessing a service or (more likely) actively using a server. - security: - - oauth2: - - users - - users:activity!user=username parameters: - name: name description: username @@ -293,10 +236,6 @@ paths: /users/{name}/server: post: summary: Start a user's single-user notebook server - security: - - oauth2: - - users - - users:servers parameters: - name: name description: username @@ -323,10 +262,6 @@ paths: description: The user's notebook server has not yet started, but has been requested delete: summary: Stop a user's server - security: - - oauth2: - - users - - users:servers parameters: - name: name description: username @@ -341,11 +276,6 @@ paths: /users/{name}/servers/{server_name}: post: summary: Start a user's single-user named-server notebook server - security: - - oauth2: - - users - - users:servers - - users:servers!server=servername parameters: - name: name description: username @@ -377,11 +307,6 @@ paths: description: The user's notebook named-server has not yet started, but has been requested delete: summary: Stop a user's named-server - security: - - oauth2: - - users - - users:servers - - users:servers!server=servername parameters: - name: name description: username @@ -419,9 +344,6 @@ paths: type: string get: summary: List tokens for the user - security: - - oauth2: - - users:tokens responses: '200': description: The list of tokens @@ -435,9 +357,6 @@ paths: description: No such user post: summary: Create a new token for the user - security: - - oauth2: - - users:tokens parameters: - name: token_params in: body @@ -471,9 +390,6 @@ paths: type: string get: summary: Get the model for a token by id - security: - - oauth2: - - users:tokens responses: '200': description: The info for the new token @@ -481,19 +397,12 @@ paths: $ref: '#/definitions/Token' delete: summary: Delete (revoke) a token by id - security: - - oauth2: - - users:tokens responses: '204': description: The token has been deleted /user: get: summary: Return authenticated user's model - security: - - oauth2: - - all - - read:all responses: '200': description: The authenticated user's model is returned. @@ -502,10 +411,6 @@ paths: /groups: get: summary: List groups - security: - - oauth2: - - groups - - read:groups responses: '200': description: The list of groups @@ -516,11 +421,6 @@ paths: /groups/{name}: get: summary: Get a group by name - security: - - oauth2: - - groups - - groups!group=groupname - - read:groups parameters: - name: name description: group name @@ -534,9 +434,6 @@ paths: $ref: '#/definitions/Group' post: summary: Create a group - security: - - oauth2: - - admin:groups parameters: - name: name description: group name @@ -550,9 +447,6 @@ paths: $ref: '#/definitions/Group' delete: summary: Delete a group - security: - - oauth2: - - admin:groups parameters: - name: name description: group name @@ -565,10 +459,6 @@ paths: /groups/{name}/users: post: summary: Add users to a group - security: - - oauth2: - - groups - - groups!group=groupname parameters: - name: name description: group name @@ -594,10 +484,6 @@ paths: $ref: '#/definitions/Group' delete: summary: Remove users from a group - security: - - oauth2: - - groups - - groups!group=groupname parameters: - name: name description: group name @@ -622,9 +508,6 @@ paths: /services: get: summary: List services - security: - - oauth2: - - read:services responses: '200': description: The service list @@ -635,9 +518,6 @@ paths: /services/{name}: get: summary: Get a service by name - security: - - oauth2: - - read:services parameters: - name: name description: service name @@ -653,9 +533,6 @@ paths: get: summary: Get the proxy's routing table description: A convenience alias for getting the routing table directly from the proxy - security: - - oauth2: - - proxy responses: '200': description: Routing table @@ -664,18 +541,12 @@ paths: description: configurable-http-proxy routing table (see configurable-http-proxy docs for details) post: summary: Force the Hub to sync with the proxy - security: - - oauth2: - - proxy responses: '200': description: Success patch: summary: Notify the Hub about a new proxy description: Notifies the Hub of a new proxy to use. - security: - - oauth2: - - proxy parameters: - name: body in: body @@ -708,9 +579,6 @@ paths: in the JSON request body. Logging in via this method is only available when the active Authenticator accepts passwords (e.g. not OAuth). - security: - - oauth2: - - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope parameters: - name: credentials in: body @@ -735,9 +603,6 @@ paths: /authorizations/token/{token}: get: summary: Identify a user or service from an API token - security: - - oauth2: - - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path @@ -768,7 +633,6 @@ paths: $ref: '#/definitions/User' '404': description: A user is not found. - deprecated: true # minrk: let’s not add a scope for this, let’s remove it /oauth2/authorize: get: summary: 'OAuth 2.0 authorize endpoint' @@ -850,9 +714,6 @@ paths: /shutdown: post: summary: Shutdown the Hub - security: - - oauth2: - - shutdown parameters: - name: body in: body @@ -886,11 +747,6 @@ definitions: admin: type: boolean description: Whether the user is an admin - roles: - type: array - description: The names of roles this user has - items: - type: string groups: type: array description: The names of groups where this user is a member From 4142dc1bc08a72dfcca3b5571b8c6eadfd3282f7 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 21 Oct 2020 16:36:50 +0200 Subject: [PATCH 010/270] update to roles utils --- jupyterhub/apihandlers/users.py | 8 +- jupyterhub/app.py | 15 ++- jupyterhub/roles.py | 161 ++++++++++++-------------------- jupyterhub/tests/mocking.py | 3 +- jupyterhub/tests/test_api.py | 25 +++-- jupyterhub/tests/test_roles.py | 40 ++++---- 6 files changed, 112 insertions(+), 140 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 8398de6d..c253e4ea 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -88,7 +88,7 @@ class UserListAPIHandler(APIHandler): user = self.user_from_username(name) if admin: user.admin = True - roles.DefaultRoles.add_default_role(self.db, user) + roles.update_roles(self.db, user) self.db.commit() try: await maybe_future(self.authenticator.add_user(user)) @@ -151,7 +151,7 @@ class UserAPIHandler(APIHandler): self._check_user_model(data) if 'admin' in data: user.admin = data['admin'] - roles.DefaultRoles.add_default_role(self.db, user) + roles.update_roles(self.db, user) self.db.commit() try: @@ -208,9 +208,9 @@ class UserAPIHandler(APIHandler): if key == 'auth_state': await user.save_auth_state(value) else: - if key == 'admin' and value != user.admin: - roles.DefaultRoles.change_admin(self.db, user=user, admin=value) setattr(user, key, value) + if key == 'admin': + roles.update_roles(self.db, user=user) self.db.commit() user_ = self.user_model(user) user_['auth_state'] = await user.get_auth_state() diff --git a/jupyterhub/app.py b/jupyterhub/app.py index f72f899e..70483993 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1715,7 +1715,6 @@ class JupyterHub(Application): for name in admin_users: # ensure anyone specified as admin in config is admin in db - # and gets admin role user = orm.User.find(db, name) if user is None: user = orm.User(name=name, admin=True) @@ -1825,11 +1824,15 @@ class JupyterHub(Application): """Load default and predefined roles into the database""" db = self.db # load default roles - roles.DefaultRoles.load_to_database(db) + default_roles = roles.get_default_roles() + for role in default_roles: + roles.add_role(db, role) # load predefined roles from config file for predef_role in self.load_roles: - role = roles.add_predef_role(db, predef_role) + roles.add_role(db, predef_role) + role = orm.Role.find(db, predef_role['name']) + # handle users for username in predef_role['users']: username = self.authenticator.normalize_username(username) @@ -1847,9 +1850,11 @@ class JupyterHub(Application): db.add(user) roles.add_user(db, user=user, role=role) - # make sure every existing user has a default user or admin role + # make sure all users have at least one role (update with default) for user in db.query(orm.User): - roles.DefaultRoles.add_default_role(db, user) + if len(user.roles) < 1: + roles.update_roles(db, user) + db.commit() async def _add_tokens(self, token_dict, kind): diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index ac5180e2..53e0c637 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -4,83 +4,58 @@ from .orm import Role -# define default roles -class DefaultRoles: +def get_default_roles(): - user = Role(name='user', description='Everything the user can do', scopes=['all']) - admin = Role( - name='admin', - description='Admin privileges (currently can do everything)', - scopes=[ - 'all', - 'users', - 'users:tokens', - 'admin:users', - 'admin:users:servers', - 'groups', - 'admin:groups', - 'read:services', - 'proxy', - 'shutdown', - ], - ) - server = Role( - name='server', - description='Post activity only', - scopes=['users:activity!user=username'], - ) - roles = (user, admin, server) + """Returns a list of default roles dictionaries""" - def __init__(cls, roles=roles): - cls.roles = roles + default_roles = [ + { + 'name': 'user', + 'description': 'Everything the user can do', + 'scopes': ['all'], + }, + { + 'name': 'admin', + 'description': 'Admin privileges (currently can do everything)', + 'scopes': [ + 'all', + 'users', + 'users:tokens', + 'admin:users', + 'admin:users:servers', + 'groups', + 'admin:groups', + 'read:services', + 'proxy', + 'shutdown', + ], + }, + { + 'name': 'server', + 'description': 'Post activity only', + 'scopes': ['users:activity!user=username'], + }, + ] + return default_roles - @classmethod - def get_user_role(cls, db): - return Role.find(db, name=cls.user.name) - @classmethod - def get_admin_role(cls, db): - return Role.find(db, name=cls.admin.name) +def add_role(db, role_dict): - @classmethod - def get_server_role(cls, db): - return Role.find(db, name=cls.server.name) + """Adds a new role to database or modifies an existing one""" - @classmethod - def load_to_database(cls, db): - for role in cls.roles: - db_role = Role.find(db, name=role.name) - if db_role is None: - new_role = Role( - name=role.name, description=role.description, scopes=role.scopes, - ) - db.add(new_role) - db.commit() + role = Role.find(db, role_dict['name']) - @classmethod - def add_default_role(cls, db, user): - role = None - if user.admin and cls.admin not in user.roles: - role = cls.get_admin_role(db) - if not user.admin and cls.user not in user.roles: - role = cls.get_user_role(db) - if role is not None: - add_user(db, user, role) - db.commit() - - @classmethod - def change_admin(cls, db, user, admin): - user_role = cls.get_user_role(db) - admin_role = cls.get_admin_role(db) - if admin: - if user_role in user.roles: - remove_user(db, user, user_role) - add_user(db, user, admin_role) - else: - if admin_role in user.roles: - remove_user(db, user, admin_role) - add_user(db, user, user_role) - db.commit() + if role is None: + role = Role( + name=role_dict['name'], + description=role_dict['description'], + scopes=role_dict['scopes'], + ) + db.add(role) + else: + role.description = role_dict['description'] + role.scopes = role_dict['scopes'] + db.commit() def add_user(db, user, role): @@ -95,33 +70,21 @@ def remove_user(db, user, role): db.commit() -def add_predef_role(db, predef_role): - """ - Returns either the role to write into db or updated role if already in db - """ - role = Role.find(db, predef_role['name']) - # if a new role, add to db, if existing, rewrite its attributes apart from the name - if role is None: - role = Role( - name=predef_role['name'], - description=predef_role['description'], - scopes=predef_role['scopes'], - ) - db.add(role) - db.commit() +def update_roles(db, user): + + """Updates roles if user has no role with default or when user admin status is changed""" + + user_role = Role.find(db, 'user') + admin_role = Role.find(db, 'admin') + + if user.admin: + if user_role in user.roles: + remove_user(db, user, user_role) + add_user(db, user, admin_role) else: - # check if it's not one of the default roles - if not any(d.name == predef_role['name'] for d in DefaultRoles.roles): - # if description and scopes specified, rewrite the old ones - if 'description' in predef_role.keys(): - role.description = predef_role['description'] - if 'scopes' in predef_role.keys(): - role.scopes = predef_role['scopes'] - # FIXME - for now deletes old users and writes new ones - role.users = [] - else: - raise ValueError( - "The role %r is a default role that cannot be overwritten, use a different role name" - % predef_role['name'] - ) - return role + if admin_role in user.roles: + remove_user(db, user, admin_role) + # only add user role if the user has no other roles + if len(user.roles) < 1: + add_user(db, user, user_role) + db.commit() diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index d7fddf8b..003e193c 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -336,7 +336,8 @@ class MockHub(JupyterHub): user = self.db.query(orm.User).filter(orm.User.name == 'user').first() if user is None: user = orm.User(name='user') - roles.DefaultRoles.add_default_role(self.db, user=user) + user_role = orm.Role.find(self.db, 'user') + roles.add_user(self.db, user=user, role=user_role) self.db.add(user) self.db.commit() diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index dab18512..f46c22c6 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -233,8 +233,8 @@ async def test_add_user(app): assert user.name == name assert not user.admin # assert newuser has default 'user' role - assert roles.DefaultRoles.get_user_role(db=db) in user.roles - assert roles.DefaultRoles.get_admin_role(db=db) not in user.roles + assert orm.Role.find(db, 'user') in user.roles + assert orm.Role.find(db, 'admin') not in user.roles @mark.user @@ -291,8 +291,8 @@ async def test_add_multi_user(app): assert user.name == name assert not user.admin # assert default 'user' role added - assert roles.DefaultRoles.get_user_role(db=db) in user.roles - assert roles.DefaultRoles.get_admin_role(db=db) not in user.roles + assert orm.Role.find(db, 'user') in user.roles + assert orm.Role.find(db, 'admin') not in user.roles # try to create the same users again r = await api_request( @@ -333,8 +333,8 @@ async def test_add_multi_user_admin(app): assert user is not None assert user.name == name assert user.admin - assert roles.DefaultRoles.get_user_role(db=db) not in user.roles - assert roles.DefaultRoles.get_admin_role(db=db) in user.roles + assert orm.Role.find(db, 'user') not in user.roles + assert orm.Role.find(db, 'admin') in user.roles @mark.user @@ -369,13 +369,12 @@ async def test_add_admin(app): ) assert r.status_code == 201 user = find_user(db, name) - user_role = orm.Role.find(db, 'user') assert user is not None assert user.name == name assert user.admin # assert newadmin has default 'admin' role - assert roles.DefaultRoles.get_user_role(db=db) not in user.roles - assert roles.DefaultRoles.get_admin_role(db=db) in user.roles + assert orm.Role.find(db, 'user') not in user.roles + assert orm.Role.find(db, 'admin') in user.roles @mark.user @@ -397,8 +396,8 @@ async def test_make_admin(app): assert user is not None assert user.name == name assert not user.admin - assert roles.DefaultRoles.get_user_role(db=db) in user.roles - assert roles.DefaultRoles.get_admin_role(db=db) not in user.roles + assert orm.Role.find(db, 'user') in user.roles + assert orm.Role.find(db, 'admin') not in user.roles r = await api_request( app, 'users', name, method='patch', data=json.dumps({'admin': True}) @@ -409,8 +408,8 @@ async def test_make_admin(app): assert user is not None assert user.name == name assert user.admin - assert roles.DefaultRoles.get_user_role(db=db) not in user.roles - assert roles.DefaultRoles.get_admin_role(db=db) in user.roles + assert orm.Role.find(db, 'user') not in user.roles + assert orm.Role.find(db, 'admin') in user.roles @mark.user diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 5c3c0689..8b20fcf3 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -3,7 +3,7 @@ from pytest import mark from .. import orm -from ..roles import DefaultRoles +from .. import roles from .mocking import MockHub @@ -95,37 +95,41 @@ def test_role_delete_cascade(db): @mark.role async def test_load_roles(tmpdir, request): """Test loading default and predefined roles in app.py""" - to_load = [ + roles_to_load = [ { 'name': 'teacher', 'description': 'Access users information, servers and groups without create/delete privileges', 'scopes': ['users', 'groups'], 'users': ['cyclops', 'gandalf'], - } + }, + { + 'name': 'user', + 'description': 'Only read access', + 'scopes': ['read:all'], + 'users': ['test_user'], + }, ] - kwargs = {'load_roles': to_load} + kwargs = {'load_roles': roles_to_load} ssl_enabled = getattr(request.module, "ssl_enabled", False) if ssl_enabled: kwargs['internal_certs_location'] = str(tmpdir) - # keep the users and groups from test_load_groups - hub = MockHub(test_clean_db=False, **kwargs) + hub = MockHub(**kwargs) hub.init_db() + db = hub.db await hub.init_users() await hub.init_roles() - db = hub.db - # test default roles loaded to database - assert DefaultRoles.get_user_role(db) is not None - assert DefaultRoles.get_admin_role(db) is not None - assert DefaultRoles.get_server_role(db) is not None - # test if every existing user has a correct default role + # test if the 'user' role has been overwritten + user_role = orm.Role.find(db, 'user') + assert user_role is not None + assert user_role.scopes == ['read:all'] + # test other default roles loaded to database + assert orm.Role.find(db, 'user') is not None + assert orm.Role.find(db, 'admin') is not None + assert orm.Role.find(db, 'server') is not None + # test if every existing user has a role (and no duplicates) for user in db.query(orm.User): + assert len(user.roles) > 0 assert len(user.roles) == len(set(user.roles)) - if user.admin: - assert DefaultRoles.get_admin_role(db) in user.roles - assert DefaultRoles.get_user_role(db) not in user.roles - else: - assert DefaultRoles.get_user_role(db) in user.roles - assert DefaultRoles.get_admin_role(db) not in user.roles # test if predefined roles loaded and assigned teacher_role = orm.Role.find(db, name='teacher') assert teacher_role is not None From dece64d2480542d2c00b700ff63997d30ce30a92 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 27 Oct 2020 09:43:43 +0100 Subject: [PATCH 011/270] Separated scope from other decorators --- jupyterhub/utils.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 424c48a7..a3f324ad 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -4,6 +4,7 @@ import asyncio import concurrent.futures import errno +import functools import hashlib import inspect import os @@ -298,18 +299,31 @@ def metrics_authentication(self): raise web.HTTPError(403) -@auth_decorator -def needs_scope(self, scope, **kwargs): +def needs_scope(scope): """Decorator to restrict access to users or services with the required scope""" - if scope not in self.current_scopes: - # Check if access is not restricted to user/server/group - match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") - subscopes = filter(lambda s: re.search(match_string, s), self.current_scopes) - subset = [subscope.split('=')[1] for subscope in subscopes] - if not subset: - raise web.HTTPError(403, "Action is not authorized with current scopes") - else: - kwargs['subset'] = subset + + def scope_decorator(func): + @functools.wraps(func) + def _auth_func(self, *args, **kwargs): + if scope not in self.current_scopes: + # Check if access is not restricted to user/server/group + match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") + subscopes = filter( + lambda s: re.search(match_string, s), self.current_scopes + ) + subset = [subscope.split('=')[1] for subscope in subscopes] + if not subset: + raise web.HTTPError( + 403, "Action is not authorized with current scopes" + ) + else: + kwargs['subset'] = subset + result = func(self, *args, **kwargs) + return result + + return _auth_func + + return scope_decorator # Token utilities From 087c763d410afa09ccf0834db6695bbf51e2271e Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 28 Oct 2020 11:16:03 +0100 Subject: [PATCH 012/270] adding roles to services --- jupyterhub/apihandlers/base.py | 7 +- jupyterhub/apihandlers/services.py | 1 + jupyterhub/app.py | 54 +++++++----- jupyterhub/orm.py | 11 +++ jupyterhub/roles.py | 2 + jupyterhub/services/service.py | 1 + jupyterhub/tests/populate_db.py | 3 +- jupyterhub/tests/test_api.py | 2 + jupyterhub/tests/test_roles.py | 109 ++++++++++++++++++++++--- jupyterhub/tests/test_services_auth.py | 4 +- 10 files changed, 158 insertions(+), 36 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 8ebc15d4..8bd05ecc 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -222,7 +222,12 @@ class APIHandler(BaseHandler): def service_model(self, service): """Get the JSON model for a Service object""" - return {'kind': 'service', 'name': service.name, 'admin': service.admin} + return { + 'kind': 'service', + 'name': service.name, + 'admin': service.admin, + 'roles': [r.name for r in service.roles], + } _user_model_types = {'name': str, 'admin': bool, 'groups': list, 'auth_state': dict} diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 3d1f7bcc..10ee1fec 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -18,6 +18,7 @@ def service_model(service): return { 'name': service.name, 'admin': service.admin, + 'roles': [r.name for r in service.roles], 'url': service.url, 'prefix': service.server.base_url if service.server else '', 'command': service.command, diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 70483993..6618c6f0 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1834,26 +1834,39 @@ class JupyterHub(Application): role = orm.Role.find(db, predef_role['name']) # handle users - for username in predef_role['users']: - username = self.authenticator.normalize_username(username) - if not ( - await maybe_future(self.authenticator.check_allowed(username, None)) - ): - raise ValueError( - "Username %r is not in Authenticator.allowed_users" % username - ) - user = orm.User.find(db, name=username) - if user is None: - if not self.authenticator.validate_username(username): - raise ValueError("Role username %r is not valid" % username) - user = orm.User(name=username) - db.add(user) - roles.add_user(db, user=user, role=role) + if 'users' in predef_role.keys(): + for username in predef_role['users']: + username = self.authenticator.normalize_username(username) + if not ( + await maybe_future( + self.authenticator.check_allowed(username, None) + ) + ): + raise ValueError( + "Username %r is not in Authenticator.allowed_users" + % username + ) + user = orm.User.find(db, name=username) + if user is None: + raise ValueError("%r does not exist" % username) + else: + roles.add_user(db, user=user, role=role) - # make sure all users have at least one role (update with default) - for user in db.query(orm.User): - if len(user.roles) < 1: - roles.update_roles(db, user) + # handle services + if 'services' in predef_role.keys(): + for servicename in predef_role['services']: + service = orm.Service.find(db, name=servicename) + if service is None: + raise ValueError("%r does not exist" % servicename) + else: + roles.add_user(db, user=service, role=role) + + # make sure all users and services have at least one role (update with default) + Classes = [orm.User, orm.Service] + for ormClass in Classes: + for obj in db.query(ormClass): + if len(obj.roles) < 1: + roles.update_roles(db, obj) db.commit() @@ -1968,6 +1981,7 @@ class JupyterHub(Application): base_url=self.base_url, db=self.db, orm=orm_service, + roles=orm_service.roles, domain=domain, host=host, hub=self.hub, @@ -2435,9 +2449,9 @@ class JupyterHub(Application): self.init_oauth() await self.init_users() await self.init_groups() - await self.init_roles() self.init_services() await self.init_api_tokens() + await self.init_roles() self.init_tornado_settings() self.init_handlers() self.init_tornado_application() diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 1a518bf0..66d9f31d 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -141,6 +141,16 @@ user_role_map = Table( Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), ) +# service:role many:many mapping table +service_role_map = Table( + 'service_role_map', + Base.metadata, + Column( + 'service_id', ForeignKey('services.id', ondelete='CASCADE'), primary_key=True + ), + Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), +) + class Role(Base): """User Roles""" @@ -151,6 +161,7 @@ class Role(Base): description = Column(Unicode(1023)) scopes = Column(JSONList) users = relationship('User', secondary='user_role_map', backref='roles') + services = relationship('Service', secondary='service_role_map', backref='roles') def __repr__(self): return "<%s %s (%s) - scopes: %s>" % ( diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 53e0c637..a56b3344 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -55,6 +55,8 @@ def add_role(db, role_dict): else: role.description = role_dict['description'] role.scopes = role_dict['scopes'] + role.users = [] + role.services = [] db.commit() diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index 10883cb1..44fd763c 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -267,6 +267,7 @@ class Service(LoggingConfigurable): base_url = Unicode() db = Any() orm = Any() + roles = Any() cookie_options = Dict() oauth_provider = Any() diff --git a/jupyterhub/tests/populate_db.py b/jupyterhub/tests/populate_db.py index fd8cb9a1..fec3d7e9 100644 --- a/jupyterhub/tests/populate_db.py +++ b/jupyterhub/tests/populate_db.py @@ -10,8 +10,7 @@ from datetime import datetime import jupyterhub from jupyterhub import orm -# FIXME - for later versions of jupyterhub add code to test Roles -# from jupyterhub.orm import Role +# FIXME - for later versions of jupyterhub add code to test roles def populate_db(url): diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index f46c22c6..966dadcf 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1536,6 +1536,7 @@ async def test_get_services(app, mockservice_url): mockservice.name: { 'name': mockservice.name, 'admin': True, + 'roles': [], 'command': mockservice.command, 'pid': mockservice.proc.pid, 'prefix': mockservice.server.base_url, @@ -1561,6 +1562,7 @@ async def test_get_service(app, mockservice_url): assert service == { 'name': mockservice.name, 'admin': True, + 'roles': [], 'command': mockservice.command, 'pid': mockservice.proc.pid, 'prefix': mockservice.server.base_url, diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 8b20fcf3..1e4ebe1d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -4,33 +4,45 @@ from pytest import mark from .. import orm from .. import roles +from ..utils import maybe_future from .mocking import MockHub @mark.role -def test_roles(db): +def test_orm_roles(db): """Test orm roles setup""" user = orm.User(name='falafel') db.add(user) + service = orm.Service(name='kebab') + db.add(service) role = orm.Role(name='default') db.add(role) db.commit() assert role.users == [] + assert role.services == [] assert user.roles == [] + assert service.roles == [] role.users.append(user) + role.services.append(service) db.commit() assert role.users == [user] assert user.roles == [role] + assert role.services == [service] + assert service.roles == [role] db.delete(user) db.commit() assert role.users == [] db.delete(role) + db.commit() + assert service.roles == [] + db.delete(service) + db.commit() @mark.role -def test_role_delete_cascade(db): +def test_orm_role_delete_cascade(db): """Orm roles cascade""" user1 = orm.User(name='user1') user2 = orm.User(name='user2') @@ -93,8 +105,25 @@ def test_role_delete_cascade(db): @mark.role -async def test_load_roles(tmpdir, request): - """Test loading default and predefined roles in app.py""" +async def test_load_default_roles(tmpdir, request): + """Test loading default roles in app.py""" + kwargs = {} + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + await hub.init_roles() + # test default roles loaded to database + assert orm.Role.find(db, 'user') is not None + assert orm.Role.find(db, 'admin') is not None + assert orm.Role.find(db, 'server') is not None + + +@mark.role +async def test_load_roles_users(tmpdir, request): + """Test loading predefined roles for users in app.py""" roles_to_load = [ { 'name': 'teacher', @@ -106,7 +135,7 @@ async def test_load_roles(tmpdir, request): 'name': 'user', 'description': 'Only read access', 'scopes': ['read:all'], - 'users': ['test_user'], + 'users': ['bilbo'], }, ] kwargs = {'load_roles': roles_to_load} @@ -116,20 +145,28 @@ async def test_load_roles(tmpdir, request): hub = MockHub(**kwargs) hub.init_db() db = hub.db + hub.authenticator.admin_users = ['admin'] + hub.authenticator.allowed_users = ['cyclops', 'gandalf', 'bilbo', 'gargamel'] await hub.init_users() + for user in db.query(orm.User): + print(user.name) await hub.init_roles() - # test if the 'user' role has been overwritten + + # test if the 'user' role has been overwritten and assigned user_role = orm.Role.find(db, 'user') + admin_role = orm.Role.find(db, 'admin') assert user_role is not None assert user_role.scopes == ['read:all'] - # test other default roles loaded to database - assert orm.Role.find(db, 'user') is not None - assert orm.Role.find(db, 'admin') is not None - assert orm.Role.find(db, 'server') is not None - # test if every existing user has a role (and no duplicates) + + # test if every user has a role (and no duplicates) + # and admins have admin role for user in db.query(orm.User): assert len(user.roles) > 0 assert len(user.roles) == len(set(user.roles)) + if user.admin: + assert admin_role in user.roles + assert user_role not in user.roles + # test if predefined roles loaded and assigned teacher_role = orm.Role.find(db, name='teacher') assert teacher_role is not None @@ -137,3 +174,53 @@ async def test_load_roles(tmpdir, request): assert teacher_role in gandalf_user.roles cyclops_user = orm.User.find(db, name='cyclops') assert teacher_role in cyclops_user.roles + + +@mark.role +async def test_load_roles_services(tmpdir, request): + roles_to_load = [ + { + 'name': 'culler', + 'description': 'Cull idle servers', + 'scopes': ['users:servers', 'admin:servers'], + 'services': ['cull_idle'], + }, + ] + kwargs = {'load_roles': roles_to_load} + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(test_clean_db=False, **kwargs) + hub.init_db() + db = hub.db + # add test services to db + services = [ + {'name': 'cull_idle', 'admin': False}, + {'name': 'user_service', 'admin': False}, + {'name': 'admin_service', 'admin': True}, + ] + for service_specs in services: + service = orm.Service.find(db, service_specs['name']) + if service is None: + service = orm.Service( + name=service_specs['name'], admin=service_specs['admin'] + ) + db.add(service) + db.commit() + await hub.init_roles() + + # test if every service has a role (and no duplicates) + admin_role = orm.Role.find(db, name='admin') + user_role = orm.Role.find(db, name='user') + for service in db.query(orm.Service): + assert len(service.roles) > 0 + assert len(service.roles) == len(set(service.roles)) + if service.admin: + assert admin_role in service.roles + assert user_role not in service.roles + + # test if predefined roles loaded and assigned + culler_role = orm.Role.find(db, name='culler') + cull_idle = orm.Service.find(db, name='cull_idle') + assert culler_role in cull_idle.roles + assert user_role not in cull_idle.roles diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 867d1d97..a0bf5d43 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -295,7 +295,7 @@ async def test_hubauth_service_token(app, mockservice_url): ) r.raise_for_status() reply = r.json() - assert reply == {'kind': 'service', 'name': name, 'admin': False} + assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} assert not r.cookies # token in ?token parameter @@ -304,7 +304,7 @@ async def test_hubauth_service_token(app, mockservice_url): ) r.raise_for_status() reply = r.json() - assert reply == {'kind': 'service', 'name': name, 'admin': False} + assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} r = await async_requests.get( public_url(app, mockservice_url) + '/whoami/?token=no-such-token', From 21ea4ad2b62a1fbae1544a2c7c9c373aa5028c46 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 28 Oct 2020 16:23:21 +0100 Subject: [PATCH 013/270] Implemented mock scopes --- jupyterhub/handlers/base.py | 5 +++++ jupyterhub/tests/mocking.py | 2 ++ jupyterhub/tests/utils.py | 22 ++++++++++++++++++++++ jupyterhub/utils.py | 8 ++++---- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index c8b2dc9e..0012ea96 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -83,6 +83,7 @@ class BaseHandler(RequestHandler): except Exception: self.log.exception("Failed to get current user") self._jupyterhub_user = None + self.scopes = [] return await maybe_future(super().prepare()) @@ -426,6 +427,10 @@ class BaseHandler(RequestHandler): # don't let errors here raise more than once self._jupyterhub_user = None self.log.exception("Error getting current user") + if self._jupyterhub_user is not None: + self.scopes = self.settings.get("mock_scopes", []) + else: + self.scopes = [] return self._jupyterhub_user @property diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 47b38f87..6d6a3adf 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -53,6 +53,7 @@ from ..spawner import SimpleLocalProcessSpawner from ..utils import random_port from ..utils import url_path_join from .utils import async_requests +from .utils import get_all_scopes from .utils import public_host from .utils import public_url from .utils import ssl_setup @@ -299,6 +300,7 @@ class MockHub(JupyterHub): super().init_tornado_application() # reconnect tornado_settings so that mocks can update the real thing self.tornado_settings = self.users.settings = self.tornado_application.settings + self.tornado_settings['mock_scopes'] = get_all_scopes() def init_services(self): # explicitly expire services before reinitializing diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 09aeb196..9f81d5f0 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -194,3 +194,25 @@ def public_url(app, user_or_service=None, path=''): return host + ujoin(prefix, path) else: return host + prefix + + +def get_all_scopes(): + scopes = [ + 'all', + 'all', + 'users', + 'users:name', + 'users:groups', + 'users:activity', + 'users:servers', + 'users:tokens', + 'admin:users', + 'admin:users:servers', + 'groups', + 'admin:groups', + 'read:services', + 'proxy', + 'shutdown', + ] + read_only = ["read:%s" % el for el in scopes] + return scopes + read_only diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index a3f324ad..133c0fd4 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -305,12 +305,12 @@ def needs_scope(scope): def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): - if scope not in self.current_scopes: + self.log.warning("Scope needed: " + scope) + self.log.warning("Scope possessed: %s" % ", ".join(self.scopes)) + if scope not in self.scopes: # Check if access is not restricted to user/server/group match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") - subscopes = filter( - lambda s: re.search(match_string, s), self.current_scopes - ) + subscopes = filter(lambda s: re.search(match_string, s), self.scopes) subset = [subscope.split('=')[1] for subscope in subscopes] if not subset: raise web.HTTPError( From e26fa682c15c40d54eae6614d182f78d5dae12ed Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 28 Oct 2020 17:45:58 +0100 Subject: [PATCH 014/270] Implemented mock scopes in tests and fixed scopes --- jupyterhub/apihandlers/hub.py | 1 - jupyterhub/apihandlers/users.py | 6 +-- jupyterhub/tests/mocking.py | 4 +- jupyterhub/tests/test_api.py | 23 ++++++++++-- jupyterhub/tests/utils.py | 65 ++++++++++++++++++++++----------- 5 files changed, 68 insertions(+), 31 deletions(-) diff --git a/jupyterhub/apihandlers/hub.py b/jupyterhub/apihandlers/hub.py index 77eec918..afededb8 100644 --- a/jupyterhub/apihandlers/hub.py +++ b/jupyterhub/apihandlers/hub.py @@ -66,7 +66,6 @@ class RootAPIHandler(APIHandler): class InfoAPIHandler(APIHandler): - @needs_scope('admin') # Todo: Probably too strict def get(self): """GET /api/info returns detailed info about the Hub and its API. diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index e73be2eb..36cd3957 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -28,7 +28,7 @@ class SelfAPIHandler(APIHandler): Based on the authentication info. Acts as a 'whoami' for auth tokens. """ - @needs_scope('read:users') + @needs_scope('all') async def get(self): user = self.current_user if user is None: @@ -382,7 +382,7 @@ class UserTokenAPIHandler(APIHandler): class UserServerAPIHandler(APIHandler): """Start and stop single-user servers""" - @needs_scope('user:servers') + @needs_scope('users:servers') async def post(self, name, server_name='', subset=None): user = self.find_user(name) if server_name: @@ -432,7 +432,7 @@ class UserServerAPIHandler(APIHandler): self.set_header('Content-Type', 'text/plain') self.set_status(status) - @needs_scope('user:servers') + @needs_scope('users:servers') async def delete(self, name, server_name=''): user = self.find_user(name) options = self.get_json_body() diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 6d6a3adf..0bdd87b4 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -53,7 +53,7 @@ from ..spawner import SimpleLocalProcessSpawner from ..utils import random_port from ..utils import url_path_join from .utils import async_requests -from .utils import get_all_scopes +from .utils import get_scopes from .utils import public_host from .utils import public_url from .utils import ssl_setup @@ -300,7 +300,7 @@ class MockHub(JupyterHub): super().init_tornado_application() # reconnect tornado_settings so that mocks can update the real thing self.tornado_settings = self.users.settings = self.tornado_application.settings - self.tornado_settings['mock_scopes'] = get_all_scopes() + self.tornado_settings['mock_scopes'] = get_scopes() def init_services(self): # explicitly expire services before reinitializing diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index fa6a20d1..2f775acf 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -26,6 +26,7 @@ from .utils import api_request from .utils import async_requests from .utils import auth_header from .utils import find_user +from .utils import get_scopes # -------------------- @@ -168,7 +169,7 @@ TIMESTAMP = normalize_timestamp(datetime.now().isoformat() + 'Z') @mark.user async def test_get_users(app): db = app.db - r = await api_request(app, 'users') + r = await api_request(app, 'users', headers=auth_header(db, 'admin')) assert r.status_code == 200 users = sorted(r.json(), key=lambda d: d['name']) @@ -178,7 +179,9 @@ async def test_get_users(app): fill_user({'name': 'user', 'admin': False, 'last_activity': None}), ] - r = await api_request(app, 'users', headers=auth_header(db, 'user')) + r = await api_request( + app, 'users', headers=auth_header(db, 'user'), scopes=get_scopes('user') + ) assert r.status_code == 403 @@ -205,13 +208,24 @@ async def test_get_self(app): ) db.add(oauth_token) db.commit() - r = await api_request(app, 'user', headers={'Authorization': 'token ' + token}) + app.log.warn("Scopes:" + ", ".join(app.tornado_settings['mock_scopes'])) + r = await api_request( + app, + 'user', + headers={'Authorization': 'token ' + token}, + scopes=get_scopes('user'), + ) r.raise_for_status() model = r.json() assert model['name'] == u.name # invalid auth gets 403 - r = await api_request(app, 'user', headers={'Authorization': 'token notvalid'}) + r = await api_request( + app, + 'user', + headers={'Authorization': 'token notvalid'}, + scopes=get_scopes('user'), + ) assert r.status_code == 403 @@ -420,6 +434,7 @@ async def test_user_set_auth_state(app, auth_state_enabled): method='patch', data=json.dumps({'auth_state': auth_state}), headers=auth_header(app.db, name), + scopes=get_scopes('user'), ) assert r.status_code == 403 diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 9f81d5f0..f521aaf7 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -118,7 +118,13 @@ def auth_header(db, name): @check_db_locks async def api_request( - app, *api_path, method='get', noauth=False, bypass_proxy=False, **kwargs + app, + *api_path, + method='get', + noauth=False, + bypass_proxy=False, + scopes=None, + **kwargs ): """Make an API request""" if bypass_proxy: @@ -128,7 +134,12 @@ async def api_request( else: base_url = public_url(app, path='hub') headers = kwargs.setdefault('headers', {}) - + old_scopes = ['Nothing here'] + if scopes is not None: + old_scopes = app.tornado_settings[ + 'mock_scopes' + ] # Store old scopes so request has no side effects + app.tornado_settings['mock_scopes'] = scopes if 'Authorization' not in headers and not noauth and 'cookies' not in kwargs: # make a copy to avoid modifying arg in-place kwargs['headers'] = h = {} @@ -147,6 +158,8 @@ async def api_request( kwargs['cert'] = (app.internal_ssl_cert, app.internal_ssl_key) kwargs["verify"] = app.internal_ssl_ca resp = await f(url, **kwargs) + if scopes is not None: + app.tornado_settings['mock_scopes'] = old_scopes assert "frame-ancestors 'self'" in resp.headers['Content-Security-Policy'] assert ( ujoin(app.hub.base_url, "security/csp-report") @@ -196,23 +209,33 @@ def public_url(app, user_or_service=None, path=''): return host + prefix -def get_all_scopes(): - scopes = [ - 'all', - 'all', - 'users', - 'users:name', - 'users:groups', - 'users:activity', - 'users:servers', - 'users:tokens', - 'admin:users', - 'admin:users:servers', - 'groups', - 'admin:groups', - 'read:services', - 'proxy', - 'shutdown', - ] - read_only = ["read:%s" % el for el in scopes] +def get_scopes(role='admin'): + """Get all scopes for a role. Default role is admin, alternatives are user and service""" + all_scopes = { + 'admin': [ + 'all', + 'users', + 'users:name', + 'users:groups', + 'users:activity', + 'users:servers', + 'users:tokens', + 'admin:users', + 'admin:users:servers', + 'groups', + 'admin:groups', + 'services', + 'proxy', + 'shutdown', + ], + 'user': ['all'], + 'server': ['users:activity'], + } + scopes = all_scopes[role] + read_only = ["read:" + el for el in scopes] return scopes + read_only + + +def limit_scopes(scopes, key, name): + new_scopes = ["{}!{}={}".format(scope, key, name) for scope in scopes] + return new_scopes From 496832d7b49ce3d00a5f97a9b05d913ae39d8146 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 30 Oct 2020 15:06:48 +0100 Subject: [PATCH 015/270] Adjusted tests to allow for scopes --- jupyterhub/tests/mocking.py | 7 ++ jupyterhub/tests/test_api.py | 135 +++++++++++++++++------------------ jupyterhub/tests/utils.py | 29 +++----- 3 files changed, 80 insertions(+), 91 deletions(-) diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 0bdd87b4..7da36f4a 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -78,6 +78,13 @@ def mock_open_session(username, service, encoding): pass +def mock_role(app, role='admin', name=None): + scopes = get_scopes(role) + if name is not None: + scopes = [scope.format(username=name) for scope in scopes] + return mock.patch.dict(app.tornado_settings, {'mock_scopes': scopes}) + + class MockSpawner(SimpleLocalProcessSpawner): """Base mock spawner diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 2f775acf..86b4db89 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -19,6 +19,7 @@ import jupyterhub from .. import orm from ..utils import url_path_join as ujoin from ..utils import utcnow +from .mocking import mock_role from .mocking import public_host from .mocking import public_url from .utils import add_user @@ -178,10 +179,8 @@ async def test_get_users(app): fill_user({'name': 'admin', 'admin': True}), fill_user({'name': 'user', 'admin': False, 'last_activity': None}), ] - - r = await api_request( - app, 'users', headers=auth_header(db, 'user'), scopes=get_scopes('user') - ) + with mock_role(app, 'user'): + r = await api_request(app, 'users', headers=auth_header(db, 'user')) assert r.status_code == 403 @@ -208,24 +207,14 @@ async def test_get_self(app): ) db.add(oauth_token) db.commit() - app.log.warn("Scopes:" + ", ".join(app.tornado_settings['mock_scopes'])) - r = await api_request( - app, - 'user', - headers={'Authorization': 'token ' + token}, - scopes=get_scopes('user'), - ) + r = await api_request(app, 'user', headers={'Authorization': 'token ' + token},) r.raise_for_status() model = r.json() assert model['name'] == u.name # invalid auth gets 403 - r = await api_request( - app, - 'user', - headers={'Authorization': 'token notvalid'}, - scopes=get_scopes('user'), - ) + with mock_role(app, 'user'): + r = await api_request(app, 'user', headers={'Authorization': 'token notvalid'},) assert r.status_code == 403 @@ -244,7 +233,9 @@ async def test_add_user(app): @mark.user async def test_get_user(app): name = 'user' - r = await api_request(app, 'users', name) + _ = await api_request(app, 'users', name, headers=auth_header(app.db, name)) + with mock_role(app, role=name, name=name): + r = await api_request(app, 'users', name,) assert r.status_code == 200 user = normalize_user(r.json()) @@ -426,17 +417,15 @@ async def test_user_set_auth_state(app, auth_state_enabled): assert user.name == name user_auth_state = await user.get_auth_state() assert user_auth_state is None - - r = await api_request( - app, - 'users', - name, - method='patch', - data=json.dumps({'auth_state': auth_state}), - headers=auth_header(app.db, name), - scopes=get_scopes('user'), - ) - + with mock_role(app, 'user'): + r = await api_request( + app, + 'users', + name, + method='patch', + data=json.dumps({'auth_state': auth_state}), + headers=auth_header(app.db, name), + ) assert r.status_code == 403 user_auth_state = await user.get_auth_state() assert user_auth_state is None @@ -1281,15 +1270,16 @@ async def test_token_authenticator_noauth(app): """Create a token for a user relying on Authenticator.authenticate and no auth header""" name = 'user' data = {'auth': {'username': name, 'password': name}} - r = await api_request( - app, - 'users', - name, - 'tokens', - method='post', - data=json.dumps(data) if data else None, - noauth=True, - ) + with mock_role(app, 'admin'): + r = await api_request( + app, + 'users', + name, + 'tokens', + method='post', + data=json.dumps(data) if data else None, + noauth=True, + ) assert r.status_code == 200 reply = r.json() assert 'token' in reply @@ -1304,15 +1294,16 @@ async def test_token_authenticator_dict_noauth(app): app.authenticator.auth_state = {'who': 'cares'} name = 'user' data = {'auth': {'username': name, 'password': name}} - r = await api_request( - app, - 'users', - name, - 'tokens', - method='post', - data=json.dumps(data) if data else None, - noauth=True, - ) + with mock_role(app, 'user'): + r = await api_request( + app, + 'users', + name, + 'tokens', + method='post', + data=json.dumps(data) if data else None, + noauth=True, + ) assert r.status_code == 200 reply = r.json() assert 'token' in reply @@ -1336,7 +1327,8 @@ async def test_token_list(app, as_user, for_user, status): if for_user != 'missing': for_user_obj = add_user(app.db, app, name=for_user) headers = {'Authorization': 'token %s' % u.new_api_token()} - r = await api_request(app, 'users', for_user, 'tokens', headers=headers) + with mock_role(app, role=as_user, name=as_user): + r = await api_request(app, 'users', for_user, 'tokens', headers=headers) assert r.status_code == status if status != 200: return @@ -1347,9 +1339,10 @@ async def test_token_list(app, as_user, for_user, status): assert all(token['user'] == for_user for token in reply['oauth_tokens']) # validate individual token ids for token in reply['api_tokens'] + reply['oauth_tokens']: - r = await api_request( - app, 'users', for_user, 'tokens', token['id'], headers=headers - ) + with mock_role(app, role=as_user, name=as_user): + r = await api_request( + app, 'users', for_user, 'tokens', token['id'], headers=headers + ) r.raise_for_status() reply = r.json() assert normalize_token(reply) == normalize_token(token) @@ -1531,8 +1524,8 @@ async def test_get_services(app, mockservice_url): 'display': True, } } - - r = await api_request(app, 'services', headers=auth_header(db, 'user')) + with mock_role(app, 'user'): + r = await api_request(app, 'services', headers=auth_header(db, 'user')) assert r.status_code == 403 @@ -1555,16 +1548,17 @@ async def test_get_service(app, mockservice_url): 'info': {}, 'display': True, } - - r = await api_request( - app, - 'services/%s' % mockservice.name, - headers={'Authorization': 'token %s' % mockservice.api_token}, - ) - r.raise_for_status() - r = await api_request( - app, 'services/%s' % mockservice.name, headers=auth_header(db, 'user') - ) + with mock_role(app, 'service'): + r = await api_request( + app, + 'services/%s' % mockservice.name, + headers={'Authorization': 'token %s' % mockservice.api_token}, + ) + r.raise_for_status() + with mock_role(app, 'user'): + r = await api_request( + app, 'services/%s' % mockservice.name, headers=auth_header(db, 'user') + ) assert r.status_code == 403 @@ -1612,13 +1606,14 @@ async def test_info(app): async def test_update_activity_403(app, user, admin_user): token = user.new_api_token() - r = await api_request( - app, - "users/{}/activity".format(admin_user.name), - headers={"Authorization": "token {}".format(token)}, - data="{}", - method="post", - ) + with mock_role(app, 'user'): + r = await api_request( + app, + "users/{}/activity".format(admin_user.name), + headers={"Authorization": "token {}".format(token)}, + data="{}", + method="post", + ) assert r.status_code == 403 diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index f521aaf7..7db84a79 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -118,13 +118,7 @@ def auth_header(db, name): @check_db_locks async def api_request( - app, - *api_path, - method='get', - noauth=False, - bypass_proxy=False, - scopes=None, - **kwargs + app, *api_path, method='get', noauth=False, bypass_proxy=False, **kwargs ): """Make an API request""" if bypass_proxy: @@ -134,12 +128,6 @@ async def api_request( else: base_url = public_url(app, path='hub') headers = kwargs.setdefault('headers', {}) - old_scopes = ['Nothing here'] - if scopes is not None: - old_scopes = app.tornado_settings[ - 'mock_scopes' - ] # Store old scopes so request has no side effects - app.tornado_settings['mock_scopes'] = scopes if 'Authorization' not in headers and not noauth and 'cookies' not in kwargs: # make a copy to avoid modifying arg in-place kwargs['headers'] = h = {} @@ -158,8 +146,6 @@ async def api_request( kwargs['cert'] = (app.internal_ssl_cert, app.internal_ssl_key) kwargs["verify"] = app.internal_ssl_ca resp = await f(url, **kwargs) - if scopes is not None: - app.tornado_settings['mock_scopes'] = old_scopes assert "frame-ancestors 'self'" in resp.headers['Content-Security-Policy'] assert ( ujoin(app.hub.base_url, "security/csp-report") @@ -228,14 +214,15 @@ def get_scopes(role='admin'): 'proxy', 'shutdown', ], - 'user': ['all'], + 'user': [ + 'all', + 'users!user={username}', + 'users:activity!user={username}', + 'users:tokens!user={username}', + ], 'server': ['users:activity'], + 'service': ['services'], } scopes = all_scopes[role] read_only = ["read:" + el for el in scopes] return scopes + read_only - - -def limit_scopes(scopes, key, name): - new_scopes = ["{}!{}={}".format(scope, key, name) for scope in scopes] - return new_scopes From 422fbf8dcc8671bc6edd77c6156dc4e173c6f951 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 30 Oct 2020 15:07:10 +0100 Subject: [PATCH 016/270] Fixed scoping and authentication --- jupyterhub/apihandlers/users.py | 26 +++++++++++++------------- jupyterhub/handlers/base.py | 2 +- jupyterhub/utils.py | 19 ++++++++----------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 36cd3957..d2439c0a 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -28,7 +28,7 @@ class SelfAPIHandler(APIHandler): Based on the authentication info. Acts as a 'whoami' for auth tokens. """ - @needs_scope('all') + # @needs_scope('read:users') # Should be read:users:user=username async def get(self): user = self.current_user if user is None: @@ -41,12 +41,8 @@ class SelfAPIHandler(APIHandler): class UserListAPIHandler(APIHandler): @needs_scope('read:users') - def get(self, subset=None): + def get(self): users = self.db.query(orm.User) - if subset is not None: - users = users.filter( - User.name.in_(subset) - ) # Should result in only one db query data = [ self.user_model(u, include_servers=True, include_state=True) for u in users ] @@ -131,7 +127,7 @@ class UserAPIHandler(APIHandler): async def get(self, name, subset=None): user = self.find_user(name) if subset is not None: - if user not in subset: + if name not in subset: raise web.HTTPError(403, "No access to users") model = self.user_model( @@ -224,12 +220,14 @@ class UserAPIHandler(APIHandler): class UserTokenListAPIHandler(APIHandler): """API endpoint for listing/creating tokens""" - @needs_scope('users:tokens') - def get(self, name): + @needs_scope('read:users:tokens') + def get(self, name, subset=None): """Get tokens for a given user""" user = self.find_user(name) if not user: raise web.HTTPError(404, "No such user: %s" % name) + if subset is not None and name not in subset: + raise web.HTTPError(403, "No access to tokens") now = datetime.utcnow() @@ -258,7 +256,6 @@ class UserTokenListAPIHandler(APIHandler): oauth_tokens.append(self.token_model(token)) self.write(json.dumps({'api_tokens': api_tokens, 'oauth_tokens': oauth_tokens})) - @needs_scope('users:tokens') async def post(self, name): body = self.get_json_body() or {} if not isinstance(body, dict): @@ -323,7 +320,6 @@ class UserTokenListAPIHandler(APIHandler): class UserTokenAPIHandler(APIHandler): """API endpoint for retrieving/deleting individual tokens""" - @needs_scope('read:users:tokens') def find_token_by_id(self, user, token_id): """Find a token object by token-id key @@ -349,20 +345,24 @@ class UserTokenAPIHandler(APIHandler): return orm_token @needs_scope('read:users:tokens') - def get(self, name, token_id): + def get(self, name, token_id, subset=None): """""" user = self.find_user(name) if not user: raise web.HTTPError(404, "No such user: %s" % name) + if subset is not None and name not in subset: + raise web.HTTPError(403, "No token access allowed") token = self.find_token_by_id(user, token_id) self.write(json.dumps(self.token_model(token))) @needs_scope('users:tokens') - def delete(self, name, token_id): + def delete(self, name, token_id, subset=None): """Delete a token""" user = self.find_user(name) if not user: raise web.HTTPError(404, "No such user: %s" % name) + if subset is not None and name not in subset: + raise web.HTTPError(403, "No token access allowed") token = self.find_token_by_id(user, token_id) # deleting an oauth token deletes *all* oauth tokens for that client if isinstance(token, orm.OAuthAccessToken): diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 0012ea96..841de4e4 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -427,7 +427,7 @@ class BaseHandler(RequestHandler): # don't let errors here raise more than once self._jupyterhub_user = None self.log.exception("Error getting current user") - if self._jupyterhub_user is not None: + if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): self.scopes = self.settings.get("mock_scopes", []) else: self.scopes = [] diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 133c0fd4..7b9acc4b 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -305,21 +305,18 @@ def needs_scope(scope): def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): - self.log.warning("Scope needed: " + scope) - self.log.warning("Scope possessed: %s" % ", ".join(self.scopes)) - if scope not in self.scopes: - # Check if access is not restricted to user/server/group + allows_subset = 'subset' in func.__code__.co_varnames + if scope in self.scopes: + return func(self, *args, **kwargs) + elif allows_subset: + # Check if access is not restricted to user/server/service match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") subscopes = filter(lambda s: re.search(match_string, s), self.scopes) subset = [subscope.split('=')[1] for subscope in subscopes] - if not subset: - raise web.HTTPError( - 403, "Action is not authorized with current scopes" - ) - else: + if subset: kwargs['subset'] = subset - result = func(self, *args, **kwargs) - return result + return func(self, *args, **kwargs) + raise web.HTTPError(403, "Action is not authorized with current scopes") return _auth_func From 154edebbf4d81f7eaed481c57c037001c3c1062b Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 5 Nov 2020 15:40:00 +0100 Subject: [PATCH 017/270] Added scope utilities and tests for them --- jupyterhub/handlers/base.py | 4 +- jupyterhub/tests/test_scopes.py | 83 +++++++++++++++++++++++++++++++++ jupyterhub/utils.py | 37 ++++++++++++++- 3 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 jupyterhub/tests/test_scopes.py diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 841de4e4..f86d0cb3 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -78,12 +78,12 @@ class BaseHandler(RequestHandler): The current user (None if not logged in) may be accessed via the `self.current_user` property during the handling of any request. """ + self.scopes = [] try: await self.get_current_user() except Exception: self.log.exception("Failed to get current user") self._jupyterhub_user = None - self.scopes = [] return await maybe_future(super().prepare()) @@ -429,8 +429,6 @@ class BaseHandler(RequestHandler): self.log.exception("Error getting current user") if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): self.scopes = self.settings.get("mock_scopes", []) - else: - self.scopes = [] return self._jupyterhub_user @property diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py new file mode 100644 index 00000000..6c8326e0 --- /dev/null +++ b/jupyterhub/tests/test_scopes.py @@ -0,0 +1,83 @@ +""" +test scopes as used in rbac +""" +from unittest import mock + +import pytest +from tornado import web + +from ..utils import check_scope +from ..utils import needs_scope +from ..utils import parse_scopes +from .utils import get_scopes + + +def test_scope_constructor(): + user1 = 'george' + user2 = 'michael' + scope_list = [ + 'users', + 'read:users!user={}'.format(user1), + 'read:users!user={}'.format(user2), + ] + parsed_scopes = parse_scopes(scope_list) + + assert 'read:users' in parsed_scopes + assert parsed_scopes['users'] + assert set(parsed_scopes['read:users']['user']) == {user1, user2} + + +def test_scope_precendence(): + scope_list = ['read:users!user=maeby', 'read:users'] + parsed_scopes = parse_scopes(scope_list) + assert parsed_scopes['read:users'] == True + + +def test_scope_check_present(): + scope_list = ['read:users'] + parsed_scopes = parse_scopes(scope_list) + assert check_scope('read:users', parsed_scopes) + assert check_scope('read:users!user=maeby', parsed_scopes) + + +def test_scope_check_not_present(): # What should this return when the broad scope is asked and a small one satisfied? + scope_list = ['read:users!user=maeby'] + parsed_scopes = parse_scopes(scope_list) + assert not check_scope('read:users', parsed_scopes) + assert not check_scope('read:users', parsed_scopes, user='gob') + assert not check_scope('read:users', parsed_scopes, server='gob/server') + + +def test_scope_filters(): + scope_list = ['read:users', 'read:users!group=bluths', 'read:users!user=maeby'] + parsed_scopes = parse_scopes(scope_list) + assert check_scope('read:users!group=bluths', parsed_scopes) + assert check_scope('read:users!user=maeby', parsed_scopes) + + +def test_scope_one_filter_only(): + with pytest.raises(AttributeError): + check_scope('all', parse_scopes(['all']), user='george_michael', group='bluths') + + +class Test: + def __init__(self): + self.scopes = ['read:users'] + + @needs_scope('read:users') + def foo(self, user): + return True + + +def test_scope_def(): + obj = Test() + obj.scopes = ['read:users'] + assert obj.foo('user') + assert obj.foo('user2') + + +def test_wrong_scope(): + obj = Test() + obj.scopes = [] + with pytest.raises(web.HTTPError): + obj.foo('user1') diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 7b9acc4b..ef71c514 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -299,13 +299,48 @@ def metrics_authentication(self): raise web.HTTPError(403) +def check_scope(req_scope, scopes, **kwargs): + if len(kwargs) > 1: + raise AttributeError("Please specify exactly one filter") + base_scope = req_scope.split('!')[0] + if base_scope not in scopes: + return False + if scopes[base_scope] == True: # is this pretty? + return True + # Apply filters + if not kwargs: + return False + filter_ = list(kwargs)[0] + if filter_ not in scopes[base_scope]: + return False + return kwargs[filter_] in scopes[req_scope][filter_] + + +def parse_scopes(scope_list): + parsed_scopes = {} + for scope in scope_list: + scope_ = scope.split('!') + base_scope = scope_[0] + if len(scope_) > 1: + filter_ = scope_[1] + if base_scope not in parsed_scopes: + parsed_scopes[base_scope] = {} + key, val = filter_.split('=') + if key not in parsed_scopes[base_scope]: + parsed_scopes[base_scope][key] = [] + parsed_scopes[base_scope][key].append(val) + else: + parsed_scopes[base_scope] = True + return parsed_scopes + + def needs_scope(scope): """Decorator to restrict access to users or services with the required scope""" def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): - allows_subset = 'subset' in func.__code__.co_varnames + allows_subset = 'subset' in inspect.signature(func).parameters if scope in self.scopes: return func(self, *args, **kwargs) elif allows_subset: From fad0679ce483b99d158aca28dd275014658880f8 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 5 Nov 2020 16:35:42 +0100 Subject: [PATCH 018/270] Refactored api method param names --- jupyterhub/apihandlers/groups.py | 64 +++++++++++---------- jupyterhub/apihandlers/services.py | 4 +- jupyterhub/apihandlers/users.py | 92 +++++++++++++++--------------- 3 files changed, 84 insertions(+), 76 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index a6cfeb8f..686292ee 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -23,14 +23,14 @@ class _GroupAPIHandler(APIHandler): users.append(user.orm_user) return users - def find_group(self, name): + def find_group(self, group_name): """Find and return a group by name. Raise 404 if not found. """ - group = orm.Group.find(self.db, name=name) + group = orm.Group.find(self.db, name=group_name) if group is None: - raise web.HTTPError(404, "No such group: %s", name) + raise web.HTTPError(404, "No such group: %s", group_name) return group @@ -78,14 +78,14 @@ class GroupAPIHandler(_GroupAPIHandler): """View and modify groups by name""" @needs_scope('read:groups') - def get(self, name, subset=None): - if subset is not None and name not in subset: - raise web.HTTPError(403, "No read access to group {}".format(name)) - group = self.find_group(name) + def get(self, group_name, subset=None): + if subset is not None and group_name not in subset: + raise web.HTTPError(403, "No read access to group {}".format(group_name)) + group = self.find_group(group_name) self.write(json.dumps(self.group_model(group))) @needs_scope('admin:groups') - async def post(self, name): + async def post(self, group_name): """POST creates a group by name""" model = self.get_json_body() if model is None: @@ -93,30 +93,30 @@ class GroupAPIHandler(_GroupAPIHandler): else: self._check_group_model(model) - existing = orm.Group.find(self.db, name=name) + existing = orm.Group.find(self.db, name=group_name) if existing is not None: - raise web.HTTPError(409, "Group %s already exists" % name) + raise web.HTTPError(409, "Group %s already exists" % group_name) usernames = model.get('users', []) # check that users exist users = self._usernames_to_users(usernames) # create the group - self.log.info("Creating new group %s with %i users", name, len(users)) + self.log.info("Creating new group %s with %i users", group_name, len(users)) self.log.debug("Users: %s", usernames) - group = orm.Group(name=name, users=users) + group = orm.Group(name=group_name, users=users) self.db.add(group) self.db.commit() self.write(json.dumps(self.group_model(group))) self.set_status(201) @needs_scope('admin:groups') - def delete(self, name, subset=None): + def delete(self, group_name, subset=None): """Delete a group by name""" - if subset is not None and name not in subset: - raise web.HTTPError(403, "No write access to group {}".format(name)) - group = self.find_group(name) - self.log.info("Deleting group %s", name) + if subset is not None and group_name not in subset: + raise web.HTTPError(403, "No write access to group {}".format(group_name)) + group = self.find_group(group_name) + self.log.info("Deleting group %s", group_name) self.db.delete(group) self.db.commit() self.set_status(204) @@ -126,42 +126,48 @@ class GroupUsersAPIHandler(_GroupAPIHandler): """Modify a group's user list""" @needs_scope('groups') - def post(self, name, subset=None): + def post(self, group_name, subset=None): """POST adds users to a group""" - if subset is not None and name not in subset: - raise web.HTTPError(403, "No access to add users to group {}".format(name)) - group = self.find_group(name) + if subset is not None and group_name not in subset: + raise web.HTTPError( + 403, "No access to add users to group {}".format(group_name) + ) + group = self.find_group(group_name) data = self.get_json_body() self._check_group_model(data) if 'users' not in data: raise web.HTTPError(400, "Must specify users to add") - self.log.info("Adding %i users to group %s", len(data['users']), name) + self.log.info("Adding %i users to group %s", len(data['users']), group_name) self.log.debug("Adding: %s", data['users']) for user in self._usernames_to_users(data['users']): if user not in group.users: group.users.append(user) else: - self.log.warning("User %s already in group %s", user.name, name) + self.log.warning("User %s already in group %s", user.name, group_name) self.db.commit() self.write(json.dumps(self.group_model(group))) @needs_scope('groups') - async def delete(self, name, subset=None): + async def delete(self, group_name, subset=None): """DELETE removes users from a group""" - if subset is not None and name not in subset: - raise web.HTTPError(403, "No access to add users to group {}".format(name)) - group = self.find_group(name) + if subset is not None and group_name not in subset: + raise web.HTTPError( + 403, "No access to add users to group {}".format(group_name) + ) + group = self.find_group(group_name) data = self.get_json_body() self._check_group_model(data) if 'users' not in data: raise web.HTTPError(400, "Must specify users to delete") - self.log.info("Removing %i users from group %s", len(data['users']), name) + self.log.info("Removing %i users from group %s", len(data['users']), group_name) self.log.debug("Removing: %s", data['users']) for user in self._usernames_to_users(data['users']): if user in group.users: group.users.remove(user) else: - self.log.warning("User %s already not in group %s", user.name, name) + self.log.warning( + "User %s already not in group %s", user.name, group_name + ) self.db.commit() self.write(json.dumps(self.group_model(group))) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index b0310350..068fd645 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -58,8 +58,8 @@ def admin_or_self(method): class ServiceAPIHandler(APIHandler): @needs_scope('read:services') - def get(self, name): - service = self.services[name] + def get(self, service_name): + service = self.services[service_name] self.write(json.dumps(service_model(service))) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index d2439c0a..2566f3ad 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -124,10 +124,10 @@ def admin_or_self(method): class UserAPIHandler(APIHandler): @needs_scope('read:users') - async def get(self, name, subset=None): - user = self.find_user(name) + async def get(self, user_name, subset=None): + user = self.find_user(user_name) if subset is not None: - if name not in subset: + if user_name not in subset: raise web.HTTPError(403, "No access to users") model = self.user_model( @@ -143,13 +143,13 @@ class UserAPIHandler(APIHandler): self.write(json.dumps(model)) @needs_scope('admin:users') - async def post(self, name): + async def post(self, user_name): data = self.get_json_body() - user = self.find_user(name) + user = self.find_user(user_name) if user is not None: - raise web.HTTPError(409, "User %s already exists" % name) + raise web.HTTPError(409, "User %s already exists" % user_name) - user = self.user_from_username(name) + user = self.user_from_username(user_name) if data: self._check_user_model(data) if 'admin' in data: @@ -159,31 +159,33 @@ class UserAPIHandler(APIHandler): try: await maybe_future(self.authenticator.add_user(user)) except Exception: - self.log.error("Failed to create user: %s" % name, exc_info=True) + self.log.error("Failed to create user: %s" % user_name, exc_info=True) # remove from registry self.users.delete(user) - raise web.HTTPError(400, "Failed to create user: %s" % name) + raise web.HTTPError(400, "Failed to create user: %s" % user_name) self.write(json.dumps(self.user_model(user))) self.set_status(201) @needs_scope('admin:users') - async def delete(self, name): - user = self.find_user(name) + async def delete(self, user_name): + user = self.find_user(user_name) if user is None: raise web.HTTPError(404) if user.name == self.current_user.name: raise web.HTTPError(400, "Cannot delete yourself!") if user.spawner._stop_pending: raise web.HTTPError( - 400, "%s's server is in the process of stopping, please wait." % name + 400, + "%s's server is in the process of stopping, please wait." % user_name, ) if user.running: await self.stop_single_user(user) if user.spawner._stop_pending: raise web.HTTPError( 400, - "%s's server is in the process of stopping, please wait." % name, + "%s's server is in the process of stopping, please wait." + % user_name, ) await maybe_future(self.authenticator.delete_user(user)) @@ -193,13 +195,13 @@ class UserAPIHandler(APIHandler): self.set_status(204) @needs_scope('admin:users') - async def patch(self, name): - user = self.find_user(name) + async def patch(self, user_name): + user = self.find_user(user_name) if user is None: raise web.HTTPError(404) data = self.get_json_body() self._check_user_model(data) - if 'name' in data and data['name'] != name: + if 'name' in data and data['name'] != user_name: # check if the new name is already taken inside db if self.find_user(data['name']): raise web.HTTPError( @@ -221,12 +223,12 @@ class UserTokenListAPIHandler(APIHandler): """API endpoint for listing/creating tokens""" @needs_scope('read:users:tokens') - def get(self, name, subset=None): + def get(self, user_name, subset=None): """Get tokens for a given user""" - user = self.find_user(name) + user = self.find_user(user_name) if not user: - raise web.HTTPError(404, "No such user: %s" % name) - if subset is not None and name not in subset: + raise web.HTTPError(404, "No such user: %s" % user_name) + if subset is not None and user_name not in subset: raise web.HTTPError(403, "No access to tokens") now = datetime.utcnow() @@ -256,7 +258,7 @@ class UserTokenListAPIHandler(APIHandler): oauth_tokens.append(self.token_model(token)) self.write(json.dumps({'api_tokens': api_tokens, 'oauth_tokens': oauth_tokens})) - async def post(self, name): + async def post(self, user_name): body = self.get_json_body() or {} if not isinstance(body, dict): raise web.HTTPError(400, "Body must be a JSON dict or empty") @@ -284,11 +286,11 @@ class UserTokenListAPIHandler(APIHandler): if requester is None: # couldn't identify requester raise web.HTTPError(403) - user = self.find_user(name) + user = self.find_user(user_name) if requester is not user and not requester.admin: raise web.HTTPError(403, "Only admins can request tokens for other users") if not user: - raise web.HTTPError(404, "No such user: %s" % name) + raise web.HTTPError(404, "No such user: %s" % user_name) if requester is not user: kind = 'user' if isinstance(requester, User) else 'service' @@ -345,23 +347,23 @@ class UserTokenAPIHandler(APIHandler): return orm_token @needs_scope('read:users:tokens') - def get(self, name, token_id, subset=None): + def get(self, user_name, token_id, subset=None): """""" - user = self.find_user(name) + user = self.find_user(user_name) if not user: - raise web.HTTPError(404, "No such user: %s" % name) - if subset is not None and name not in subset: + raise web.HTTPError(404, "No such user: %s" % user_name) + if subset is not None and user_name not in subset: raise web.HTTPError(403, "No token access allowed") token = self.find_token_by_id(user, token_id) self.write(json.dumps(self.token_model(token))) @needs_scope('users:tokens') - def delete(self, name, token_id, subset=None): + def delete(self, user_name, token_id, subset=None): """Delete a token""" - user = self.find_user(name) + user = self.find_user(user_name) if not user: - raise web.HTTPError(404, "No such user: %s" % name) - if subset is not None and name not in subset: + raise web.HTTPError(404, "No such user: %s" % user_name) + if subset is not None and user_name not in subset: raise web.HTTPError(403, "No token access allowed") token = self.find_token_by_id(user, token_id) # deleting an oauth token deletes *all* oauth tokens for that client @@ -383,8 +385,8 @@ class UserServerAPIHandler(APIHandler): """Start and stop single-user servers""" @needs_scope('users:servers') - async def post(self, name, server_name='', subset=None): - user = self.find_user(name) + async def post(self, user_name, server_name='', subset=None): + user = self.find_user(user_name) if server_name: if not self.allow_named_servers: raise web.HTTPError(400, "Named servers are not enabled.") @@ -403,7 +405,7 @@ class UserServerAPIHandler(APIHandler): 400, "User {} already has the maximum of {} named servers." " One must be deleted before a new server can be created".format( - name, self.named_server_limit_per_user + user_name, self.named_server_limit_per_user ), ) spawner = user.spawners[server_name] @@ -433,8 +435,8 @@ class UserServerAPIHandler(APIHandler): self.set_status(status) @needs_scope('users:servers') - async def delete(self, name, server_name=''): - user = self.find_user(name) + async def delete(self, user_name, server_name=''): + user = self.find_user(user_name) options = self.get_json_body() remove = (options or {}).get('remove', False) @@ -451,7 +453,7 @@ class UserServerAPIHandler(APIHandler): raise web.HTTPError(400, "Named servers are not enabled.") if server_name not in user.orm_spawners: raise web.HTTPError( - 404, "%s has no server named '%s'" % (name, server_name) + 404, "%s has no server named '%s'" % (user_name, server_name) ) elif remove: raise web.HTTPError(400, "Cannot delete the default server") @@ -496,18 +498,18 @@ class UserAdminAccessAPIHandler(APIHandler): """ @needs_scope('users:servers') - def post(self, name): + def post(self, user_name): self.log.warning( "Deprecated in JupyterHub 0.8." " Admin access API is not needed now that we use OAuth." ) current = self.current_user self.log.warning( - "Admin user %s has requested access to %s's server", current.name, name + "Admin user %s has requested access to %s's server", current.name, user_name ) if not self.settings.get('admin_access', False): raise web.HTTPError(403, "admin access to user servers disabled") - user = self.find_user(name) + user = self.find_user(user_name) if user is None: raise web.HTTPError(404) @@ -552,7 +554,7 @@ class SpawnProgressAPIHandler(APIHandler): await asyncio.wait([self._finish_future], timeout=self.keepalive_interval) @needs_scope('read:users:servers') - async def get(self, username, server_name='', subset=None): + async def get(self, user_name, server_name='', subset=None): self.set_header('Cache-Control', 'no-cache') if server_name is None: server_name = '' @@ -561,7 +563,7 @@ class SpawnProgressAPIHandler(APIHandler): raise web.HTTPError( 403, "No read access to server {}".format(server_name) ) - user = self.find_user(username) + user = self.find_user(user_name) if user is None: # no such user raise web.HTTPError(404) @@ -700,11 +702,11 @@ class ActivityAPIHandler(APIHandler): return servers @needs_scope('users') - def post(self, username): - user = self.find_user(username) + def post(self, user_name): + user = self.find_user(user_name) if user is None: # no such user - raise web.HTTPError(404, "No such user: %r", username) + raise web.HTTPError(404, "No such user: %r", user_name) body = self.get_json_body() if not isinstance(body, dict): From 365921d162e2816abd02bc497ed6d65ee61587a0 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 9 Nov 2020 14:25:02 +0100 Subject: [PATCH 019/270] Added filtering to decorator and added tests --- jupyterhub/apihandlers/groups.py | 20 +++--------- jupyterhub/apihandlers/users.py | 33 ++++--------------- jupyterhub/tests/test_scopes.py | 41 ++++++++++++++++++++--- jupyterhub/utils.py | 56 +++++++++++++++++++++++--------- 4 files changed, 87 insertions(+), 63 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 686292ee..e69a70a2 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -78,9 +78,7 @@ class GroupAPIHandler(_GroupAPIHandler): """View and modify groups by name""" @needs_scope('read:groups') - def get(self, group_name, subset=None): - if subset is not None and group_name not in subset: - raise web.HTTPError(403, "No read access to group {}".format(group_name)) + def get(self, group_name): group = self.find_group(group_name) self.write(json.dumps(self.group_model(group))) @@ -111,10 +109,8 @@ class GroupAPIHandler(_GroupAPIHandler): self.set_status(201) @needs_scope('admin:groups') - def delete(self, group_name, subset=None): + def delete(self, group_name): """Delete a group by name""" - if subset is not None and group_name not in subset: - raise web.HTTPError(403, "No write access to group {}".format(group_name)) group = self.find_group(group_name) self.log.info("Deleting group %s", group_name) self.db.delete(group) @@ -126,12 +122,8 @@ class GroupUsersAPIHandler(_GroupAPIHandler): """Modify a group's user list""" @needs_scope('groups') - def post(self, group_name, subset=None): + def post(self, group_name): """POST adds users to a group""" - if subset is not None and group_name not in subset: - raise web.HTTPError( - 403, "No access to add users to group {}".format(group_name) - ) group = self.find_group(group_name) data = self.get_json_body() self._check_group_model(data) @@ -148,12 +140,8 @@ class GroupUsersAPIHandler(_GroupAPIHandler): self.write(json.dumps(self.group_model(group))) @needs_scope('groups') - async def delete(self, group_name, subset=None): + async def delete(self, group_name): """DELETE removes users from a group""" - if subset is not None and group_name not in subset: - raise web.HTTPError( - 403, "No access to add users to group {}".format(group_name) - ) group = self.find_group(group_name) data = self.get_json_body() self._check_group_model(data) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 2566f3ad..2d59e092 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -124,12 +124,8 @@ def admin_or_self(method): class UserAPIHandler(APIHandler): @needs_scope('read:users') - async def get(self, user_name, subset=None): + async def get(self, user_name): user = self.find_user(user_name) - if subset is not None: - if user_name not in subset: - raise web.HTTPError(403, "No access to users") - model = self.user_model( user, include_servers=True, include_state=self.current_user.admin ) @@ -223,16 +219,13 @@ class UserTokenListAPIHandler(APIHandler): """API endpoint for listing/creating tokens""" @needs_scope('read:users:tokens') - def get(self, user_name, subset=None): + def get(self, user_name): """Get tokens for a given user""" user = self.find_user(user_name) if not user: raise web.HTTPError(404, "No such user: %s" % user_name) - if subset is not None and user_name not in subset: - raise web.HTTPError(403, "No access to tokens") now = datetime.utcnow() - api_tokens = [] def sort_key(token): @@ -347,24 +340,20 @@ class UserTokenAPIHandler(APIHandler): return orm_token @needs_scope('read:users:tokens') - def get(self, user_name, token_id, subset=None): + def get(self, user_name, token_id): """""" user = self.find_user(user_name) if not user: raise web.HTTPError(404, "No such user: %s" % user_name) - if subset is not None and user_name not in subset: - raise web.HTTPError(403, "No token access allowed") token = self.find_token_by_id(user, token_id) self.write(json.dumps(self.token_model(token))) @needs_scope('users:tokens') - def delete(self, user_name, token_id, subset=None): + def delete(self, user_name, token_id): """Delete a token""" user = self.find_user(user_name) if not user: raise web.HTTPError(404, "No such user: %s" % user_name) - if subset is not None and user_name not in subset: - raise web.HTTPError(403, "No token access allowed") token = self.find_token_by_id(user, token_id) # deleting an oauth token deletes *all* oauth tokens for that client if isinstance(token, orm.OAuthAccessToken): @@ -385,16 +374,11 @@ class UserServerAPIHandler(APIHandler): """Start and stop single-user servers""" @needs_scope('users:servers') - async def post(self, user_name, server_name='', subset=None): + async def post(self, user_name, server_name=''): user = self.find_user(user_name) if server_name: if not self.allow_named_servers: raise web.HTTPError(400, "Named servers are not enabled.") - if subset is not None: - if server_name not in subset: - raise web.HTTPError( - 403, "No access to create {}".format(server_name) - ) if ( self.named_server_limit_per_user > 0 and server_name not in user.orm_spawners @@ -554,15 +538,10 @@ class SpawnProgressAPIHandler(APIHandler): await asyncio.wait([self._finish_future], timeout=self.keepalive_interval) @needs_scope('read:users:servers') - async def get(self, user_name, server_name='', subset=None): + async def get(self, user_name, server_name=''): self.set_header('Cache-Control', 'no-cache') if server_name is None: server_name = '' - if subset is not None: - if server_name not in subset: - raise web.HTTPError( - 403, "No read access to server {}".format(server_name) - ) user = self.find_user(user_name) if user is None: # no such user diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 6c8326e0..4099a9cc 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -60,24 +60,55 @@ def test_scope_one_filter_only(): check_scope('all', parse_scopes(['all']), user='george_michael', group='bluths') +def test_scope_parse_server_name(): + scope_list = ['users:servers!server=maeby/server1', 'read:users!user=maeby'] + parsed_scopes = parse_scopes(scope_list) + assert check_scope('users:servers', parsed_scopes, user='maeby', server='server1') + + class Test: def __init__(self): - self.scopes = ['read:users'] + self.scopes = ['users'] - @needs_scope('read:users') - def foo(self, user): + @needs_scope('users') + def foo(self, user_name): + return True + + @needs_scope('users:servers') + def bar(self, user_name, server_name): return True def test_scope_def(): obj = Test() - obj.scopes = ['read:users'] + obj.scopes = ['users'] assert obj.foo('user') assert obj.foo('user2') -def test_wrong_scope(): +def test_scope_wrong(): obj = Test() obj.scopes = [] with pytest.raises(web.HTTPError): obj.foo('user1') + + +def test_scope_filter(): + obj = Test() + obj.scopes = ['users!user=gob', 'users!user=michael'] + assert obj.foo('gob') + with pytest.raises(web.HTTPError): + obj.foo('buster') + + +def test_scope_servername(): + obj = Test() + obj.scopes = ['users:servers!server=gob/server1'] + assert obj.bar(user_name='gob', server_name='server1') + assert obj.bar('gob', 'server1') + with pytest.raises(web.HTTPError): + obj.bar('gob', 'server3') + with pytest.raises(web.HTTPError): + obj.bar('maeby', 'server1') + with pytest.raises(web.HTTPError): + obj.bar('maeby', 'server2') diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index ef71c514..0b46e91e 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -300,6 +300,10 @@ def metrics_authentication(self): def check_scope(req_scope, scopes, **kwargs): + # Parse user name and server name together + if 'user' in kwargs and 'server' in kwargs: + user_name = kwargs.pop('user') + kwargs['server'] = "{}/{}".format(user_name, kwargs['server']) if len(kwargs) > 1: raise AttributeError("Please specify exactly one filter") base_scope = req_scope.split('!')[0] @@ -317,6 +321,26 @@ def check_scope(req_scope, scopes, **kwargs): def parse_scopes(scope_list): + """ + Parses scopes and filters in something akin to JSON style + + For instance, scope list ["users", "groups:group=foo", "users:servers:server=bar", "users:servers:server=baz"] + would lead to scope model + { + "users":True, + "users:admin":{ + "user":[ + "alice" + ] + }, + "users:servers":{ + "server":[ + "bar", + "baz" + ] + } + } + """ parsed_scopes = {} for scope in scope_list: scope_ = scope.split('!') @@ -325,10 +349,11 @@ def parse_scopes(scope_list): filter_ = scope_[1] if base_scope not in parsed_scopes: parsed_scopes[base_scope] = {} - key, val = filter_.split('=') - if key not in parsed_scopes[base_scope]: - parsed_scopes[base_scope][key] = [] - parsed_scopes[base_scope][key].append(val) + if parsed_scopes[base_scope] != True: + key, val = filter_.split('=') + if key not in parsed_scopes[base_scope]: + parsed_scopes[base_scope][key] = [] + parsed_scopes[base_scope][key].append(val) else: parsed_scopes[base_scope] = True return parsed_scopes @@ -340,18 +365,19 @@ def needs_scope(scope): def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): - allows_subset = 'subset' in inspect.signature(func).parameters - if scope in self.scopes: + sig = inspect.signature(func) + bound_sig = sig.bind(self, *args, **kwargs) + bound_sig.apply_defaults() + s_kwargs = {} + for resource in {'user', 'server', 'group', 'service'}: + resource_name = resource + '_name' + if resource_name in bound_sig.arguments: + resource_value = bound_sig.arguments[resource_name] + s_kwargs[resource] = resource_value + if check_scope(scope, parse_scopes(self.scopes), **s_kwargs): return func(self, *args, **kwargs) - elif allows_subset: - # Check if access is not restricted to user/server/service - match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") - subscopes = filter(lambda s: re.search(match_string, s), self.scopes) - subset = [subscope.split('=')[1] for subscope in subscopes] - if subset: - kwargs['subset'] = subset - return func(self, *args, **kwargs) - raise web.HTTPError(403, "Action is not authorized with current scopes") + else: + raise web.HTTPError(403, "Action is not authorized with current scopes") return _auth_func From 14468b3849e18fc4dd368372cf95c535ff1797d6 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 9 Nov 2020 16:06:53 +0100 Subject: [PATCH 020/270] Changed scopes --- jupyterhub/apihandlers/groups.py | 6 ++---- jupyterhub/apihandlers/services.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index e69a70a2..14c9d325 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -35,12 +35,10 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @needs_scope('read:groups') - def get(self, subset=None): + @needs_scope('read:groups') # Todo: Filter allowed here? + def get(self): """List groups""" groups = self.db.query(orm.Group) - if subset is not None: - groups = groups.filter(orm.Group.name.in_(subset)) data = [self.group_model(g) for g in groups] self.write(json.dumps(data)) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 068fd645..914483c9 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -29,7 +29,7 @@ def service_model(service): class ServiceListAPIHandler(APIHandler): - @needs_scope('read:services') + @needs_scope('read:services') # Todo: allow filter here? def get(self): data = {name: service_model(service) for name, service in self.services.items()} self.write(json.dumps(data)) From 9f6d37cf482f68815da8b8e6f3b0b93479b96ade Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 9 Nov 2020 16:07:09 +0100 Subject: [PATCH 021/270] Parametrized scope test suite --- jupyterhub/tests/test_scopes.py | 116 +++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 4099a9cc..0ff032b2 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -1,15 +1,11 @@ -""" -test scopes as used in rbac -""" -from unittest import mock - +"""Test scopes for API handlers""" import pytest +from pytest import mark from tornado import web from ..utils import check_scope from ..utils import needs_scope from ..utils import parse_scopes -from .utils import get_scopes def test_scope_constructor(): @@ -71,44 +67,84 @@ class Test: self.scopes = ['users'] @needs_scope('users') - def foo(self, user_name): + def user_thing(self, user_name): return True @needs_scope('users:servers') - def bar(self, user_name, server_name): + def server_thing(self, user_name, server_name): + return True + + @needs_scope('read:groups') + def group_thing(self, group_name): + return True + + @needs_scope('services') + def service_thing(self, service_name): + return True + + @needs_scope('users') + def other_thing(self, other_name): return True -def test_scope_def(): +@mark.parametrize( + "scopes, method, arguments, is_allowed", + [ + (['users'], 'user_thing', ('user',), True), + (['users'], 'user_thing', ('michael',), True), + ([''], 'user_thing', ('michael',), False), + (['read:users'], 'user_thing', ('gob',), False), + (['read:users'], 'user_thing', ('michael',), False), + (['users!user=george'], 'user_thing', ('george',), True), + (['users!user=george'], 'user_thing', ('oscar',), False), + (['users!user=george', 'users!user=oscar'], 'user_thing', ('oscar',), True), + (['users:servers'], 'server_thing', ('user1', 'server_1'), True), + (['users:servers'], 'server_thing', ('user1', ''), True), + (['users:servers'], 'server_thing', ('user1', None), True), + ( + ['users:servers!server=maeby/bluth'], + 'server_thing', + ('maeby', 'bluth'), + True, + ), + (['users:servers!server=maeby/bluth'], 'server_thing', ('gob', 'bluth'), False), + ( + ['users:servers!server=maeby/bluth'], + 'server_thing', + ('maybe', 'bluth2'), + False, + ), + (['services'], 'service_thing', ('service1',), True), + ( + ['users!user=george', 'read:groups!group=bluths'], + 'group_thing', + ('bluths',), + True, + ), + ( + ['users!user=george', 'read:groups!group=bluths'], + 'group_thing', + ('george',), + False, + ), + ( + ['groups!group=george', 'read:groups!group=bluths'], + 'group_thing', + ('george',), + False, + ), + (['users'], 'other_thing', ('gob',), True), + (['read:users'], 'other_thing', ('gob',), False), + (['users!user=gob'], 'other_thing', ('gob',), False), + (['users!user=gob'], 'other_thing', ('maeby',), False), + ], +) +def test_scope_method_access(scopes, method, arguments, is_allowed): obj = Test() - obj.scopes = ['users'] - assert obj.foo('user') - assert obj.foo('user2') - - -def test_scope_wrong(): - obj = Test() - obj.scopes = [] - with pytest.raises(web.HTTPError): - obj.foo('user1') - - -def test_scope_filter(): - obj = Test() - obj.scopes = ['users!user=gob', 'users!user=michael'] - assert obj.foo('gob') - with pytest.raises(web.HTTPError): - obj.foo('buster') - - -def test_scope_servername(): - obj = Test() - obj.scopes = ['users:servers!server=gob/server1'] - assert obj.bar(user_name='gob', server_name='server1') - assert obj.bar('gob', 'server1') - with pytest.raises(web.HTTPError): - obj.bar('gob', 'server3') - with pytest.raises(web.HTTPError): - obj.bar('maeby', 'server1') - with pytest.raises(web.HTTPError): - obj.bar('maeby', 'server2') + obj.scopes = scopes + api_call = getattr(obj, method) + if is_allowed: + assert api_call(*arguments) + else: + with pytest.raises(web.HTTPError): + api_call(*arguments) From 2e9ecfff02c5bfaee187fcf8402000c325c1bf2b Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 17 Nov 2020 09:56:48 +0100 Subject: [PATCH 022/270] WIP: implementing expanding groups --- jupyterhub/utils.py | 47 ++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 0b46e91e..25285164 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -19,6 +19,7 @@ import warnings from binascii import b2a_hex from datetime import datetime from datetime import timezone +from enum import Enum from hmac import compare_digest from operator import itemgetter @@ -34,6 +35,8 @@ from tornado.httpclient import HTTPError from tornado.log import app_log from tornado.platform.asyncio import to_asyncio_future +from .. import orm + def random_port(): """Get a single random port.""" @@ -299,6 +302,18 @@ def metrics_authentication(self): raise web.HTTPError(403) +class Scope(Enum): + ALL = True + + +def expand_groups_to_users(db, filter_scope): + """Update the group filters to account for the individual users""" + if 'group' in filter_scope: + groups = db.query(orm.Group) + user_set = orm.User.query.filter(orm.User.group.in_(groups)) + return user_set.get_names() + + def check_scope(req_scope, scopes, **kwargs): # Parse user name and server name together if 'user' in kwargs and 'server' in kwargs: @@ -306,18 +321,17 @@ def check_scope(req_scope, scopes, **kwargs): kwargs['server'] = "{}/{}".format(user_name, kwargs['server']) if len(kwargs) > 1: raise AttributeError("Please specify exactly one filter") - base_scope = req_scope.split('!')[0] - if base_scope not in scopes: + if req_scope not in scopes: return False - if scopes[base_scope] == True: # is this pretty? + if scopes[req_scope] == Scope.ALL: return True # Apply filters if not kwargs: return False - filter_ = list(kwargs)[0] - if filter_ not in scopes[base_scope]: + filter_, filter_value = list(kwargs.items())[0] + if filter_ not in scopes[req_scope]: return False - return kwargs[filter_] in scopes[req_scope][filter_] + return filter_value in scopes[req_scope][filter_] def parse_scopes(scope_list): @@ -343,19 +357,16 @@ def parse_scopes(scope_list): """ parsed_scopes = {} for scope in scope_list: - scope_ = scope.split('!') - base_scope = scope_[0] - if len(scope_) > 1: - filter_ = scope_[1] - if base_scope not in parsed_scopes: - parsed_scopes[base_scope] = {} - if parsed_scopes[base_scope] != True: - key, val = filter_.split('=') - if key not in parsed_scopes[base_scope]: - parsed_scopes[base_scope][key] = [] - parsed_scopes[base_scope][key].append(val) + base_scope, _, filter_ = scope.partition('!') + if base_scope not in parsed_scopes: + parsed_scopes[base_scope] = {} + if parsed_scopes[base_scope] != Scope.ALL: + key, _, val = filter_.partition('=') + if key not in parsed_scopes[base_scope]: + parsed_scopes[base_scope][key] = [] + parsed_scopes[base_scope][key].append(val) else: - parsed_scopes[base_scope] = True + parsed_scopes[base_scope] = Scope.ALL return parsed_scopes From 99c3f77c58b6e28e8b46ab8ef7167730a812d835 Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Wed, 18 Nov 2020 17:12:26 +0100 Subject: [PATCH 023/270] WIP Implemented scopes --- jupyterhub/tests/test_scopes.py | 38 ++++++++++++++-------- jupyterhub/utils.py | 56 +++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 0ff032b2..494ec8f9 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -6,6 +6,7 @@ from tornado import web from ..utils import check_scope from ..utils import needs_scope from ..utils import parse_scopes +from ..utils import Scope def test_scope_constructor(): @@ -26,43 +27,54 @@ def test_scope_constructor(): def test_scope_precendence(): scope_list = ['read:users!user=maeby', 'read:users'] parsed_scopes = parse_scopes(scope_list) - assert parsed_scopes['read:users'] == True + assert parsed_scopes['read:users'] == Scope.ALL def test_scope_check_present(): + handler = None scope_list = ['read:users'] parsed_scopes = parse_scopes(scope_list) - assert check_scope('read:users', parsed_scopes) - assert check_scope('read:users!user=maeby', parsed_scopes) + assert check_scope(handler, 'read:users', parsed_scopes) + assert check_scope(handler, 'read:users', parsed_scopes, user='maeby') -def test_scope_check_not_present(): # What should this return when the broad scope is asked and a small one satisfied? +def test_scope_check_not_present(): + handler = None scope_list = ['read:users!user=maeby'] parsed_scopes = parse_scopes(scope_list) - assert not check_scope('read:users', parsed_scopes) - assert not check_scope('read:users', parsed_scopes, user='gob') - assert not check_scope('read:users', parsed_scopes, server='gob/server') + assert not check_scope(handler, 'read:users', parsed_scopes) + assert not check_scope(handler, 'read:users', parsed_scopes, user='gob') + assert not check_scope( + handler, 'read:users', parsed_scopes, user='gob', server='server' + ) def test_scope_filters(): + handler = None scope_list = ['read:users', 'read:users!group=bluths', 'read:users!user=maeby'] parsed_scopes = parse_scopes(scope_list) - assert check_scope('read:users!group=bluths', parsed_scopes) - assert check_scope('read:users!user=maeby', parsed_scopes) + assert check_scope(handler, 'read:users', parsed_scopes, group='bluth') + assert check_scope(handler, 'read:users', parsed_scopes, user='maeby') def test_scope_one_filter_only(): + handler = None with pytest.raises(AttributeError): - check_scope('all', parse_scopes(['all']), user='george_michael', group='bluths') + check_scope( + handler, 'all', parse_scopes(['all']), user='george_michael', group='bluths' + ) def test_scope_parse_server_name(): + handler = None scope_list = ['users:servers!server=maeby/server1', 'read:users!user=maeby'] parsed_scopes = parse_scopes(scope_list) - assert check_scope('users:servers', parsed_scopes, user='maeby', server='server1') + assert check_scope( + handler, 'users:servers', parsed_scopes, user='maeby', server='server1' + ) -class Test: +class MockAPI: def __init__(self): self.scopes = ['users'] @@ -140,7 +152,7 @@ class Test: ], ) def test_scope_method_access(scopes, method, arguments, is_allowed): - obj = Test() + obj = MockAPI() obj.scopes = scopes api_call = getattr(obj, method) if is_allowed: diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 25285164..092e3460 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -9,7 +9,6 @@ import hashlib import inspect import os import random -import re import socket import ssl import sys @@ -35,7 +34,7 @@ from tornado.httpclient import HTTPError from tornado.log import app_log from tornado.platform.asyncio import to_asyncio_future -from .. import orm +from . import orm def random_port(): @@ -306,15 +305,40 @@ class Scope(Enum): ALL = True +def needs_scope_expansion(filter_, filter_value, sub_scope): + """ + Check if there is a requirements to expand the `group` scope to individual `user` scopes. + Assumptions: + req_scopes in scopes + filter_ != Scope.ALL + + This can be made arbitrarily intelligent but that would make it more complex + """ + if not (filter_ == 'user' and 'group' in sub_scope): + return False + if 'user' in sub_scope: + return filter_value not in sub_scope['user'] + else: + return True + + def expand_groups_to_users(db, filter_scope): """Update the group filters to account for the individual users""" if 'group' in filter_scope: groups = db.query(orm.Group) user_set = orm.User.query.filter(orm.User.group.in_(groups)) - return user_set.get_names() + return [user.name for user in user_set] -def check_scope(req_scope, scopes, **kwargs): +def check_user_in_expanded_scope(handler, user_name, scope_group_names): + user = handler.find_user(user_name) + if user is None: + raise web.HTTPError(404, 'No such user found') + group_names = {group.name for group in user.groups} + return bool(scope_group_names & group_names) + + +def check_scope(api_handler, req_scope, scopes, **kwargs): # Parse user name and server name together if 'user' in kwargs and 'server' in kwargs: user_name = kwargs.pop('user') @@ -329,19 +353,24 @@ def check_scope(req_scope, scopes, **kwargs): if not kwargs: return False filter_, filter_value = list(kwargs.items())[0] - if filter_ not in scopes[req_scope]: - return False - return filter_value in scopes[req_scope][filter_] + sub_scope = scopes[req_scope] + if filter_ not in sub_scope: + if needs_scope_expansion(filter_, filter_value, sub_scope): + group_names = sub_scope['groups'] + return check_user_in_expanded_scope(api_handler, filter_value, group_names) + else: + return False + return filter_value in sub_scope[filter_] def parse_scopes(scope_list): """ Parses scopes and filters in something akin to JSON style - For instance, scope list ["users", "groups:group=foo", "users:servers:server=bar", "users:servers:server=baz"] + For instance, scope list ["users", "groups!group=foo", "users:servers!server=bar", "users:servers!server=baz"] would lead to scope model { - "users":True, + "users":scope.ALL, "users:admin":{ "user":[ "alice" @@ -358,15 +387,15 @@ def parse_scopes(scope_list): parsed_scopes = {} for scope in scope_list: base_scope, _, filter_ = scope.partition('!') - if base_scope not in parsed_scopes: + if not filter_: + parsed_scopes[base_scope] = Scope.ALL + elif base_scope not in parsed_scopes: parsed_scopes[base_scope] = {} if parsed_scopes[base_scope] != Scope.ALL: key, _, val = filter_.partition('=') if key not in parsed_scopes[base_scope]: parsed_scopes[base_scope][key] = [] parsed_scopes[base_scope][key].append(val) - else: - parsed_scopes[base_scope] = Scope.ALL return parsed_scopes @@ -385,7 +414,8 @@ def needs_scope(scope): if resource_name in bound_sig.arguments: resource_value = bound_sig.arguments[resource_name] s_kwargs[resource] = resource_value - if check_scope(scope, parse_scopes(self.scopes), **s_kwargs): + parsed_scopes = parse_scopes(self.scopes) + if check_scope(self, scope, parsed_scopes, **s_kwargs): return func(self, *args, **kwargs) else: raise web.HTTPError(403, "Action is not authorized with current scopes") From 54cb31b3a9d69d50042affc3ea53324f95fc86b8 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 18 Nov 2020 17:29:15 +0100 Subject: [PATCH 024/270] Removed circular import --- jupyterhub/utils.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 092e3460..1b2ce995 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -34,8 +34,6 @@ from tornado.httpclient import HTTPError from tornado.log import app_log from tornado.platform.asyncio import to_asyncio_future -from . import orm - def random_port(): """Get a single random port.""" @@ -322,12 +320,13 @@ def needs_scope_expansion(filter_, filter_value, sub_scope): return True -def expand_groups_to_users(db, filter_scope): - """Update the group filters to account for the individual users""" - if 'group' in filter_scope: - groups = db.query(orm.Group) - user_set = orm.User.query.filter(orm.User.group.in_(groups)) - return [user.name for user in user_set] +# def expand_groups_to_users(db, filter_scope): +# """Update the group filters to account for the individual users""" +# if 'group' in filter_scope: +# groups = db.query(orm.Group) +# user_set = orm.User.query.filter(orm.User.group.in_(groups)) +# return [user.name for user in user_set] +# def check_user_in_expanded_scope(handler, user_name, scope_group_names): From c0cadc384d1a23dc52f4d22aa297946e029d21c6 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 19 Nov 2020 08:22:52 +0100 Subject: [PATCH 025/270] adding roles to tokens --- jupyterhub/apihandlers/base.py | 4 + jupyterhub/apihandlers/users.py | 17 ++- jupyterhub/app.py | 79 +++++----- jupyterhub/handlers/base.py | 3 + jupyterhub/orm.py | 25 +++ jupyterhub/roles.py | 159 ++++++++++++++----- jupyterhub/tests/mocking.py | 6 +- jupyterhub/tests/populate_db.py | 2 - jupyterhub/tests/test_api.py | 7 +- jupyterhub/tests/test_named_servers.py | 6 +- jupyterhub/tests/test_orm.py | 1 - jupyterhub/tests/test_roles.py | 201 +++++++++++++++++++++---- jupyterhub/tests/utils.py | 3 + 13 files changed, 382 insertions(+), 131 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 8bd05ecc..a416e6c8 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -150,10 +150,13 @@ class APIHandler(BaseHandler): expires_at = None if isinstance(token, orm.APIToken): kind = 'api_token' + roles = [r.name for r in token.roles] extra = {'note': token.note} expires_at = token.expires_at elif isinstance(token, orm.OAuthAccessToken): kind = 'oauth' + # oauth tokens do not bear roles + roles = [] extra = {'oauth_client': token.client.description or token.client.client_id} if token.expires_at: expires_at = datetime.fromtimestamp(token.expires_at) @@ -174,6 +177,7 @@ class APIHandler(BaseHandler): owner_key: owner, 'id': token.api_id, 'kind': kind, + 'roles': [role for role in roles], 'created': isoformat(token.created), 'last_activity': isoformat(token.last_activity), 'expires_at': isoformat(expires_at), diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index c253e4ea..2a072190 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -14,6 +14,7 @@ from tornado.iostream import StreamClosedError from .. import orm from .. import roles +from ..roles import update_roles from ..user import User from ..utils import admin_only from ..utils import isoformat @@ -88,7 +89,7 @@ class UserListAPIHandler(APIHandler): user = self.user_from_username(name) if admin: user.admin = True - roles.update_roles(self.db, user) + update_roles(self.db, obj=user, kind='users') self.db.commit() try: await maybe_future(self.authenticator.add_user(user)) @@ -151,7 +152,7 @@ class UserAPIHandler(APIHandler): self._check_user_model(data) if 'admin' in data: user.admin = data['admin'] - roles.update_roles(self.db, user) + update_roles(self.db, obj=user, kind='users') self.db.commit() try: @@ -210,7 +211,7 @@ class UserAPIHandler(APIHandler): else: setattr(user, key, value) if key == 'admin': - roles.update_roles(self.db, user=user) + update_roles(self.db, obj=user, kind='users') self.db.commit() user_ = self.user_model(user) user_['auth_state'] = await user.get_auth_state() @@ -296,9 +297,13 @@ class UserTokenListAPIHandler(APIHandler): if requester is not user: note += " by %s %s" % (kind, requester.name) - api_token = user.new_api_token( - note=note, expires_in=body.get('expires_in', None) - ) + token_roles = body.get('roles') + try: + api_token = user.new_api_token( + note=note, expires_in=body.get('expires_in', None), roles=token_roles + ) + except ValueError: + raise web.HTTPError(404, "Requested roles %r not found" % token_roles) if requester is not user: self.log.info( "%s %s requested API token for %s", diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 6618c6f0..4ea92bc7 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -318,18 +318,21 @@ class JupyterHub(Application): For instance:: - roles = [ - { - 'name': 'teacher', - 'description': 'Access users information, servers and groups without create/delete privileges', - 'scopes': ['users', 'groups'], - 'users': ['cyclops', 'wolverine'] - } - ] + load_roles = [ + { + 'name': 'teacher', + 'description': 'Access users information, servers and groups without create/delete privileges', + 'scopes': ['users', 'groups'], + 'users': ['cyclops', 'gandalf'], + 'services': [], + 'tokens': [] + } + ] + All keys apart from 'name' are optional. See all the available scopes in the JupyterHub REST API documentation. - The default roles are in roles.py. + Default roles are defined in roles.py. """, ).tag(config=True) @@ -1823,6 +1826,8 @@ class JupyterHub(Application): async def init_roles(self): """Load default and predefined roles into the database""" db = self.db + role_bearers = ['users', 'services', 'tokens'] + # load default roles default_roles = roles.get_default_roles() for role in default_roles: @@ -1831,43 +1836,31 @@ class JupyterHub(Application): # load predefined roles from config file for predef_role in self.load_roles: roles.add_role(db, predef_role) - role = orm.Role.find(db, predef_role['name']) - - # handle users - if 'users' in predef_role.keys(): - for username in predef_role['users']: - username = self.authenticator.normalize_username(username) - if not ( - await maybe_future( - self.authenticator.check_allowed(username, None) + # add users, services and/or tokens + for bearer in role_bearers: + if bearer in predef_role.keys(): + for bname in predef_role[bearer]: + if bearer == 'users': + bname = self.authenticator.normalize_username(bname) + if not ( + await maybe_future( + self.authenticator.check_allowed(bname, None) + ) + ): + raise ValueError( + "Username %r is not in Authenticator.allowed_users" + % bname + ) + roles.add_obj( + db, objname=bname, kind=bearer, rolename=predef_role['name'] ) - ): - raise ValueError( - "Username %r is not in Authenticator.allowed_users" - % username - ) - user = orm.User.find(db, name=username) - if user is None: - raise ValueError("%r does not exist" % username) - else: - roles.add_user(db, user=user, role=role) - # handle services - if 'services' in predef_role.keys(): - for servicename in predef_role['services']: - service = orm.Service.find(db, name=servicename) - if service is None: - raise ValueError("%r does not exist" % servicename) - else: - roles.add_user(db, user=service, role=role) - - # make sure all users and services have at least one role (update with default) - Classes = [orm.User, orm.Service] - for ormClass in Classes: - for obj in db.query(ormClass): + # make sure all users, services and tokens have at least one role (update with default) + for bearer in role_bearers: + Class = roles.get_orm_class(bearer) + for obj in db.query(Class): if len(obj.roles) < 1: - roles.update_roles(db, obj) - + roles.update_roles(db, obj=obj, kind=bearer) db.commit() async def _add_tokens(self, token_dict, kind): diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index c8b2dc9e..89722008 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -30,6 +30,7 @@ from tornado.web import RequestHandler from .. import __version__ from .. import orm +from .. import roles from ..metrics import PROXY_ADD_DURATION_SECONDS from ..metrics import PROXY_DELETE_DURATION_SECONDS from ..metrics import ProxyDeleteStatus @@ -453,6 +454,7 @@ class BaseHandler(RequestHandler): # not found, create and register user u = orm.User(name=username) self.db.add(u) + roles.update_roles(self.db, obj=u, kind='users') self.db.commit() user = self._user_from_orm(u) return user @@ -722,6 +724,7 @@ class BaseHandler(RequestHandler): # Only set `admin` if the authenticator returned an explicit value. if admin is not None and admin != user.admin: user.admin = admin + roles.update_roles(self.db, obj=user, kind='users') self.db.commit() # always set auth_state and commit, # because there could be key-rotation or clearing of previous values diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 66d9f31d..90ca63f7 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -39,6 +39,9 @@ from sqlalchemy.types import Text from sqlalchemy.types import TypeDecorator from tornado.log import app_log +from .roles import add_role +from .roles import get_default_roles +from .roles import update_roles from .utils import compare_token from .utils import hash_token from .utils import new_token @@ -151,6 +154,18 @@ service_role_map = Table( Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), ) +# token:role many:many mapping table +api_token_role_map = Table( + 'api_token_role_map', + Base.metadata, + Column( + 'api_token_id', + ForeignKey('api_tokens.id', ondelete='CASCADE'), + primary_key=True, + ), + Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), +) + class Role(Base): """User Roles""" @@ -162,6 +177,7 @@ class Role(Base): scopes = Column(JSONList) users = relationship('User', secondary='user_role_map', backref='roles') services = relationship('Service', secondary='service_role_map', backref='roles') + tokens = relationship('APIToken', secondary='api_token_role_map', backref='roles') def __repr__(self): return "<%s %s (%s) - scopes: %s>" % ( @@ -570,6 +586,7 @@ class APIToken(Hashed, Base): token=None, user=None, service=None, + roles=None, note='', generated=True, expires_in=None, @@ -598,6 +615,14 @@ class APIToken(Hashed, Base): if expires_in is not None: orm_token.expires_at = cls.now() + timedelta(seconds=expires_in) db.add(orm_token) + # load default roles if they haven't been initiated + # correct to have this here? otherwise some tests fail + user_role = Role.find(db, 'user') + if not user_role: + default_roles = get_default_roles() + for role in default_roles: + add_role(db, role) + update_roles(db, obj=orm_token, kind='tokens', roles=roles) db.commit() return token diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index a56b3344..7f78067e 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -1,12 +1,12 @@ """Roles utils""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from .orm import Role +from . import orm def get_default_roles(): - """Returns a list of default roles dictionaries""" + """Returns a list of default role dictionaries""" default_roles = [ { @@ -43,50 +43,127 @@ def add_role(db, role_dict): """Adds a new role to database or modifies an existing one""" - role = Role.find(db, role_dict['name']) + if 'name' not in role_dict.keys(): + raise ValueError('Role must have a name') + else: + name = role_dict['name'] + role = orm.Role.find(db, name) + + description = role_dict.get('description') + scopes = role_dict.get('scopes') if role is None: - role = Role( - name=role_dict['name'], - description=role_dict['description'], - scopes=role_dict['scopes'], - ) + role = orm.Role(name=name, description=description, scopes=scopes,) db.add(role) else: - role.description = role_dict['description'] - role.scopes = role_dict['scopes'] - role.users = [] - role.services = [] + if description: + role.description = description + if scopes: + role.scopes = scopes db.commit() -def add_user(db, user, role): - if role is not None and role not in user.roles: - user.roles.append(role) - db.commit() - - -def remove_user(db, user, role): - if role is not None and role in user.roles: - user.roles.remove(role) - db.commit() - - -def update_roles(db, user): - - """Updates roles if user has no role with default or when user admin status is changed""" - - user_role = Role.find(db, 'user') - admin_role = Role.find(db, 'admin') - - if user.admin: - if user_role in user.roles: - remove_user(db, user, user_role) - add_user(db, user, admin_role) +def get_orm_class(kind): + if kind == 'users': + Class = orm.User + elif kind == 'services': + Class = orm.Service + elif kind == 'tokens': + Class = orm.APIToken else: - if admin_role in user.roles: - remove_user(db, user, admin_role) - # only add user role if the user has no other roles - if len(user.roles) < 1: - add_user(db, user, user_role) - db.commit() + raise ValueError("kind must be users, services or tokens, not %r" % kind) + + return Class + + +def existing_only(func): + + """Decorator for checking if objects and roles exist""" + + def check_existence(db, objname, kind, rolename): + + Class = get_orm_class(kind) + obj = Class.find(db, objname) + role = orm.Role.find(db, rolename) + + if obj is None: + raise ValueError("%r of kind %r does not exist" % (objname, kind)) + elif role is None: + raise ValueError("Role %r does not exist" % rolename) + else: + func(db, obj, kind, role) + + return check_existence + + +@existing_only +def add_obj(db, objname, kind, rolename): + + """Adds a role for users, services or tokens""" + + if rolename not in objname.roles: + objname.roles.append(rolename) + db.commit() + + +@existing_only +def remove_obj(db, objname, kind, rolename): + + """Removes a role for users, services or tokens""" + + if rolename in objname.roles: + objname.roles.remove(rolename) + db.commit() + + +def switch_default_role(db, obj, kind, admin): + + """Switch between default user and admin roles for users/services""" + + user_role = orm.Role.find(db, 'user') + admin_role = orm.Role.find(db, 'admin') + + def add_and_remove(db, obj, kind, current_role, new_role): + + if current_role in obj.roles: + remove_obj(db, objname=obj.name, kind=kind, rolename=current_role.name) + # only add new default role if the user has no other roles + if len(obj.roles) < 1: + add_obj(db, objname=obj.name, kind=kind, rolename=new_role.name) + + if admin: + add_and_remove(db, obj, kind, user_role, admin_role) + else: + add_and_remove(db, obj, kind, admin_role, user_role) + + +def update_roles(db, obj, kind, roles=None): + + """Updates object's roles if specified, + assigns default if no roles specified""" + + Class = get_orm_class(kind) + user_role = orm.Role.find(db, 'user') + + if roles: + for rolename in roles: + if Class == orm.APIToken: + # FIXME - check if specified roles do not add permissions + # on top of the token owner's scopes + role = orm.Role.find(db, rolename) + if role: + role.tokens.append(obj) + else: + raise ValueError('Role %r does not exist' % rolename) + else: + add_obj(db, objname=obj.name, kind=kind, rolename=rolename) + else: + # tokens can have only 'user' role as default + # assign the default only for user tokens + if Class == orm.APIToken: + if len(obj.roles) < 1 and obj.user is not None: + user_role.tokens.append(obj) + db.commit() + # users and services can have 'user' or 'admin' roles as default + else: + switch_default_role(db, obj, kind, obj.admin) diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 003e193c..154a9922 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -312,7 +312,7 @@ class MockHub(JupyterHub): test_clean_db = Bool(True) def init_db(self): - """Ensure we start with a clean user list""" + """Ensure we start with a clean user & role list""" super().init_db() if self.test_clean_db: for user in self.db.query(orm.User): @@ -336,10 +336,10 @@ class MockHub(JupyterHub): user = self.db.query(orm.User).filter(orm.User.name == 'user').first() if user is None: user = orm.User(name='user') - user_role = orm.Role.find(self.db, 'user') - roles.add_user(self.db, user=user, role=user_role) self.db.add(user) self.db.commit() + roles.update_roles(self.db, obj=user, kind='users') + self.db.commit() def stop(self): super().stop() diff --git a/jupyterhub/tests/populate_db.py b/jupyterhub/tests/populate_db.py index fec3d7e9..2b5c6007 100644 --- a/jupyterhub/tests/populate_db.py +++ b/jupyterhub/tests/populate_db.py @@ -10,8 +10,6 @@ from datetime import datetime import jupyterhub from jupyterhub import orm -# FIXME - for later versions of jupyterhub add code to test roles - def populate_db(url): """Populate a jupyterhub database""" diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 966dadcf..9d6a5dca 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -70,7 +70,7 @@ async def test_referer_check(app): # add admin user user = find_user(app.db, 'admin') if user is None: - user = add_user(app.db, name='admin', admin=True, roles=['admin']) + user = add_user(app.db, name='admin', admin=True) cookies = await app.login_user('admin') r = await api_request( @@ -1159,7 +1159,7 @@ async def test_token_as_user_deprecated(app, as_user, for_user, status): # ensure both users exist u = add_user(app.db, app, name=as_user) if for_user != 'missing': - add_user(app.db, app, name=for_user) + for_user_obj = add_user(app.db, app, name=for_user) data = {'username': for_user} headers = {'Authorization': 'token %s' % u.new_api_token()} r = await api_request( @@ -1252,7 +1252,7 @@ async def test_token_for_user(app, as_user, for_user, status): # ensure both users exist u = add_user(app.db, app, name=as_user) if for_user != 'missing': - add_user(app.db, app, name=for_user) + for_user_obj = add_user(app.db, app, name=for_user) data = {'username': for_user} headers = {'Authorization': 'token %s' % u.new_api_token()} r = await api_request( @@ -1269,6 +1269,7 @@ async def test_token_for_user(app, as_user, for_user, status): if status != 200: return assert 'token' in reply + token_id = reply['id'] r = await api_request(app, 'users', for_user, 'tokens', token_id, headers=headers) r.raise_for_status() diff --git a/jupyterhub/tests/test_named_servers.py b/jupyterhub/tests/test_named_servers.py index 20e515a2..884921c0 100644 --- a/jupyterhub/tests/test_named_servers.py +++ b/jupyterhub/tests/test_named_servers.py @@ -56,6 +56,7 @@ async def test_default_server(app, named_servers): assert user_model == fill_user( { 'name': username, + 'roles': ['user'], 'auth_state': None, 'server': user.url, 'servers': { @@ -86,7 +87,7 @@ async def test_default_server(app, named_servers): user_model = normalize_user(r.json()) assert user_model == fill_user( - {'name': username, 'servers': {}, 'auth_state': None} + {'name': username, 'roles': ['user'], 'servers': {}, 'auth_state': None} ) @@ -117,6 +118,7 @@ async def test_create_named_server(app, named_servers): assert user_model == fill_user( { 'name': username, + 'roles': ['user'], 'auth_state': None, 'servers': { servername: { @@ -159,7 +161,7 @@ async def test_delete_named_server(app, named_servers): user_model = normalize_user(r.json()) assert user_model == fill_user( - {'name': username, 'auth_state': None, 'servers': {}} + {'name': username, 'roles': ['user'], 'auth_state': None, 'servers': {}} ) # wrapper Spawner is gone assert servername not in user.spawners diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index 4b6c12ae..e9a7975c 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -560,4 +560,3 @@ def test_expiring_oauth_code(app, user): assert orm_code in db.query(orm.OAuthCode) orm.OAuthCode.purge_expired(db) assert orm_code not in db.query(orm.OAuthCode) - diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 1e4ebe1d..da398dc9 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1,48 +1,87 @@ """Test roles""" -# import pytest +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. +import json + from pytest import mark from .. import orm from .. import roles from ..utils import maybe_future from .mocking import MockHub +from .utils import add_user +from .utils import api_request @mark.role def test_orm_roles(db): """Test orm roles setup""" + user_role = orm.Role.find(db, name='user') + if not user_role: + user_role = orm.Role(name='user') + db.add(user_role) + db.commit() + + service_role = orm.Role(name='service') + db.add(service_role) + db.commit() + user = orm.User(name='falafel') db.add(user) + db.commit() + service = orm.Service(name='kebab') db.add(service) - role = orm.Role(name='default') - db.add(role) db.commit() - assert role.users == [] - assert role.services == [] + + assert user_role.users == [] + assert user_role.services == [] + assert service_role.users == [] + assert service_role.services == [] assert user.roles == [] assert service.roles == [] - role.users.append(user) - role.services.append(service) + user_role.users.append(user) + service_role.services.append(service) db.commit() - assert role.users == [user] - assert user.roles == [role] - assert role.services == [service] - assert service.roles == [role] + assert user_role.users == [user] + assert user.roles == [user_role] + assert service_role.services == [service] + assert service.roles == [service_role] + # check token creation without specifying its role + # assigns it the default 'user' role + token = user.new_api_token() + user_token = orm.APIToken.find(db, token=token) + assert user_token in user_role.tokens + assert user_role in user_token.roles + + # check creating token with a specific role + token = service.new_api_token(roles=['service']) + service_token = orm.APIToken.find(db, token=token) + assert service_token in service_role.tokens + assert service_role in service_token.roles + + # check deleting user removes the user and the token from roles db.delete(user) db.commit() - assert role.users == [] - db.delete(role) + assert user_role.users == [] + assert user_token not in user_role.tokens + # check deleting the service token removes it from 'service' role + db.delete(service_token) + db.commit() + assert service_token not in service_role.tokens + # check deleting the 'service' role removes it from service roles + db.delete(service_role) db.commit() assert service.roles == [] + db.delete(service) db.commit() @mark.role -def test_orm_role_delete_cascade(db): +def test_orm_roles_delete_cascade(db): """Orm roles cascade""" user1 = orm.User(name='user1') user2 = orm.User(name='user2') @@ -148,8 +187,6 @@ async def test_load_roles_users(tmpdir, request): hub.authenticator.admin_users = ['admin'] hub.authenticator.allowed_users = ['cyclops', 'gandalf', 'bilbo', 'gargamel'] await hub.init_users() - for user in db.query(orm.User): - print(user.name) await hub.init_roles() # test if the 'user' role has been overwritten and assigned @@ -178,6 +215,11 @@ async def test_load_roles_users(tmpdir, request): @mark.role async def test_load_roles_services(tmpdir, request): + services = [ + {'name': 'cull_idle', 'api_token': 'some-token'}, + {'name': 'user_service', 'api_token': 'some-other-token'}, + {'name': 'admin_service', 'api_token': 'secret-token', 'admin': True}, + ] roles_to_load = [ { 'name': 'culler', @@ -190,22 +232,20 @@ async def test_load_roles_services(tmpdir, request): ssl_enabled = getattr(request.module, "ssl_enabled", False) if ssl_enabled: kwargs['internal_certs_location'] = str(tmpdir) - hub = MockHub(test_clean_db=False, **kwargs) + hub = MockHub(**kwargs) hub.init_db() db = hub.db - # add test services to db - services = [ - {'name': 'cull_idle', 'admin': False}, - {'name': 'user_service', 'admin': False}, - {'name': 'admin_service', 'admin': True}, - ] - for service_specs in services: - service = orm.Service.find(db, service_specs['name']) - if service is None: - service = orm.Service( - name=service_specs['name'], admin=service_specs['admin'] - ) - db.add(service) + # clean db of previous services and add testing ones + for service in db.query(orm.Service): + db.delete(service) + db.commit() + for service in services: + orm_service = orm.Service.find(db, name=service['name']) + if orm_service is None: + # not found, create a new one + orm_service = orm.Service(name=service['name']) + db.add(orm_service) + orm_service.admin = service.get('admin', False) db.commit() await hub.init_roles() @@ -224,3 +264,104 @@ async def test_load_roles_services(tmpdir, request): cull_idle = orm.Service.find(db, name='cull_idle') assert culler_role in cull_idle.roles assert user_role not in cull_idle.roles + + # delete the test services + for service in db.query(orm.Service): + db.delete(service) + db.commit() + + +@mark.role +async def test_load_roles_tokens(tmpdir, request): + services = [ + {'name': 'cull_idle', 'admin': True, 'api_token': 'another-secret-token'} + ] + user_tokens = { + 'secret-token': 'cyclops', + 'super-secret-token': 'admin', + } + service_tokens = { + 'another-secret-token': 'cull_idle', + } + roles_to_load = [ + { + 'name': 'culler', + 'description': 'Cull idle servers', + 'scopes': ['users:servers', 'admin:servers'], + 'tokens': ['another-secret-token'], + }, + ] + kwargs = { + 'load_roles': roles_to_load, + 'services': services, + 'api_tokens': user_tokens, + 'service_tokens': service_tokens, + } + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + hub.authenticator.admin_users = ['admin'] + hub.authenticator.allowed_users = ['cyclops', 'gandalf'] + await hub.init_users() + await hub.init_api_tokens() + await hub.init_roles() + + # test if another-secret-token has culler role + service = orm.Service.find(db, 'cull_idle') + culler_role = orm.Role.find(db, 'culler') + token = orm.APIToken.find(db, 'another-secret-token') + assert len(token.roles) == 1 + assert culler_role in token.roles + + # test if all other tokens have default 'user' role + user_role = orm.Role.find(db, 'user') + sec_token = orm.APIToken.find(db, 'secret-token') + assert user_role in sec_token.roles + s_sec_token = orm.APIToken.find(db, 'super-secret-token') + assert user_role in s_sec_token.roles + + +@mark.role +@mark.parametrize( + "headers, role_list, status", + [ + ({}, None, 200), + ({}, ['reader'], 200), + ({}, ['non-existing'], 404), + # FIXME - add requesting token with 'not allowed' role + # granting more permission than the token owner has + ], +) +async def test_get_new_token_via_api(app, headers, role_list, status): + user = add_user(app.db, app, name='user') + roles.add_role(app.db, {'name': 'reader', 'scopes': ['read:all']}) + if role_list: + body = json.dumps({'roles': role_list}) + else: + body = '' + # request a new token + r = await api_request( + app, 'users/user/tokens', method='post', headers=headers, data=body + ) + assert r.status_code == status + if status != 200: + return + # check the new-token reply for roles + reply = r.json() + assert 'token' in reply + assert reply['user'] == 'user' + if not role_list: + assert reply['roles'] == ['user'] + else: + assert reply['roles'] == ['reader'] + token_id = reply['id'] + + # delete the token + r = await api_request(app, 'users/user/tokens', token_id, method='delete') + assert r.status_code == 204 + # verify deletion + r = await api_request(app, 'users/user/tokens', token_id) + assert r.status_code == 404 diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 09aeb196..4c542871 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -6,6 +6,7 @@ from certipy import Certipy from jupyterhub import orm from jupyterhub.objects import Server +from jupyterhub.roles import update_roles from jupyterhub.utils import url_path_join as ujoin @@ -101,6 +102,8 @@ def add_user(db, app=None, **kwargs): for attr, value in kwargs.items(): setattr(orm_user, attr, value) db.commit() + requested_roles = kwargs.get('roles') + update_roles(db, obj=orm_user, kind='users', roles=requested_roles) if app: return app.users[orm_user.id] else: From 18ed1b58cc6c47df7f21dddafc49d99edd839fc8 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 19 Nov 2020 09:17:03 +0100 Subject: [PATCH 026/270] added roles to token model and POST /users/{name}/tokens request body --- docs/rest-api.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index beb5e181..0c07e640 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -451,6 +451,9 @@ paths: note: type: string description: A note attached to the token for future bookkeeping + roles: + type: list + description: A list of role names that the token should have responses: '201': description: The newly created token @@ -458,6 +461,8 @@ paths: $ref: '#/definitions/Token' '400': description: Body must be a JSON dict or empty + '403': + description: Requested role does not exist /users/{name}/tokens/{token_id}: parameters: - name: name @@ -972,6 +977,11 @@ definitions: admin: type: boolean description: Whether the service is an admin + roles: + type: array + description: The names of roles this service has + items: + type: string url: type: string description: The internal url where the service is running @@ -1006,6 +1016,11 @@ definitions: service: type: string description: The service that owns the token (undefined of owned by a user) + roles: + type: array + description: The names of roles this token has + items: + type: string note: type: string description: A note about the token, typically describing what it was created for. From 71d99e11800caf9e830af738c461c460b8131c40 Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Thu, 19 Nov 2020 09:57:50 +0100 Subject: [PATCH 027/270] Update with expand group test --- jupyterhub/tests/test_api.py | 1 - jupyterhub/tests/test_scopes.py | 23 +++++++++++++++++++++-- jupyterhub/utils.py | 18 ++++++++++-------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 86b4db89..fa37037a 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -27,7 +27,6 @@ from .utils import api_request from .utils import async_requests from .utils import auth_header from .utils import find_user -from .utils import get_scopes # -------------------- diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 494ec8f9..4e2ed343 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -3,10 +3,13 @@ import pytest from pytest import mark from tornado import web +from .. import orm from ..utils import check_scope from ..utils import needs_scope from ..utils import parse_scopes from ..utils import Scope +from .utils import api_request +from .utils import auth_header def test_scope_constructor(): @@ -74,7 +77,7 @@ def test_scope_parse_server_name(): ) -class MockAPI: +class MockAPIHandler: def __init__(self): self.scopes = ['users'] @@ -152,7 +155,7 @@ class MockAPI: ], ) def test_scope_method_access(scopes, method, arguments, is_allowed): - obj = MockAPI() + obj = MockAPIHandler() obj.scopes = scopes api_call = getattr(obj, method) if is_allowed: @@ -160,3 +163,19 @@ def test_scope_method_access(scopes, method, arguments, is_allowed): else: with pytest.raises(web.HTTPError): api_call(*arguments) + + +async def test_expand_groups(app): + db = app.db + user = orm.User(name='gob') + group = orm.Group(name='bluth') + db.add(group) + db.add(user) + group.users.append(user) + db.commit() + scopes = ['read:users!user=micheal', 'read:users!group=bluth', 'read:groups'] + app.tornado_settings['mock_scopes'] = scopes + r = await api_request(app, 'users', 'micheal', headers=auth_header(db, 'micheal')) + assert r.status_code == 200 + r = await api_request(app, 'users', 'gob', headers=auth_header(db, 'user')) + assert r.status_code == 200 diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 1b2ce995..0d54dc31 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -307,7 +307,6 @@ def needs_scope_expansion(filter_, filter_value, sub_scope): """ Check if there is a requirements to expand the `group` scope to individual `user` scopes. Assumptions: - req_scopes in scopes filter_ != Scope.ALL This can be made arbitrarily intelligent but that would make it more complex @@ -334,7 +333,7 @@ def check_user_in_expanded_scope(handler, user_name, scope_group_names): if user is None: raise web.HTTPError(404, 'No such user found') group_names = {group.name for group in user.groups} - return bool(scope_group_names & group_names) + return bool(set(scope_group_names) & group_names) def check_scope(api_handler, req_scope, scopes, **kwargs): @@ -354,12 +353,15 @@ def check_scope(api_handler, req_scope, scopes, **kwargs): filter_, filter_value = list(kwargs.items())[0] sub_scope = scopes[req_scope] if filter_ not in sub_scope: - if needs_scope_expansion(filter_, filter_value, sub_scope): - group_names = sub_scope['groups'] - return check_user_in_expanded_scope(api_handler, filter_value, group_names) - else: - return False - return filter_value in sub_scope[filter_] + valid_scope = False + else: + valid_scope = filter_value in sub_scope[filter_] + if not valid_scope and needs_scope_expansion(filter_, filter_value, sub_scope): + group_names = sub_scope['group'] + valid_scope |= check_user_in_expanded_scope( + api_handler, filter_value, group_names + ) + return valid_scope def parse_scopes(scope_list): From d5e7a42135d9acf0cbd3e181a1024e2dfbfc3968 Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Thu, 19 Nov 2020 17:06:31 +0100 Subject: [PATCH 028/270] More scope unit tests --- jupyterhub/tests/test_scopes.py | 40 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 4e2ed343..52bd0d64 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -165,17 +165,31 @@ def test_scope_method_access(scopes, method, arguments, is_allowed): api_call(*arguments) -async def test_expand_groups(app): - db = app.db - user = orm.User(name='gob') +@mark.parametrize( + "name, status_code", + [ + ('martha', 200), + ('michael', 200), + ('gob', 200), + ('tobias', 403), + ('ann', 404), # this leaks a bit of information, what do we think about that? + ], +) +async def test_expand_groups(app, name, status_code): + app.init_db() group = orm.Group(name='bluth') - db.add(group) - db.add(user) - group.users.append(user) - db.commit() - scopes = ['read:users!user=micheal', 'read:users!group=bluth', 'read:groups'] - app.tornado_settings['mock_scopes'] = scopes - r = await api_request(app, 'users', 'micheal', headers=auth_header(db, 'micheal')) - assert r.status_code == 200 - r = await api_request(app, 'users', 'gob', headers=auth_header(db, 'user')) - assert r.status_code == 200 + app.db.add(group) + for user_name in ['gob', 'michael']: + user = orm.User(name=user_name) + app.db.add(user) + group.users.append(user) + app.db.add(orm.User(name='tobias')) + app.db.add(orm.User(name='martha')) + app.db.commit() + app.tornado_settings['mock_scopes'] = [ + 'read:users!user=martha', + 'read:users!group=bluth', + 'read:groups', + ] + r = await api_request(app, 'users', name) + assert r.status_code == status_code From d7d27ad97a8d93e1b8858840c672caf71027daee Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Mon, 23 Nov 2020 13:26:36 +0100 Subject: [PATCH 029/270] Fixed scopes and added more specific logs/errors --- jupyterhub/apihandlers/services.py | 2 +- jupyterhub/apihandlers/users.py | 5 +++-- jupyterhub/tests/test_scopes.py | 32 +++++++++++++++--------------- jupyterhub/utils.py | 21 ++++++++++---------- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 914483c9..068fd645 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -29,7 +29,7 @@ def service_model(service): class ServiceListAPIHandler(APIHandler): - @needs_scope('read:services') # Todo: allow filter here? + @needs_scope('read:services') def get(self): data = {name: service_model(service) for name, service in self.services.items()} self.write(json.dumps(data)) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 2d59e092..e82fa5ae 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -28,7 +28,6 @@ class SelfAPIHandler(APIHandler): Based on the authentication info. Acts as a 'whoami' for auth tokens. """ - # @needs_scope('read:users') # Should be read:users:user=username async def get(self): user = self.current_user if user is None: @@ -36,6 +35,8 @@ class SelfAPIHandler(APIHandler): user = self.get_current_user_oauth_token() if user is None: raise web.HTTPError(403) + # Later: filter based on scopes. + # Perhaps user self.write(json.dumps(self.user_model(user))) @@ -48,7 +49,7 @@ class UserListAPIHandler(APIHandler): ] self.write(json.dumps(data)) - @needs_scope('users') + @needs_scope('admin:users') async def post(self): data = self.get_json_body() if not data or not isinstance(data, dict) or not data.get('usernames'): diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 52bd0d64..858d2e63 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -8,6 +8,7 @@ from ..utils import check_scope from ..utils import needs_scope from ..utils import parse_scopes from ..utils import Scope +from .utils import add_user from .utils import api_request from .utils import auth_header @@ -166,30 +167,29 @@ def test_scope_method_access(scopes, method, arguments, is_allowed): @mark.parametrize( - "name, status_code", + "user_name, in_group, status_code", [ - ('martha', 200), - ('michael', 200), - ('gob', 200), - ('tobias', 403), - ('ann', 404), # this leaks a bit of information, what do we think about that? + ('martha', False, 200), + ('michael', True, 200), + ('gob', True, 200), + ('tobias', False, 403), + ('ann', False, 403), ], ) -async def test_expand_groups(app, name, status_code): - app.init_db() - group = orm.Group(name='bluth') - app.db.add(group) - for user_name in ['gob', 'michael']: - user = orm.User(name=user_name) - app.db.add(user) +async def test_expand_groups(app, user_name, in_group, status_code): + user = add_user(app.db, name=user_name) + group_name = 'bluth' + group = orm.Group.find(app.db, name=group_name) + if not group: + group = orm.Group(name=group_name) + app.db.add(group) + if in_group and user not in group.users: group.users.append(user) - app.db.add(orm.User(name='tobias')) - app.db.add(orm.User(name='martha')) app.db.commit() app.tornado_settings['mock_scopes'] = [ 'read:users!user=martha', 'read:users!group=bluth', 'read:groups', ] - r = await api_request(app, 'users', name) + r = await api_request(app, 'users', user_name) assert r.status_code == status_code diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 0d54dc31..e4ec0944 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -319,15 +319,6 @@ def needs_scope_expansion(filter_, filter_value, sub_scope): return True -# def expand_groups_to_users(db, filter_scope): -# """Update the group filters to account for the individual users""" -# if 'group' in filter_scope: -# groups = db.query(orm.Group) -# user_set = orm.User.query.filter(orm.User.group.in_(groups)) -# return [user.name for user in user_set] -# - - def check_user_in_expanded_scope(handler, user_name, scope_group_names): user = handler.find_user(user_name) if user is None: @@ -419,7 +410,17 @@ def needs_scope(scope): if check_scope(self, scope, parsed_scopes, **s_kwargs): return func(self, *args, **kwargs) else: - raise web.HTTPError(403, "Action is not authorized with current scopes") + self.log.warning( + "Not authorizing access to {}. Requires scope {}, not derived from scopes {}".format( + self.request.path, scope, ", ".join(self.scopes) + ) + ) + raise web.HTTPError( + 403, + "Action is not authorized with current scopes; requires {}".format( + scope + ), + ) return _auth_func From f6d635997c0077cd6c897a15698313dd0405755f Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Tue, 24 Nov 2020 10:03:16 +0100 Subject: [PATCH 030/270] Changed logging call --- jupyterhub/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index e4ec0944..bb66eacf 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -410,7 +410,7 @@ def needs_scope(scope): if check_scope(self, scope, parsed_scopes, **s_kwargs): return func(self, *args, **kwargs) else: - self.log.warning( + app_log.warning( "Not authorizing access to {}. Requires scope {}, not derived from scopes {}".format( self.request.path, scope, ", ".join(self.scopes) ) From 73020a70f2a22c3549426aee6c0fb2ced1554db7 Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Mon, 30 Nov 2020 23:16:00 +0100 Subject: [PATCH 031/270] Mocked request.path --- jupyterhub/tests/test_scopes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 858d2e63..66fe7e84 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -1,7 +1,11 @@ """Test scopes for API handlers""" +from unittest import mock + import pytest +import tornado from pytest import mark from tornado import web +from tornado.httputil import HTTPServerRequest from .. import orm from ..utils import check_scope @@ -10,7 +14,6 @@ from ..utils import parse_scopes from ..utils import Scope from .utils import add_user from .utils import api_request -from .utils import auth_header def test_scope_constructor(): @@ -157,6 +160,7 @@ class MockAPIHandler: ) def test_scope_method_access(scopes, method, arguments, is_allowed): obj = MockAPIHandler() + obj.request = mock.Mock(spec=HTTPServerRequest) obj.scopes = scopes api_call = getattr(obj, method) if is_allowed: From de04ae147195e2c9ebcb9d8c82aa117c213edfbe Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 1 Dec 2020 08:44:29 +0100 Subject: [PATCH 032/270] verifying api requested token roles permissions against the token owner permissions --- jupyterhub/apihandlers/users.py | 8 ++- jupyterhub/roles.py | 105 ++++++++++++++++++++++++++++++-- jupyterhub/tests/test_roles.py | 8 +-- 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 2a072190..226be587 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -302,8 +302,14 @@ class UserTokenListAPIHandler(APIHandler): api_token = user.new_api_token( note=note, expires_in=body.get('expires_in', None), roles=token_roles ) - except ValueError: + except NameError: raise web.HTTPError(404, "Requested roles %r not found" % token_roles) + except ValueError: + raise web.HTTPError( + 403, + "Requested token roles %r have higher permissions than the token owner" + % token_roles, + ) if requester is not user: self.log.info( "%s %s requested API token for %s", diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 7f78067e..96fe5284 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -1,6 +1,8 @@ """Roles utils""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +from itertools import chain + from . import orm @@ -39,6 +41,86 @@ def get_default_roles(): return default_roles +def get_scopes(): + + """ + Returns a dictionary of scopes: + scopes.keys() = scopes of highest level and scopes that have their own subscopes + scopes.values() = a list of first level subscopes or None + """ + + scopes = { + 'all': ['read:all'], + 'users': ['read:users', 'users:activity!user=username', 'users:servers'], + 'read:users': [ + 'read:users!user=username', + 'read:users:name', + 'read:users:groups', + 'read:users:activity', + 'read:users:servers', + ], + 'read:users:activity': ['read:users:activity!group=groupname'], + 'users:servers': ['users:servers!server=servername'], + 'users:tokens': ['read:users:tokens'], + 'admin:users': None, + 'admin:users:servers': None, + 'groups': ['groups!group=groupname', 'read:groups'], + 'admin:groups': None, + 'read:services': None, + 'proxy': None, + 'shutdown': None, + } + + return scopes + + +def expand_scope(scopename): + + """Returns a set of all subscopes""" + + scopes = get_scopes() + subscopes = [scopename] + + def expand_subscopes(index): + + more_subscopes = list( + filter(lambda scope: scope in scopes.keys(), subscopes[index:]) + ) + for scope in more_subscopes: + subscopes.extend(scopes[scope]) + + if scopename in scopes.keys() and scopes[scopename] is not None: + subscopes.extend(scopes[scopename]) + # record the index from where it should check for "subscopes of sub-subscopes" + index_for_sssc = len(subscopes) + # check for "subscopes of subscopes" + expand_subscopes(index=1) + # check for "subscopes of sub-subscopes" + expand_subscopes(index=index_for_sssc) + + expanded_scope = set(subscopes) + + return expanded_scope + + +def get_subscopes(role=None, roles=None): + + """Returns a set of all available subscopes for a specified role or list of roles""" + + scope_list = [] + if role: + scope_list = role.scopes + elif roles: + for role in roles: + scope_list.extend(role.scopes) + else: + raise ValueError('Function get_subscopes is missing an argument') + + scopes = list(chain.from_iterable(list(map(expand_scope, scope_list)))) + + return set(scopes) + + def add_role(db, role_dict): """Adds a new role to database or modifies an existing one""" @@ -148,13 +230,28 @@ def update_roles(db, obj, kind, roles=None): if roles: for rolename in roles: if Class == orm.APIToken: - # FIXME - check if specified roles do not add permissions - # on top of the token owner's scopes + role = orm.Role.find(db, rolename) if role: - role.tokens.append(obj) + # compare the requested role permissions with the owner's permissions (scopes) + token_scopes = get_subscopes(role=role) + # find the owner and their roles + owner = None + if obj.user_id: + owner = db.query(orm.User).get(obj.user_id) + elif obj.service_id: + owner = db.query(orm.Service).get(obj.service_id) + if owner: + owner_scopes = get_subscopes(roles=owner.roles) + if token_scopes.issubset(owner_scopes): + role.tokens.append(obj) + else: + raise ValueError( + 'Requested token role %r has higher permissions than the token owner' + % rolename + ) else: - raise ValueError('Role %r does not exist' % rolename) + raise NameError('Role %r does not exist' % rolename) else: add_obj(db, objname=obj.name, kind=kind, rolename=rolename) else: diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index da398dc9..340647eb 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -18,11 +18,11 @@ def test_orm_roles(db): """Test orm roles setup""" user_role = orm.Role.find(db, name='user') if not user_role: - user_role = orm.Role(name='user') + user_role = orm.Role(name='user', scopes=['all', 'read:all']) db.add(user_role) db.commit() - service_role = orm.Role(name='service') + service_role = orm.Role(name='service', scopes=['users:servers']) db.add(service_role) db.commit() @@ -331,13 +331,13 @@ async def test_load_roles_tokens(tmpdir, request): ({}, None, 200), ({}, ['reader'], 200), ({}, ['non-existing'], 404), - # FIXME - add requesting token with 'not allowed' role - # granting more permission than the token owner has + ({}, ['user_creator'], 403), ], ) async def test_get_new_token_via_api(app, headers, role_list, status): user = add_user(app.db, app, name='user') roles.add_role(app.db, {'name': 'reader', 'scopes': ['read:all']}) + roles.add_role(app.db, {'name': 'user_creator', 'scopes': ['admin:users']}) if role_list: body = json.dumps({'roles': role_list}) else: From ab297a7747e271affd8267d57352e5ce904c8587 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 3 Dec 2020 14:53:53 +0100 Subject: [PATCH 033/270] added scope expansion unit testing --- jupyterhub/roles.py | 7 ++---- jupyterhub/tests/test_roles.py | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 96fe5284..aabbf7bd 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -51,20 +51,17 @@ def get_scopes(): scopes = { 'all': ['read:all'], - 'users': ['read:users', 'users:activity!user=username', 'users:servers'], + 'users': ['read:users', 'users:activity', 'users:servers'], 'read:users': [ - 'read:users!user=username', 'read:users:name', 'read:users:groups', 'read:users:activity', 'read:users:servers', ], - 'read:users:activity': ['read:users:activity!group=groupname'], - 'users:servers': ['users:servers!server=servername'], 'users:tokens': ['read:users:tokens'], 'admin:users': None, 'admin:users:servers': None, - 'groups': ['groups!group=groupname', 'read:groups'], + 'groups': ['read:groups'], 'admin:groups': None, 'read:services': None, 'proxy': None, diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 340647eb..bdc8b98a 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -144,6 +144,45 @@ def test_orm_roles_delete_cascade(db): @mark.role +@mark.parametrize( + "scopes, subscopes", + [ + ( + ['users'], + { + 'users', + 'read:users', + 'users:activity', + 'users:servers', + 'read:users:name', + 'read:users:groups', + 'read:users:activity', + 'read:users:servers', + }, + ), + ( + ['read:users'], + { + 'read:users', + 'read:users:name', + 'read:users:groups', + 'read:users:activity', + 'read:users:servers', + }, + ), + (['read:users:servers'], {'read:users:servers'}), + (['admin:groups'], {'admin:groups'}), + ], +) +def test_get_subscopes(db, scopes, subscopes): + """Test role scopes expansion into their subscopes""" + roles.add_role(db, {'name': 'testing_scopes', 'scopes': scopes}) + role = orm.Role.find(db, name='testing_scopes') + response = roles.get_subscopes(role) + assert response == subscopes + db.delete(role) + + async def test_load_default_roles(tmpdir, request): """Test loading default roles in app.py""" kwargs = {} From c514259f1aead2a939bba836648b9d655433d19c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 8 Dec 2020 08:28:23 +0100 Subject: [PATCH 034/270] addressed review comments from Omar --- jupyterhub/roles.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index aabbf7bd..74eb5a11 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -28,6 +28,7 @@ def get_default_roles(): 'groups', 'admin:groups', 'read:services', + 'read:hub', 'proxy', 'shutdown', ], @@ -64,6 +65,7 @@ def get_scopes(): 'groups': ['read:groups'], 'admin:groups': None, 'read:services': None, + 'read:hub': None, 'proxy': None, 'shutdown': None, } @@ -100,22 +102,18 @@ def expand_scope(scopename): return expanded_scope -def get_subscopes(role=None, roles=None): +def get_subscopes(*args): """Returns a set of all available subscopes for a specified role or list of roles""" scope_list = [] - if role: - scope_list = role.scopes - elif roles: - for role in roles: - scope_list.extend(role.scopes) - else: - raise ValueError('Function get_subscopes is missing an argument') - scopes = list(chain.from_iterable(list(map(expand_scope, scope_list)))) + for role in args: + scope_list.extend(role.scopes) - return set(scopes) + scopes = set(chain.from_iterable(list(map(expand_scope, scope_list)))) + + return scopes def add_role(db, role_dict): @@ -132,7 +130,7 @@ def add_role(db, role_dict): scopes = role_dict.get('scopes') if role is None: - role = orm.Role(name=name, description=description, scopes=scopes,) + role = orm.Role(name=name, description=description, scopes=scopes) db.add(role) else: if description: @@ -231,7 +229,7 @@ def update_roles(db, obj, kind, roles=None): role = orm.Role.find(db, rolename) if role: # compare the requested role permissions with the owner's permissions (scopes) - token_scopes = get_subscopes(role=role) + token_scopes = get_subscopes(role) # find the owner and their roles owner = None if obj.user_id: @@ -239,7 +237,7 @@ def update_roles(db, obj, kind, roles=None): elif obj.service_id: owner = db.query(orm.Service).get(obj.service_id) if owner: - owner_scopes = get_subscopes(roles=owner.roles) + owner_scopes = get_subscopes(*owner.roles) if token_scopes.issubset(owner_scopes): role.tokens.append(obj) else: From 4ab2e3aa0ad88d97135826a8be610656ccce80a6 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 7 Dec 2020 15:41:34 +0100 Subject: [PATCH 035/270] Fixed merge request after cherrypick --- jupyterhub/apihandlers/hub.py | 7 ++----- jupyterhub/tests/test_api.py | 6 ++++-- jupyterhub/tests/test_scopes.py | 4 ++-- jupyterhub/tests/utils.py | 1 + 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jupyterhub/apihandlers/hub.py b/jupyterhub/apihandlers/hub.py index f2bfd17e..c9df504f 100644 --- a/jupyterhub/apihandlers/hub.py +++ b/jupyterhub/apihandlers/hub.py @@ -57,8 +57,6 @@ class RootAPIHandler(APIHandler): def get(self): """GET /api/ returns info about the Hub and its API. - It is not an authenticated endpoint. - For now, it just returns the version of JupyterHub itself. """ data = {'version': __version__} @@ -66,12 +64,11 @@ class RootAPIHandler(APIHandler): class InfoAPIHandler(APIHandler): + @needs_scope('read:hub') def get(self): """GET /api/info returns detailed info about the Hub and its API. - It is not an authenticated endpoint. - - For now, it just returns the version of JupyterHub itself. + Currently, it returns information on the python version, spawner and authenticator """ def _class_info(typ): diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index c740820e..53fbb011 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1618,14 +1618,16 @@ async def test_root_api(app): if app.internal_ssl: kwargs['cert'] = (app.internal_ssl_cert, app.internal_ssl_key) kwargs["verify"] = app.internal_ssl_ca - r = await async_requests.get(url, **kwargs) + with mock_role(app): + r = await api_request(app, bypass_proxy=True) r.raise_for_status() expected = {'version': jupyterhub.__version__} assert r.json() == expected async def test_info(app): - r = await api_request(app, 'info') + with mock_role(app): + r = await api_request(app, 'info') r.raise_for_status() data = r.json() assert data['version'] == jupyterhub.__version__ diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 66fe7e84..db588c96 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -97,7 +97,7 @@ class MockAPIHandler: def group_thing(self, group_name): return True - @needs_scope('services') + @needs_scope('read:services') def service_thing(self, service_name): return True @@ -133,7 +133,7 @@ class MockAPIHandler: ('maybe', 'bluth2'), False, ), - (['services'], 'service_thing', ('service1',), True), + (['read:services'], 'service_thing', ('service1',), True), ( ['users!user=george', 'read:groups!group=bluths'], 'group_thing', diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 8876705a..c09a7247 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -223,6 +223,7 @@ def get_scopes(role='admin'): 'services', 'proxy', 'shutdown', + 'read:hub', ], 'user': [ 'all', From 9de90706415200bf3a3861e69d07d271d1d72746 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 9 Dec 2020 14:50:50 +0100 Subject: [PATCH 036/270] fixed scope test attr error for older_requirements.txt test --- jupyterhub/roles.py | 2 +- jupyterhub/utils.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 74eb5a11..544aa08f 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -217,7 +217,7 @@ def switch_default_role(db, obj, kind, admin): def update_roles(db, obj, kind, roles=None): """Updates object's roles if specified, - assigns default if no roles specified""" + assigns default if no roles specified""" Class = get_orm_class(kind) user_role = orm.Role.find(db, 'user') diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 26bae333..0de66778 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -406,9 +406,15 @@ def needs_scope(scope): if check_scope(self, scope, parsed_scopes, **s_kwargs): return func(self, *args, **kwargs) else: + # catching attr error occurring for older_requirements test + # could be done more ellegantly? + try: + request_path = self.request.path + except AttributeError: + request_path = 'the requested API' app_log.warning( "Not authorizing access to {}. Requires scope {}, not derived from scopes {}".format( - self.request.path, scope, ", ".join(self.scopes) + request_path, scope, ", ".join(self.scopes) ) ) raise web.HTTPError( From 16657e0c885a92cd64726c766605df37defc7199 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 9 Dec 2020 17:34:33 +0100 Subject: [PATCH 037/270] Integrated scopes with roles --- jupyterhub/handlers/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index ba6c92b8..85c217c1 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -430,7 +430,7 @@ class BaseHandler(RequestHandler): self._jupyterhub_user = None self.log.exception("Error getting current user") if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): - self.scopes = self.settings.get("mock_scopes", []) + self.scopes = roles.get_subscopes(*self._jupyterhub_user.roles) return self._jupyterhub_user @property From 62c56ec2c8eeeb7bcfdf5c56afd160d7338cac28 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 9 Dec 2020 17:34:49 +0100 Subject: [PATCH 038/270] Started work on fixing tests --- jupyterhub/apihandlers/groups.py | 2 +- jupyterhub/tests/test_scopes.py | 25 +++++++++++++++++++------ jupyterhub/utils.py | 2 -- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 14c9d325..83c7b7b9 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -35,7 +35,7 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @needs_scope('read:groups') # Todo: Filter allowed here? + @needs_scope('read:groups') # Todo: Apply filter on results def get(self): """List groups""" groups = self.db.query(orm.Group) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index db588c96..99442f8f 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -8,12 +8,14 @@ from tornado import web from tornado.httputil import HTTPServerRequest from .. import orm +from .. import roles from ..utils import check_scope from ..utils import needs_scope from ..utils import parse_scopes from ..utils import Scope from .utils import add_user from .utils import api_request +from .utils import auth_header def test_scope_constructor(): @@ -181,6 +183,17 @@ def test_scope_method_access(scopes, method, arguments, is_allowed): ], ) async def test_expand_groups(app, user_name, in_group, status_code): + test_role = { + 'name': 'test', + 'description': '', + 'users': [user_name], + 'scopes': [ + 'read:users!user=martha', + 'read:users!group=bluth', + 'read:groups', + ], + } + roles.add_role(app.db, test_role) user = add_user(app.db, name=user_name) group_name = 'bluth' group = orm.Group.find(app.db, name=group_name) @@ -189,11 +202,11 @@ async def test_expand_groups(app, user_name, in_group, status_code): app.db.add(group) if in_group and user not in group.users: group.users.append(user) + kind = 'users' + roles.update_roles(app.db, user, kind, roles=['test']) + roles.remove_obj(app.db, user_name, kind, 'user') app.db.commit() - app.tornado_settings['mock_scopes'] = [ - 'read:users!user=martha', - 'read:users!group=bluth', - 'read:groups', - ] - r = await api_request(app, 'users', user_name) + r = await api_request( + app, 'users', user_name, headers=auth_header(app.db, user_name) + ) assert r.status_code == status_code diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 0de66778..885707c5 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -304,8 +304,6 @@ def needs_scope_expansion(filter_, filter_value, sub_scope): Check if there is a requirements to expand the `group` scope to individual `user` scopes. Assumptions: filter_ != Scope.ALL - - This can be made arbitrarily intelligent but that would make it more complex """ if not (filter_ == 'user' and 'group' in sub_scope): return False From 3eccf7abdd7e3f7d40629d6a96b354b872672087 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 14 Dec 2020 17:39:06 +0100 Subject: [PATCH 039/270] Changed scopes from list to set and made filters additive --- jupyterhub/handlers/base.py | 2 +- jupyterhub/roles.py | 10 ------ jupyterhub/tests/test_api.py | 20 +++++------ jupyterhub/tests/test_scopes.py | 18 ++++++---- jupyterhub/utils.py | 59 +++++++++++++++++++++++---------- 5 files changed, 63 insertions(+), 46 deletions(-) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 85c217c1..d8a5781a 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -80,7 +80,7 @@ class BaseHandler(RequestHandler): The current user (None if not logged in) may be accessed via the `self.current_user` property during the handling of any request. """ - self.scopes = [] + self.scopes = set() try: await self.get_current_user() except Exception: diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 544aa08f..be50689b 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -7,7 +7,6 @@ from . import orm def get_default_roles(): - """Returns a list of default role dictionaries""" default_roles = [ @@ -43,7 +42,6 @@ def get_default_roles(): def get_scopes(): - """ Returns a dictionary of scopes: scopes.keys() = scopes of highest level and scopes that have their own subscopes @@ -74,7 +72,6 @@ def get_scopes(): def expand_scope(scopename): - """Returns a set of all subscopes""" scopes = get_scopes() @@ -103,7 +100,6 @@ def expand_scope(scopename): def get_subscopes(*args): - """Returns a set of all available subscopes for a specified role or list of roles""" scope_list = [] @@ -117,7 +113,6 @@ def get_subscopes(*args): def add_role(db, role_dict): - """Adds a new role to database or modifies an existing one""" if 'name' not in role_dict.keys(): @@ -154,7 +149,6 @@ def get_orm_class(kind): def existing_only(func): - """Decorator for checking if objects and roles exist""" def check_existence(db, objname, kind, rolename): @@ -175,7 +169,6 @@ def existing_only(func): @existing_only def add_obj(db, objname, kind, rolename): - """Adds a role for users, services or tokens""" if rolename not in objname.roles: @@ -185,7 +178,6 @@ def add_obj(db, objname, kind, rolename): @existing_only def remove_obj(db, objname, kind, rolename): - """Removes a role for users, services or tokens""" if rolename in objname.roles: @@ -194,7 +186,6 @@ def remove_obj(db, objname, kind, rolename): def switch_default_role(db, obj, kind, admin): - """Switch between default user and admin roles for users/services""" user_role = orm.Role.find(db, 'user') @@ -215,7 +206,6 @@ def switch_default_role(db, obj, kind, admin): def update_roles(db, obj, kind, roles=None): - """Updates object's roles if specified, assigns default if no roles specified""" diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 47992e90..89e24a34 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1628,17 +1628,15 @@ async def test_get_service(app, mockservice_url): 'info': {}, 'display': True, } - with mock_role(app, 'service'): - r = await api_request( - app, - 'services/%s' % mockservice.name, - headers={'Authorization': 'token %s' % mockservice.api_token}, - ) - r.raise_for_status() - with mock_role(app, 'user'): - r = await api_request( - app, 'services/%s' % mockservice.name, headers=auth_header(db, 'user') - ) + r = await api_request( + app, + 'services/%s' % mockservice.name, + headers={'Authorization': 'token %s' % mockservice.api_token}, + ) + r.raise_for_status() + r = await api_request( + app, 'services/%s' % mockservice.name, headers=auth_header(db, 'user') + ) assert r.status_code == 403 diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 99442f8f..9b66d9fa 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -66,12 +66,15 @@ def test_scope_filters(): assert check_scope(handler, 'read:users', parsed_scopes, user='maeby') -def test_scope_one_filter_only(): +def test_scope_multiple_filters(): handler = None - with pytest.raises(AttributeError): - check_scope( - handler, 'all', parse_scopes(['all']), user='george_michael', group='bluths' - ) + assert check_scope( + handler, + 'read:users', + parse_scopes(['read:users!user=george_michael']), + user='george_michael', + group='bluths', + ) def test_scope_parse_server_name(): @@ -85,7 +88,7 @@ def test_scope_parse_server_name(): class MockAPIHandler: def __init__(self): - self.scopes = ['users'] + self.scopes = {'users'} @needs_scope('users') def user_thing(self, user_name): @@ -162,8 +165,9 @@ 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.scopes = scopes + obj.scopes = set(scopes) api_call = getattr(obj, method) if is_allowed: assert api_call(*arguments) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 885707c5..4a6282d4 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -295,10 +295,37 @@ def metrics_authentication(self): raise web.HTTPError(403) +# Todo: Move all scope-related methods to scope module class Scope(Enum): ALL = True +def get_user_scopes(name): + """ + Scopes have a metascope 'all' that should be expanded to everything a user can do. + At the moment that is a user-filtered version (optional read) access to + users + users:name + users:groups + users:activity + users:servers + users:tokens + + """ + scope_list = [ + 'users', + 'users:name', + 'users:groups', + 'users:activity', + 'users:servers', + 'users:tokens', + ] + scope_list.extend( + ['read:' + scope for scope in scope_list] + ) # Todo: Put this in closure + return {"{}!user={}".format(scope, name) for scope in scope_list} + + def needs_scope_expansion(filter_, filter_value, sub_scope): """ Check if there is a requirements to expand the `group` scope to individual `user` scopes. @@ -324,29 +351,24 @@ def check_user_in_expanded_scope(handler, user_name, scope_group_names): def check_scope(api_handler, req_scope, scopes, **kwargs): # Parse user name and server name together if 'user' in kwargs and 'server' in kwargs: - user_name = kwargs.pop('user') - kwargs['server'] = "{}/{}".format(user_name, kwargs['server']) - if len(kwargs) > 1: - raise AttributeError("Please specify exactly one filter") + kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) if req_scope not in scopes: return False if scopes[req_scope] == Scope.ALL: return True # Apply filters - if not kwargs: - return False - filter_, filter_value = list(kwargs.items())[0] sub_scope = scopes[req_scope] - if filter_ not in sub_scope: - valid_scope = False - else: - valid_scope = filter_value in sub_scope[filter_] - if not valid_scope and needs_scope_expansion(filter_, filter_value, sub_scope): - group_names = sub_scope['group'] - valid_scope |= check_user_in_expanded_scope( - api_handler, filter_value, group_names - ) - return valid_scope + for ( + filter_, + filter_value, + ) in kwargs.items(): # Interface change: Now can have multiple filters + if filter_ in sub_scope and filter_value in sub_scope[filter_]: + return True + if needs_scope_expansion(filter_, filter_value, sub_scope): + group_names = sub_scope['group'] + if check_user_in_expanded_scope(api_handler, filter_value, group_names): + return True + return False def parse_scopes(scope_list): @@ -400,6 +422,9 @@ def needs_scope(scope): if resource_name in bound_sig.arguments: resource_value = bound_sig.arguments[resource_name] s_kwargs[resource] = resource_value + if 'all' in self.scopes and self.current_user: + # todo: What if no user is found? See test_api/test_referer_check + self.scopes |= get_user_scopes(self.current_user.name) parsed_scopes = parse_scopes(self.scopes) if check_scope(self, scope, parsed_scopes, **s_kwargs): return func(self, *args, **kwargs) From 8a7320b318ac5d84d0a15e44beb8c7e766cfd87e Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 16 Dec 2020 11:17:43 +0100 Subject: [PATCH 040/270] fixed default roles for mocked services --- jupyterhub/roles.py | 13 +++++++++++++ jupyterhub/tests/conftest.py | 2 ++ jupyterhub/tests/test_api.py | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 544aa08f..1dd0d86e 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -259,3 +259,16 @@ def update_roles(db, obj, kind, roles=None): # users and services can have 'user' or 'admin' roles as default else: switch_default_role(db, obj, kind, obj.admin) + + +def mock_roles(app, name, kind): + + """Loads and assigns default roles for mocked objects""" + + Class = get_orm_class(kind) + + obj = Class.find(app.db, name=name) + default_roles = get_default_roles() + for role in default_roles: + add_role(app.db, role) + update_roles(db=app.db, obj=obj, kind=kind) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 104ca635..45bfd203 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -44,6 +44,7 @@ import jupyterhub.services.service from . import mocking from .. import crypto from .. import orm +from ..roles import mock_roles from ..utils import random_port from .mocking import MockHub from .test_services import mockservice_cmd @@ -245,6 +246,7 @@ def _mockservice(request, app, url=False): ): app.services = [spec] app.init_services() + mock_roles(app, name, 'services') assert name in app._service_map service = app._service_map[name] diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index d2ccbba4..199c7943 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1594,7 +1594,7 @@ async def test_get_services(app, mockservice_url): mockservice.name: { 'name': mockservice.name, 'admin': True, - 'roles': [], + 'roles': ['admin'], 'command': mockservice.command, 'pid': mockservice.proc.pid, 'prefix': mockservice.server.base_url, @@ -1620,7 +1620,7 @@ async def test_get_service(app, mockservice_url): assert service == { 'name': mockservice.name, 'admin': True, - 'roles': [], + 'roles': ['admin'], 'command': mockservice.command, 'pid': mockservice.proc.pid, 'prefix': mockservice.server.base_url, From f10fc0f0c0a2318ab61c77e82e9e6e36952ee60a Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Dec 2020 14:46:08 +0100 Subject: [PATCH 041/270] No more need for mock roles --- jupyterhub/tests/mocking.py | 7 --- jupyterhub/tests/test_api.py | 115 ++++++++++++++++------------------- 2 files changed, 51 insertions(+), 71 deletions(-) diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 74340562..24b03f2e 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -78,13 +78,6 @@ def mock_open_session(username, service, encoding): pass -def mock_role(app, role='admin', name=None): - scopes = get_scopes(role) - if name is not None: - scopes = [scope.format(username=name) for scope in scopes] - return mock.patch.dict(app.tornado_settings, {'mock_scopes': scopes}) - - class MockSpawner(SimpleLocalProcessSpawner): """Base mock spawner diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 89e24a34..dc4a3987 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -18,7 +18,6 @@ from .. import roles from ..objects import Server from ..utils import url_path_join as ujoin from ..utils import utcnow -from .mocking import mock_role from .mocking import public_host from .mocking import public_url from .utils import add_user @@ -181,8 +180,7 @@ async def test_get_users(app): {'name': 'user', 'admin': False, 'roles': ['user'], 'last_activity': None} ), ] - with mock_role(app, 'user'): - r = await api_request(app, 'users', headers=auth_header(db, 'user')) + r = await api_request(app, 'users', headers=auth_header(db, 'user')) assert r.status_code == 403 @@ -284,12 +282,11 @@ async def test_get_self(app): assert model['name'] == u.name # invalid auth gets 403 - with mock_role(app, 'user'): - r = await api_request( - app, - 'user', - headers={'Authorization': 'token notvalid'}, - ) + r = await api_request( + app, + 'user', + headers={'Authorization': 'token notvalid'}, + ) assert r.status_code == 403 @@ -314,12 +311,11 @@ async def test_add_user(app): async def test_get_user(app): name = 'user' _ = await api_request(app, 'users', name, headers=auth_header(app.db, name)) - with mock_role(app, role=name, name=name): - r = await api_request( - app, - 'users', - name, - ) + r = await api_request( + app, + 'users', + name, + ) assert r.status_code == 200 user = normalize_user(r.json()) @@ -518,15 +514,14 @@ async def test_user_set_auth_state(app, auth_state_enabled): assert user.name == name user_auth_state = await user.get_auth_state() assert user_auth_state is None - with mock_role(app, 'user'): - r = await api_request( - app, - 'users', - name, - method='patch', - data=json.dumps({'auth_state': auth_state}), - headers=auth_header(app.db, name), - ) + r = await api_request( + app, + 'users', + name, + method='patch', + data=json.dumps({'auth_state': auth_state}), + headers=auth_header(app.db, name), + ) assert r.status_code == 403 user_auth_state = await user.get_auth_state() assert user_auth_state is None @@ -1348,16 +1343,15 @@ async def test_token_authenticator_noauth(app): """Create a token for a user relying on Authenticator.authenticate and no auth header""" name = 'user' data = {'auth': {'username': name, 'password': name}} - with mock_role(app, 'admin'): - r = await api_request( - app, - 'users', - name, - 'tokens', - method='post', - data=json.dumps(data) if data else None, - noauth=True, - ) + r = await api_request( + app, + 'users', + name, + 'tokens', + method='post', + data=json.dumps(data) if data else None, + noauth=True, + ) assert r.status_code == 200 reply = r.json() assert 'token' in reply @@ -1372,16 +1366,15 @@ async def test_token_authenticator_dict_noauth(app): app.authenticator.auth_state = {'who': 'cares'} name = 'user' data = {'auth': {'username': name, 'password': name}} - with mock_role(app, 'user'): - r = await api_request( - app, - 'users', - name, - 'tokens', - method='post', - data=json.dumps(data) if data else None, - noauth=True, - ) + r = await api_request( + app, + 'users', + name, + 'tokens', + method='post', + data=json.dumps(data) if data else None, + noauth=True, + ) assert r.status_code == 200 reply = r.json() assert 'token' in reply @@ -1405,8 +1398,7 @@ async def test_token_list(app, as_user, for_user, status): if for_user != 'missing': for_user_obj = add_user(app.db, app, name=for_user) headers = {'Authorization': 'token %s' % u.new_api_token()} - with mock_role(app, role=as_user, name=as_user): - r = await api_request(app, 'users', for_user, 'tokens', headers=headers) + r = await api_request(app, 'users', for_user, 'tokens', headers=headers) assert r.status_code == status if status != 200: return @@ -1417,10 +1409,9 @@ async def test_token_list(app, as_user, for_user, status): assert all(token['user'] == for_user for token in reply['oauth_tokens']) # validate individual token ids for token in reply['api_tokens'] + reply['oauth_tokens']: - with mock_role(app, role=as_user, name=as_user): - r = await api_request( - app, 'users', for_user, 'tokens', token['id'], headers=headers - ) + r = await api_request( + app, 'users', for_user, 'tokens', token['id'], headers=headers + ) r.raise_for_status() reply = r.json() assert normalize_token(reply) == normalize_token(token) @@ -1603,8 +1594,7 @@ async def test_get_services(app, mockservice_url): 'display': True, } } - with mock_role(app, 'user'): - r = await api_request(app, 'services', headers=auth_header(db, 'user')) + r = await api_request(app, 'services', headers=auth_header(db, 'user')) assert r.status_code == 403 @@ -1647,16 +1637,14 @@ async def test_root_api(app): if app.internal_ssl: kwargs['cert'] = (app.internal_ssl_cert, app.internal_ssl_key) kwargs["verify"] = app.internal_ssl_ca - with mock_role(app): - r = await api_request(app, bypass_proxy=True) + r = await api_request(app, bypass_proxy=True) r.raise_for_status() expected = {'version': jupyterhub.__version__} assert r.json() == expected async def test_info(app): - with mock_role(app): - r = await api_request(app, 'info') + r = await api_request(app, 'info') r.raise_for_status() data = r.json() assert data['version'] == jupyterhub.__version__ @@ -1686,14 +1674,13 @@ async def test_info(app): async def test_update_activity_403(app, user, admin_user): token = user.new_api_token() - with mock_role(app, 'user'): - r = await api_request( - app, - "users/{}/activity".format(admin_user.name), - headers={"Authorization": "token {}".format(token)}, - data="{}", - method="post", - ) + r = await api_request( + app, + "users/{}/activity".format(admin_user.name), + headers={"Authorization": "token {}".format(token)}, + data="{}", + method="post", + ) assert r.status_code == 403 From 5e8864f29df3054cfe6af4c77a05430c2bd1450c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 16 Dec 2020 11:17:43 +0100 Subject: [PATCH 042/270] fixed default roles for mocked services --- jupyterhub/apihandlers/base.py | 11 +++- jupyterhub/app.py | 18 ++++-- jupyterhub/orm.py | 9 +++ jupyterhub/roles.py | 36 +++++++++++- jupyterhub/tests/conftest.py | 2 + jupyterhub/tests/test_api.py | 13 +++-- jupyterhub/tests/test_roles.py | 102 ++++++++++++++++++++++++++++++++- 7 files changed, 175 insertions(+), 16 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index a416e6c8..e6524cff 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -222,6 +222,7 @@ class APIHandler(BaseHandler): 'kind': 'group', 'name': group.name, 'users': [u.name for u in group.users], + 'roles': [r.name for r in group.roles], } def service_model(self, service): @@ -233,9 +234,15 @@ class APIHandler(BaseHandler): 'roles': [r.name for r in service.roles], } - _user_model_types = {'name': str, 'admin': bool, 'groups': list, 'auth_state': dict} + _user_model_types = { + 'name': str, + 'admin': bool, + 'groups': list, + 'roles': list, + 'auth_state': dict, + } - _group_model_types = {'name': str, 'users': list} + _group_model_types = {'name': str, 'users': list, 'roles': list} def _check_model(self, model, model_types, name): """Check a model provided by a REST API request diff --git a/jupyterhub/app.py b/jupyterhub/app.py index c7571453..28c70e29 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -326,7 +326,8 @@ class JupyterHub(Application): 'scopes': ['users', 'groups'], 'users': ['cyclops', 'gandalf'], 'services': [], - 'tokens': [] + 'tokens': [], + 'groups': [] } ] @@ -1827,7 +1828,7 @@ class JupyterHub(Application): async def init_roles(self): """Load default and predefined roles into the database""" db = self.db - role_bearers = ['users', 'services', 'tokens'] + role_bearers = ['groups', 'users', 'services', 'tokens'] # load default roles default_roles = roles.get_default_roles() @@ -1857,11 +1858,18 @@ class JupyterHub(Application): ) # make sure all users, services and tokens have at least one role (update with default) + # groups can be without a role but all group members should have the same role(s) as the group for bearer in role_bearers: Class = roles.get_orm_class(bearer) - for obj in db.query(Class): - if len(obj.roles) < 1: - roles.update_roles(db, obj=obj, kind=bearer) + if bearer == 'groups': + for group in db.query(Class): + for user in group.users: + rolenames = roles.get_rolenames(group.roles) + roles.update_roles(db, obj=user, kind='users', roles=rolenames) + else: + for obj in db.query(Class): + if len(obj.roles) < 1: + roles.update_roles(db, obj=obj, kind=bearer) db.commit() async def _add_tokens(self, token_dict, kind): diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 90ca63f7..42089c10 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -166,6 +166,14 @@ api_token_role_map = Table( Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), ) +# group:role many:many mapping table +group_role_map = Table( + 'group_role_map', + Base.metadata, + Column('group_id', ForeignKey('groups.id', ondelete='CASCADE'), primary_key=True), + Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), +) + class Role(Base): """User Roles""" @@ -178,6 +186,7 @@ class Role(Base): users = relationship('User', secondary='user_role_map', backref='roles') services = relationship('Service', secondary='service_role_map', backref='roles') tokens = relationship('APIToken', secondary='api_token_role_map', backref='roles') + groups = relationship('Group', secondary='group_role_map', backref='roles') def __repr__(self): return "<%s %s (%s) - scopes: %s>" % ( diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 544aa08f..6291a3ce 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -147,12 +147,26 @@ def get_orm_class(kind): Class = orm.Service elif kind == 'tokens': Class = orm.APIToken + elif kind == 'groups': + Class = orm.Group else: - raise ValueError("kind must be users, services or tokens, not %r" % kind) + raise ValueError( + "kind must be users, services, tokens or groups, not %r" % kind + ) return Class +def get_rolenames(role_list): + + """Return a list of rolenames from a list of roles""" + + rolenames = [] + for role in role_list: + rolenames.append(role.name) + return rolenames + + def existing_only(func): """Decorator for checking if objects and roles exist""" @@ -176,7 +190,7 @@ def existing_only(func): @existing_only def add_obj(db, objname, kind, rolename): - """Adds a role for users, services or tokens""" + """Adds a role for users, services, tokens or groups""" if rolename not in objname.roles: objname.roles.append(rolename) @@ -250,12 +264,28 @@ def update_roles(db, obj, kind, roles=None): else: add_obj(db, objname=obj.name, kind=kind, rolename=rolename) else: + # groups can be without a role + if Class == orm.Group: + pass # tokens can have only 'user' role as default # assign the default only for user tokens - if Class == orm.APIToken: + elif Class == orm.APIToken: if len(obj.roles) < 1 and obj.user is not None: user_role.tokens.append(obj) db.commit() # users and services can have 'user' or 'admin' roles as default else: switch_default_role(db, obj, kind, obj.admin) + + +def mock_roles(app, name, kind): + + """Loads and assigns default roles for mocked objects""" + + Class = get_orm_class(kind) + + obj = Class.find(app.db, name=name) + default_roles = get_default_roles() + for role in default_roles: + add_role(app.db, role) + update_roles(db=app.db, obj=obj, kind=kind) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 104ca635..45bfd203 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -44,6 +44,7 @@ import jupyterhub.services.service from . import mocking from .. import crypto from .. import orm +from ..roles import mock_roles from ..utils import random_port from .mocking import MockHub from .test_services import mockservice_cmd @@ -245,6 +246,7 @@ def _mockservice(request, app, url=False): ): app.services = [spec] app.init_services() + mock_roles(app, name, 'services') assert name in app._service_map service = app._service_map[name] diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index d2ccbba4..df2dd302 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1446,7 +1446,7 @@ async def test_groups_list(app): r = await api_request(app, 'groups') r.raise_for_status() reply = r.json() - assert reply == [{'kind': 'group', 'name': 'alphaflight', 'users': []}] + assert reply == [{'kind': 'group', 'name': 'alphaflight', 'users': [], 'roles': []}] @mark.group @@ -1481,7 +1481,12 @@ async def test_group_get(app): r = await api_request(app, 'groups/alphaflight') r.raise_for_status() reply = r.json() - assert reply == {'kind': 'group', 'name': 'alphaflight', 'users': ['sasquatch']} + assert reply == { + 'kind': 'group', + 'name': 'alphaflight', + 'users': ['sasquatch'], + 'roles': [], + } @mark.group @@ -1594,7 +1599,7 @@ async def test_get_services(app, mockservice_url): mockservice.name: { 'name': mockservice.name, 'admin': True, - 'roles': [], + 'roles': ['admin'], 'command': mockservice.command, 'pid': mockservice.proc.pid, 'prefix': mockservice.server.base_url, @@ -1620,7 +1625,7 @@ async def test_get_service(app, mockservice_url): assert service == { 'name': mockservice.name, 'admin': True, - 'roles': [], + 'roles': ['admin'], 'command': mockservice.command, 'pid': mockservice.proc.pid, 'prefix': mockservice.server.base_url, diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index bdc8b98a..90c108fd 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -26,6 +26,18 @@ def test_orm_roles(db): db.add(service_role) db.commit() + group_role = orm.Role(name='group', scopes=['read:users']) + db.add(group_role) + db.commit() + + group_role = orm.Role(name='group', scopes=['read:users']) + db.add(group_role) + db.commit() + + group_role = orm.Role(name='group', scopes=['read:users']) + db.add(group_role) + db.commit() + user = orm.User(name='falafel') db.add(user) db.commit() @@ -34,20 +46,30 @@ def test_orm_roles(db): db.add(service) db.commit() + group = orm.Group(name='fast-food') + db.add(group) + db.commit() + assert user_role.users == [] assert user_role.services == [] + assert user_role.groups == [] assert service_role.users == [] assert service_role.services == [] + assert service_role.groups == [] assert user.roles == [] assert service.roles == [] + assert group.roles == [] user_role.users.append(user) service_role.services.append(service) + group_role.groups.append(group) db.commit() assert user_role.users == [user] assert user.roles == [user_role] assert service_role.services == [service] assert service.roles == [service_role] + assert group_role.groups == [group] + assert group.roles == [group_role] # check token creation without specifying its role # assigns it the default 'user' role @@ -67,16 +89,22 @@ def test_orm_roles(db): db.commit() assert user_role.users == [] assert user_token not in user_role.tokens - # check deleting the service token removes it from 'service' role + # check deleting the service token removes it from service_role db.delete(service_token) db.commit() assert service_token not in service_role.tokens - # check deleting the 'service' role removes it from service roles + # check deleting the service_role removes it from service.roles db.delete(service_role) db.commit() assert service.roles == [] + # check deleting the group removes it from group_roles + db.delete(group) + db.commit() + assert group_role.groups == [] + # clean up db db.delete(service) + db.delete(group_role) db.commit() @@ -310,6 +338,76 @@ async def test_load_roles_services(tmpdir, request): db.commit() +@mark.role +async def test_load_roles_groups(tmpdir, request): + """Test loading predefined roles for groups in app.py""" + groups_to_load = { + 'group1': ['gandalf'], + 'group2': ['bilbo', 'gargamel'], + 'group3': ['cyclops'], + } + roles_to_load = [ + { + 'name': 'assistant', + 'description': 'Access users information only', + 'scopes': ['read:users'], + 'groups': ['group2'], + }, + { + 'name': 'head', + 'description': 'Whole user access', + 'scopes': ['users', 'admin:users'], + 'groups': ['group3'], + }, + ] + kwargs = {'load_groups': groups_to_load, 'load_roles': roles_to_load} + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + hub.authenticator.allowed_users = ['cyclops', 'gandalf', 'bilbo', 'gargamel'] + await hub.init_users() + await hub.init_groups() + await hub.init_roles() + + assist_role = orm.Role.find(db, name='assistant') + head_role = orm.Role.find(db, name='head') + user_role = orm.Role.find(db, name='user') + + group1 = orm.Group.find(db, name='group1') + group2 = orm.Group.find(db, name='group2') + group3 = orm.Group.find(db, name='group3') + + gandalf = orm.User.find(db, name='gandalf') + bilbo = orm.User.find(db, name='bilbo') + gargamel = orm.User.find(db, name='gargamel') + cyclops = orm.User.find(db, name='cyclops') + + # test group roles + assert group1.roles == [] + assert group2 in assist_role.groups + assert group3 in head_role.groups + + # test group members' roles + assert assist_role in bilbo.roles + assert assist_role in gargamel.roles + assert head_role in cyclops.roles + + # check the default user_role assignment + # FIXME - should users with group roles still have default? + assert user_role in gandalf.roles + assert user_role not in bilbo.roles + assert user_role not in gargamel.roles + assert user_role not in cyclops.roles + + +# FIXME +# @mark.role +# async def test_group_roles_delete_cascade(tmpdir, request): + + @mark.role async def test_load_roles_tokens(tmpdir, request): services = [ From f4ba57b1d741498b38aff1d23d49768e7bc21723 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 4 Jan 2021 16:24:50 +0100 Subject: [PATCH 043/270] Implemented filter list skeleton --- jupyterhub/apihandlers/groups.py | 6 ++-- jupyterhub/apihandlers/services.py | 4 ++- jupyterhub/apihandlers/users.py | 6 ++-- jupyterhub/utils.py | 53 ++++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 83c7b7b9..54c05e73 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -35,10 +35,12 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @needs_scope('read:groups') # Todo: Apply filter on results - def get(self): + @needs_scope('read:groups') + def get(self, scope_filter=None): """List groups""" groups = self.db.query(orm.Group) + if scope_filter is not None: + groups.filter(orm.Group.name._in(scope_filter)) data = [self.group_model(g) for g in groups] self.write(json.dumps(data)) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 58c5ed69..277b8954 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -31,8 +31,10 @@ def service_model(service): class ServiceListAPIHandler(APIHandler): @needs_scope('read:services') - def get(self): + def get(self, scope_filter=None): data = {name: service_model(service) for name, service in self.services.items()} + if scope_filter is not None: + data = dict(filter(lambda tup: tup[0] in scope_filter)) self.write(json.dumps(data)) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 669f45fa..77927545 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -38,8 +38,6 @@ class SelfAPIHandler(APIHandler): user = self.get_current_user_oauth_token() if user is None: raise web.HTTPError(403) - # Later: filter based on scopes. - # Perhaps user self.write(json.dumps(self.user_model(user))) @@ -53,7 +51,7 @@ class UserListAPIHandler(APIHandler): return any(spawner.ready for spawner in user.spawners.values()) @needs_scope('read:users') - def get(self): + def get(self, scope_filter=None): state_filter = self.get_argument("state", None) # post_filter @@ -94,6 +92,8 @@ class UserListAPIHandler(APIHandler): else: # no filter, return all users query = self.db.query(orm.User) + if scope_filter is not None: + query.filter(orm.User.name.in_(scope_filter)) data = [ self.user_model(u, include_servers=True, include_state=True) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 4a6282d4..5e1daf69 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -320,9 +320,7 @@ def get_user_scopes(name): 'users:servers', 'users:tokens', ] - scope_list.extend( - ['read:' + scope for scope in scope_list] - ) # Todo: Put this in closure + scope_list.extend(['read:' + scope for scope in scope_list]) return {"{}!user={}".format(scope, name) for scope in scope_list} @@ -348,6 +346,29 @@ def check_user_in_expanded_scope(handler, user_name, scope_group_names): return bool(set(scope_group_names) & group_names) +def _flatten_groups(groups): + user_set = {} + for group in groups: + user_set |= group.users + return user_set + + +def _get_scope_filter(req_scope, sub_scope): + # Rough draft + scope_translator = { + 'read:users': 'users', + 'users': 'users', + 'read:groups': 'groups', + } + if req_scope not in scope_translator: + raise AttributeError("Scope not found") + kind = scope_translator[req_scope] + scope_filter = None # todo: orm.Class(kind).find + if 'group' in sub_scope and kind == 'user': + scope_filter += _flatten_groups(sub_scope['group']) + return set(scope_filter) + + def check_scope(api_handler, req_scope, scopes, **kwargs): # Parse user name and server name together if 'user' in kwargs and 'server' in kwargs: @@ -358,17 +379,23 @@ def check_scope(api_handler, req_scope, scopes, **kwargs): return True # Apply filters sub_scope = scopes[req_scope] - for ( - filter_, - filter_value, - ) in kwargs.items(): # Interface change: Now can have multiple filters - if filter_ in sub_scope and filter_value in sub_scope[filter_]: - return True - if needs_scope_expansion(filter_, filter_value, sub_scope): - group_names = sub_scope['group'] - if check_user_in_expanded_scope(api_handler, filter_value, group_names): + if 'scope_filter' in kwargs: + scope_filter = _get_scope_filter(req_scope, sub_scope) + kwargs['scope_filter'] = scope_filter + return True + else: + # Interface change: Now can have multiple filters + for (filter_, filter_value) in kwargs.items(): + if filter_ in sub_scope and filter_value in sub_scope[filter_]: return True - return False + if needs_scope_expansion(filter_, filter_value, sub_scope): + group_names = sub_scope['group'] + if check_user_in_expanded_scope(api_handler, filter_value, group_names): + return True + return False + + +# Todo: make some methods private def parse_scopes(scope_list): From 82bebfaff2465085c6292294163f079683e0db6d Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Mon, 4 Jan 2021 22:44:23 +0100 Subject: [PATCH 044/270] Added unit tests and fixed bugs in scope filter --- jupyterhub/apihandlers/groups.py | 2 +- jupyterhub/apihandlers/users.py | 2 +- jupyterhub/roles.py | 2 +- jupyterhub/tests/test_scopes.py | 98 ++++++++++++++++++++++++++++++++ jupyterhub/utils.py | 50 ++++++++++++---- 5 files changed, 139 insertions(+), 15 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 54c05e73..a340868c 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -40,7 +40,7 @@ class GroupListAPIHandler(_GroupAPIHandler): """List groups""" groups = self.db.query(orm.Group) if scope_filter is not None: - groups.filter(orm.Group.name._in(scope_filter)) + groups = groups.filter(orm.Group.name.in_(scope_filter)) data = [self.group_model(g) for g in groups] self.write(json.dumps(data)) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 77927545..92f6df27 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -93,7 +93,7 @@ class UserListAPIHandler(APIHandler): # no filter, return all users query = self.db.query(orm.User) if scope_filter is not None: - query.filter(orm.User.name.in_(scope_filter)) + query = query.filter(orm.User.name.in_(scope_filter)) data = [ self.user_model(u, include_servers=True, include_state=True) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 545ce7f4..bb2eab44 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -135,7 +135,7 @@ def add_role(db, role_dict): db.commit() -def get_orm_class(kind): +def get_orm_class(kind): # Todo: merge and move to orm.py if kind == 'users': Class = orm.User elif kind == 'services': diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 9b66d9fa..0c2281fd 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -1,4 +1,5 @@ """Test scopes for API handlers""" +import json from unittest import mock import pytest @@ -214,3 +215,100 @@ async def test_expand_groups(app, user_name, in_group, status_code): app, 'users', user_name, headers=auth_header(app.db, user_name) ) assert r.status_code == status_code + + +async def test_user_filter(app): + user_name = 'rollerblade' + test_role = { + 'name': 'test', + 'description': '', + 'users': [user_name], + 'scopes': [ + 'read:users!user=lindsay', + 'read:users!user=gob', + 'read:users!user=oscar', + ], + } + roles.add_role(app.db, test_role) + name_in_scope = {'lindsay', 'oscar', 'gob'} + outside_scope = {'maeby', 'marta'} + group_name = 'bluth' + group = orm.Group.find(app.db, name=group_name) + if not group: + group = orm.Group(name=group_name) + app.db.add(group) + for name in name_in_scope | outside_scope: + user = add_user(app.db, name=name) + if name not in group.users: + group.users.append(user) + kind = 'users' + user = add_user(app.db, name=user_name) + roles.update_roles(app.db, user, kind, roles=['test']) + roles.remove_obj(app.db, user_name, kind, 'user') + app.db.commit() + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + data = json.loads(r.content) + result_names = {user['name'] for user in data} + assert result_names == name_in_scope + + +async def test_user_filter_with_group(app): # todo: Move role setup to setup method + user_name = 'sally' + test_role = { + 'name': 'test', + 'description': '', + 'users': [user_name], + 'scopes': ['read:users!group=sitwell'], + } + roles.add_role(app.db, test_role) + user = add_user(app.db, name=user_name) + name_set = {'sally', 'stan'} + group_name = 'sitwell' + group = orm.Group.find(app.db, name=group_name) + if not group: + group = orm.Group(name=group_name) + app.db.add(group) + for name in name_set: + user = add_user(app.db, name=name) + if name not in group.users: + group.users.append(user) + kind = 'users' + roles.update_roles(app.db, user, kind, roles=['test']) + roles.remove_obj(app.db, user_name, kind, 'user') + app.db.commit() + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + data = json.loads(r.content) + result_names = {user['name'] for user in data} + assert result_names == name_set + + +async def test_group_scope_filter(app): + user_name = 'rollerblade' + test_role = { + 'name': 'test', + 'description': '', + 'users': [user_name], + 'scopes': [ + 'read:groups!group=sitwell', + 'read:groups!group=bluths', + ], + } + roles.add_role(app.db, test_role) + user = add_user(app.db, name=user_name) + group_set = {'sitwell', 'bluths', 'austero'} + for group_name in group_set: + group = orm.Group.find(app.db, name=group_name) + if not group: + group = orm.Group(name=group_name) + app.db.add(group) + kind = 'users' + roles.update_roles(app.db, user, kind, roles=['test']) + roles.remove_obj(app.db, user_name, kind, 'user') + app.db.commit() + r = await api_request(app, 'groups', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + data = json.loads(r.content) + result_names = {user['name'] for user in data} + assert result_names == {'sitwell', 'bluths'} diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 5e1daf69..006e4269 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -30,6 +30,8 @@ from tornado.httpclient import HTTPError from tornado.log import app_log from tornado.platform.asyncio import to_asyncio_future +from . import orm # todo: only necessary for scopes, move later + def random_port(): """Get a single random port.""" @@ -347,25 +349,45 @@ def check_user_in_expanded_scope(handler, user_name, scope_group_names): def _flatten_groups(groups): - user_set = {} + user_set = set() for group in groups: - user_set |= group.users + user_set |= { + user.name for user in group.users + } # todo: I think this could be one query, no for loop return user_set -def _get_scope_filter(req_scope, sub_scope): +def get_orm_class(kind): + class_dict = { + 'users': orm.User, + 'services': orm.Service, + 'tokens': orm.APIToken, + 'groups': orm.Group, + } + if kind not in class_dict: + raise ValueError( + "Kind must be one of %s, not %s" % (", ".join(class_dict), kind) + ) + return class_dict[kind] + + +def _get_scope_filter(db, req_scope, sub_scope): # Rough draft scope_translator = { 'read:users': 'users', - 'users': 'users', + 'read:services': 'services', 'read:groups': 'groups', } if req_scope not in scope_translator: - raise AttributeError("Scope not found") + raise AttributeError("Scope not found; scope filter not constructed") kind = scope_translator[req_scope] - scope_filter = None # todo: orm.Class(kind).find - if 'group' in sub_scope and kind == 'user': - scope_filter += _flatten_groups(sub_scope['group']) + Class = get_orm_class(kind) + sub_scope_values = next(iter(sub_scope.values())) + query = db.query(Class).filter(Class.name.in_(sub_scope_values)) + scope_filter = [entry.name for entry in query.all()] + if 'group' in sub_scope and kind == 'users': + groups = db.query(orm.Group).filter(orm.Group.name.in_(sub_scope['group'])) + scope_filter += _flatten_groups(groups) return set(scope_filter) @@ -380,9 +402,8 @@ def check_scope(api_handler, req_scope, scopes, **kwargs): # Apply filters sub_scope = scopes[req_scope] if 'scope_filter' in kwargs: - scope_filter = _get_scope_filter(req_scope, sub_scope) - kwargs['scope_filter'] = scope_filter - return True + scope_filter = _get_scope_filter(api_handler.db, req_scope, sub_scope) + return scope_filter else: # Interface change: Now can have multiple filters for (filter_, filter_value) in kwargs.items(): @@ -449,11 +470,16 @@ def needs_scope(scope): if resource_name in bound_sig.arguments: resource_value = bound_sig.arguments[resource_name] s_kwargs[resource] = resource_value + if 'scope_filter' in bound_sig.arguments: + s_kwargs['scope_filter'] = None if 'all' in self.scopes and self.current_user: # todo: What if no user is found? See test_api/test_referer_check self.scopes |= get_user_scopes(self.current_user.name) parsed_scopes = parse_scopes(self.scopes) - if check_scope(self, scope, parsed_scopes, **s_kwargs): + scope_filter = check_scope(self, scope, parsed_scopes, **s_kwargs) + if scope_filter: + if isinstance(scope_filter, set): + kwargs['scope_filter'] = scope_filter return func(self, *args, **kwargs) else: # catching attr error occurring for older_requirements test From 662017f260bb662b3878075705520b6fa056a07a Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Tue, 5 Jan 2021 11:42:53 +0100 Subject: [PATCH 045/270] Refactored scope module. Implemented filter in *ListApiHandlers --- jupyterhub/apihandlers/groups.py | 3 +- jupyterhub/apihandlers/hub.py | 3 +- jupyterhub/apihandlers/proxy.py | 3 +- jupyterhub/apihandlers/services.py | 3 +- jupyterhub/apihandlers/users.py | 3 +- jupyterhub/handlers/pages.py | 4 +- jupyterhub/scopes.py | 216 ++++++++++++++++++++++++++++ jupyterhub/tests/test_api.py | 17 ++- jupyterhub/tests/test_scopes.py | 41 +++--- jupyterhub/utils.py | 219 +---------------------------- 10 files changed, 260 insertions(+), 252 deletions(-) create mode 100644 jupyterhub/scopes.py diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index a340868c..93a6202d 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -6,8 +6,7 @@ import json from tornado import web from .. import orm -from ..utils import admin_only -from ..utils import needs_scope +from ..scopes import needs_scope from .base import APIHandler diff --git a/jupyterhub/apihandlers/hub.py b/jupyterhub/apihandlers/hub.py index c9df504f..80e9c986 100644 --- a/jupyterhub/apihandlers/hub.py +++ b/jupyterhub/apihandlers/hub.py @@ -8,8 +8,7 @@ from tornado import web from tornado.ioloop import IOLoop from .._version import __version__ -from ..utils import admin_only -from ..utils import needs_scope +from ..scopes import needs_scope from .base import APIHandler diff --git a/jupyterhub/apihandlers/proxy.py b/jupyterhub/apihandlers/proxy.py index 81430879..048e36fa 100644 --- a/jupyterhub/apihandlers/proxy.py +++ b/jupyterhub/apihandlers/proxy.py @@ -5,8 +5,7 @@ import json from tornado import web -from ..utils import admin_only -from ..utils import needs_scope +from ..scopes import needs_scope from .base import APIHandler diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 277b8954..792d4b52 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -9,8 +9,7 @@ import json from tornado import web from .. import orm -from ..utils import admin_only -from ..utils import needs_scope +from ..scopes import needs_scope from .base import APIHandler diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 92f6df27..49c1fdda 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -14,13 +14,12 @@ from tornado import web from tornado.iostream import StreamClosedError from .. import orm -from .. import roles from ..roles import update_roles +from ..scopes import needs_scope from ..user import User from ..utils import isoformat from ..utils import iterate_until from ..utils import maybe_future -from ..utils import needs_scope from ..utils import url_path_join from .base import APIHandler diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index 98ebddec..7a6f11b2 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -17,7 +17,7 @@ from .. import orm from ..metrics import SERVER_POLL_DURATION_SECONDS from ..metrics import ServerPollStatus from ..pagination import Pagination -from ..utils import admin_only +from ..scopes import needs_scope from ..utils import maybe_future from ..utils import url_path_join from .base import BaseHandler @@ -455,7 +455,7 @@ class AdminHandler(BaseHandler): """Render the admin page.""" @web.authenticated - @admin_only + @needs_scope('admin:users') async def get(self): page, per_page, offset = Pagination(config=self.config).get_page_args(self) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py new file mode 100644 index 00000000..d0eba1a7 --- /dev/null +++ b/jupyterhub/scopes.py @@ -0,0 +1,216 @@ +import functools +import inspect +from enum import Enum + +from tornado import web +from tornado.log import app_log + +from . import orm + + +class Scope(Enum): + ALL = True + + +def get_user_scopes(name): + """ + Scopes have a metascope 'all' that should be expanded to everything a user can do. + At the moment that is a user-filtered version (optional read) access to + users + users:name + users:groups + users:activity + users:servers + users:tokens + + """ + scope_list = [ + 'users', + 'users:name', + 'users:groups', + 'users:activity', + 'users:servers', + 'users:tokens', + ] + scope_list.extend(['read:' + scope for scope in scope_list]) + return {"{}!user={}".format(scope, name) for scope in scope_list} + + +def _needs_scope_expansion(filter_, filter_value, sub_scope): + """ + Check if there is a requirements to expand the `group` scope to individual `user` scopes. + Assumptions: + filter_ != Scope.ALL + """ + if not (filter_ == 'user' and 'group' in sub_scope): + return False + if 'user' in sub_scope: + return filter_value not in sub_scope['user'] + else: + return True + + +def _check_user_in_expanded_scope(handler, user_name, scope_group_names): + user = handler.find_user(user_name) + if user is None: + raise web.HTTPError(404, 'No such user found') + group_names = {group.name for group in user.groups} + return bool(set(scope_group_names) & group_names) + + +def _flatten_groups(groups): + user_set = set() + for group in groups: + user_set |= { + user.name for user in group.users + } # todo: I think this could be one query, no for loop + return user_set + + +def get_orm_class(kind): + class_dict = { + 'users': orm.User, + 'services': orm.Service, + 'tokens': orm.APIToken, + 'groups': orm.Group, + } + if kind not in class_dict: + raise ValueError( + "Kind must be one of %s, not %s" % (", ".join(class_dict), kind) + ) + return class_dict[kind] + + +def _get_scope_filter(db, req_scope, sub_scope): + # Rough draft + scope_translator = { + 'read:users': 'users', + 'read:services': 'services', + 'read:groups': 'groups', + } + if req_scope not in scope_translator: + raise AttributeError("Scope not found; scope filter not constructed") + kind = scope_translator[req_scope] + Class = get_orm_class(kind) + sub_scope_values = next(iter(sub_scope.values())) + query = db.query(Class).filter(Class.name.in_(sub_scope_values)) + scope_filter = [entry.name for entry in query.all()] + if 'group' in sub_scope and kind == 'users': + groups = db.query(orm.Group).filter(orm.Group.name.in_(sub_scope['group'])) + scope_filter += _flatten_groups(groups) + return set(scope_filter) + + +def _check_scope(api_handler, req_scope, scopes, **kwargs): + # Parse user name and server name together + if 'user' in kwargs and 'server' in kwargs: + kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) + if req_scope not in scopes: + return False + if scopes[req_scope] == Scope.ALL: + return True + # Apply filters + sub_scope = scopes[req_scope] + if 'scope_filter' in kwargs: + scope_filter = _get_scope_filter(api_handler.db, req_scope, sub_scope) + return scope_filter + else: + # Interface change: Now can have multiple filters + for (filter_, filter_value) in kwargs.items(): + if filter_ in sub_scope and filter_value in sub_scope[filter_]: + return True + if _needs_scope_expansion(filter_, filter_value, sub_scope): + group_names = sub_scope['group'] + if _check_user_in_expanded_scope( + api_handler, filter_value, group_names + ): + return True + return False + + +def _parse_scopes(scope_list): + """ + Parses scopes and filters in something akin to JSON style + + For instance, scope list ["users", "groups!group=foo", "users:servers!server=bar", "users:servers!server=baz"] + would lead to scope model + { + "users":scope.ALL, + "users:admin":{ + "user":[ + "alice" + ] + }, + "users:servers":{ + "server":[ + "bar", + "baz" + ] + } + } + """ + parsed_scopes = {} + for scope in scope_list: + base_scope, _, filter_ = scope.partition('!') + if not filter_: + parsed_scopes[base_scope] = Scope.ALL + elif base_scope not in parsed_scopes: + parsed_scopes[base_scope] = {} + if parsed_scopes[base_scope] != Scope.ALL: + key, _, val = filter_.partition('=') + if key not in parsed_scopes[base_scope]: + parsed_scopes[base_scope][key] = [] + parsed_scopes[base_scope][key].append(val) + return parsed_scopes + + +def needs_scope(scope): + """Decorator to restrict access to users or services with the required scope""" + + def scope_decorator(func): + @functools.wraps(func) + def _auth_func(self, *args, **kwargs): + sig = inspect.signature(func) + bound_sig = sig.bind(self, *args, **kwargs) + bound_sig.apply_defaults() + s_kwargs = {} + for resource in {'user', 'server', 'group', 'service'}: + resource_name = resource + '_name' + if resource_name in bound_sig.arguments: + resource_value = bound_sig.arguments[resource_name] + s_kwargs[resource] = resource_value + if 'scope_filter' in bound_sig.arguments: + s_kwargs['scope_filter'] = None + if 'all' in self.scopes and self.current_user: + # todo: What if no user is found? See test_api/test_referer_check + self.scopes |= get_user_scopes(self.current_user.name) + parsed_scopes = _parse_scopes(self.scopes) + scope_filter = _check_scope(self, scope, parsed_scopes, **s_kwargs) + if ( + scope_filter + ): # Todo: This checks if True or set of resource names. Not very nice yet + if isinstance(scope_filter, set): + kwargs['scope_filter'] = scope_filter + return func(self, *args, **kwargs) + else: + # catching attr error occurring for older_requirements test + # could be done more ellegantly? + try: + request_path = self.request.path + except AttributeError: + request_path = 'the requested API' + app_log.warning( + "Not authorizing access to {}. Requires scope {}, not derived from scopes {}".format( + request_path, scope, ", ".join(self.scopes) + ) + ) + raise web.HTTPError( + 403, + "Action is not authorized with current scopes; requires {}".format( + scope + ), + ) + + return _auth_func + + return scope_decorator diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 3f200ac3..ff7b2389 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -14,7 +14,6 @@ from pytest import mark import jupyterhub from .. import orm -from .. import roles from ..objects import Server from ..utils import url_path_join as ujoin from ..utils import utcnow @@ -167,21 +166,27 @@ TIMESTAMP = normalize_timestamp(datetime.now().isoformat() + 'Z') @mark.user @mark.role -async def test_get_users(app): +async def test_get_users(app): # todo: Sync with scope tests db = app.db r = await api_request(app, 'users', headers=auth_header(db, 'admin')) assert r.status_code == 200 users = sorted(r.json(), key=lambda d: d['name']) users = [normalize_user(u) for u in users] + user_model = { + 'name': 'user', + 'admin': False, + 'roles': ['user'], + 'last_activity': None, + } assert users == [ fill_user({'name': 'admin', 'admin': True, 'roles': ['admin']}), - fill_user( - {'name': 'user', 'admin': False, 'roles': ['user'], 'last_activity': None} - ), + fill_user(user_model), ] r = await api_request(app, 'users', headers=auth_header(db, 'user')) - assert r.status_code == 403 + assert r.status_code == 200 + r_user_model = json.loads(r.text)[0] + assert r_user_model['name'] == user_model['name'] @mark.user diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 0c2281fd..9b66c47a 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -3,17 +3,16 @@ import json from unittest import mock import pytest -import tornado from pytest import mark from tornado import web from tornado.httputil import HTTPServerRequest from .. import orm from .. import roles -from ..utils import check_scope -from ..utils import needs_scope -from ..utils import parse_scopes -from ..utils import Scope +from ..scopes import _check_scope +from ..scopes import _parse_scopes +from ..scopes import needs_scope +from ..scopes import Scope from .utils import add_user from .utils import api_request from .utils import auth_header @@ -27,7 +26,7 @@ def test_scope_constructor(): 'read:users!user={}'.format(user1), 'read:users!user={}'.format(user2), ] - parsed_scopes = parse_scopes(scope_list) + parsed_scopes = _parse_scopes(scope_list) assert 'read:users' in parsed_scopes assert parsed_scopes['users'] @@ -36,25 +35,25 @@ def test_scope_constructor(): def test_scope_precendence(): scope_list = ['read:users!user=maeby', 'read:users'] - parsed_scopes = parse_scopes(scope_list) + parsed_scopes = _parse_scopes(scope_list) assert parsed_scopes['read:users'] == Scope.ALL def test_scope_check_present(): handler = None scope_list = ['read:users'] - parsed_scopes = parse_scopes(scope_list) - assert check_scope(handler, 'read:users', parsed_scopes) - assert check_scope(handler, 'read:users', parsed_scopes, user='maeby') + parsed_scopes = _parse_scopes(scope_list) + assert _check_scope(handler, 'read:users', parsed_scopes) + assert _check_scope(handler, 'read:users', parsed_scopes, user='maeby') def test_scope_check_not_present(): handler = None scope_list = ['read:users!user=maeby'] - parsed_scopes = parse_scopes(scope_list) - assert not check_scope(handler, 'read:users', parsed_scopes) - assert not check_scope(handler, 'read:users', parsed_scopes, user='gob') - assert not check_scope( + parsed_scopes = _parse_scopes(scope_list) + assert not _check_scope(handler, 'read:users', parsed_scopes) + assert not _check_scope(handler, 'read:users', parsed_scopes, user='gob') + assert not _check_scope( handler, 'read:users', parsed_scopes, user='gob', server='server' ) @@ -62,17 +61,17 @@ def test_scope_check_not_present(): def test_scope_filters(): handler = None scope_list = ['read:users', 'read:users!group=bluths', 'read:users!user=maeby'] - parsed_scopes = parse_scopes(scope_list) - assert check_scope(handler, 'read:users', parsed_scopes, group='bluth') - assert check_scope(handler, 'read:users', parsed_scopes, user='maeby') + parsed_scopes = _parse_scopes(scope_list) + assert _check_scope(handler, 'read:users', parsed_scopes, group='bluth') + assert _check_scope(handler, 'read:users', parsed_scopes, user='maeby') def test_scope_multiple_filters(): handler = None - assert check_scope( + assert _check_scope( handler, 'read:users', - parse_scopes(['read:users!user=george_michael']), + _parse_scopes(['read:users!user=george_michael']), user='george_michael', group='bluths', ) @@ -81,8 +80,8 @@ def test_scope_multiple_filters(): def test_scope_parse_server_name(): handler = None scope_list = ['users:servers!server=maeby/server1', 'read:users!user=maeby'] - parsed_scopes = parse_scopes(scope_list) - assert check_scope( + parsed_scopes = _parse_scopes(scope_list) + assert _check_scope( handler, 'users:servers', parsed_scopes, user='maeby', server='server1' ) diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 006e4269..a469d603 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -4,7 +4,6 @@ import asyncio import concurrent.futures import errno -import functools import hashlib import inspect import os @@ -18,7 +17,6 @@ import warnings from binascii import b2a_hex from datetime import datetime from datetime import timezone -from enum import Enum from hmac import compare_digest from operator import itemgetter @@ -30,8 +28,6 @@ from tornado.httpclient import HTTPError from tornado.log import app_log from tornado.platform.asyncio import to_asyncio_future -from . import orm # todo: only necessary for scopes, move later - def random_port(): """Get a single random port.""" @@ -283,8 +279,13 @@ def authenticated_403(self): @auth_decorator def admin_only(self): - """Decorator for restricting access to admin users""" + """Decorator for restricting access to admin users + Deprecated in favor of scopes.need_scope() + """ user = self.current_user + app_log.warning( + "Admin decorator is deprecated and will be removed soon. Use scope-based decorator instead" + ) if user is None or not user.admin: raise web.HTTPError(403) @@ -297,214 +298,6 @@ def metrics_authentication(self): raise web.HTTPError(403) -# Todo: Move all scope-related methods to scope module -class Scope(Enum): - ALL = True - - -def get_user_scopes(name): - """ - Scopes have a metascope 'all' that should be expanded to everything a user can do. - At the moment that is a user-filtered version (optional read) access to - users - users:name - users:groups - users:activity - users:servers - users:tokens - - """ - scope_list = [ - 'users', - 'users:name', - 'users:groups', - 'users:activity', - 'users:servers', - 'users:tokens', - ] - scope_list.extend(['read:' + scope for scope in scope_list]) - return {"{}!user={}".format(scope, name) for scope in scope_list} - - -def needs_scope_expansion(filter_, filter_value, sub_scope): - """ - Check if there is a requirements to expand the `group` scope to individual `user` scopes. - Assumptions: - filter_ != Scope.ALL - """ - if not (filter_ == 'user' and 'group' in sub_scope): - return False - if 'user' in sub_scope: - return filter_value not in sub_scope['user'] - else: - return True - - -def check_user_in_expanded_scope(handler, user_name, scope_group_names): - user = handler.find_user(user_name) - if user is None: - raise web.HTTPError(404, 'No such user found') - group_names = {group.name for group in user.groups} - return bool(set(scope_group_names) & group_names) - - -def _flatten_groups(groups): - user_set = set() - for group in groups: - user_set |= { - user.name for user in group.users - } # todo: I think this could be one query, no for loop - return user_set - - -def get_orm_class(kind): - class_dict = { - 'users': orm.User, - 'services': orm.Service, - 'tokens': orm.APIToken, - 'groups': orm.Group, - } - if kind not in class_dict: - raise ValueError( - "Kind must be one of %s, not %s" % (", ".join(class_dict), kind) - ) - return class_dict[kind] - - -def _get_scope_filter(db, req_scope, sub_scope): - # Rough draft - scope_translator = { - 'read:users': 'users', - 'read:services': 'services', - 'read:groups': 'groups', - } - if req_scope not in scope_translator: - raise AttributeError("Scope not found; scope filter not constructed") - kind = scope_translator[req_scope] - Class = get_orm_class(kind) - sub_scope_values = next(iter(sub_scope.values())) - query = db.query(Class).filter(Class.name.in_(sub_scope_values)) - scope_filter = [entry.name for entry in query.all()] - if 'group' in sub_scope and kind == 'users': - groups = db.query(orm.Group).filter(orm.Group.name.in_(sub_scope['group'])) - scope_filter += _flatten_groups(groups) - return set(scope_filter) - - -def check_scope(api_handler, req_scope, scopes, **kwargs): - # Parse user name and server name together - if 'user' in kwargs and 'server' in kwargs: - kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) - if req_scope not in scopes: - return False - if scopes[req_scope] == Scope.ALL: - return True - # Apply filters - sub_scope = scopes[req_scope] - if 'scope_filter' in kwargs: - scope_filter = _get_scope_filter(api_handler.db, req_scope, sub_scope) - return scope_filter - else: - # Interface change: Now can have multiple filters - for (filter_, filter_value) in kwargs.items(): - if filter_ in sub_scope and filter_value in sub_scope[filter_]: - return True - if needs_scope_expansion(filter_, filter_value, sub_scope): - group_names = sub_scope['group'] - if check_user_in_expanded_scope(api_handler, filter_value, group_names): - return True - return False - - -# Todo: make some methods private - - -def parse_scopes(scope_list): - """ - Parses scopes and filters in something akin to JSON style - - For instance, scope list ["users", "groups!group=foo", "users:servers!server=bar", "users:servers!server=baz"] - would lead to scope model - { - "users":scope.ALL, - "users:admin":{ - "user":[ - "alice" - ] - }, - "users:servers":{ - "server":[ - "bar", - "baz" - ] - } - } - """ - parsed_scopes = {} - for scope in scope_list: - base_scope, _, filter_ = scope.partition('!') - if not filter_: - parsed_scopes[base_scope] = Scope.ALL - elif base_scope not in parsed_scopes: - parsed_scopes[base_scope] = {} - if parsed_scopes[base_scope] != Scope.ALL: - key, _, val = filter_.partition('=') - if key not in parsed_scopes[base_scope]: - parsed_scopes[base_scope][key] = [] - parsed_scopes[base_scope][key].append(val) - return parsed_scopes - - -def needs_scope(scope): - """Decorator to restrict access to users or services with the required scope""" - - def scope_decorator(func): - @functools.wraps(func) - def _auth_func(self, *args, **kwargs): - sig = inspect.signature(func) - bound_sig = sig.bind(self, *args, **kwargs) - bound_sig.apply_defaults() - s_kwargs = {} - for resource in {'user', 'server', 'group', 'service'}: - resource_name = resource + '_name' - if resource_name in bound_sig.arguments: - resource_value = bound_sig.arguments[resource_name] - s_kwargs[resource] = resource_value - if 'scope_filter' in bound_sig.arguments: - s_kwargs['scope_filter'] = None - if 'all' in self.scopes and self.current_user: - # todo: What if no user is found? See test_api/test_referer_check - self.scopes |= get_user_scopes(self.current_user.name) - parsed_scopes = parse_scopes(self.scopes) - scope_filter = check_scope(self, scope, parsed_scopes, **s_kwargs) - if scope_filter: - if isinstance(scope_filter, set): - kwargs['scope_filter'] = scope_filter - return func(self, *args, **kwargs) - else: - # catching attr error occurring for older_requirements test - # could be done more ellegantly? - try: - request_path = self.request.path - except AttributeError: - request_path = 'the requested API' - app_log.warning( - "Not authorizing access to {}. Requires scope {}, not derived from scopes {}".format( - request_path, scope, ", ".join(self.scopes) - ) - ) - raise web.HTTPError( - 403, - "Action is not authorized with current scopes; requires {}".format( - scope - ), - ) - - return _auth_func - - return scope_decorator - - # Token utilities From e21713c24f7ceee34f2b3a823b44bd8e37d54749 Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Tue, 5 Jan 2021 12:57:26 +0100 Subject: [PATCH 046/270] Improved group expansion by reducing SQL queries --- jupyterhub/scopes.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index d0eba1a7..ac2e2ae8 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -58,15 +58,6 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): return bool(set(scope_group_names) & group_names) -def _flatten_groups(groups): - user_set = set() - for group in groups: - user_set |= { - user.name for user in group.users - } # todo: I think this could be one query, no for loop - return user_set - - def get_orm_class(kind): class_dict = { 'users': orm.User, @@ -94,11 +85,12 @@ def _get_scope_filter(db, req_scope, sub_scope): Class = get_orm_class(kind) sub_scope_values = next(iter(sub_scope.values())) query = db.query(Class).filter(Class.name.in_(sub_scope_values)) - scope_filter = [entry.name for entry in query.all()] + scope_filter = {entry.name for entry in query.all()} if 'group' in sub_scope and kind == 'users': - groups = db.query(orm.Group).filter(orm.Group.name.in_(sub_scope['group'])) - scope_filter += _flatten_groups(groups) - return set(scope_filter) + groups = orm.Group.name.in_(sub_scope['group']) + users_in_groups = db.query(orm.User).join(orm.Group.users).filter(groups) + scope_filter |= {user.name for user in users_in_groups} + return scope_filter def _check_scope(api_handler, req_scope, scopes, **kwargs): @@ -186,9 +178,8 @@ def needs_scope(scope): self.scopes |= get_user_scopes(self.current_user.name) parsed_scopes = _parse_scopes(self.scopes) scope_filter = _check_scope(self, scope, parsed_scopes, **s_kwargs) - if ( - scope_filter - ): # Todo: This checks if True or set of resource names. Not very nice yet + # todo: This checks if True or set of resource names. Not very nice yet + if scope_filter: if isinstance(scope_filter, set): kwargs['scope_filter'] = scope_filter return func(self, *args, **kwargs) @@ -200,7 +191,7 @@ def needs_scope(scope): except AttributeError: request_path = 'the requested API' app_log.warning( - "Not authorizing access to {}. Requires scope {}, not derived from scopes {}".format( + "Not authorizing access to {}. Requires scope {}, not derived from scopes [{}]".format( request_path, scope, ", ".join(self.scopes) ) ) From 82c837eb89a8bfb37f3a38de76c33105d05b27ad Mon Sep 17 00:00:00 2001 From: Omar Richardson Date: Tue, 5 Jan 2021 19:58:39 +0100 Subject: [PATCH 047/270] Refactored orm.get_class, improved resource filtereing --- jupyterhub/app.py | 2 +- jupyterhub/orm.py | 15 +++++++++++++++ jupyterhub/roles.py | 22 +++------------------- jupyterhub/scopes.py | 32 +++++++++++--------------------- jupyterhub/tests/test_api.py | 5 +++-- jupyterhub/tests/test_scopes.py | 11 ++++------- 6 files changed, 37 insertions(+), 50 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index c7571453..b8465a44 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1858,7 +1858,7 @@ class JupyterHub(Application): # make sure all users, services and tokens have at least one role (update with default) for bearer in role_bearers: - Class = roles.get_orm_class(bearer) + Class = orm.get_class(bearer) for obj in db.query(Class): if len(obj.roles) < 1: roles.update_roles(db, obj=obj, kind=bearer) diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 90ca63f7..828badce 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -978,3 +978,18 @@ def new_session_factory( # this off gives us a major performance boost session_factory = sessionmaker(bind=engine, expire_on_commit=expire_on_commit) return session_factory + + +def get_class(resource_name): + """Translates resource string names to ORM classes""" + class_dict = { + 'users': User, + 'services': Service, + 'tokens': APIToken, + 'groups': Group, + } + if resource_name not in class_dict: + raise ValueError( + "Kind must be one of %s, not %s" % (", ".join(class_dict), resource_name) + ) + return class_dict[resource_name] diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index bb2eab44..c46f7e19 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -135,25 +135,12 @@ def add_role(db, role_dict): db.commit() -def get_orm_class(kind): # Todo: merge and move to orm.py - if kind == 'users': - Class = orm.User - elif kind == 'services': - Class = orm.Service - elif kind == 'tokens': - Class = orm.APIToken - else: - raise ValueError("kind must be users, services or tokens, not %r" % kind) - - return Class - - def existing_only(func): """Decorator for checking if objects and roles exist""" def check_existence(db, objname, kind, rolename): - Class = get_orm_class(kind) + Class = orm.get_class(kind) obj = Class.find(db, objname) role = orm.Role.find(db, rolename) @@ -209,7 +196,7 @@ def update_roles(db, obj, kind, roles=None): """Updates object's roles if specified, assigns default if no roles specified""" - Class = get_orm_class(kind) + Class = orm.get_class(kind) user_role = orm.Role.find(db, 'user') if roles: @@ -252,11 +239,8 @@ def update_roles(db, obj, kind, roles=None): def mock_roles(app, name, kind): - """Loads and assigns default roles for mocked objects""" - - Class = get_orm_class(kind) - + Class = orm.get_class(kind) obj = Class.find(app.db, name=name) default_roles = get_default_roles() for role in default_roles: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index ac2e2ae8..a67d3ce4 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -22,7 +22,6 @@ def get_user_scopes(name): users:activity users:servers users:tokens - """ scope_list = [ 'users', @@ -51,29 +50,16 @@ def _needs_scope_expansion(filter_, filter_value, sub_scope): def _check_user_in_expanded_scope(handler, user_name, scope_group_names): + """Check if username is present in set of allowed groups""" user = handler.find_user(user_name) if user is None: raise web.HTTPError(404, 'No such user found') - group_names = {group.name for group in user.groups} + group_names = {group.name for group in user.groups} # Todo: Replace with SQL query return bool(set(scope_group_names) & group_names) -def get_orm_class(kind): - class_dict = { - 'users': orm.User, - 'services': orm.Service, - 'tokens': orm.APIToken, - 'groups': orm.Group, - } - if kind not in class_dict: - raise ValueError( - "Kind must be one of %s, not %s" % (", ".join(class_dict), kind) - ) - return class_dict[kind] - - def _get_scope_filter(db, req_scope, sub_scope): - # Rough draft + """Produce a filter for `*ListAPIHandlers* so that get method knows which models to return""" scope_translator = { 'read:users': 'users', 'read:services': 'services', @@ -82,7 +68,7 @@ def _get_scope_filter(db, req_scope, sub_scope): if req_scope not in scope_translator: raise AttributeError("Scope not found; scope filter not constructed") kind = scope_translator[req_scope] - Class = get_orm_class(kind) + Class = orm.get_class(kind) sub_scope_values = next(iter(sub_scope.values())) query = db.query(Class).filter(Class.name.in_(sub_scope_values)) scope_filter = {entry.name for entry in query.all()} @@ -94,6 +80,10 @@ def _get_scope_filter(db, req_scope, sub_scope): def _check_scope(api_handler, req_scope, scopes, **kwargs): + """Check if scopes satisfy requirements + Returns either Scope.ALL for unrestricted access, Scope.NONE for refused access or + an iterable with a filter + """ # Parse user name and server name together if 'user' in kwargs and 'server' in kwargs: kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) @@ -178,10 +168,10 @@ def needs_scope(scope): self.scopes |= get_user_scopes(self.current_user.name) parsed_scopes = _parse_scopes(self.scopes) scope_filter = _check_scope(self, scope, parsed_scopes, **s_kwargs) - # todo: This checks if True or set of resource names. Not very nice yet + # todo: This checks if True/False or set of resource names. Can be improved + if isinstance(scope_filter, set): + kwargs['scope_filter'] = scope_filter if scope_filter: - if isinstance(scope_filter, set): - kwargs['scope_filter'] = scope_filter return func(self, *args, **kwargs) else: # catching attr error occurring for older_requirements test diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index ff7b2389..a6883149 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -25,6 +25,7 @@ from .utils import async_requests from .utils import auth_header from .utils import find_user + # -------------------- # Authentication tests # -------------------- @@ -166,7 +167,7 @@ TIMESTAMP = normalize_timestamp(datetime.now().isoformat() + 'Z') @mark.user @mark.role -async def test_get_users(app): # todo: Sync with scope tests +async def test_get_users(app): db = app.db r = await api_request(app, 'users', headers=auth_header(db, 'admin')) assert r.status_code == 200 @@ -185,7 +186,7 @@ async def test_get_users(app): # todo: Sync with scope tests ] r = await api_request(app, 'users', headers=auth_header(db, 'user')) assert r.status_code == 200 - r_user_model = json.loads(r.text)[0] + r_user_model = r.json()[0] assert r_user_model['name'] == user_model['name'] diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 9b66c47a..49a794bb 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -217,7 +217,7 @@ async def test_expand_groups(app, user_name, in_group, status_code): async def test_user_filter(app): - user_name = 'rollerblade' + user_name = 'rita' test_role = { 'name': 'test', 'description': '', @@ -247,8 +247,7 @@ async def test_user_filter(app): app.db.commit() r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - data = json.loads(r.content) - result_names = {user['name'] for user in data} + result_names = {user['name'] for user in r.json()} assert result_names == name_in_scope @@ -278,8 +277,7 @@ async def test_user_filter_with_group(app): # todo: Move role setup to setup me app.db.commit() r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - data = json.loads(r.content) - result_names = {user['name'] for user in data} + result_names = {user['name'] for user in r.json()} assert result_names == name_set @@ -308,6 +306,5 @@ async def test_group_scope_filter(app): app.db.commit() r = await api_request(app, 'groups', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - data = json.loads(r.content) - result_names = {user['name'] for user in data} + result_names = {user['name'] for user in r.json()} assert result_names == {'sitwell', 'bluths'} From 1a513f8dd966873b8e4495e5121c5da41db45087 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 5 Jan 2021 15:50:01 +0100 Subject: [PATCH 048/270] added roles to groups --- docs/rest-api.yml | 9 ++++ jupyterhub/app.py | 19 ++----- jupyterhub/roles.py | 88 ++++++++++++++++++++----------- jupyterhub/tests/test_roles.py | 64 +++++++++------------- jupyterhub/tests/test_services.py | 1 + 5 files changed, 98 insertions(+), 83 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 869fa85b..22127456 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -41,6 +41,7 @@ securityDefinitions: read:groups: Read-only access to groups admin:groups: Grants access to create/delete groups read:services: Read-only access to services + read:hub: Read-only access to detailed information about JupyterHub proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy shutdown: Grants access to shutdown the Hub security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope all) or have both (either can be used)? @@ -71,6 +72,9 @@ paths: /info: get: summary: Get detailed info about JupyterHub + security: + - oauth2: + - read:hub description: | Detailed JupyterHub information, including Python version, JupyterHub's version and executable path, @@ -983,6 +987,11 @@ definitions: description: The names of users who are members of this group items: type: string + roles: + type: array + description: The names of roles this group has + items: + type: string Service: type: object properties: diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 28c70e29..98565f92 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1828,7 +1828,7 @@ class JupyterHub(Application): async def init_roles(self): """Load default and predefined roles into the database""" db = self.db - role_bearers = ['groups', 'users', 'services', 'tokens'] + role_bearers = ['users', 'services', 'tokens', 'groups'] # load default roles default_roles = roles.get_default_roles() @@ -1838,7 +1838,7 @@ class JupyterHub(Application): # load predefined roles from config file for predef_role in self.load_roles: roles.add_role(db, predef_role) - # add users, services and/or tokens + # add users, services, tokens and/or groups for bearer in role_bearers: if bearer in predef_role.keys(): for bname in predef_role[bearer]: @@ -1857,20 +1857,9 @@ class JupyterHub(Application): db, objname=bname, kind=bearer, rolename=predef_role['name'] ) - # make sure all users, services and tokens have at least one role (update with default) - # groups can be without a role but all group members should have the same role(s) as the group + # make sure role bearers have at least a default role for bearer in role_bearers: - Class = roles.get_orm_class(bearer) - if bearer == 'groups': - for group in db.query(Class): - for user in group.users: - rolenames = roles.get_rolenames(group.roles) - roles.update_roles(db, obj=user, kind='users', roles=rolenames) - else: - for obj in db.query(Class): - if len(obj.roles) < 1: - roles.update_roles(db, obj=obj, kind=bearer) - db.commit() + roles.check_for_default_roles(db, bearer) async def _add_tokens(self, token_dict, kind): """Add tokens for users or services to the database""" diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 6291a3ce..f8943558 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -3,6 +3,8 @@ # Distributed under the terms of the Modified BSD License. from itertools import chain +from sqlalchemy import func + from . import orm @@ -36,7 +38,7 @@ def get_default_roles(): { 'name': 'server', 'description': 'Post activity only', - 'scopes': ['users:activity!user=username'], + 'scopes': ['users:activity'], }, ] return default_roles @@ -157,16 +159,6 @@ def get_orm_class(kind): return Class -def get_rolenames(role_list): - - """Return a list of rolenames from a list of roles""" - - rolenames = [] - for role in role_list: - rolenames.append(role.name) - return rolenames - - def existing_only(func): """Decorator for checking if objects and roles exist""" @@ -228,6 +220,32 @@ def switch_default_role(db, obj, kind, admin): add_and_remove(db, obj, kind, admin_role, user_role) +def check_token_roles(db, token, role): + + """Returns a set of token scopes from its roles and a set of + token's owner scopes from their roles and their group roles""" + + token_scopes = get_subscopes(role) + owner = None + roles_to_check = [] + + # find the owner and their roles + if token.user_id: + owner = db.query(orm.User).get(token.user_id) + roles_to_check.extend(owner.roles) + # if user is a member of any groups, include the groups' roles as well + for group in owner.groups: + roles_to_check.extend(group.roles) + + elif token.service_id: + owner = db.query(orm.Service).get(token.service_id) + roles_to_check = owner.roles + + owner_scopes = get_subscopes(*roles_to_check) + + return token_scopes, owner_scopes + + def update_roles(db, obj, kind, roles=None): """Updates object's roles if specified, @@ -235,30 +253,21 @@ def update_roles(db, obj, kind, roles=None): Class = get_orm_class(kind) user_role = orm.Role.find(db, 'user') + admin_role = orm.Role.find(db, 'admin') if roles: for rolename in roles: if Class == orm.APIToken: - role = orm.Role.find(db, rolename) if role: - # compare the requested role permissions with the owner's permissions (scopes) - token_scopes = get_subscopes(role) - # find the owner and their roles - owner = None - if obj.user_id: - owner = db.query(orm.User).get(obj.user_id) - elif obj.service_id: - owner = db.query(orm.Service).get(obj.service_id) - if owner: - owner_scopes = get_subscopes(*owner.roles) - if token_scopes.issubset(owner_scopes): - role.tokens.append(obj) - else: - raise ValueError( - 'Requested token role %r has higher permissions than the token owner' - % rolename - ) + token_scopes, owner_scopes = check_token_roles(db, obj, role) + if token_scopes.issubset(owner_scopes): + role.tokens.append(obj) + else: + raise ValueError( + 'Requested token role %r has higher permissions than the token owner' + % rolename + ) else: raise NameError('Role %r does not exist' % rolename) else: @@ -272,12 +281,31 @@ def update_roles(db, obj, kind, roles=None): elif Class == orm.APIToken: if len(obj.roles) < 1 and obj.user is not None: user_role.tokens.append(obj) - db.commit() + db.commit() # users and services can have 'user' or 'admin' roles as default else: switch_default_role(db, obj, kind, obj.admin) +def check_for_default_roles(db, bearer): + + """Checks that all role bearers have at least one role (default if none). + Groups can be without a role""" + + Class = get_orm_class(bearer) + if Class == orm.Group: + pass + else: + for obj in ( + db.query(Class) + .outerjoin(orm.Role, Class.roles) + .group_by(Class.id) + .having(func.count(orm.Role.id) == 0) + ): + update_roles(db, obj=obj, kind=bearer) + db.commit() + + def mock_roles(app, name, kind): """Loads and assigns default roles for mocked objects""" diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 90c108fd..06e9fff1 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -30,14 +30,6 @@ def test_orm_roles(db): db.add(group_role) db.commit() - group_role = orm.Role(name='group', scopes=['read:users']) - db.add(group_role) - db.commit() - - group_role = orm.Role(name='group', scopes=['read:users']) - db.add(group_role) - db.commit() - user = orm.User(name='falafel') db.add(user) db.commit() @@ -367,46 +359,21 @@ async def test_load_roles_groups(tmpdir, request): hub = MockHub(**kwargs) hub.init_db() db = hub.db - hub.authenticator.allowed_users = ['cyclops', 'gandalf', 'bilbo', 'gargamel'] - await hub.init_users() await hub.init_groups() await hub.init_roles() assist_role = orm.Role.find(db, name='assistant') head_role = orm.Role.find(db, name='head') - user_role = orm.Role.find(db, name='user') group1 = orm.Group.find(db, name='group1') group2 = orm.Group.find(db, name='group2') group3 = orm.Group.find(db, name='group3') - gandalf = orm.User.find(db, name='gandalf') - bilbo = orm.User.find(db, name='bilbo') - gargamel = orm.User.find(db, name='gargamel') - cyclops = orm.User.find(db, name='cyclops') - # test group roles assert group1.roles == [] assert group2 in assist_role.groups assert group3 in head_role.groups - # test group members' roles - assert assist_role in bilbo.roles - assert assist_role in gargamel.roles - assert head_role in cyclops.roles - - # check the default user_role assignment - # FIXME - should users with group roles still have default? - assert user_role in gandalf.roles - assert user_role not in bilbo.roles - assert user_role not in gargamel.roles - assert user_role not in cyclops.roles - - -# FIXME -# @mark.role -# async def test_group_roles_delete_cascade(tmpdir, request): - @mark.role async def test_load_roles_tokens(tmpdir, request): @@ -465,16 +432,37 @@ async def test_load_roles_tokens(tmpdir, request): @mark.parametrize( "headers, role_list, status", [ + # no role requested - gets default 'user' role ({}, None, 200), - ({}, ['reader'], 200), + # role scopes within the user's default 'user' role + ({}, ['self-reader'], 200), + # role scopes outside of the user's role but within the group's role scopes of which the user is a member + ({}, ['users-reader'], 200), + # non-existing role request ({}, ['non-existing'], 404), - ({}, ['user_creator'], 403), + # role scopes outside of both user's role and group's role scopes + ({}, ['users-creator'], 403), ], ) async def test_get_new_token_via_api(app, headers, role_list, status): user = add_user(app.db, app, name='user') - roles.add_role(app.db, {'name': 'reader', 'scopes': ['read:all']}) - roles.add_role(app.db, {'name': 'user_creator', 'scopes': ['admin:users']}) + + roles.add_role(app.db, {'name': 'self-reader', 'scopes': ['read:all']}) + roles.add_role(app.db, {'name': 'users-reader', 'scopes': ['read:users']}) + roles.add_role(app.db, {'name': 'users-creator', 'scopes': ['admin:users']}) + # add role for a group + roles.add_role(app.db, {'name': 'group_role', 'scopes': ['read:users']}) + + # create a group and add the user and group_role + group = orm.Group.find(app.db, 'test_group') + if not group: + group = orm.Group(name='test_group') + app.db.add(group) + group.users.append(user) + group_role = orm.Role.find(app.db, 'group_role') + group.roles.append(group_role) + app.db.commit() + if role_list: body = json.dumps({'roles': role_list}) else: @@ -493,7 +481,7 @@ async def test_get_new_token_via_api(app, headers, role_list, status): if not role_list: assert reply['roles'] == ['user'] else: - assert reply['roles'] == ['reader'] + assert reply['roles'] == role_list token_id = reply['id'] # delete the token diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index fd46dd0f..9f42d0dd 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -90,6 +90,7 @@ async def test_external_service(app): await maybe_future(app.init_services()) await app.init_api_tokens() await app.proxy.add_all_services(app._service_map) + await app.init_roles() service = app._service_map[name] url = public_url(app, service) + '/api/users' From 7e30e1998c9b25b28bf4add3b758e459c18a1dda Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 11 Jan 2021 20:39:22 +0100 Subject: [PATCH 049/270] Fixed test --- jupyterhub/tests/test_services.py | 1 + 1 file changed, 1 insertion(+) diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index fd46dd0f..379f92aa 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -88,6 +88,7 @@ async def test_external_service(app): } ] await maybe_future(app.init_services()) + await maybe_future(app.init_roles()) await app.init_api_tokens() await app.proxy.add_all_services(app._service_map) From e9ad8ca8acce398086c6973abf2c826d5c7bd9fa Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 11 Jan 2021 20:51:04 +0100 Subject: [PATCH 050/270] Stacking scope decorators works --- jupyterhub/handlers/pages.py | 2 ++ jupyterhub/tests/test_scopes.py | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index 7a6f11b2..d16e9e9b 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -455,7 +455,9 @@ class AdminHandler(BaseHandler): """Render the admin page.""" @web.authenticated + @needs_scope('users') @needs_scope('admin:users') + @needs_scope('admin:users:servers') async def get(self): page, per_page, offset = Pagination(config=self.config).get_page_args(self) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 49a794bb..911f310e 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -110,6 +110,11 @@ class MockAPIHandler: def other_thing(self, other_name): return True + @needs_scope('users') + @needs_scope('read:services') + def secret_thing(self): + return True + @mark.parametrize( "scopes, method, arguments, is_allowed", @@ -176,6 +181,23 @@ def test_scope_method_access(scopes, method, arguments, is_allowed): api_call(*arguments) +def test_double_scoped_method_succeeds(): + obj = MockAPIHandler() + obj.current_user = mock.Mock(name='lucille') + obj.request = mock.Mock(spec=HTTPServerRequest) + obj.scopes = {'users', 'read:services'} + assert obj.secret_thing() + + +def test_double_scoped_method_denials(): + obj = MockAPIHandler() + obj.current_user = mock.Mock(name='lucille2') + obj.request = mock.Mock(spec=HTTPServerRequest) + obj.scopes = {'users', 'read:groups'} + with pytest.raises(web.HTTPError): + obj.secret_thing() + + @mark.parametrize( "user_name, in_group, status_code", [ @@ -252,7 +274,7 @@ async def test_user_filter(app): async def test_user_filter_with_group(app): # todo: Move role setup to setup method - user_name = 'sally' + user_name = 'sally' # Fixme: fails randomly? scopes not always loaded? test_role = { 'name': 'test', 'description': '', From 3f47860d176b518adec4dba8edc453041919c06a Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 14 Jan 2021 10:25:17 +0100 Subject: [PATCH 051/270] Fixed test error --- jupyterhub/tests/test_scopes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 911f310e..1f78fef1 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -274,7 +274,7 @@ async def test_user_filter(app): async def test_user_filter_with_group(app): # todo: Move role setup to setup method - user_name = 'sally' # Fixme: fails randomly? scopes not always loaded? + user_name = 'sally' test_role = { 'name': 'test', 'description': '', @@ -290,9 +290,9 @@ async def test_user_filter_with_group(app): # todo: Move role setup to setup me group = orm.Group(name=group_name) app.db.add(group) for name in name_set: - user = add_user(app.db, name=name) + new_user = add_user(app.db, name=name) if name not in group.users: - group.users.append(user) + group.users.append(new_user) kind = 'users' roles.update_roles(app.db, user, kind, roles=['test']) roles.remove_obj(app.db, user_name, kind, 'user') From f90b4e13df61a1f318ad6378221bda570bb0333c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 15 Jan 2021 15:32:58 +0100 Subject: [PATCH 052/270] added token role check during loading config file and logs for role creation/changes/assignements --- jupyterhub/app.py | 13 +- jupyterhub/roles.py | 75 ++++++++++-- jupyterhub/tests/conftest.py | 2 +- jupyterhub/tests/test_roles.py | 210 ++++++++++++++++++++++++++++----- 4 files changed, 255 insertions(+), 45 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 98565f92..51b081cb 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1828,17 +1828,20 @@ class JupyterHub(Application): async def init_roles(self): """Load default and predefined roles into the database""" db = self.db - role_bearers = ['users', 'services', 'tokens', 'groups'] + role_bearers = ['users', 'services', 'groups'] # load default roles + self.log.debug('Loading default roles to database') default_roles = roles.get_default_roles() for role in default_roles: roles.add_role(db, role) # load predefined roles from config file + self.log.debug('Loading predefined roles from config file to database') for predef_role in self.load_roles: roles.add_role(db, predef_role) - # add users, services, tokens and/or groups + # add users, services, and/or groups, + # tokens need to be checked for permissions for bearer in role_bearers: if bearer in predef_role.keys(): for bname in predef_role[bearer]: @@ -1861,6 +1864,12 @@ class JupyterHub(Application): for bearer in role_bearers: roles.check_for_default_roles(db, bearer) + # now add roles to tokens if their owner's permissions allow + roles.add_predef_roles_tokens(db, self.load_roles) + + # check tokens for default roles + roles.check_for_default_roles(db, bearer='tokens') + async def _add_tokens(self, token_dict, kind): """Add tokens for users or services to the database""" if kind == 'user': diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index f8943558..b943749e 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -4,6 +4,7 @@ from itertools import chain from sqlalchemy import func +from tornado.log import app_log from . import orm @@ -122,8 +123,10 @@ def add_role(db, role_dict): """Adds a new role to database or modifies an existing one""" + default_roles = get_default_roles() + if 'name' not in role_dict.keys(): - raise ValueError('Role must have a name') + raise ValueError('Role definition in config file must have a name!') else: name = role_dict['name'] role = orm.Role.find(db, name) @@ -134,11 +137,17 @@ def add_role(db, role_dict): if role is None: role = orm.Role(name=name, description=description, scopes=scopes) db.add(role) + if role_dict not in default_roles: + app_log.info('Adding role %s to database', name) else: if description: - role.description = description + if role.description != description: + app_log.info('Changing role %s description to %s', name, description) + role.description = description if scopes: - role.scopes = scopes + if role.scopes != scopes: + app_log.info('Changing role %s scopes to %s', name, scopes) + role.scopes = scopes db.commit() @@ -184,9 +193,15 @@ def add_obj(db, objname, kind, rolename): """Adds a role for users, services, tokens or groups""" + if kind == 'tokens': + log_objname = objname + else: + log_objname = objname.name + if rolename not in objname.roles: objname.roles.append(rolename) db.commit() + app_log.info('Adding role %s for %s: %s', rolename.name, kind[:-1], log_objname) @existing_only @@ -194,9 +209,17 @@ def remove_obj(db, objname, kind, rolename): """Removes a role for users, services or tokens""" + if kind == 'tokens': + log_objname = objname + else: + log_objname = objname.name + if rolename in objname.roles: objname.roles.remove(rolename) db.commit() + app_log.info( + 'Removing role %s for %s: %s', rolename.name, kind[:-1], log_objname + ) def switch_default_role(db, obj, kind, admin): @@ -260,36 +283,67 @@ def update_roles(db, obj, kind, roles=None): if Class == orm.APIToken: role = orm.Role.find(db, rolename) if role: + app_log.debug( + 'Checking token permissions against requested role %s', rolename + ) token_scopes, owner_scopes = check_token_roles(db, obj, role) if token_scopes.issubset(owner_scopes): role.tokens.append(obj) + app_log.info( + 'Adding role %s for %s: %s', role.name, kind[:-1], obj + ) else: raise ValueError( - 'Requested token role %r has higher permissions than the token owner' - % rolename + 'Requested token role %r of %r with scopes %r has higher permissions than the owner scopes %r' + % (rolename, obj, token_scopes, owner_scopes) ) else: raise NameError('Role %r does not exist' % rolename) else: add_obj(db, objname=obj.name, kind=kind, rolename=rolename) else: + # CHECK ME - Does the default role assignment here make sense? + # groups can be without a role if Class == orm.Group: pass # tokens can have only 'user' role as default # assign the default only for user tokens + # service tokens with no specified role remain without any role (no default) elif Class == orm.APIToken: + app_log.debug('Assigning default roles to tokens') if len(obj.roles) < 1 and obj.user is not None: user_role.tokens.append(obj) db.commit() + app_log.info('Adding role %s to token %s', 'user', obj) # users and services can have 'user' or 'admin' roles as default else: + app_log.debug('Assigning default roles to %s', kind) switch_default_role(db, obj, kind, obj.admin) +def add_predef_roles_tokens(db, predef_roles): + + """Adds tokens to predefined roles in config file + if their permissions allow""" + + for predef_role in predef_roles: + if 'tokens' in predef_role.keys(): + token_role = orm.Role.find(db, name=predef_role['name']) + for token_name in predef_role['tokens']: + token = orm.APIToken.find(db, token_name) + if token is None: + raise ValueError( + "Token %r does not exist and cannot assign it to role %r" + % (token_name, token_role.name) + ) + else: + update_roles(db, obj=token, kind='tokens', roles=[token_role.name]) + + def check_for_default_roles(db, bearer): - """Checks that all role bearers have at least one role (default if none). + """Checks that role bearers have at least one role (default if none). Groups can be without a role""" Class = get_orm_class(bearer) @@ -306,14 +360,15 @@ def check_for_default_roles(db, bearer): db.commit() -def mock_roles(app, name, kind): +def mock_roles(db, name, kind): """Loads and assigns default roles for mocked objects""" Class = get_orm_class(kind) - obj = Class.find(app.db, name=name) + obj = Class.find(db, name=name) default_roles = get_default_roles() for role in default_roles: - add_role(app.db, role) - update_roles(db=app.db, obj=obj, kind=kind) + add_role(db, role) + app_log.info('Assigning default roles to mocked %s: %s', kind[:-1], name) + update_roles(db=db, obj=obj, kind=kind) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 45bfd203..93b6b77c 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -246,7 +246,7 @@ def _mockservice(request, app, url=False): ): app.services = [spec] app.init_services() - mock_roles(app, name, 'services') + mock_roles(app.db, name, 'services') assert name in app._service_map service = app._service_map[name] diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 06e9fff1..3082cd24 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -277,8 +277,13 @@ async def test_load_roles_services(tmpdir, request): services = [ {'name': 'cull_idle', 'api_token': 'some-token'}, {'name': 'user_service', 'api_token': 'some-other-token'}, - {'name': 'admin_service', 'api_token': 'secret-token', 'admin': True}, + {'name': 'admin_service', 'api_token': 'secret-token'}, ] + service_tokens = { + 'some-token': 'cull_idle', + 'some-other-token': 'user_service', + 'secret-token': 'admin_service', + } roles_to_load = [ { 'name': 'culler', @@ -287,24 +292,21 @@ async def test_load_roles_services(tmpdir, request): 'services': ['cull_idle'], }, ] - kwargs = {'load_roles': roles_to_load} + kwargs = { + 'load_roles': roles_to_load, + 'services': services, + 'service_tokens': service_tokens, + } ssl_enabled = getattr(request.module, "ssl_enabled", False) if ssl_enabled: kwargs['internal_certs_location'] = str(tmpdir) hub = MockHub(**kwargs) hub.init_db() db = hub.db - # clean db of previous services and add testing ones - for service in db.query(orm.Service): - db.delete(service) - db.commit() - for service in services: - orm_service = orm.Service.find(db, name=service['name']) - if orm_service is None: - # not found, create a new one - orm_service = orm.Service(name=service['name']) - db.add(orm_service) - orm_service.admin = service.get('admin', False) + await hub.init_api_tokens() + # make 'admin_service' admin + admin_service = orm.Service.find(db, 'admin_service') + admin_service.admin = True db.commit() await hub.init_roles() @@ -329,6 +331,11 @@ async def test_load_roles_services(tmpdir, request): db.delete(service) db.commit() + # delete the test tokens + for token in db.query(orm.APIToken): + db.delete(token) + db.commit() + @mark.role async def test_load_roles_groups(tmpdir, request): @@ -376,30 +383,23 @@ async def test_load_roles_groups(tmpdir, request): @mark.role -async def test_load_roles_tokens(tmpdir, request): - services = [ - {'name': 'cull_idle', 'admin': True, 'api_token': 'another-secret-token'} - ] +async def test_load_roles_user_tokens(tmpdir, request): user_tokens = { 'secret-token': 'cyclops', + 'secrety-token': 'gandalf', 'super-secret-token': 'admin', } - service_tokens = { - 'another-secret-token': 'cull_idle', - } roles_to_load = [ { - 'name': 'culler', - 'description': 'Cull idle servers', - 'scopes': ['users:servers', 'admin:servers'], - 'tokens': ['another-secret-token'], + 'name': 'reader', + 'description': 'Read-only own model', + 'scopes': ['read:all'], + 'tokens': ['secrety-token'], }, ] kwargs = { 'load_roles': roles_to_load, - 'services': services, 'api_tokens': user_tokens, - 'service_tokens': service_tokens, } ssl_enabled = getattr(request.module, "ssl_enabled", False) if ssl_enabled: @@ -413,12 +413,10 @@ async def test_load_roles_tokens(tmpdir, request): await hub.init_api_tokens() await hub.init_roles() - # test if another-secret-token has culler role - service = orm.Service.find(db, 'cull_idle') - culler_role = orm.Role.find(db, 'culler') - token = orm.APIToken.find(db, 'another-secret-token') - assert len(token.roles) == 1 - assert culler_role in token.roles + # test if gandalf's token has the 'reader' role + reader_role = orm.Role.find(db, 'reader') + token = orm.APIToken.find(db, 'secrety-token') + assert reader_role in token.roles # test if all other tokens have default 'user' role user_role = orm.Role.find(db, 'user') @@ -427,6 +425,154 @@ async def test_load_roles_tokens(tmpdir, request): s_sec_token = orm.APIToken.find(db, 'super-secret-token') assert user_role in s_sec_token.roles + # delete the test tokens + for token in db.query(orm.APIToken): + db.delete(token) + db.commit() + + +@mark.role +async def test_load_roles_user_tokens_not_allowed(tmpdir, request): + user_tokens = { + 'secret-token': 'bilbo', + } + roles_to_load = [ + { + 'name': 'user-reader', + 'description': 'Read-only any user model', + 'scopes': ['read:users'], + 'tokens': ['secret-token'], + }, + ] + kwargs = { + 'load_roles': roles_to_load, + 'api_tokens': user_tokens, + } + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + hub.authenticator.allowed_users = ['bilbo'] + await hub.init_users() + await hub.init_api_tokens() + + response = 'allowed' + # bilbo has only default 'user' role + # while bilbo's token is requesting role with higher permissions + try: + await hub.init_roles() + except ValueError: + response = 'denied' + + assert response == 'denied' + + # delete the test tokens + for token in db.query(orm.APIToken): + db.delete(token) + db.commit() + + +@mark.role +async def test_load_roles_service_tokens(tmpdir, request): + services = [{'name': 'cull_idle', 'api_token': 'another-secret-token'}] + service_tokens = { + 'another-secret-token': 'cull_idle', + } + roles_to_load = [ + { + 'name': 'culler', + 'description': 'Cull idle servers', + 'scopes': ['users:servers', 'admin:users:servers'], + 'tokens': ['another-secret-token'], + }, + ] + kwargs = { + 'load_roles': roles_to_load, + 'services': services, + 'service_tokens': service_tokens, + } + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + await hub.init_api_tokens() + # make the service admin + service = orm.Service.find(db, 'cull_idle') + service.admin = True + await hub.init_roles() + + # test if another-secret-token has culler role + culler_role = orm.Role.find(db, 'culler') + token = orm.APIToken.find(db, 'another-secret-token') + assert len(token.roles) == 1 + assert culler_role in token.roles + + # delete the test services + for service in db.query(orm.Service): + db.delete(service) + db.commit() + + # delete the test tokens + for token in db.query(orm.APIToken): + db.delete(token) + db.commit() + + +@mark.role +async def test_load_roles_service_tokens_not_allowed(tmpdir, request): + services = [{'name': 'some-service', 'api_token': 'secret-token'}] + service_tokens = { + 'secret-token': 'some-service', + } + roles_to_load = [ + { + 'name': 'user-reader', + 'description': 'Read-only user models', + 'scopes': ['read:users'], + 'services': ['some-service'], + }, + # 'culler' role has higher permissions that the token's owner 'some-service' + { + 'name': 'culler', + 'description': 'Cull idle servers', + 'scopes': ['users:servers', 'admin:users:servers'], + 'tokens': ['secret-token'], + }, + ] + kwargs = { + 'load_roles': roles_to_load, + 'services': services, + 'service_tokens': service_tokens, + } + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + await hub.init_api_tokens() + response = 'allowed' + try: + await hub.init_roles() + except ValueError: + response = 'denied' + + assert response == 'denied' + + # delete the test services + for service in db.query(orm.Service): + db.delete(service) + db.commit() + + # delete the test tokens + for token in db.query(orm.APIToken): + db.delete(token) + db.commit() + @mark.role @mark.parametrize( From d0369197d461d1f2a547fca609194da9d372eaef Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 25 Jan 2021 21:36:52 +0100 Subject: [PATCH 053/270] Fixed a bug, added some docs, but running into DB/API issues --- jupyterhub/apihandlers/hub.py | 4 +- jupyterhub/apihandlers/services.py | 2 +- jupyterhub/scopes.py | 5 +- jupyterhub/tests/test_scopes.py | 119 +++++++++++++++++++---------- 4 files changed, 84 insertions(+), 46 deletions(-) diff --git a/jupyterhub/apihandlers/hub.py b/jupyterhub/apihandlers/hub.py index 80e9c986..3a4787f5 100644 --- a/jupyterhub/apihandlers/hub.py +++ b/jupyterhub/apihandlers/hub.py @@ -56,6 +56,7 @@ class RootAPIHandler(APIHandler): def get(self): """GET /api/ returns info about the Hub and its API. + It is not an authenticated endpoint For now, it just returns the version of JupyterHub itself. """ data = {'version': __version__} @@ -67,7 +68,8 @@ class InfoAPIHandler(APIHandler): def get(self): """GET /api/info returns detailed info about the Hub and its API. - Currently, it returns information on the python version, spawner and authenticator + Currently, it returns information on the python version, spawner and authenticator. + Since this information might be sensitive, it is an authenticated endpoint """ def _class_info(typ): diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 792d4b52..13e46724 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -33,7 +33,7 @@ class ServiceListAPIHandler(APIHandler): def get(self, scope_filter=None): data = {name: service_model(service) for name, service in self.services.items()} if scope_filter is not None: - data = dict(filter(lambda tup: tup[0] in scope_filter)) + data = dict(filter(lambda tup: tup[0] in scope_filter, data.items())) self.write(json.dumps(data)) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index a67d3ce4..a06b8910 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -68,9 +68,9 @@ def _get_scope_filter(db, req_scope, sub_scope): if req_scope not in scope_translator: raise AttributeError("Scope not found; scope filter not constructed") kind = scope_translator[req_scope] - Class = orm.get_class(kind) + Resource = orm.get_class(kind) sub_scope_values = next(iter(sub_scope.values())) - query = db.query(Class).filter(Class.name.in_(sub_scope_values)) + query = db.query(Resource).filter(Resource.name.in_(sub_scope_values)) scope_filter = {entry.name for entry in query.all()} if 'group' in sub_scope and kind == 'users': groups = orm.Group.name.in_(sub_scope['group']) @@ -164,7 +164,6 @@ def needs_scope(scope): if 'scope_filter' in bound_sig.arguments: s_kwargs['scope_filter'] = None if 'all' in self.scopes and self.current_user: - # todo: What if no user is found? See test_api/test_referer_check self.scopes |= get_user_scopes(self.current_user.name) parsed_scopes = _parse_scopes(self.scopes) scope_filter = _check_scope(self, scope, parsed_scopes, **s_kwargs) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 911f310e..aac08837 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -13,9 +13,11 @@ from ..scopes import _check_scope from ..scopes import _parse_scopes from ..scopes import needs_scope from ..scopes import Scope +from .mocking import MockHub from .utils import add_user from .utils import api_request from .utils import auth_header +from .utils import public_url def test_scope_constructor(): @@ -125,6 +127,7 @@ class MockAPIHandler: (['read:users'], 'user_thing', ('gob',), False), (['read:users'], 'user_thing', ('michael',), False), (['users!user=george'], 'user_thing', ('george',), True), + (['users!user=george'], 'user_thing', ('fake_user',), False), (['users!user=george'], 'user_thing', ('oscar',), False), (['users!user=george', 'users!user=oscar'], 'user_thing', ('oscar',), True), (['users:servers'], 'server_thing', ('user1', 'server_1'), True), @@ -198,6 +201,16 @@ def test_double_scoped_method_denials(): obj.secret_thing() +def generate_test_role(user_name, scopes, role_name='test'): + role = { + 'name': role_name, + 'description': '', + 'users': [user_name], + 'scopes': scopes, + } + return role + + @mark.parametrize( "user_name, in_group, status_code", [ @@ -238,19 +251,28 @@ async def test_expand_groups(app, user_name, in_group, status_code): assert r.status_code == status_code +async def test_non_existing_user(app): + user_name = 'shade' + user = add_user(app.db, name=user_name) + app.db.commit() + app.db.delete(user) + app.db.commit() + print(app.db.query(orm.User).all()) # no shade + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + print(r.json()) # shade + # Fixme: no shade in db, user models still throw shade + assert r.status_code == 404 + + async def test_user_filter(app): user_name = 'rita' - test_role = { - 'name': 'test', - 'description': '', - 'users': [user_name], - 'scopes': [ - 'read:users!user=lindsay', - 'read:users!user=gob', - 'read:users!user=oscar', - ], - } + user = add_user(app.db, name=user_name) + app.db.commit() + scopes = ['read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar'] + test_role = generate_test_role(user, scopes) roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') name_in_scope = {'lindsay', 'oscar', 'gob'} outside_scope = {'maeby', 'marta'} group_name = 'bluth' @@ -262,10 +284,6 @@ async def test_user_filter(app): user = add_user(app.db, name=name) if name not in group.users: group.users.append(user) - kind = 'users' - user = add_user(app.db, name=user_name) - roles.update_roles(app.db, user, kind, roles=['test']) - roles.remove_obj(app.db, user_name, kind, 'user') app.db.commit() r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 @@ -273,16 +291,44 @@ async def test_user_filter(app): assert result_names == name_in_scope -async def test_user_filter_with_group(app): # todo: Move role setup to setup method - user_name = 'sally' # Fixme: fails randomly? scopes not always loaded? - test_role = { - 'name': 'test', - 'description': '', - 'users': [user_name], - 'scopes': ['read:users!group=sitwell'], - } - roles.add_role(app.db, test_role) +async def test_service_filter(app): + services = [ + {'name': 'cull_idle', 'api_token': 'some-token'}, + {'name': 'user_service', 'api_token': 'some-other-token'}, + ] + for service in app.db.query(orm.Service): + app.db.delete(service) + for service in services: + orm_service = orm.Service.find(app.db, name=service['name']) + if orm_service is None: + # not found, create a new one + orm_service = orm.Service(name=service['name']) + app.db.add(orm_service) + app.db.commit() + app.init_services() + user_name = 'buster' user = add_user(app.db, name=user_name) + app.db.commit() + test_role = generate_test_role(user, ['read:services!service=cull_idle']) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + r = await api_request(app, 'services', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + result_names = {service['name'] for service in r.json()} + # Fixme: Again DB/API sync issue + assert result_names == {'culler'} + + +async def test_user_filter_with_group(app): + # Move role setup to setup method? + user_name = 'sally' + add_user(app.db, name=user_name) + external_user_name = 'britta' + add_user(app.db, name=external_user_name) + test_role = generate_test_role(user_name, ['read:users!group=sitwell']) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + name_set = {'sally', 'stan'} group_name = 'sitwell' group = orm.Group.find(app.db, name=group_name) @@ -293,40 +339,31 @@ async def test_user_filter_with_group(app): # todo: Move role setup to setup me user = add_user(app.db, name=name) if name not in group.users: group.users.append(user) - kind = 'users' - roles.update_roles(app.db, user, kind, roles=['test']) - roles.remove_obj(app.db, user_name, kind, 'user') app.db.commit() + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 result_names = {user['name'] for user in r.json()} assert result_names == name_set + assert external_user_name not in result_names async def test_group_scope_filter(app): user_name = 'rollerblade' - test_role = { - 'name': 'test', - 'description': '', - 'users': [user_name], - 'scopes': [ - 'read:groups!group=sitwell', - 'read:groups!group=bluths', - ], - } + add_user(app.db, name=user_name) + scopes = ['read:groups!group=sitwell', 'read:groups!group=bluth'] + test_role = generate_test_role(user_name, scopes) roles.add_role(app.db, test_role) - user = add_user(app.db, name=user_name) - group_set = {'sitwell', 'bluths', 'austero'} + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + + group_set = {'sitwell', 'bluth', 'austero'} for group_name in group_set: group = orm.Group.find(app.db, name=group_name) if not group: group = orm.Group(name=group_name) app.db.add(group) - kind = 'users' - roles.update_roles(app.db, user, kind, roles=['test']) - roles.remove_obj(app.db, user_name, kind, 'user') app.db.commit() r = await api_request(app, 'groups', headers=auth_header(app.db, user_name)) assert r.status_code == 200 result_names = {user['name'] for user in r.json()} - assert result_names == {'sitwell', 'bluths'} + assert result_names == {'sitwell', 'bluth'} From 590bd1a849d8be21666d752e18b1abb317d64095 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 26 Jan 2021 14:20:39 +0100 Subject: [PATCH 054/270] Fixed tests --- jupyterhub/tests/test_scopes.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index aac08837..e918cebc 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -254,14 +254,11 @@ async def test_expand_groups(app, user_name, in_group, status_code): async def test_non_existing_user(app): user_name = 'shade' user = add_user(app.db, name=user_name) + auth_ = auth_header(app.db, user_name) + app.users.delete(user) app.db.commit() - app.db.delete(user) - app.db.commit() - print(app.db.query(orm.User).all()) # no shade - r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) - print(r.json()) # shade - # Fixme: no shade in db, user models still throw shade - assert r.status_code == 404 + r = await api_request(app, 'users', headers=auth_) + assert r.status_code == 403 async def test_user_filter(app): @@ -296,15 +293,8 @@ async def test_service_filter(app): {'name': 'cull_idle', 'api_token': 'some-token'}, {'name': 'user_service', 'api_token': 'some-other-token'}, ] - for service in app.db.query(orm.Service): - app.db.delete(service) for service in services: - orm_service = orm.Service.find(app.db, name=service['name']) - if orm_service is None: - # not found, create a new one - orm_service = orm.Service(name=service['name']) - app.db.add(orm_service) - app.db.commit() + app.services.append(service) app.init_services() user_name = 'buster' user = add_user(app.db, name=user_name) @@ -314,9 +304,8 @@ async def test_service_filter(app): roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') r = await api_request(app, 'services', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - result_names = {service['name'] for service in r.json()} - # Fixme: Again DB/API sync issue - assert result_names == {'culler'} + service_names = set(r.json().keys()) + assert service_names == {'cull_idle'} async def test_user_filter_with_group(app): From b160a0e344ecddefc6d6104b5a2eb0af52dec71f Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 26 Jan 2021 16:08:23 +0100 Subject: [PATCH 055/270] Consistent messages regardless of whether resources exist or not --- jupyterhub/apihandlers/services.py | 1 + jupyterhub/scopes.py | 8 +++-- jupyterhub/tests/test_api.py | 4 +-- jupyterhub/tests/test_scopes.py | 52 ++++++++++++++++++++++++++---- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 13e46724..0b4cced1 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -39,6 +39,7 @@ class ServiceListAPIHandler(APIHandler): def admin_or_self(method): """Decorator for restricting access to either the target service or admin""" + """***Deprecated in favor of RBAC, use scope-based decorator***""" def decorated_method(self, name): current = self.current_user diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index a06b8910..c06e6f59 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -53,7 +53,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): """Check if username is present in set of allowed groups""" user = handler.find_user(user_name) if user is None: - raise web.HTTPError(404, 'No such user found') + raise web.HTTPError(404, "No access to resources or resources not found") group_names = {group.name for group in user.groups} # Todo: Replace with SQL query return bool(set(scope_group_names) & group_names) @@ -66,7 +66,7 @@ def _get_scope_filter(db, req_scope, sub_scope): 'read:groups': 'groups', } if req_scope not in scope_translator: - raise AttributeError("Scope not found; scope filter not constructed") + raise AttributeError("Internal error: inconsistent scope situation") kind = scope_translator[req_scope] Resource = orm.get_class(kind) sub_scope_values = next(iter(sub_scope.values())) @@ -97,6 +97,8 @@ def _check_scope(api_handler, req_scope, scopes, **kwargs): scope_filter = _get_scope_filter(api_handler.db, req_scope, sub_scope) return scope_filter else: + if not kwargs: + return False # Separated from 404 error below because in this case we don't leak information # Interface change: Now can have multiple filters for (filter_, filter_value) in kwargs.items(): if filter_ in sub_scope and filter_value in sub_scope[filter_]: @@ -107,7 +109,7 @@ def _check_scope(api_handler, req_scope, scopes, **kwargs): api_handler, filter_value, group_names ): return True - return False + raise web.HTTPError(404, "No access to resources or resources not found") def _parse_scopes(scope_list): diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index a6883149..501aed62 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1395,7 +1395,7 @@ async def test_token_authenticator_dict_noauth(app): [ ('admin', 'other', 200), ('admin', 'missing', 404), - ('user', 'other', 403), + ('user', 'other', 404), ('user', 'user', 200), ], ) @@ -1687,7 +1687,7 @@ async def test_update_activity_403(app, user, admin_user): data="{}", method="post", ) - assert r.status_code == 403 + assert r.status_code == 404 async def test_update_activity_admin(app, user, admin_user): diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index e918cebc..13041883 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -54,10 +54,10 @@ def test_scope_check_not_present(): scope_list = ['read:users!user=maeby'] parsed_scopes = _parse_scopes(scope_list) assert not _check_scope(handler, 'read:users', parsed_scopes) - assert not _check_scope(handler, 'read:users', parsed_scopes, user='gob') - assert not _check_scope( - handler, 'read:users', parsed_scopes, user='gob', server='server' - ) + with pytest.raises(web.HTTPError): + _check_scope(handler, 'read:users', parsed_scopes, user='gob') + with pytest.raises(web.HTTPError): + _check_scope(handler, 'read:users', parsed_scopes, user='gob', server='server') def test_scope_filters(): @@ -217,8 +217,8 @@ def generate_test_role(user_name, scopes, role_name='test'): ('martha', False, 200), ('michael', True, 200), ('gob', True, 200), - ('tobias', False, 403), - ('ann', False, 403), + ('tobias', False, 404), + ('ann', False, 404), ], ) async def test_expand_groups(app, user_name, in_group, status_code): @@ -251,7 +251,7 @@ async def test_expand_groups(app, user_name, in_group, status_code): assert r.status_code == status_code -async def test_non_existing_user(app): +async def test_by_fake_user(app): user_name = 'shade' user = add_user(app.db, name=user_name) auth_ = auth_header(app.db, user_name) @@ -261,6 +261,44 @@ async def test_non_existing_user(app): assert r.status_code == 403 +err_message = "No access to resources or resources not found" + + +async def test_request_fake_user(app): + user_name = 'buster' + fake_user = 'annyong' + add_user(app.db, name=user_name) + test_role = generate_test_role(user_name, ['read:users!group=stuff']) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + app.db.commit() + r = await api_request( + app, 'users', fake_user, headers=auth_header(app.db, user_name) + ) + assert r.status_code == 404 + # Consistency between no user and user not accessible + assert r.json()['message'] == err_message + + +async def test_request_user_outside_group(app): + user_name = 'buster' + fake_user = 'hello' + add_user(app.db, name=user_name) + add_user(app.db, name=fake_user) + test_role = generate_test_role(user_name, ['read:users!group=stuff']) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + app.db.commit() + print(orm.User.find(db=app.db, name=user_name).roles) + r = await api_request( + app, 'users', fake_user, headers=auth_header(app.db, user_name) + ) + assert r.status_code == 404 + # Consistency between no user and user not accessible + assert r.json()['message'] == err_message + + async def test_user_filter(app): user_name = 'rita' user = add_user(app.db, name=user_name) From d9e8c7fe480ccc82eaf1dce3356eb259d819981e Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 8 Feb 2021 18:51:17 +0100 Subject: [PATCH 056/270] Moved parsing, started implementation of vertical filtering --- jupyterhub/apihandlers/base.py | 41 +++++++++---- jupyterhub/apihandlers/services.py | 13 +++- jupyterhub/handlers/base.py | 15 ++++- jupyterhub/scopes.py | 21 +++---- jupyterhub/tests/test_scopes.py | 96 ++++++++++++++++++------------ 5 files changed, 116 insertions(+), 70 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index a416e6c8..d3d64a3a 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -189,22 +189,37 @@ class APIHandler(BaseHandler): """Get the JSON model for a User object""" if isinstance(user, orm.User): user = self.users[user.id] + model = {'kind': 'user'} + # Todo: Should 'name' be included in all access? + self.log.debug( + "Asking for models with scopes [%s]" % ", ".join(self.parsed_scopes) + ) # debug + if 'read:users' in self.parsed_scopes: + model.update( + { + 'name': user.name, + 'admin': user.admin, + 'roles': [r.name for r in user.roles], + 'groups': [g.name for g in user.groups], + 'server': user.url if user.running else None, + 'pending': None, + 'created': isoformat(user.created), + 'last_activity': isoformat(user.last_activity), + } + ) + server_permission = True + else: + if 'read:users:name' in self.parsed_scopes: + model['name'] = user.name + if 'read:users:groups' in self.parsed_scopes: + model['groups'] = [g.name for g in user.groups] + if 'read:users:activity' in self.parsed_scopes: + model['last_activity'] = isoformat(user.last_activity) + server_permission = 'read:users:servers' in self.parsed_scopes - model = { - 'kind': 'user', - 'name': user.name, - 'admin': user.admin, - 'roles': [r.name for r in user.roles], - 'groups': [g.name for g in user.groups], - 'server': user.url if user.running else None, - 'pending': None, - 'created': isoformat(user.created), - 'last_activity': isoformat(user.last_activity), - } if '' in user.spawners: model['pending'] = user.spawners[''].pending - - if not include_servers: + if not (include_servers and server_permission): model['servers'] = None return model diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 0b4cced1..8a038f27 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -31,9 +31,16 @@ def service_model(service): class ServiceListAPIHandler(APIHandler): @needs_scope('read:services') def get(self, scope_filter=None): - data = {name: service_model(service) for name, service in self.services.items()} - if scope_filter is not None: - data = dict(filter(lambda tup: tup[0] in scope_filter, data.items())) + if scope_filter is None: + data = { + name: service_model(service) for name, service in self.services.items() + } + else: + data = { + name: service_model(service) + for name, service in self.services.items() + if name in scope_filter + } self.write(json.dumps(data)) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 3104a902..422794c5 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -31,6 +31,7 @@ from tornado.web import RequestHandler from .. import __version__ from .. import orm from .. import roles +from .. import scopes from ..metrics import PROXY_ADD_DURATION_SECONDS from ..metrics import PROXY_DELETE_DURATION_SECONDS from ..metrics import ProxyDeleteStatus @@ -80,7 +81,8 @@ class BaseHandler(RequestHandler): The current user (None if not logged in) may be accessed via the `self.current_user` property during the handling of any request. """ - self.scopes = set() + self.raw_scopes = set() + self.parsed_scopes = set() try: await self.get_current_user() except Exception: @@ -429,10 +431,16 @@ class BaseHandler(RequestHandler): # don't let errors here raise more than once self._jupyterhub_user = None self.log.exception("Error getting current user") - if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): - self.scopes = roles.get_subscopes(*self._jupyterhub_user.roles) + self._parse_scopes() return self._jupyterhub_user + def _parse_scopes(self): + if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): + self.raw_scopes = roles.get_subscopes(*self._jupyterhub_user.roles) + if 'all' in self.raw_scopes: + self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + @property def current_user(self): """Override .current_user accessor from tornado @@ -989,6 +997,7 @@ class BaseHandler(RequestHandler): self.log.critical( "Aborting due to %i consecutive spawn failures", failure_count ) + # abort in 2 seconds to allow pending handlers to resolve # mostly propagating errors for the current failures def abort(): diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index c06e6f59..8a01f9bb 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -54,7 +54,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): user = handler.find_user(user_name) if user is None: raise web.HTTPError(404, "No access to resources or resources not found") - group_names = {group.name for group in user.groups} # Todo: Replace with SQL query + group_names = {group.name for group in user.groups} # SQL query faster? return bool(set(scope_group_names) & group_names) @@ -79,7 +79,7 @@ def _get_scope_filter(db, req_scope, sub_scope): return scope_filter -def _check_scope(api_handler, req_scope, scopes, **kwargs): +def _check_scope(api_handler, req_scope, **kwargs): """Check if scopes satisfy requirements Returns either Scope.ALL for unrestricted access, Scope.NONE for refused access or an iterable with a filter @@ -87,12 +87,12 @@ def _check_scope(api_handler, req_scope, scopes, **kwargs): # Parse user name and server name together if 'user' in kwargs and 'server' in kwargs: kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) - if req_scope not in scopes: + if req_scope not in api_handler.parsed_scopes: return False - if scopes[req_scope] == Scope.ALL: + if api_handler.parsed_scopes[req_scope] == Scope.ALL: return True # Apply filters - sub_scope = scopes[req_scope] + sub_scope = api_handler.parsed_scopes[req_scope] if 'scope_filter' in kwargs: scope_filter = _get_scope_filter(api_handler.db, req_scope, sub_scope) return scope_filter @@ -112,7 +112,7 @@ def _check_scope(api_handler, req_scope, scopes, **kwargs): raise web.HTTPError(404, "No access to resources or resources not found") -def _parse_scopes(scope_list): +def parse_scopes(scope_list): """ Parses scopes and filters in something akin to JSON style @@ -165,10 +165,7 @@ def needs_scope(scope): s_kwargs[resource] = resource_value if 'scope_filter' in bound_sig.arguments: s_kwargs['scope_filter'] = None - if 'all' in self.scopes and self.current_user: - self.scopes |= get_user_scopes(self.current_user.name) - parsed_scopes = _parse_scopes(self.scopes) - scope_filter = _check_scope(self, scope, parsed_scopes, **s_kwargs) + scope_filter = _check_scope(self, scope, **s_kwargs) # todo: This checks if True/False or set of resource names. Can be improved if isinstance(scope_filter, set): kwargs['scope_filter'] = scope_filter @@ -176,14 +173,14 @@ def needs_scope(scope): return func(self, *args, **kwargs) else: # catching attr error occurring for older_requirements test - # could be done more ellegantly? + # could be done more elegantly? try: request_path = self.request.path except AttributeError: request_path = 'the requested API' app_log.warning( "Not authorizing access to {}. Requires scope {}, not derived from scopes [{}]".format( - request_path, scope, ", ".join(self.scopes) + request_path, scope, ", ".join(self.raw_scopes) ) ) raise web.HTTPError( diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 13041883..8539f2e0 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -9,15 +9,20 @@ from tornado.httputil import HTTPServerRequest from .. import orm from .. import roles +from ..handlers import BaseHandler from ..scopes import _check_scope -from ..scopes import _parse_scopes from ..scopes import needs_scope +from ..scopes import parse_scopes from ..scopes import Scope -from .mocking import MockHub from .utils import add_user from .utils import api_request from .utils import auth_header -from .utils import public_url + + +def get_handler_with_scopes(scopes): + handler = mock.Mock(spec=BaseHandler) + handler.parsed_scopes = parse_scopes(scopes) + return handler def test_scope_constructor(): @@ -28,7 +33,7 @@ def test_scope_constructor(): 'read:users!user={}'.format(user1), 'read:users!user={}'.format(user2), ] - parsed_scopes = _parse_scopes(scope_list) + parsed_scopes = parse_scopes(scope_list) assert 'read:users' in parsed_scopes assert parsed_scopes['users'] @@ -37,60 +42,49 @@ def test_scope_constructor(): def test_scope_precendence(): scope_list = ['read:users!user=maeby', 'read:users'] - parsed_scopes = _parse_scopes(scope_list) + parsed_scopes = parse_scopes(scope_list) assert parsed_scopes['read:users'] == Scope.ALL def test_scope_check_present(): - handler = None - scope_list = ['read:users'] - parsed_scopes = _parse_scopes(scope_list) - assert _check_scope(handler, 'read:users', parsed_scopes) - assert _check_scope(handler, 'read:users', parsed_scopes, user='maeby') + handler = get_handler_with_scopes(['read:users']) + assert _check_scope(handler, 'read:users') + assert _check_scope(handler, 'read:users', user='maeby') def test_scope_check_not_present(): - handler = None - scope_list = ['read:users!user=maeby'] - parsed_scopes = _parse_scopes(scope_list) - assert not _check_scope(handler, 'read:users', parsed_scopes) + handler = get_handler_with_scopes(['read:users!user=maeby']) + assert not _check_scope(handler, 'read:users') with pytest.raises(web.HTTPError): - _check_scope(handler, 'read:users', parsed_scopes, user='gob') + _check_scope(handler, 'read:users', user='gob') with pytest.raises(web.HTTPError): - _check_scope(handler, 'read:users', parsed_scopes, user='gob', server='server') + _check_scope(handler, 'read:users', user='gob', server='server') def test_scope_filters(): - handler = None - scope_list = ['read:users', 'read:users!group=bluths', 'read:users!user=maeby'] - parsed_scopes = _parse_scopes(scope_list) - assert _check_scope(handler, 'read:users', parsed_scopes, group='bluth') - assert _check_scope(handler, 'read:users', parsed_scopes, user='maeby') + handler = get_handler_with_scopes( + ['read:users', 'read:users!group=bluths', 'read:users!user=maeby'] + ) + assert _check_scope(handler, 'read:users', group='bluth') + assert _check_scope(handler, 'read:users', user='maeby') def test_scope_multiple_filters(): - handler = None - assert _check_scope( - handler, - 'read:users', - _parse_scopes(['read:users!user=george_michael']), - user='george_michael', - group='bluths', - ) + handler = get_handler_with_scopes(['read:users!user=george_michael']) + assert _check_scope(handler, 'read:users', user='george_michael', group='bluths') def test_scope_parse_server_name(): - handler = None - scope_list = ['users:servers!server=maeby/server1', 'read:users!user=maeby'] - parsed_scopes = _parse_scopes(scope_list) - assert _check_scope( - handler, 'users:servers', parsed_scopes, user='maeby', server='server1' + handler = get_handler_with_scopes( + ['users:servers!server=maeby/server1', 'read:users!user=maeby'] ) + assert _check_scope(handler, 'users:servers', user='maeby', server='server1') class MockAPIHandler: def __init__(self): - self.scopes = {'users'} + self.raw_scopes = {'users'} + self.parsed_scopes = {} @needs_scope('users') def user_thing(self, user_name): @@ -175,7 +169,8 @@ 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.scopes = set(scopes) + obj.raw_scopes = set(scopes) + obj.parsed_scopes = parse_scopes(obj.raw_scopes) api_call = getattr(obj, method) if is_allowed: assert api_call(*arguments) @@ -188,7 +183,8 @@ def test_double_scoped_method_succeeds(): obj = MockAPIHandler() obj.current_user = mock.Mock(name='lucille') obj.request = mock.Mock(spec=HTTPServerRequest) - obj.scopes = {'users', 'read:services'} + obj.raw_scopes = {'users', 'read:services'} + obj.parsed_scopes = parse_scopes(obj.raw_scopes) assert obj.secret_thing() @@ -196,7 +192,8 @@ def test_double_scoped_method_denials(): obj = MockAPIHandler() obj.current_user = mock.Mock(name='lucille2') obj.request = mock.Mock(spec=HTTPServerRequest) - obj.scopes = {'users', 'read:groups'} + obj.raw_scopes = {'users', 'read:groups'} + obj.parsed_scopes = parse_scopes(obj.raw_scopes) with pytest.raises(web.HTTPError): obj.secret_thing() @@ -290,7 +287,6 @@ async def test_request_user_outside_group(app): roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') app.db.commit() - print(orm.User.find(db=app.db, name=user_name).roles) r = await api_request( app, 'users', fake_user, headers=auth_header(app.db, user_name) ) @@ -394,3 +390,25 @@ async def test_group_scope_filter(app): assert r.status_code == 200 result_names = {user['name'] for user in r.json()} assert result_names == {'sitwell', 'bluth'} + + +async def test_vertical_filter(app): + user_name = 'lindsey' + add_user(app.db, name=user_name) + test_role = generate_test_role(user_name, ['read:users:names']) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + app.db.commit() + + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + assert set(r.json().keys()) == {'names'} + + +async def test_stacked_vertical_filter(app): + pass + + +async def test_cross_filter(app): + pass From de2e8ff3558335f64460219978ba90318f7bdf4e Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 11 Feb 2021 14:08:26 +0100 Subject: [PATCH 057/270] Implemented vertical filtering in user method --- jupyterhub/apihandlers/base.py | 120 ++++++++++++++++++++--------- jupyterhub/apihandlers/groups.py | 3 +- jupyterhub/apihandlers/services.py | 5 +- jupyterhub/apihandlers/users.py | 26 ++++--- jupyterhub/scopes.py | 94 ++++++++++------------ 5 files changed, 144 insertions(+), 104 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index d3d64a3a..7bbb88d6 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -10,6 +10,7 @@ from tornado import web from .. import orm from ..handlers import BaseHandler +from ..handlers import scopes from ..utils import isoformat from ..utils import url_path_join @@ -62,6 +63,38 @@ class APIHandler(BaseHandler): return False return True + def get_scope_filter(self, req_scope): + """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return""" + scope_translator = { + 'read:users': 'users', + 'read:services': 'services', + 'read:groups': 'groups', + } + if req_scope not in scope_translator: + raise AttributeError("Internal error: inconsistent scope situation") + kind = scope_translator[req_scope] + Resource = orm.get_class(kind) + try: + sub_scope = self.parsed_scopes[req_scope] + except AttributeError: + raise web.HTTPError( + 403, + "Resource scope %s (that was just accessed) not found in scopes anymore" + % req_scope, + ) + if sub_scope == scopes.Scope.ALL: + return None # Full access + sub_scope_values = next(iter(sub_scope.values())) + query = self.db.query(Resource).filter(Resource.name.in_(sub_scope_values)) + scope_filter = {entry.name for entry in query.all()} + if 'group' in sub_scope and kind == 'users': + groups = orm.Group.name.in_(sub_scope['group']) + users_in_groups = ( + self.db.query(orm.User).join(orm.Group.users).filter(groups) + ) + scope_filter |= {user.name for user in users_in_groups} + return scope_filter + def get_current_user_cookie(self): """Override get_user_cookie to check Referer header""" cookie_user = super().get_current_user_cookie() @@ -189,46 +222,61 @@ class APIHandler(BaseHandler): """Get the JSON model for a User object""" if isinstance(user, orm.User): user = self.users[user.id] - model = {'kind': 'user'} + model = { + 'kind': 'user', + 'name': user.name, + 'admin': user.admin, + 'roles': [r.name for r in user.roles], + 'groups': [g.name for g in user.groups], + 'server': user.url if user.running else None, + 'pending': None, + 'created': isoformat(user.created), + 'last_activity': isoformat(user.last_activity), + } + access_map = { + 'read:users': { + 'kind', + 'name', + 'admin', + 'roles', + 'groups', + 'server', + 'servers', + 'pending', + 'created', + 'last_activity', + }, + 'read:users:name': {'kind', 'name'}, + 'read:users:groups': {'kind', 'name', 'groups'}, + 'read:users:activity': {'kind', 'name', 'last_activity'}, + 'read:users:servers': {'kind', 'name', 'servers'}, + } # Todo: Should 'name' be included in all access? self.log.debug( - "Asking for models with scopes [%s]" % ", ".join(self.parsed_scopes) - ) # debug - if 'read:users' in self.parsed_scopes: - model.update( - { - 'name': user.name, - 'admin': user.admin, - 'roles': [r.name for r in user.roles], - 'groups': [g.name for g in user.groups], - 'server': user.url if user.running else None, - 'pending': None, - 'created': isoformat(user.created), - 'last_activity': isoformat(user.last_activity), - } - ) - server_permission = True - else: - if 'read:users:name' in self.parsed_scopes: - model['name'] = user.name - if 'read:users:groups' in self.parsed_scopes: - model['groups'] = [g.name for g in user.groups] - if 'read:users:activity' in self.parsed_scopes: - model['last_activity'] = isoformat(user.last_activity) - server_permission = 'read:users:servers' in self.parsed_scopes - - if '' in user.spawners: + "Asking for user models with scopes [%s]" % ", ".join(self.raw_scopes) + ) + allowed_keys = set() + for scope in access_map: + if scope in self.parsed_scopes: + scope_filter = self.get_scope_filter(scope) + if scope_filter is None or user.name in scope_filter: + allowed_keys |= access_map[scope] + model = {key: model[key] for key in allowed_keys if key in model} + if not model: + return model # No access to this user + if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending - if not (include_servers and server_permission): + if not (include_servers and 'servers' in allowed_keys): model['servers'] = None - return model - - servers = model['servers'] = {} - for name, spawner in user.spawners.items(): - # include 'active' servers, not just ready - # (this includes pending events) - if spawner.active: - servers[name] = self.server_model(spawner, include_state=include_state) + else: + servers = model['servers'] = {} + for name, spawner in user.spawners.items(): + # include 'active' servers, not just ready + # (this includes pending events) + if spawner.active: + servers[name] = self.server_model( + spawner, include_state=include_state + ) return model def group_model(self, group): diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 93a6202d..f0dceab4 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -35,9 +35,10 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): @needs_scope('read:groups') - def get(self, scope_filter=None): + def get(self): """List groups""" groups = self.db.query(orm.Group) + scope_filter = self.get_scope_filter(self.db) if scope_filter is not None: groups = groups.filter(orm.Group.name.in_(scope_filter)) data = [self.group_model(g) for g in groups] diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 8a038f27..5a48e385 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -30,7 +30,8 @@ def service_model(service): class ServiceListAPIHandler(APIHandler): @needs_scope('read:services') - def get(self, scope_filter=None): + def get(self): + scope_filter = self.get_scope_filter('read:services') if scope_filter is None: data = { name: service_model(service) for name, service in self.services.items() @@ -46,7 +47,7 @@ class ServiceListAPIHandler(APIHandler): def admin_or_self(method): """Decorator for restricting access to either the target service or admin""" - """***Deprecated in favor of RBAC, use scope-based decorator***""" + """***Deprecated in favor of RBAC. Use scope-based decorator***""" def decorated_method(self, name): current = self.current_user diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 7b267d82..59619931 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -53,8 +53,14 @@ class UserListAPIHandler(APIHandler): user = self.users[orm_user] return any(spawner.ready for spawner in user.spawners.values()) - @needs_scope('read:users') - def get(self, scope_filter=None): + @needs_scope( + 'read:users', + 'read:users:names', + 'reda:users:servers', + 'read:users:groups', + 'read:users:activity', + ) + def get(self): state_filter = self.get_argument("state", None) # post_filter @@ -95,14 +101,14 @@ class UserListAPIHandler(APIHandler): else: # no filter, return all users query = self.db.query(orm.User) - if scope_filter is not None: - query = query.filter(orm.User.name.in_(scope_filter)) - - data = [ - self.user_model(u, include_servers=True, include_state=True) - for u in query - if (post_filter is None or post_filter(u)) - ] + data = [] + for u in query: + if post_filter is None or post_filter(u): + user_model = self.user_model( + u, include_servers=True, include_state=True + ) + if user_model: + data.append(user_model) self.write(json.dumps(data)) @needs_scope('admin:users') diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 8a01f9bb..613935eb 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -1,5 +1,6 @@ import functools import inspect +import re from enum import Enum from tornado import web @@ -58,58 +59,46 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): return bool(set(scope_group_names) & group_names) -def _get_scope_filter(db, req_scope, sub_scope): - """Produce a filter for `*ListAPIHandlers* so that get method knows which models to return""" - scope_translator = { - 'read:users': 'users', - 'read:services': 'services', - 'read:groups': 'groups', - } - if req_scope not in scope_translator: - raise AttributeError("Internal error: inconsistent scope situation") - kind = scope_translator[req_scope] - Resource = orm.get_class(kind) - sub_scope_values = next(iter(sub_scope.values())) - query = db.query(Resource).filter(Resource.name.in_(sub_scope_values)) - scope_filter = {entry.name for entry in query.all()} - if 'group' in sub_scope and kind == 'users': - groups = orm.Group.name.in_(sub_scope['group']) - users_in_groups = db.query(orm.User).join(orm.Group.users).filter(groups) - scope_filter |= {user.name for user in users_in_groups} - return scope_filter - - def _check_scope(api_handler, req_scope, **kwargs): """Check if scopes satisfy requirements - Returns either Scope.ALL for unrestricted access, Scope.NONE for refused access or + Returns either True for unrestricted access, False for refused access or an iterable with a filter """ # Parse user name and server name together + try: + api_name = api_handler.request.path + except: + api_name = type(api_handler).__name__ if 'user' in kwargs and 'server' in kwargs: kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) if req_scope not in api_handler.parsed_scopes: + app_log.debug("No scopes present to access %s" % api_name) return False if api_handler.parsed_scopes[req_scope] == Scope.ALL: + app_log.debug("Unrestricted access to %s call", api_name) return True # Apply filters sub_scope = api_handler.parsed_scopes[req_scope] - if 'scope_filter' in kwargs: - scope_filter = _get_scope_filter(api_handler.db, req_scope, sub_scope) - return scope_filter - else: - if not kwargs: - return False # Separated from 404 error below because in this case we don't leak information - # Interface change: Now can have multiple filters - for (filter_, filter_value) in kwargs.items(): - if filter_ in sub_scope and filter_value in sub_scope[filter_]: + if not kwargs: + app_log.debug( + "Client has restricted access to %s. In-method filtering" % api_name + ) + return True + for (filter_, filter_value) in kwargs.items(): + if filter_ in sub_scope and filter_value in sub_scope[filter_]: + app_log.debug( + "Restricted client access supported by endpoint %s" % api_name + ) + return True + if _needs_scope_expansion(filter_, filter_value, sub_scope): + group_names = sub_scope['group'] + if _check_user_in_expanded_scope(api_handler, filter_value, group_names): + app_log.debug("Restricted client access supported with group expansion") return True - if _needs_scope_expansion(filter_, filter_value, sub_scope): - group_names = sub_scope['group'] - if _check_user_in_expanded_scope( - api_handler, filter_value, group_names - ): - return True - raise web.HTTPError(404, "No access to resources or resources not found") + app_log.debug( + "Client access refused; filters do not match API endpoint %s request" % api_name + ) + raise web.HTTPError(404, "No access to resources or resources not found") def parse_scopes(scope_list): @@ -120,7 +109,7 @@ def parse_scopes(scope_list): would lead to scope model { "users":scope.ALL, - "users:admin":{ + "admin:users":{ "user":[ "alice" ] @@ -148,7 +137,7 @@ def parse_scopes(scope_list): return parsed_scopes -def needs_scope(scope): +def needs_scope(*scopes): """Decorator to restrict access to users or services with the required scope""" def scope_decorator(func): @@ -163,30 +152,25 @@ def needs_scope(scope): if resource_name in bound_sig.arguments: resource_value = bound_sig.arguments[resource_name] s_kwargs[resource] = resource_value - if 'scope_filter' in bound_sig.arguments: - s_kwargs['scope_filter'] = None - scope_filter = _check_scope(self, scope, **s_kwargs) - # todo: This checks if True/False or set of resource names. Can be improved - if isinstance(scope_filter, set): - kwargs['scope_filter'] = scope_filter - if scope_filter: + has_access = False + for scope in scopes: + has_access |= _check_scope(self, scope, **s_kwargs) + if has_access: return func(self, *args, **kwargs) else: - # catching attr error occurring for older_requirements test - # could be done more elegantly? try: - request_path = self.request.path + end_point = self.request.path except AttributeError: - request_path = 'the requested API' + end_point = self.__name__ app_log.warning( - "Not authorizing access to {}. Requires scope {}, not derived from scopes [{}]".format( - request_path, scope, ", ".join(self.raw_scopes) + "Not authorizing access to {}. Requires any of [{}], not derived from scopes [{}]".format( + end_point, ", ".join(scopes), ", ".join(self.raw_scopes) ) ) raise web.HTTPError( 403, - "Action is not authorized with current scopes; requires {}".format( - scope + "Action is not authorized with current scopes; requires any of [{}]".format( + ", ".join(scopes) ), ) From be34146d29fec83290e138d003b0a6ad34658b3e Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 12 Feb 2021 09:55:21 +0100 Subject: [PATCH 058/270] back-up with commenting out only --- docs/requirements.txt | 1 + docs/source/changelog.md | 9 +++--- docs/source/conf.py | 7 ++-- docs/source/getting-started/faq.md | 2 +- docs/source/index.rst | 8 +++++ docs/source/rbac.md | 51 ++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 docs/source/rbac.md diff --git a/docs/requirements.txt b/docs/requirements.txt index 2d9da795..bba34b26 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,6 +4,7 @@ alabaster_jupyterhub # Temporary fix of #3021. Revert back to released autodoc-traits when # 0.1.0 released. https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043459715049cd84.zip +myst_parser pydata-sphinx-theme pytablewriter>=0.56 recommonmark>=0.6 diff --git a/docs/source/changelog.md b/docs/source/changelog.md index ffa2c029..66330e11 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -423,12 +423,11 @@ whether it was through discussion, testing, documentation, or development. allowing the Authenticator to *require* that authentication data is fresh immediately before the user's server is launched. -```eval_rst -.. seealso:: +```{seealso} - - :meth:`.Authenticator.refresh_user` - - :meth:`.Spawner.create_certs` - - :meth:`.Spawner.move_certs` + - {meth}`.Authenticator.refresh_user` + - {meth}`.Spawner.create_certs` + - {meth}`.Spawner.move_certs` ``` #### New features diff --git a/docs/source/conf.py b/docs/source/conf.py index 317420d7..e403e939 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -19,7 +19,8 @@ extensions = [ 'autodoc_traits', 'sphinx_copybutton', 'sphinx-jsonschema', - 'recommonmark', + #'recommonmark', + 'myst_parser', ] # The master toctree document. @@ -111,9 +112,9 @@ class HelpAllDirective(SphinxDirective): def setup(app): - app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) + # app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) app.add_css_file('custom.css') - app.add_transform(AutoStructify) + # app.add_transform(AutoStructify) app.add_directive('jupyterhub-generate-config', ConfigDirective) app.add_directive('jupyterhub-help-all', HelpAllDirective) diff --git a/docs/source/getting-started/faq.md b/docs/source/getting-started/faq.md index ae912847..f18227e9 100644 --- a/docs/source/getting-started/faq.md +++ b/docs/source/getting-started/faq.md @@ -1,7 +1,7 @@ # Frequently asked questions -### How do I share links to notebooks? +## How do I share links to notebooks? In short, where you see `/user/name/notebooks/foo.ipynb` use `/hub/user-redirect/notebooks/foo.ipynb` (replace `/user/name` with `/hub/user-redirect`). diff --git a/docs/source/index.rst b/docs/source/index.rst index 8d51a6bc..dfcc3e68 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -108,6 +108,14 @@ API Reference api/index +RBAC Reference +-------------- + +.. toctree:: + :maxdepth: 2 + + rbac + Contributing ------------ diff --git a/docs/source/rbac.md b/docs/source/rbac.md new file mode 100644 index 00000000..857fca1c --- /dev/null +++ b/docs/source/rbac.md @@ -0,0 +1,51 @@ +# JupyterHub RBAC + +Role Based Access Control (RBAC) in JupyterHub serves to provide finer grained access to perform actions by users or services. + +## Motivation +The JupyterHub API requires authentication before allowing changes to the administration system. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, cannot disrupt the status of the Hub. + +This system is functional, but lacks flexibility. If your Hub serves a number of users in different departments, you might want to delegate permissions to other users or automate certain processes. With this framework, appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilige](https://en.wikipedia.org/wiki/Principle_of_least_privilege). + +To remedy situations like this, we implement an RBAC system. By equipping users, groups and services with *roles* that supply them with a collection of permissions (*scopes*), administrators are able to fine-tune which parties are able to access which resources. + +### Available scopes + +[](./reference/rest-api.rst) documentation details all available scopes and which of these are required for what particular API request. + +The roles can then be defined as follows: +```python +c.JupyterHub.load_groups = { + 'class-A': ['johan', 'student1', 'student2'], + 'class-B': ['johan', 'student3', 'student4'] +} +c.JupyterHub.load_roles = [ + { +   'name': 'class-A-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-A'], +   'groups': ['class-A'] + }, + { +   'name': 'class-B-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-B'], +   'groups': ['class-B'] + }, + { +   'name': 'teacher', +   'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', +   'scopes': ['read:users!group=class-A', 'read:users!group=class-B', 'users:servers!group=class-A', 'users:servers!group=class-B'], +   'users': ['johan'] + } +] +``` +In the above example, `johan` has privileges inherited from class-A and class-B roles and the `teacher` role on top of those. Note the filters (`!group=`) limiting the priviliges only to the class-A and class-B group members. + +## Technical Implementation + +```{admonition} Here's my title +:class: warning + +Here's my admonition content +``` From 746be73e5663bb9965bd21d1b449d30edd9e818c Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 15 Feb 2021 14:03:37 +0100 Subject: [PATCH 059/270] Fixed vertical filtering in user models, but does not work for OAuth yet --- jupyterhub/apihandlers/base.py | 59 ++++++++++++++++++-------------- jupyterhub/apihandlers/groups.py | 2 +- jupyterhub/handlers/base.py | 5 +-- jupyterhub/scopes.py | 1 + jupyterhub/tests/test_api.py | 4 ++- jupyterhub/tests/test_scopes.py | 12 ++++--- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 7bbb88d6..b686c88c 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -2,6 +2,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import json +import re from datetime import datetime from http.client import responses @@ -64,15 +65,19 @@ class APIHandler(BaseHandler): return True def get_scope_filter(self, req_scope): - """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return""" - scope_translator = { - 'read:users': 'users', - 'read:services': 'services', - 'read:groups': 'groups', - } - if req_scope not in scope_translator: - raise AttributeError("Internal error: inconsistent scope situation") - kind = scope_translator[req_scope] + """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return + If the APIHandler has unrestricted access + """ + kind_regex = re.compile(r':?(users|services|groups):?') + try: + kind = re.search(kind_regex, req_scope).group(1) + except AttributeError: + self.log.warning( + "Regex error while processing scope %s, throwing 500", req_scope + ) + raise web.HTTPError( + log_message="Unrecognized scope guard on method: %s" % req_scope + ) Resource = orm.get_class(kind) try: sub_scope = self.parsed_scopes[req_scope] @@ -246,7 +251,7 @@ class APIHandler(BaseHandler): 'created', 'last_activity', }, - 'read:users:name': {'kind', 'name'}, + 'read:users:names': {'kind', 'name'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, @@ -255,28 +260,32 @@ class APIHandler(BaseHandler): self.log.debug( "Asking for user models with scopes [%s]" % ", ".join(self.raw_scopes) ) + self.log.debug( + "Current requests have db loaded scopes [%s]" % self.current_user + ) allowed_keys = set() + # if not self.parsed_scopes: + # self.parse_scopes() for scope in access_map: if scope in self.parsed_scopes: scope_filter = self.get_scope_filter(scope) if scope_filter is None or user.name in scope_filter: allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} - if not model: - return model # No access to this user - if '' in user.spawners and 'pending' in allowed_keys: - model['pending'] = user.spawners[''].pending - if not (include_servers and 'servers' in allowed_keys): - model['servers'] = None - else: - servers = model['servers'] = {} - for name, spawner in user.spawners.items(): - # include 'active' servers, not just ready - # (this includes pending events) - if spawner.active: - servers[name] = self.server_model( - spawner, include_state=include_state - ) + if model: + if '' in user.spawners and 'pending' in allowed_keys: + model['pending'] = user.spawners[''].pending + if ( + include_servers and 'servers' in allowed_keys + ): # Todo: Log breaking change: now no server component in user model if no access + servers = model['servers'] = {} + for name, spawner in user.spawners.items(): + # include 'active' servers, not just ready + # (this includes pending events) + if spawner.active: + servers[name] = self.server_model( + spawner, include_state=include_state + ) return model def group_model(self, group): diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index f0dceab4..9b29f91c 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -38,7 +38,7 @@ class GroupListAPIHandler(_GroupAPIHandler): def get(self): """List groups""" groups = self.db.query(orm.Group) - scope_filter = self.get_scope_filter(self.db) + scope_filter = self.get_scope_filter('read:groups') if scope_filter is not None: groups = groups.filter(orm.Group.name.in_(scope_filter)) data = [self.group_model(g) for g in groups] diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 422794c5..84fea357 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -427,16 +427,17 @@ class BaseHandler(RequestHandler): if user and isinstance(user, User): user = await self.refresh_auth(user) self._jupyterhub_user = user + self._parse_scopes() except Exception: # don't let errors here raise more than once self._jupyterhub_user = None self.log.exception("Error getting current user") - self._parse_scopes() return self._jupyterhub_user def _parse_scopes(self): if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): - self.raw_scopes = roles.get_subscopes(*self._jupyterhub_user.roles) + if self.current_user: # Todo: Deal with oauth tokens + self.raw_scopes = roles.get_subscopes(*self.current_user.roles) if 'all' in self.raw_scopes: self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 613935eb..ace3feac 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -143,6 +143,7 @@ def needs_scope(*scopes): def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): + self.parse_scopes() # Todo: Check most practical locations for parsing scopes sig = inspect.signature(func) bound_sig = sig.bind(self, *args, **kwargs) bound_sig.apply_defaults() diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index cd97dea5..af822bc6 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -260,7 +260,9 @@ async def test_get_self(app): db = app.db # basic get self - r = await api_request(app, 'user') + r = await api_request( + app, 'user', headers=auth_header(db, 'user') + ) # Todo: check after dealing with oauth r.raise_for_status() assert r.json()['kind'] == 'user' diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 8539f2e0..82b41fc7 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -54,7 +54,7 @@ def test_scope_check_present(): def test_scope_check_not_present(): handler = get_handler_with_scopes(['read:users!user=maeby']) - assert not _check_scope(handler, 'read:users') + assert _check_scope(handler, 'read:users') with pytest.raises(web.HTTPError): _check_scope(handler, 'read:users', user='gob') with pytest.raises(web.HTTPError): @@ -103,7 +103,8 @@ class MockAPIHandler: return True @needs_scope('users') - def other_thing(self, other_name): + def other_thing(self, non_filter_argument): + # Rely on inner vertical filtering return True @needs_scope('users') @@ -161,8 +162,8 @@ class MockAPIHandler: ), (['users'], 'other_thing', ('gob',), True), (['read:users'], 'other_thing', ('gob',), False), - (['users!user=gob'], 'other_thing', ('gob',), False), - (['users!user=gob'], 'other_thing', ('maeby',), False), + (['users!user=gob'], 'other_thing', ('gob',), True), + (['users!user=gob'], 'other_thing', ('maeby',), True), ], ) def test_scope_method_access(scopes, method, arguments, is_allowed): @@ -403,7 +404,8 @@ async def test_vertical_filter(app): r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - assert set(r.json().keys()) == {'names'} + allowed_keys = {'name', 'kind'} + assert set([key for user in r.json() for key in user.keys()]) == allowed_keys async def test_stacked_vertical_filter(app): From 6a3274e33c03ace7dba3e03f236e7c996fc4ff20 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 15 Feb 2021 15:23:18 +0100 Subject: [PATCH 060/270] Fixed get_self OAuth test --- jupyterhub/apihandlers/base.py | 16 ++-------------- jupyterhub/handlers/base.py | 14 ++++++++------ jupyterhub/scopes.py | 9 ++++++--- jupyterhub/tests/test_scopes.py | 12 +++++++++++- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index b686c88c..cfdf8043 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -238,19 +238,9 @@ class APIHandler(BaseHandler): 'created': isoformat(user.created), 'last_activity': isoformat(user.last_activity), } + access_map = { - 'read:users': { - 'kind', - 'name', - 'admin', - 'roles', - 'groups', - 'server', - 'servers', - 'pending', - 'created', - 'last_activity', - }, + 'read:users': set(model.keys()), # All available components 'read:users:names': {'kind', 'name'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, @@ -264,8 +254,6 @@ class APIHandler(BaseHandler): "Current requests have db loaded scopes [%s]" % self.current_user ) allowed_keys = set() - # if not self.parsed_scopes: - # self.parse_scopes() for scope in access_map: if scope in self.parsed_scopes: scope_filter = self.get_scope_filter(scope) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 84fea357..cda05418 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -435,12 +435,14 @@ class BaseHandler(RequestHandler): return self._jupyterhub_user def _parse_scopes(self): - if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): - if self.current_user: # Todo: Deal with oauth tokens - self.raw_scopes = roles.get_subscopes(*self.current_user.roles) - if 'all' in self.raw_scopes: - self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + if self._jupyterhub_user is not None: + self.raw_scopes = roles.get_subscopes(*self.current_user.roles) + oauth_token = self.get_current_user_oauth_token() + if oauth_token: + self.raw_scopes |= scopes.get_user_scopes(oauth_token.name) + if 'all' in self.raw_scopes: + self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) @property def current_user(self): diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index ace3feac..80665c8a 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -13,7 +13,7 @@ class Scope(Enum): ALL = True -def get_user_scopes(name): +def get_user_scopes(name, read_only=False): """ Scopes have a metascope 'all' that should be expanded to everything a user can do. At the moment that is a user-filtered version (optional read) access to @@ -32,7 +32,11 @@ def get_user_scopes(name): 'users:servers', 'users:tokens', ] - scope_list.extend(['read:' + scope for scope in scope_list]) + read_scope_list = ['read:' + scope for scope in scope_list] + if read_only: + scope_list = read_scope_list + else: + scope_list.extend(read_scope_list) return {"{}!user={}".format(scope, name) for scope in scope_list} @@ -143,7 +147,6 @@ def needs_scope(*scopes): def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): - self.parse_scopes() # Todo: Check most practical locations for parsing scopes sig = inspect.signature(func) bound_sig = sig.bind(self, *args, **kwargs) bound_sig.apply_defaults() diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 82b41fc7..a869e84a 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -409,7 +409,17 @@ async def test_vertical_filter(app): async def test_stacked_vertical_filter(app): - pass + user_name = 'user' + test_role = generate_test_role(user_name, ['read:users:names']) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + app.db.commit() + + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + allowed_keys = {'name', 'kind'} + assert set([key for user in r.json() for key in user.keys()]) == allowed_keys async def test_cross_filter(app): From 7d1b6a202151ea736e90c9b0c2987b6184eb323d Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Mon, 15 Feb 2021 16:19:13 +0100 Subject: [PATCH 061/270] split the docs in docs/source/rbac folder --- docs/requirements.txt | 2 +- docs/source/conf.py | 7 -- docs/source/images/role-scope-resolution.png | Bin 0 -> 48730 bytes docs/source/index.rst | 2 +- docs/source/rbac.md | 51 ------------- docs/source/rbac/index.md | 29 +++++++ docs/source/rbac/roles.md | 61 +++++++++++++++ docs/source/rbac/scopes.md | 40 ++++++++++ docs/source/rbac/tech-implementation.md | 33 ++++++++ docs/source/rbac/use-cases.md | 75 +++++++++++++++++++ 10 files changed, 240 insertions(+), 60 deletions(-) create mode 100644 docs/source/images/role-scope-resolution.png delete mode 100644 docs/source/rbac.md create mode 100644 docs/source/rbac/index.md create mode 100644 docs/source/rbac/roles.md create mode 100644 docs/source/rbac/scopes.md create mode 100644 docs/source/rbac/tech-implementation.md create mode 100644 docs/source/rbac/use-cases.md diff --git a/docs/requirements.txt b/docs/requirements.txt index bba34b26..efdb9f07 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,7 +4,7 @@ alabaster_jupyterhub # Temporary fix of #3021. Revert back to released autodoc-traits when # 0.1.0 released. https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043459715049cd84.zip -myst_parser +myst-parser pydata-sphinx-theme pytablewriter>=0.56 recommonmark>=0.6 diff --git a/docs/source/conf.py b/docs/source/conf.py index e403e939..379c7761 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -53,11 +53,6 @@ todo_include_todos = False # Set the default role so we can use `foo` instead of ``foo`` default_role = 'literal' -# -- Source ------------------------------------------------------------- - -import recommonmark -from recommonmark.transform import AutoStructify - # -- Config ------------------------------------------------------------- from jupyterhub.app import JupyterHub from docutils import nodes @@ -112,9 +107,7 @@ class HelpAllDirective(SphinxDirective): def setup(app): - # app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) app.add_css_file('custom.css') - # app.add_transform(AutoStructify) app.add_directive('jupyterhub-generate-config', ConfigDirective) app.add_directive('jupyterhub-help-all', HelpAllDirective) diff --git a/docs/source/images/role-scope-resolution.png b/docs/source/images/role-scope-resolution.png new file mode 100644 index 0000000000000000000000000000000000000000..5605b906a926cea15522a20e71d1f6253d846a78 GIT binary patch literal 48730 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 IS8ebA9~a{ZcmMzZ literal 0 HcmV?d00001 diff --git a/docs/source/index.rst b/docs/source/index.rst index dfcc3e68..396a67dc 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -114,7 +114,7 @@ RBAC Reference .. toctree:: :maxdepth: 2 - rbac + rbac/index Contributing ------------ diff --git a/docs/source/rbac.md b/docs/source/rbac.md deleted file mode 100644 index 857fca1c..00000000 --- a/docs/source/rbac.md +++ /dev/null @@ -1,51 +0,0 @@ -# JupyterHub RBAC - -Role Based Access Control (RBAC) in JupyterHub serves to provide finer grained access to perform actions by users or services. - -## Motivation -The JupyterHub API requires authentication before allowing changes to the administration system. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, cannot disrupt the status of the Hub. - -This system is functional, but lacks flexibility. If your Hub serves a number of users in different departments, you might want to delegate permissions to other users or automate certain processes. With this framework, appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilige](https://en.wikipedia.org/wiki/Principle_of_least_privilege). - -To remedy situations like this, we implement an RBAC system. By equipping users, groups and services with *roles* that supply them with a collection of permissions (*scopes*), administrators are able to fine-tune which parties are able to access which resources. - -### Available scopes - -[](./reference/rest-api.rst) documentation details all available scopes and which of these are required for what particular API request. - -The roles can then be defined as follows: -```python -c.JupyterHub.load_groups = { - 'class-A': ['johan', 'student1', 'student2'], - 'class-B': ['johan', 'student3', 'student4'] -} -c.JupyterHub.load_roles = [ - { -   'name': 'class-A-student', -   'description': 'Grants access to information about the group', -   'scopes': ['read:groups!group=class-A'], -   'groups': ['class-A'] - }, - { -   'name': 'class-B-student', -   'description': 'Grants access to information about the group', -   'scopes': ['read:groups!group=class-B'], -   'groups': ['class-B'] - }, - { -   'name': 'teacher', -   'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', -   'scopes': ['read:users!group=class-A', 'read:users!group=class-B', 'users:servers!group=class-A', 'users:servers!group=class-B'], -   'users': ['johan'] - } -] -``` -In the above example, `johan` has privileges inherited from class-A and class-B roles and the `teacher` role on top of those. Note the filters (`!group=`) limiting the priviliges only to the class-A and class-B group members. - -## Technical Implementation - -```{admonition} Here's my title -:class: warning - -Here's my admonition content -``` diff --git a/docs/source/rbac/index.md b/docs/source/rbac/index.md new file mode 100644 index 00000000..7c8b08a6 --- /dev/null +++ b/docs/source/rbac/index.md @@ -0,0 +1,29 @@ +# JupyterHub RBAC + +Role Based Access Control (RBAC) in JupyterHub serves to provide finer grained access to perform actions by users or services. + +## Motivation +The JupyterHub API requires authentication before allowing changes to the administration system. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, cannot disrupt the status of the Hub. + +This system is functional, but lacks flexibility. If your Hub serves a number of users in different departments, you might want to delegate permissions to other users or automate certain processes. With this framework, appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilige](https://en.wikipedia.org/wiki/Principle_of_least_privilege). + +To remedy situations like this, we implement an RBAC system. By equipping users, groups and services with *roles* that supply them with a collection of permissions (*scopes*), administrators are able to fine-tune which parties are able to access which resources. + +## Definitions +__Scopes__ are specific permissions used to evaluate API requests. For example: the API endpoint `users/servers`, which enables starting or stopping user servers, is guarded by the scope `users:servers`. + +Scopes are not directly assigned to requesters. Rather, when a client performs an API call, their access will be evaluated based on their assigned roles. + +__Roles__ are collections of scopes that specify the level of what a client is allowed to do. For example, a group administrator may be granted permission to control the servers of group members, but not to create, modify or delete group members themselves. +Within the RBAC framework, this is achieved by assigning a role to the administrator that covers exactly those privileges. + +## Technical Overview + +```{toctree} +:maxdepth: 2 + +roles +scopes +tech-implementation +use-cases +``` diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md new file mode 100644 index 00000000..42092c9d --- /dev/null +++ b/docs/source/rbac/roles.md @@ -0,0 +1,61 @@ +# Roles +JupyterHub provides three **default roles** which are automatically loaded to the database at the startup: + +```{admonition} **Default roles** +- **_user_** role carries single `all` scope that grants _least user access_ to perform only default user actions. +- **_admin_** role contains all available scopes and grants full rights to all actions similarly to the current admin status. +- **_server_** role allows for posting activity only through the single `users:activity` scope. +``` + +Roles can also be customly defined and assigned to users, services, groups and tokens. + +**_Users_** and **_services_** are assigned a default role if no custom role is requested based on their admin status. + +**_Tokens_**’ roles cannot grant the token higher permissions than their owner’s roles. If no specific role is requested, tokens are assigned the default _user_ role. + +**_Groups_** do not require any role and are not assigned any roles by default. Once group roles are defined and assigned, the privileges of each group member are extended with the group roles in the background during the API request permission check. This is useful for requesting the same permissions for several users. + +(define_role_target)= + +## Defining Roles + +### In `jupyterhub_config.py` + +Roles can be defined or modified in the configuration file as a list of dictionaries. An example: +```python +c.JupyterHub.load_roles = [ + { +   'name': 'Server rights', +   'description': 'Allows parties to start and stop user servers', +   'scopes': ['users:servers', 'read:users:servers'], +   'users': ['alice', 'bob'], +   'services': ['idle-culler'], +   'groups': ['admin-group'], +   'tokens': ['foo-6f6e65','bar-74776f'] + } +] +``` +The role `server-rights` now allows the starting and stopping of servers by users `alice` and `bob` and the service `idle-culler`, and any member of the `admin-group` or requests using the tokens `foo-6f6e65`/`bar-74776f` (providing the tokens owner has at least the same permissions). + +Another example: +```python +c.JupyterHub.load_roles.append({ + 'description': 'Read-only user models', + 'name': 'reader', + 'scopes': ['read:users'], + 'services': ['external'], + 'users': ['maria', 'joe'] + } +) +``` + +The role `reader` allows users `maria` and `joe` and service `external` to read (but not modify) any user’s model. + +```{admonition} Requirements +:class: warning +In a role definition, the `name` field is required, while all other fields are optional. +Moreover, `users`, `services`, `groups` and `tokens` only accept objects that already exist or are defined previously in the file. +It is not possible to implicitly add a new user to the database by defining a new role. +``` + +In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. Any previously defined role bearers will remain unchanged, but newly defined requesters (in this case `maria` and `joe` and `external`) will be assigned the new role definition. diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md new file mode 100644 index 00000000..81f7c693 --- /dev/null +++ b/docs/source/rbac/scopes.md @@ -0,0 +1,40 @@ +# Scopes + +A scope has a syntax-based design that reveals which resources it provides access to: +- The base`resource` scopes, such as `users` or `groups`, provides non-elevated 'default' read or write permissions to the resource itself and all sub-resources. For instance, the scope`users:servers` is included within the scope`users`. +- The elevated `admin:resource` scopes extend permissions beyond default. For instance, where the scope `users` provides read and write access to user information, the scope `admin:users` allows creating and deleting users. +- The scope structure `resource:subresource` vertical filtering: it provides access to a subset of the information granted by the `resource` scope. For example, the scope `users:names` provides access to user names only. +- The scope structure `read:resource` (or `read:resource:subresource`) limits permissions to read-only operations on `resource` (or `subresource`). +- The scope structure `resource!user=charlie` allows for horizontal filtering: it limits access to only return resources of user `charlie`. Only one filter per scope is allowed, but filters for the same scope have an additive effect; a larger filter can be used by supplying the scope multiple times with different filters. +- A resource can be filtered based on `user`, `server`, `group` or `service` name. +By adding a scope to an existing role, all role bearers will gain the associated permissions. + +## Available scopes + +[](../reference/rest-api.rst) documentation details all available scopes and which of these are required for what particular API request. + +## Standard user scope + +The standard user scope `all` provides access to the user's own resources and subresources, including the user's model, activity, servers and tokens. For example, the scope for a user `'gerard'` covers: +- `users!user=gerard` where the `users` scope includes access to the full user model, activity and starting/stopping servers. The filter restricts this access to the user's own resources +- `users:tokens!user=gerard` allows the user to access, request and delete his own tokens only. + +*Note: I'm hoping that horizontal and vertical filtering are somehow intuitive concepts, but maybe I am making up words for things that are already pretty well defined?* + +(filtering-target)= + +## Horizontal filtering + +Horizontal filtering, also called *resource filtering*, is the concept of reducing the payload of an API call to cover only the subset of the *resources* that the scopes of the client provides them access to. +Requested resources are filtered based on the filter of the corresponding scope. For instance, if a service requests a user list (guarded with scope `read:users`) with a role that only contains scopes `read:users!user=hannah` and `read:users!user=ivan`, the returned list of user models will be an intersection of all users and the collection `{hannah, ivan}`. In case this intersection is empty, the API call returns an HTTP 404 error, regardless if any users exist outside of the clients scope filter collection. + +In case a user resource is being accessed, any scopes with *group* filters will be expanded to filters for each *user* in those groups. + +## Vertical filtering + +Vertical filtering, also called *attribute filtering*, is the concept of reducing the payload of an API call to cover only the *attributes* of the resources that the scopes of the client provides them access to. This occurs when the client scopes are subscopes of the API endpoint that is called. +For instance, if a client requests a user list with the only scope being `read:user:groups`, the returned list of user models will contain only a list of groups per user. +In case the client has multiple subscopes, the call returns the union of the data the client has access to. + + +The payload of an API call can be filtered both horizontally and vertically simultaneously. For instance, performing an API call to the endpoint `/users/` with the scope `users:names!user=juliette` returns a payload of `[{name: 'juliette'}]` (provided that this name is present in the database). diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md new file mode 100644 index 00000000..da644015 --- /dev/null +++ b/docs/source/rbac/tech-implementation.md @@ -0,0 +1,33 @@ +# Technical Implementation + +Roles are stored in the database similarly as users, services, etc. and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `add_obj` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. + +## Resolving roles and scopes +Roles and scopes are resolved on several occasions as shown in the {ref}`diagram below `. + +```{figure} ../images/role-scope-resolution.png +:align: center +:name: checkpoint-fig + +Figure 1. Checkpoints for resolving scopes in JupyterHub +``` + +### Checkpoint 1: Requesting a token with specific roles +When a token is requested with a specific role or multiple roles, the permissions of the token's owner (client in {ref}`Figure 1 `) are checked against the requested permissions to ensure the token will not grant its owner additional privileges. In practice, this corresponds to resolving all the client's roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared and if the token's scopes (s5 in {ref}`Figure 1 `) are a subset of the client's scopes, the token is issued with the requested roles (role D in {ref}`Figure 1 `). + +```{note} +The above check is also performed when roles are requested for existing tokens, e.g., when adding tokens to {ref}`role definitions through the config.py `. +``` +### Checkpoint 2: Making an API request +Each authenticated API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API (scopes s1, s5 and s6 in {ref}`Figure 1 `). + +When an API request is performed, the token's roles are again resolved into a set of scopes and compared to the required scopes in the same way as in checkpoint 1. The access to the API is then either allowed or denied. + +For instance, a token with a role with `groups!group=class-C` scope will be allowed to access the _GET /groups_ API but not allowed to make the _POST /groups/{name}_ API request. + +### Checkpoint 3: API request response +The third checkpoint takes place at the API response level. The scopes provided for the request (s5 in {ref}`Figure 1 `) are used to filter through the API response to provide access to only resource attributes specified by the scopes. + +For example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the last_activity attribute. + +For more filtering details refer to the {ref}`filtering` section. diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md new file mode 100644 index 00000000..43dad2d2 --- /dev/null +++ b/docs/source/rbac/use-cases.md @@ -0,0 +1,75 @@ +# Use Cases + +To determine which scopes a role should have it is best to follow these steps: +1. Determine what actions the role holder should have/have not access to +2. Match the actions against the JupyterHub's REST APIs +3. Check which scopes are required to access the APIs +4. Define the role with required scopes and assign to users/services/groups/tokens + +Below, different use cases are presented on how to use the RBAC framework. + +## User scripting their own access + +A regular user should be able to view and manage all of their own resources. This can be achieved using the scope `all` (or assigning the default _user_ role). If the user's access is to be restricted from modifying any of their resources (e.g., during marking), their role should be changed to read-only access, in this case scope `read:all`. + +## Service to cull idle servers + +Finding and shutting down idle servers can save a lot of computational resources. +Below follows a short tutorial on how one can add a cull-idle service to JupyterHub. + +1. Request an API token +2. Define the service (`idle-culler`) +3. Define the role (scopes `users:servers`, `admin:users:servers`) +4. Install cull-idle servers (`pip install jupyterhub-idle-culler`) +5. Add the service to `jupyterhub_config.py` +6. (Restart JupyterHub) + + +## API launcher +A service capable of creating/removing users and launching multiple servers should have access to: +1. POST and DELETE /users +2. POST and DELETE /users/{name}/server +3. Creating/deleting servers + +From the above, the scopes required for the role are +1. `admin:users` +2. `users:servers` +3. `admin:users:servers` + +If needed, the scopes can be modified to limit the associated permissions to e.g. a particular group members with `!group=groupname` filter. + +## Users as group admins/Group admin roles + +Roles can be used to specify different group member privileges. + +For example, a group of students `class-A` may have a role allowing all group members to access information about their group. Teacher `johan`, who is a member of `class-A` and a member of another group of students `class-B`, can have additional role permitting him access information about his group members as well as start/stop their servers. + +The roles can then be defined as follows: +```python +c.JupyterHub.load_groups = { + 'class-A': ['johan', 'student1', 'student2'], + 'class-B': ['johan', 'student3', 'student4'] +} +c.JupyterHub.load_roles = [ + { +   'name': 'class-A-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-A'], +   'groups': ['class-A'] + }, + { +   'name': 'class-B-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-B'], +   'groups': ['class-B'] + }, + { +   'name': 'teacher', +   'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', +   'scopes': ['read:users!group=class-A', 'read:users!group=class-B', 'users:servers!group=class-A', 'users:servers!group=class-B'], +   'users': ['johan'] + } +] +``` +In the above example, `johan` has privileges inherited from class-A and class-B roles and the `teacher` role on top of those. +**Note the filters (`!group=`) limiting the priviliges only to the `class-A` and `class-B` group members.** From 2ebd74e5d217e64450dd1242a12d5e1da086e67b Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 15 Feb 2021 16:39:11 +0100 Subject: [PATCH 062/270] Test vertical and cross-filtering --- jupyterhub/tests/test_scopes.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index a869e84a..1a70ee32 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -410,7 +410,9 @@ async def test_vertical_filter(app): async def test_stacked_vertical_filter(app): user_name = 'user' - test_role = generate_test_role(user_name, ['read:users:names']) + test_role = generate_test_role( + user_name, ['read:users:activity', 'read:users:servers'] + ) roles.add_role(app.db, test_role) roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') @@ -418,9 +420,31 @@ async def test_stacked_vertical_filter(app): r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - allowed_keys = {'name', 'kind'} - assert set([key for user in r.json() for key in user.keys()]) == allowed_keys + allowed_keys = {'name', 'kind', 'servers', 'last_activity'} + result_model = set([key for user in r.json() for key in user.keys()]) + assert result_model == allowed_keys async def test_cross_filter(app): - pass + user_name = 'abed' + add_user(app.db, name=user_name) + test_role = generate_test_role( + user_name, ['read:users:activity', 'read:users!user=abed'] + ) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + app.db.commit() + new_users = {'britta', 'jeff', 'annie'} + for new_user_name in new_users: + add_user(app.db, name=new_user_name) + app.db.commit() + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + restricted_keys = {'name', 'kind', 'last_activity'} + key_in_full_model = 'created' + for user in r.json(): + if user['name'] == user_name: + assert key_in_full_model in user + else: + assert set(user.keys()) == restricted_keys From 364baee3557b5fbafd0000bf9c9755377a1e4bce Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 15 Feb 2021 16:49:31 +0100 Subject: [PATCH 063/270] Resolved todos and added docs --- jupyterhub/apihandlers/base.py | 5 +---- jupyterhub/handlers/base.py | 1 + jupyterhub/tests/test_api.py | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index cfdf8043..2ae721f0 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -246,7 +246,6 @@ class APIHandler(BaseHandler): 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, } - # Todo: Should 'name' be included in all access? self.log.debug( "Asking for user models with scopes [%s]" % ", ".join(self.raw_scopes) ) @@ -263,9 +262,7 @@ class APIHandler(BaseHandler): if model: if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending - if ( - include_servers and 'servers' in allowed_keys - ): # Todo: Log breaking change: now no server component in user model if no access + if include_servers and 'servers' in allowed_keys: servers = model['servers'] = {} for name, spawner in user.spawners.items(): # include 'active' servers, not just ready diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index cda05418..7b3199c6 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -435,6 +435,7 @@ class BaseHandler(RequestHandler): return self._jupyterhub_user def _parse_scopes(self): + """Parse raw scope collection into a dict with filters that can be used to resolve API access""" if self._jupyterhub_user is not None: self.raw_scopes = roles.get_subscopes(*self.current_user.roles) oauth_token = self.get_current_user_oauth_token() diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index af822bc6..cd97dea5 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -260,9 +260,7 @@ async def test_get_self(app): db = app.db # basic get self - r = await api_request( - app, 'user', headers=auth_header(db, 'user') - ) # Todo: check after dealing with oauth + r = await api_request(app, 'user') r.raise_for_status() assert r.json()['kind'] == 'user' From 45a0945a6b3f979f649d7d3dd6186aeb1ae4a2d3 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 17 Feb 2021 15:46:10 +0100 Subject: [PATCH 064/270] updated requirements.txt --- docs/requirements.txt | 1 - docs/source/rbac/tech-implementation.md | 2 +- docs/source/rbac/use-cases.md | 11 ++++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index efdb9f07..8330f4c9 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -7,7 +7,6 @@ https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043 myst-parser pydata-sphinx-theme pytablewriter>=0.56 -recommonmark>=0.6 sphinx-copybutton sphinx-jsonschema sphinx>=1.7 diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index da644015..66080fe5 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -1,6 +1,6 @@ # Technical Implementation -Roles are stored in the database similarly as users, services, etc. and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `add_obj` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. +Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `add_obj` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. ## Resolving roles and scopes Roles and scopes are resolved on several occasions as shown in the {ref}`diagram below `. diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md index 43dad2d2..0024fdfa 100644 --- a/docs/source/rbac/use-cases.md +++ b/docs/source/rbac/use-cases.md @@ -42,13 +42,13 @@ If needed, the scopes can be modified to limit the associated permissions to e.g Roles can be used to specify different group member privileges. -For example, a group of students `class-A` may have a role allowing all group members to access information about their group. Teacher `johan`, who is a member of `class-A` and a member of another group of students `class-B`, can have additional role permitting him access information about his group members as well as start/stop their servers. +For example, a group of students `class-A` may have a role allowing all group members to access information about their group. Teacher `johan`, who is a student of `class-A` but a teacher of another group of students `class-B`, can have additional role permitting him to access information about `class-B` students as well as start/stop their servers. The roles can then be defined as follows: ```python c.JupyterHub.load_groups = { 'class-A': ['johan', 'student1', 'student2'], - 'class-B': ['johan', 'student3', 'student4'] + 'class-B': ['student3', 'student4'] } c.JupyterHub.load_roles = [  { @@ -66,10 +66,11 @@ c.JupyterHub.load_roles = [ {    'name': 'teacher',    'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', -   'scopes': ['read:users!group=class-A', 'read:users!group=class-B', 'users:servers!group=class-A', 'users:servers!group=class-B'], +   'scopes': [ 'read:users!group=class-B', 'users:servers!group=class-B'],    'users': ['johan']  } ] ``` -In the above example, `johan` has privileges inherited from class-A and class-B roles and the `teacher` role on top of those. -**Note the filters (`!group=`) limiting the priviliges only to the `class-A` and `class-B` group members.** +In the above example, `johan` has privileges inherited from class-A role and the `teacher` role on top of those. + +Note the filters (`!group=`) limiting the priviliges only to the particular groups. `johan` can access the servers and information of `class-B` members only. From f6c98f6aafa2aea4ad05493efc2e46d6a9b90f47 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 18 Feb 2021 17:22:12 +0100 Subject: [PATCH 065/270] Caching database calls --- jupyterhub/apihandlers/base.py | 8 +++++--- jupyterhub/handlers/base.py | 9 +++++++++ jupyterhub/scopes.py | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 7bbb88d6..daa36ef8 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -73,7 +73,6 @@ class APIHandler(BaseHandler): if req_scope not in scope_translator: raise AttributeError("Internal error: inconsistent scope situation") kind = scope_translator[req_scope] - Resource = orm.get_class(kind) try: sub_scope = self.parsed_scopes[req_scope] except AttributeError: @@ -85,8 +84,11 @@ class APIHandler(BaseHandler): if sub_scope == scopes.Scope.ALL: return None # Full access sub_scope_values = next(iter(sub_scope.values())) - query = self.db.query(Resource).filter(Resource.name.in_(sub_scope_values)) - scope_filter = {entry.name for entry in query.all()} + scope_filter = { + resource + for resource in getattr(self, "%s_names" % kind) + if resource in sub_scope_values + } if 'group' in sub_scope and kind == 'users': groups = orm.Group.name.in_(sub_scope['group']) users_in_groups = ( diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 422794c5..2a4ad108 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -432,8 +432,17 @@ class BaseHandler(RequestHandler): self._jupyterhub_user = None self.log.exception("Error getting current user") self._parse_scopes() + self._cache_db() return self._jupyterhub_user + def _cache_db(self): + for kind in {'users', 'groups', 'services'}: + Resource = orm.get_class(kind) + resources_names = { + resource.name for resource in self.db.query(Resource).all() + } + setattr(self, "%s_names" % kind, resources_names) + def _parse_scopes(self): if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): self.raw_scopes = roles.get_subscopes(*self._jupyterhub_user.roles) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 613935eb..ba5532b0 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -55,7 +55,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): user = handler.find_user(user_name) if user is None: raise web.HTTPError(404, "No access to resources or resources not found") - group_names = {group.name for group in user.groups} # SQL query faster? + group_names = {group.name for group in user.groups} return bool(set(scope_group_names) & group_names) From 6123f34b8039922016dfe8c8014c82a917281cb1 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 19 Feb 2021 09:49:09 +0100 Subject: [PATCH 066/270] Replaced implicit member call with dict --- jupyterhub/apihandlers/base.py | 4 +--- jupyterhub/handlers/base.py | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 3cf23fa1..c8617bc6 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -91,9 +91,7 @@ class APIHandler(BaseHandler): return None # Full access sub_scope_values = next(iter(sub_scope.values())) scope_filter = { - resource - for resource in getattr(self, "%s_names" % kind) - if resource in sub_scope_values + resource for resource in self.db_cache[kind] if resource in sub_scope_values } if 'group' in sub_scope and kind == 'users': groups = orm.Group.name.in_(sub_scope['group']) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 3f8c8aa8..60eddfaa 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -437,12 +437,13 @@ class BaseHandler(RequestHandler): return self._jupyterhub_user def _cache_db(self): + self.db_cache = {} for kind in {'users', 'groups', 'services'}: Resource = orm.get_class(kind) resources_names = { resource.name for resource in self.db.query(Resource).all() } - setattr(self, "%s_names" % kind, resources_names) + self.db_cache[kind] = resources_names def _parse_scopes(self): """Parse raw scope collection into a dict with filters that can be used to resolve API access""" From bc1e370d7d9922e863b76bad7b01049ead6e505c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 19 Feb 2021 12:37:20 +0100 Subject: [PATCH 067/270] updated tech implementation section --- docs/rest-api.yml | 4 +- docs/source/images/rbac-api-request-chart.png | Bin 0 -> 237823 bytes .../images/rbac-api-token-request-chart.png | Bin 0 -> 214426 bytes docs/source/images/role-scope-resolution.png | Bin 48730 -> 0 bytes docs/source/rbac/index.md | 2 +- docs/source/rbac/roles.md | 1 - docs/source/rbac/scopes.md | 3 -- docs/source/rbac/tech-implementation.md | 48 ++++++++++++------ docs/source/rbac/use-cases.md | 38 +++++++++++--- jupyterhub/apihandlers/users.py | 2 +- jupyterhub/roles.py | 2 +- 11 files changed, 68 insertions(+), 32 deletions(-) create mode 100644 docs/source/images/rbac-api-request-chart.png create mode 100644 docs/source/images/rbac-api-token-request-chart.png delete mode 100644 docs/source/images/role-scope-resolution.png diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 869fa85b..0b1ac25d 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -477,7 +477,9 @@ paths: '400': description: Body must be a JSON dict or empty '403': - description: Requested role does not exist + description: Requested roles cannot have higher permissions than the token owner + '404': + description: Requested roles not found /users/{name}/tokens/{token_id}: parameters: - name: name diff --git a/docs/source/images/rbac-api-request-chart.png b/docs/source/images/rbac-api-request-chart.png new file mode 100644 index 0000000000000000000000000000000000000000..a0476399bee51e7b9c34fdb3c4a5c2003b9c32ec GIT binary patch literal 237823 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

+c!cEhrjK+)A#du&mzfDLTA{a02_q;J- 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∨un8rnf*WCOoUFb`|CWen@oakFz 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 literal 0 HcmV?d00001 diff --git a/docs/source/images/rbac-api-token-request-chart.png b/docs/source/images/rbac-api-token-request-chart.png new file mode 100644 index 0000000000000000000000000000000000000000..5a37b225e355d144913c78adfd0e67ea9e2078c4 GIT binary patch literal 214426 zcmeFYbyU^ezb;A&(nurS-7O&?-7TGqF6jlf}_^4j!r$wT@jiJGq>y2t`~=b>{K?q?oIE<|qWsi{(GzE8+{UMA>R=bgy; zE{fc>U(+tkjEZlsZl$cU49B9wgi#zE-Q^}%v?ynhl15dL)?OSd zm5S)mwK}L!P8{s4itVk6vA2?5#v-4(>nK@$Z_nxead6XrvBY*bvmLU1br5#9+L3_S zmeiz#Vk|{UY9Nks0F{65g?DpTbW;6>qUx69z$QFLje<-ha`I%MbUs%5>U<7e`{%lD zR67-Q@&!tNU{x2>(xSiD{3dCPzuwpahQIsfB|*;Nna5oFJzv&n$L7c1-+mtKdNBmo z`pExwj=11eBnlQ>tith&>PTDKyXW#NFHonYHyrhOA~MNKDm`@cm38Uv=%!ssgun#p zMO-{aHCr{|-l9Fn*E6Qkv@U1%Dpg0X zE2Z1pW3kQBwKgrbiwu)5IO@SD;%SqN7Vk0qg?H$dp#1M|FQq)A&DfUMv}k_h92uCH zJ*eoG7kFS1^Ru7aLqDq*W_cOj=x)v?93NP6nd*BK8)CGG)i3KOfLBgl%qAT;%FiT8 zpc)mjHkIprLVR*DAJ^lJKTLtik4sn{>VEei1(+Ui&rgr^r>kkec^hH^2i;%g>mOVeZIxHoDt3=b1Y`5!% zkDeFBXG$XeA~yG&HoweeX=fWg9%+0YmGkJ5(fl^>S~@!_gX5(r!uoERaM5z2!1}J$ z^6TM16?19}Pe>F>@t(Nwz3%?~z(YvA^*%{#{)@71!Bvt=G*MidT=KH5159JMQ$TP=Z1*nnyGS^aLJzSJUgduMp zM7-VoZ;<&9P{YOuojoFri@7yx#3e#XNO)~tOitk@1$K$_J%QJlcxM;fbc6N8S90ro zax}&&Si$GX*w4HKD2KOOlk=R+alL(boPnGJ<`o|D^7v&J!lXO3%EM{P4Tn)*?~nMM88x8u$?wJXx4SCYg}V`h%e@Eg=^P5Z(}INYpFaPFzu4dYrM*oE6RSFn#c z4WFD!91u*NjZ($Zqo-t};`ZA|z7LVef)#i!_=COSy&^1SBzNtTim6+JNVtw75?=$V zWiC~|tdO~*c{q>i%6FOms`LA#F5)r6X_CB-7vYpW+%SQN|0?d;lL_O$ZkM+*y2@#AO8l_PJYhQBzZVhfn2HXNVh zc8%#~LI3np85fcn9{)VCypcvejt|9@YEF88BVrl-Yvjo#QKwWuhAwI3n=z4h8$zY^ z^)qG2zKLb-NX580$}CTh#eR$s5?JTY1S_M2ebdO>>$V zloT7nkMMCLnbXWqQ|5{n$ir9i@EN^f1u4Z81r|n$@K80CUR&jI507RcZPN|}!f3wm z(4Y5hYJL!ye=$1^pY?q|SEZ4#-afFf;o!^8en6hPK4HoXvh2jU;0}FU0vB|C0On?= zhag=vT;TDRI${$iRL%RX?iUmt3MfxARX+qvLaRn)`>!r67$zInJ8!YsVtG;6CC((O zJg*_l>f)eccnT9jXj@=siEGI{-Hf}w9pJu<_=?d_9bLNhI{$#Yj% zKOwdYElPu4r##$mWZ`5Fx(b%HpQU!Lwa7w=Lg5h4X;?GTCCzO=YA-=@3Gr30aKx}K zd`pa{;`-p9s7krfy?8(1vr$AE$P5WMCPXQSg^v??ek@w~MWP|NYwfD&bwF}Gxjzbb z&5UH2e4>uFxbpR4=_^8)u9Occ@8m=s2v3ML1y-E%@yoW+jPUsQuGcBxTHg>rsMh-P zy6DMltzOzbX}$Nu)r7X=#WK|HL#v5$#EASJpNJ&#gZb&XOJ@tSCY3Tz(27K&z2)ak zA3ohXL+2C{n=9E0mJ~uwhwzPwV#Y5or(R<+9i}w2qNBj-*KId8P9cBL48}d#vWbOH z*D1-zgBFl5&pjs?^(c+0QyNvfpd3T7AOCI$6CkL#Yy`i7NBYJpa2Bn1%pwyexLK}| zw%~paVVGQX={-+$Ek{^WzIUE+yqEnaBe^egthiG{Cr_()&h5;r^9~U>6 z9>pljI4?}#Xdx+_ZEa4aY!tPvD@A&y6|LQ4e4SA>;VC8enuI_-bp=kYQKEd};8`tV zy*b6_YSzy3S?qHwD+&cm-O%vhp95Dk#!jVZ6X+V~Cccg91aZWeuY7odE=$F2hb4s2 zR2AbArA-cWU%(y{Bp8d?x`-S*1)?f5My0vSnu#H^?yWuDo&Nf6U|QLoUw&^@Qqtar zneHvFxYEdXp=E|2Z(oj>@X5V`+EOF`cG^s#iY8C2Y*Cc-S58NG`Qf5QniJNP1(O@y zQZX3j1x8X|KaW$KozkijGN?HaeiM{wlx0fMyQ)D})2iHXo}!cT}2Q7{Op-^dIMlwTOR>M_)6O~vpX$82`PqQfCT zeOhPxqSD0Z!o395ch)@}!<(I5T-QM~nT4Z6!r2M)@uqA%JOLikKr@A&k`MSRX6@=U*_)>S=XEs}@SdXGU zM~)auzu0Elv7Y; zxGpxBPxB5n3CtYF;n{UIl)6^YcO9jc?nPhUW9h%c``X}8)R+Etp)NJ(OOUts!N}qe z$&tVed@Q>2qEp7sja<_~6{?=R?cJ$Dr2Z%QBth6}8lg!JSpvu%m*7~)nyR^-vV-Yt zAMpbH!H1eOJPBkbUGXmH7UC64{OpMIIfkx9jWOi?B50weV486pPcoZw4CxQj_(Lsz zR*sj439UCx^Gx(l5uK`);O{*a5qaCxT3fjf_b+Lmt=;B<()zGl=m zp&T^EtvNrMM15g2fZ9_L@Jc)Kmx~@xO@P-Z^u)UfZisQM+%ik(Tv7O#2;HS@T@hdC za6gHUX7A;4@BSxBEcbVB3$M!7hqR?9iJ?BGrW#bZYv)hFFl;#KL zHJ&kmf)JoyWIKrIRW3k=Wxhf<@J@1$nF=MJh*>zq@Ph@WbDg*$b# zP(7?LVf9a#2<>s63+%;kFcq~?^#!eTKlw~6HE3!o%`M@L7X}Cq z92Hq6-C`lFMx=P+lD8gACTK9?x$ZXaku93H;WY$_6rKhms~LnwTxdrQA*07V*S0tM z;<9iPvw>oHatO7v#VOvw`Vn)+H+}l4Rcj`ez000DJ=+H24$mOgLGukPCn^G4i6*Ag zgy(=j>)3d{kmPuBmE19nSb!xR0}5K1qk4d$`M0U}wah<~k;ITk5+n<;hMZFmf09xzH8;T4sM0I0WAXGD6*X{CjXRi_c{?XWOZ%i0QWo&L&Ko-xAp<%* z;wQY+r4ABWKFwjVE{`ZaQsTFX7@k7)4X+fex1ESBh!cA4=lYS?(bu0Gw=%yk*d5UF znr5zA&k4yT1mvl!P~%Gv?~@ImcEr|Lw3$q@MbJU7XuZYVsS(G$BzZPX6-J1CQA6^< z+nkVxgDsp-_ANJkK~G2uuCTD=wNKR4FmnZrzGRkyl*k=gLAc zgToR(CETE4db>B!;p2)8!ANvh980JKLa9(6&vdwL?|G|alK13A*M`KO4~{XuhNO~) zzB+1j3VQi8F)0E4QiMMO7bz~_dw19Iag<8oN|oHu>|2Ts#KwTo$(0r1@A|hSo8NqG zL@Zj1E3N5cncT{a2Q*`cex7AJ9FPlPsTvkRR#!&GFB|p4g>_&gl}gBz&GrnznN{8ePtxS^XYyMD%Oe*J}C@G zs7ge_h;&3sPA>VSa!i2R5C4uLtX~TJ@z4R2{F?SJprxT|lHSZuq(`^eL~Xsl*b%qXNSGyoBHHg%?QOFE3>IQ>fK^%*|jL9VgnGnPyWt)b~OO z2vGIP&tcM$oJwXeir?@DI)C)Z!|5<%+QxRlMx+05qZRqVn*5XH$;X%1bgs-)t>Zl^ z#Z| zMb-8EycEYfFZxb~(P7bZ59fKzF#fJBTe%oVfl)G7UG`Wwy{y$q552NAadmwbFNaz*F-iO|9J!VnHBS}yf?+zhmKrI8yruIZqh}W*w=4U z&sikYoE|)aJYT3jfBoY5VU>a;IY<)ej-fr~Teqo2N& z!Ztq-D@B6lIt=^#Y6Y%}&KFoSR!)3ZB$e`c*xKy!dG4DvoA?>DqlSoY$JExxwwMAVnl@<_lkXk zvB#AUS(IO-ShVV+Geg#-Jx&qj$DUL-Vue?->PJr&UKda6epYYh(RNPLfwu3f>o<*j z^A5pJv>vyX`R75hTL`N(3)O0!v68!uP&`IV%EweJ3al8}n|Cqe+eb+ANcp@dd=>q* zb(NzY3{Re9Cuz&c(2mu+K5I6_tSc-#O0neaGY8sP-l5}L>SiV$XzGsro#}N@Vuxr4@dU7w# zpOQzm*lzd8PRDj|SD;Mu+1nmicXr`42Cj#VPYrJDFGsiK88QWlmqjL%Ml-|R3~32D zo*h_YkySoB(p5rut*O(WYO^I85QRr;OtG#$1Y3M411F0#Qr2hFideV${<_z{SK;lL zIf`rTSNF(wS-mR~bKA@uu}sMnK{_OB)6=b*?i+6!e-o^qW~8ikDv1;$_+K)Z6hKy_ zb=dbg@Zix#84GWjv>x%C+ZE6BjBRouU$2%epzdsJSQaf^R}Lpy@j~y7r!1ji>YN{4LdyeiSvx4-jN*ju$QO3}>Y`H&Qa5+!|R7U}&6L%dk8qUX=-_+x{SDi$<;pw?mNN5jLSWroAm?na7;*Yr>#^4ZOh zACO=o5v0ga%4}3>66na2?=>O{RbsW(qfT_f!n)$Lz`Mh+$|%{x$}10D5Hyp!q{h=N zm&&1MQ6!Ejd8t>1X4Rjk5!$|}6Km(nA?e1(#4Iux=M3#on-o#}=~2rd_e-hyID7%2 zbWNNVTg8vg=INdJfia6a?b8qe$h^}>I;6t)lR<`Z=yW2XUPb4nudLavFAkU0#uYYc z+^mXlibBT)FLVMMqu0txeNQo*;Y7aqGQjQ)DbtBcOODnXrSiWpWt#M5dQv`aimTsm z#Iluw3|FB<{#<{~kLrpOe;&o}Z&l)7y(!4e&GM zLl*|^+2wQ%9A~_?w1H9z_Z|*aQA>}7x+rC#`Vf7I2*=!s2LJfjyIgQSCDcBuTidCJU?mrY9Cs7Egng-*z!OnPBf6j^1U3dDZT z3K|S3x4+yZV;J&XgdNO%^QJ~8TI*>YVnP!WdT|I&BZZZnJB4J)Y@(Mu88r1rsRYI` zYt&U&*y6L>53aJ_IUa-d8i&&8MKsJ_-J`#o!m4(xW-TS(+bEWbFVOQaTmD4t!@fm{ z2p@b|O?>A7U9T|u;I((Kx{0BtB*_w6$)a-fcl& zW1aeiOavB*OUEUy5P_C3nv>79@g-TA9UgQOci$)Dj|;1Fi?{Ka$6gQU3>Wc9KY{hk zp=gd2^7?dqRWWwI(880s@BmFUI3AdDE#3+R1s!Z9F0L#iF8;4p4QSA0`o0&E?s-Yn zXQ)<0frIlRoX@OO5%-k@ksMB>QC=;Mjw@T!DRMd&6+KJLTbr(~*uL_h$j_B%m2b%| zp;tCG3b!bz?^)?8cTeqGaP9C=(xD@QPcXPtI~b9k%6v^ zbJhmk%4;zgneaFjaRQvz;bZ0RO(-O8*wG)tSC!)BXtW5Th>%OgLe?(39+ur3%#FPU z6_CCJ?BmVdoGx71(1AP9Xs+L<(cuJycgo_71J9#^Y^Z(UB6mZ>w6G#+0E%m!4=fQ8%&Nqo!G(vrl7+)Vw$<4M z?9&4$Uz8#7T_`B@Oe@ejd#xZZVCrDUVr=GM0%7s6a|Eq5C@4V@4@YBD8;A>;3Bn`bVI(p^Co^*a z)mM^#PXS&DQCPaTI0~?`y1ToxxO1{NI9af=^YinwvT?9-a4>@r%+8+nF2)|r_Rf@# zQ~Wi@D~PkHla-^3m4iLmpPEW|fH(hM;PLgJ>78B7SY^Nq zE^r<&fR%%djgOg)gPDV$^`Fm!PZbpY?P+`GzpV)D$?9S3$jZ*b#%gExAD(b_k#PI> z_5RZ*oYg@GlT{Vs?BMET3XyPw*t<~vb5TcISLc7O>FNx5eCyA?ZOzPC!KVJK{Lg2k zWE7PD?U_e2T3FdR{(0hY^gl^2e?MuN+KW9~YH*B}DPKUjZ`*Q!6upKfiLbne(!n znVK^5^7EN8b3sfX%>1U@#?0(o#^9<F5IQ}t}jJ>mqvArqeaVju5ixrrMhu_$Q zmxGU+*_?xoA56i)$IK7z8N4(%<>cfrHihtU|6>XzCo2#M#DlxXhW2xp?`Rx!L%P&5g~?_#o`;f2Ml82LVxK86gS|7PfzXN7>fc#oWQk z4uqGLy_ti%^S^(jZe<5ib1{B28#@m>CpS1R7Y`RZ4;$A%X4Hf@IRiI;oRyu8h2yW2 zo0$qof;o+WyII*8TR>PH?JfSy`*<+|;5fjv#*fhfX8!X&IE{d~6U5lX!Aaf0!B&Xk zakpfTQ~n7mGQq#YML^!c^v{ET21CpqBku2*6En78{qs_g^}ibYzs#g&>ELev|81Us zANp^zh&s8rJ2=@WIVqV~Lrh)%>v{gO!T&asD#&)uE>4~@|A#~Uzs3pv<*?G=SqCT2 zf2^+tdGpt+zfzK|)gM!lk^M;n0>-9)ncvyi4Py4^3V|q*@-v%&-~cbVcuh>rdDtL)JpXZaX9sf^cVj1rs0Hu= zaL*vP{@gPe-QWI4{~yP@TS6Y4i;aW*F$uEss%SGuzrEx!kp3_J z{Ox`J7gqpN|IZ@-E&KkDx&Fso|1Asrw+8=@cm0pK{#zFKZw>w*@B07ETuA>;xgqud z_qhW?UBgh*1<3eQM`>+mC@2=n$A8csMIvtCO#~Mi1qp<87)%Umg7DB(Jt!zLD4AEH z>K?PZ3l<*g>*qX&77b}KVN`HW;ppE}&?!W~z(lBTKf_$3V>k{&lx2-rr<*85lvWuF zc77E>F+v&f40B2uwzrd_ub7hxBU6;&(A$Lt)H_k zn7eA2o;(T#P*4rRm<@mZ1_h1&*Dn}{|C=}d(+_gFLXA_4Wn!=7ZW`Pd+1`TD;oL>C3h6(ZQ(#h?n=U3J@f*7;tpPA$^f>jOR!7xM*D5%4*T){7- z8O8L7Z|NfZ`VUDD{0y6C`Q?;C!GM4O1Slwf>`AV>_~+DZHlekuNWSM=i2r)j;*haX zzxv+X|JWK{fZD}W&9yhxj8|~@0!&znVoJ6GN)aUVu28!EhT&QJS8kuKBFMj)J z*MwW(KUs>E3XJRL*PoFq7QLMYPcJ9atl~mJ%}01V<3w5Q4nf`=&FOIb^|rj6B({I^ zHJQQ&hkX>fzDkkJqQnqoRwgKSK{Q zzQ~__N=Kh1;A-6;L%ig3GScpQ!=m3@Xhm2g>}3qzH~I7PHYf-d1_qpzLGvR%At50S z4h}XpHZCqM21aK=N?UF}zM4iIFgPpg!SVXg=C>^8mW8IKCZH>Uy|U2J@%i0eju%KN zOcq9Dk|CxShXe=L+WxH3Z*d#R;H}bc;mHa{3Qa`u+#4s^lT~~Jw)uEf0US7cyV~Da z;UVVc`-^SfbM%av zf&=J03JJ3Q=PMbNJ6Bg%H|KjdSDQKhm%qZMrl#alSeo=$zPwgZQ86+ya&&YYN@gbY z+REdxn|&oIsXDys8H)$Stx#a`xD^nJxlxl`3ds;r4Ef1ZuQuI!+n=9|#Z^_~XLgF# zaGyPUhK)UyFA+(jkj`a4f4S&=kOWDy;1_AGoJ+_S>Kj+`i14KT;5l61^v!`RyK*O< z$|^lMJ3Bk`&rf!?-|i3gNiK15ab#pwYcqRR_Jis&DI*Uc~w_eW2fELul>xZy38xj66!eG zyh@;!TKw5DXuGF+skPnaqCYw~DB!r<87p$%=zXytgn%xPrKq6+3kwTuJlEoWfJQ6; zVksN{?i(yHz++B;Acf?#wzlFhYWf_1rQP1%j;G?!Qk>)>^*tT;ySo;;TnNUi`#Kc6%P_pk)A0A1p6b77xO0(gxq+q$obrrw@({gg?67I6*$17`*uh) zo7P)FpCjRG)PBq4Kbh8b@ICvk6>7ZIY*1y;*4WqxqAi)#u$^fEiGj_a)#FW1D5}j& zro5$z!(0jir496XAU5?jRm^50gBwW`iS>SIA-FjYnNzB6chrzLZffF70 z_AQ&;^h-Lo4c)`(*0||%XJCa+ok^efCY1~W6B7y=8q4#Gz=v_J5wHLVI=8Fib@j#F zxrPHd);4S`EJ~Spp^dU~Sp>3K=)Z2@_N*)Pz~J*{awHyW`^BR7Pzoz66O&ogg6oWa z0);;zNiMsC#WqUGsDZCvkG$IQ>0+Mq?iZyPaG(UeCF;Z185>~q zgBZCHv6>!RY;pc>Zuhx5-kvPM!^W15$0i{WwweAYMdBH3?LI}Ah-;l3eFG+c%y5o2 zn*y>N231;w_#bv5oEF6pzi7Wb9^$r{KGkiPZaI7XlR@{0*yTK%y%l!k>SS}t z?`99AbovNYb@kKB)mWt*VIeB2-gXG)Ht?0lEU;W<7E6tQMug8}`{NxJElN+RO2L=j zcUT|>R3Zcns%F-mRE~df?qAw$e}Ir}sSaaFyic|{KIfczDS_Qb>Ua5Tgm+2MX)V0G zoSmKBq5aAnWL>#);zyJGaTs|OmGR*;PON9oe1u6&Z69y(OH|%`_l_&Jkw;WsRdNv$ z$pN8tZ2Kwnp7^M%zW>ABMTt^QrByl^qLScI?}w^(kevsWdqLE`?1Y87bUv)fSW3vJ z+t}Rf@9%#c9%@``Gqb;*VhBn^%bR{#_l@B+0#0+E>+OS3yB*? zK{%1WcP0{1Y!$_>oeVDu0=09wD~OYW15Om5-)SwC-SqVvXUzFh8}p6zp_EwS7t`A= zl9G}v2Ca=U2{aM;hb^1Dq9kCR%7k!TC@4pTsV52SG&1q|bZ^Og?yok1f4uO$uI>5d zu~X3yicb0s|HP|J+I=Qr|CP$_QpZC)wH(M-BO`k=RfZ-e6pSnhsu9KX*p2#N$_``( zkeX(`ND(UYX*W9lI^CXh)#pVq{nZ^J`c-We37hvF>s73?E0%cD2ib1afh)O;+GOKCs)@;n&=Dio7`b1m?P+fN*0&rU`~R}bje zN=i!53AyMvITP4%Nl8VFyWzgz*O^zNKkntv4Q3?ldj#5lji**CmLGR*^E&%|(DC30 z>ZnK4JND4og|pncl*IYc@vRVKylk)EWp_6h$Zy%Kr+_0#K7AX|O$=}XYNvxFG*o5a zL>5Gw)c^Jx` z`pBniKl%0|5|=r@3As`0(Ml<&*E?0KEKpE-lMy(K2A=CURWoxSnf3Pee)_~lcqS>w zt9>La^pTJTL?(PM|Q@&($l$7bY|7n!tif>^!)~!MMFbV@352|8&%=}XUGyshWdAGM!WRO zIr`+JLbN?SJ&9kq4G$07&Nm)?iGE%-Lb?8e`<$^T7D?7q>Z3Za!;U903ncrZ|cx?rU_oS z=$CBVH){DSH=9RkRO)#SCelMgLj$np_bUVse7Fm8kQx4yJIszOxW9s}QL?!}uYcy= z?#CzNz6hMRWW9ZTLMOwVk8xAYaTqJ-9+8juHrGn0!G0kWjhI1Zq5-6wUty#ZPTIdU z8HPAewK|Ex0qLGT8u(tM9d(#3YJPqmRAd8CYARdyuU8^j0TkQzoaDlh=xVzT;>d<* z3w8?~^%S!LNGPRQ5&5H$6u>k&_m|*q^-pG}vzj8ZR)NgWH zXV55rB_-A0+YA1mTvf~x7|9V4;pLrKOb?O5CL!GZppIYI-`a%epB>73h&RhRcfjuZ z-Ouy9Kl5&{@-nKtoSvTEg*vJ_jnl$ydxBa>DC>Uf%D4-R{%cZ;o^pdhJH(BFGyT1o9@TL zw0mCgEWs*WeSMN^Z!Aw7SdLi4&&SWNy>bUTn6785SuyXuTjF>eln$Bfj>NWSxur_| zuOx9%jNP8=EnDn3kmrddkqPM`M{;!$1fil~M{sg@oemNP28%zcO=l|gs3syJBAG?sT6=m@Nrae$#9+|+WrPxTt!2$yrlFI~Q4!}2d2{m( zU?~7sobPY1K-NSf5xksp=(zj+p~_6VJ`77c*>ie=Yoxs@>KW!bwM;xXKwC%~_Lm^6 z5IR4el1VEO^rhF*RX7npIdQ02Zs1dkw_OBS0l2w3hNxgew3Df6Yy+5TP?h3D z+!ieSKA#RPENDN}7+*bcb#>WOR25qyT|#v0bK5CdPjL7#8B+=BfE?|(k9#3vB2C>Bp88*oZcCPa^3 z-C8LfD~E2IUfkE$2S^#9jE;+~p4ezAU4NJ7#wS%X8F6vTM;jn)>-3VVPWCnHCRp3F!&!0C%k{p4jD`=R>^ehs-vQ!01Pt&blLlSmq6IZ!`9Xo6f8VegWZ!W7yZpW)ff^XLQ+!y ziv@T0-&0mQ(-k0-?vLg5fTX{T1c=tRw4!-yom+mh0SpyvUc1@Eq@=!~c;LFr2oEn| zpl%1*qR@pe$#{7i023Y+zG2FF=gwVg7=t$tC;G|3d=;5YDNCTvay%bYRCIhcGB&oj zY(dZCwNJ)9s%mQ73JDNTzyKdBXz)|4P!s~Ox~kRw*pAZ)Igm4*1hR^)Vn{{qr^?ho zlCL$6#Yw?cn4EIWQk3(a%Tz4sUmfRCP)R&JJq3^k5U-)l6Zj`j>}P8qPl81wA08W9 z!T`|8O0CtTi@uh|S&E@w8oTL}J$xpu%FN20h<&z~!lS#KHIS<2MzozlMp{SU+1=$7xoy6z<*0YE0e1G9Nz#ATiMj9Gd zEAq`fwe7Wux)pS?fY9JF>m+7px0`*92XiGEtAfAh?o9fV^;by4^Dp-rmXO|#0nRlx zrcCl(_Gz%-!nmx2{tU3cL6K|{$gb*uC4en}$_P$&vzDL)ip@lwjh4bB)6nsi&(o(* zfByUl;KVfmjf!BwwSo7dK~F}~IBEI$(|-FgYJTK%S{qpVnxLkt%E7@Q3`(~h@Snxj zGzNX2E~+9?O~L%E`UzmLi2NnA*Ubt*If<%Fg$3g@WDnP=I@cccc6uv2NdLdv5z}R#AuD3ze5Wc@$jj9Ing9Ph~N`II-#NDYbU;>dFe047g{k2>{LhR0D318fmz>zt?;OB>6|iYlA(H zMYE9OC)}cWH6##bg-JaYEx_PQ6tk{Dh&+LZr;ngO6f-wBcXB!gL<_hWZG?PRR~Jw% zZ073sE|&Zq(l-F7xj0x_0^0&5Ff1(WdFVI@ZXlVcSzt#b);>gEJ5GF8y^5)C0F^f> zsSeQ8Up-+LyFWSU=myxLKx%oj`egy&dmxYqt=G1;3VunQ+naV>_~qCNd>qhqAheVy zy=sai8GELdGg?y4uq1AYFA1PXw(q(2U=L6(tbW!MO>P%brvpZzsHg~RTLMlmCML$E zurpaQ3W}qI#j<-84y#4mtnY^5@9ByRh&C|j3-|qA!$+L?NMQ_*7E@baTHt@VKHEX< zDFqe=d4PUK-#MKhb)jBKHdVy`9xyV%t+KMS?`LhQ0B&^!WtoMAg^Vm9hnbdkvojDD z;IDF(f+x}6BHz6$({DN77|C#Uasr8d!TtisBI!JKza9DLD%ijLo~c@@wNhIY3PD#l z>Qh7Ajg)YGBnv{Wzo!5**}4Th3t;#PwUTfC_a`|3O#u$81+t&jWU-;&6$H5TY`tBJ zQPBJ(vTKD|p8^emX>HbSBy0O8 zrVkdQ*;C;)r!~(Q?eV_y_Pu#aR$5L-L?q~Oxa@zsN?O%=JO~65t8dV4gWE1Z#yInG z)i3Ew7R&^mCy5b!`}pG%*3;GUuC)BOQ&V?$Hy!;rhvMR|1X}7@dMWBx5-LbYNI(h& zw<(b{MXr{-?!5U;<*Pl2+@qr-0IE9x4+f4%>bdq9%2|S*@or=ML}<meq?x02A0~@UU!#-!9q4c% ztoG&_S{CdVUnRztEiWkpkT-{${t>FvE^GyknnEYIjBXG_7;tpfq2q#BVe44CA~V4V zmRhV>3S912d6uuBkB|CEl>j)9m$#iN9rwLh0FLTPXB@>0xERP2ToRoJ`ry0_T9vlx z=6_*%#%vm(0hjV4jqt}oer}!|jsH%D0N?_Yv8Z@j{Y8Kf1l)F|^;Ip6sUCKlE5kxU z+Q9LF)bavQSv*6ZYLKm1J8o;7)(5NF&Iw0$0ROBli#4H&o&_={HXcN~IL*7*Y63@9 z3U?N1fOffhh592{0(kP)c)`@ikZ)h{tPM_DXb`(8V+Da2==6K4EXV)82{=DC#}#e2 z4^W+~Tj7GDCNMgfMN-Rf7OywtQ!^6V?76&|PEX^wB>Mnt``}jfvhZ^d?fQw65|YD zmjL|HP*Vf>k&%*eb-u~@6k4AJ&#tY2O8%i}O>%USds5eEH9a;9Au*A$eF%irMUBuUyB1oAJyA7MS!HZv^kZxeB5@b?Pl0G0SdxslI{ zZxbWsC+9o-JM!tyc4kU;Mbp;O31Ve+)$8*|oLbc-J`gEP`YZ<`JVC+#1XRYtLaIUX z?|>45oB;Nk%%mNklcR*w1h_>d2y>8X)Uc@;7|JCgaRCv|67oI=l7xf`Sl|I1Wx>9| z7@rGW2oxzn!COG9uYk9?>a#L1$jZyl*FcaBJGBcWqgxKzALUnohdX?(YRb!na~yz1 z0rIEeC!@gfa=>`O@1&gO@`{RRzL`Kw1{@Oz9$$KUm6y2`KIi5J%=`o<_ZY<~A6H={ zl+`??P8rfrRyNYs97*S%tF`(J(hVqLo^1vi8Xb4%b4iR^Kz=p&y~f^hdVu$t8LLRa z7m$`(uo)e^8kn{ojr~ry6ko3Z1V)iGBB71&4iW?XE3qXtgStyeLpa$U6O&|$^ zK7sdcb^lfnT?B}lW5B+792R}RB{o+gARwG*l&M3l+3|2IIP(#4tqZcTDPsiZ=H}Ao z_)M%j2>}fU>^3?&8t6hxpe6u|w;EK@Mbt2<#T7dn>ezI>K;RHh$GOX&bBWS=gS!HOXAK{clDqZTgAP!zlA^0>ho zsH^v8R?aeox0G8Nse{B=-5~zrJ05yT5m1|Zo$f$ywrBz6;1<2_UN^K4g3=Ft0 z`MTd;9)aT`BOwt2oB^c>z$utXr?H!7V80GnOm*s6m2i zR!S@a4zd`SRS^jT&=;r?7xV`&fP`*raO z3t;p5knc=Tju|VzqH!7B_GXjVlhe})F)>B&gAb?zlkQ#UY_uU8J_wg~QVvEN+TT&c=? zNnJnF&s$o^Z6=5vJja@Kh`bXY@0XF4C1f+|986*)^*I#1$CT~(?n49D@txaxYK)7S zoIDR?^;>~G=gp%TaOL*8rOVKrd-!{)6;rE@e1J&O3^@UD0VJqV_pKvsyQ0i;vxTqO zEFO+Eqnx>us&^6Dzu;fq%pLhc&Rt$1vu@)@IC9Yjte`6B>sFUB zY{7hpZcreJI>}Y`wtoo?7HCpX_+LQtp!+ecgN6lwUb3OV89!3r^HLf|J@%_oM>h)~ zndcNZ5FVL$k1!b|9YLaF`{Y|B&!QM9ChH^_R4rMhl2e1Jtq_(C^D>a0f&2nu3;bC2 zXIZ6#((llEBnfc82XsREN4-(s4R#JLu0-}P-aS7UbLf_!L9s^bIDiY7OKgj91(bb| zq&4nL>f`C>6u9kbfG55pwGMTZmnXVio;rKq#C3MQBurIo3deDGR>AHwfG)UnA9?2p zsPSTAL?AEk0{a(GZHfWf1Fb0lXw!=c2nlBa$^{A9b#L~2J8HbJ;`YUe0eLMGBL@f2 z6#!8A3CsVe>O!I52tqZEz>-uv8y*?Kk*EfRhWc}_LX_t@MG_gJx?6!N$wR!aDarR~ zb&aBWModghps?rpI*{N%c{YtY^vrQruR#mw;Y*vVUY_-Z!MZM?IL4 z@#SANnLxdFb%)&QLf_b!{3a;n>Ign!m`74+l8ey(TMs_-cwxXRWcqC{OBfQ39&CwU z?_;e41eeEQWkZV)1cm#)ZM&#;w|;AM6)Gi^ftP6yj<4+Z(>O;BE829dEG-RZoqBck zuU-nTb2TL;CA{ds=;&q^!$WxICxFR8!W&Ly55h^QaM8zm6chn;0Q$otPyL|DEFjPf zLKZ-J00A6;Vhj{A049~z%YYjyOm2M3ngfLZ(E5|S-#)&SRS4N4{=z`3pMk9!U_$|h zqfG;d0ARFu&~n9U2|Z4=FvJ+@A!)<>jv}{oX0fC?0GnNGQ^3WCQ9ZAPITdbl85E_q@V~0Zz!# zUXNTFRK$iitCEX2p*UJ?vXYueDk2ZJ&Y=4TR0&W17(*1LPd;NX%=d*dUO)ny_DS}^ ziS0eVIJ@$phW+eYR_Ghv@^jE51&A7_a@Z#cM*1A}uS*34)5(3ot``eSz8=rO%DS`b|1|9j@ zJ|KN|0kZ+UJOg~g0JL1w(waaS1C$c)OvC z0Ny|k1$<>@^~hs)M6j%^xaXI$Mv^K)2zw73K=+sa4;TIbG6A@(#Wep@1hI`$g8rHk zXKRb{#0m-Ypc;ys4J|D#MMa@;x-Lz%NkRPY!#~X{o7;N=i7tsB5f`M}EOk?p4)D5=b0#8Uc-$hB<{Dsw!=0 zZ=i|+#7P~o0w6k2PJlc@P@Z=OZVHGSp!u<{@4mnd$RQv#s%!<%D1^{ZQHwS*K{^BD z`$3)Avfpa9$N$oCe^v#60nl^Ks{2VEy$^t*Qu(gD1wL1zZdjYl5aNPGoB5yb!v`hxs? zeA7pG`aBv(tHGX6P`NE~+Pb)?sHm{8)_!4j-D$!5pba#B!PiNmD|Zx25}sizbb`(Z zenG9wriunPFK-G<)hU~J3j)0?`y8C3!sKIH_WtgsN~f+Iq`#VvpgH%utR#E3@eQS+ zlZ?#p>JeRp6M#}c;NoUru%2&xGu6Y%%IeS?j`>KI17Q)=HSPeG2gkhI$Z)v!5pEX- zq_?oJ5Fk$gXlGZC%pj1q^I4n6Mz+g#JSb$up+56h2YoX>grRS?#>kshz;RcQHMeVd ztKsRunIDCJ=Fl)y2^G-tr$rQ#l|?eN^BCEW(dxnTJbrzAcd?Yhs8tCT05k|RT>zj5 zycNhH*bkTH{2T_~rZus2mU`KY`AnG`^^n}ZI2 zkhDNQ6kF{It@HVf;?djRz>q+^0)_xhrmFvkvi}a`a{vFpVHNFAQ7EhI6d|%BBeGXW zWRFC{CQ8!DrVtg`D`aIBk&t93$qLz7k?r@mob&nKf86))kJ}%o(>ZU~`x>v;b3DfL zTG)s9S9HCuh>YY$X@5>&1e?Z|bl16GSl`{{UXu2wZfUlFE2;@*?0s|nGQd@E@z#1e zs6K(r0j(~y?=^%bWo1G%y93~*>f;*gOtyl~R|dti2UW%P)6js0NlVoEB+sw>*mnR* zBy}oHO-<+DKZFrU7bd$jpGDw2iw&|YV_XTIyx>{~(v^(r^Rqc7)w^2-@F`jb29-x> zTl@)Z@a~pvK+*SAy{sGnvYnfoOGLYogy8L)KY%E3XX4I3M5k573jpbRu6aHBxK{J& zKo21?-+NOZxUxvPI#RW-@u6t;)4Ak;B}Y5~D8nA5}? z0Le)9rEEj7#wVWxSxqU*FBlGN3OgvYa=B0VNzaQfPXKPm4>n2J&ta!hQ&Uqwj$dEt zwL%&5HS=<7(asY6`dn}_?bM^1x)IvCy1Jlmsi~9F)3JvgV;m&Yc1J&ZcCo>9gznqE zcG=MZHJ25v{khp$8Fde6y|NcxR2$i2A!lx|?|`=QT!i_;v_nZ)E|2H{&iCKM;KMAuGf&BmK_;MRdIL*Wt3C>eun9v<#E@ht}=JHGVK zWS0;p=O{YSwn8Y{f@`WQJFoB$sQV@=(gkb0av^7!bWN~wMnZzr0m__b^4wQCys+xA z7{w$e;_4AX;sGH z$e8pQ5(PZ39c5XI?o;fO%lyiDpqqe_CtEL!G;iD1@L&1q`8ZT}Mq1u28O#>sGGcHzPhTSEOQ^0wIZ~s~ymfVOl1>umQ z6m@`x=3B1$#hwVD>i;Y!fXqq8w#3szko)T*h9>}kv$yEx00_|+v9a0XC5^*~8pwj( z2+V7%j_8NuuOnsqkCrT&?DH&V`_X~VRX5B0= zZ9XO(V#9$8xvv5H0MM9Qam4ET`3Hj=eM~Y${N|jmxl!SBm z0jzkX7PobM0R$DH;ox29N~brnym0X-3K@=_l^{MkGB3+>j&F~4QZs82IEl&$dk0q> zA5!Jqpw58)XabC(s^r>}hzL2JM1ks>k?>n<0?t9yLQMUP4}0PPy`1;m3moMWI`6r; zIWj4tKtg<5UYN|_Pz0!lGHbqBo)Ltsx?19y_*0SffI>(zAciwA_R>y8Ay~u)3|C)ExyV*!X*Y`z|yqDBv8?8NX zE>v))0rL}`kEaL@fJAcZo6{r}lTkC@v_(Xa*PM~da3(7#RP2iUlMz{lf;=XU80}JM zoZjZrdQnHLtUtP2bjf;C&+KtF=FS$D`JBYLxgv8f=Z96sj3>`UO5LW)T1TPKP;v;rzA=0BUgiFqv6t$r~~!*d0~>=&)LMMHrp@fzV69w?qs326WLx;LB@=Z|g)-H>?c-*8znJGfzSB&$ z_C!1ZOC+#&0Mfpa{NdCE~w;G&OxH8<; z=<<~-s%e#Bn&hM3CH@G8hl|3atbdHkBd3`@$os6kJudmtP-7r!8ofz7zvp`o77?$W z^>+&twOOVr^u6zE4}?%R`05x$+k(uBS4@4 z^I7VB1z^{fV=8aawe-HKRBmf>8G&kzspaG z`*wAc`XhK4;3UZ5*?M`&XmK4#?2m2rB30}t8{N|&psK8_tv!!$m7$$+sQ0VOwrwMb zmv%cA=lMx0HsnWDsH#yis6-1Wbj*W^Cy07MUq}}2DBnm}-|3+vYQMPD2>J`8sIPGV zEx&IIeP(~61#gk*|4sz#HWU{oLRL*LA2PVrj?ZTy&UEIQzbd-6vtYgEZOPIG)1zb6 zf;MXeO9INWmp1@s8%%TBJEEG)&m{IQjzr@5TIL{0-=zg{mw?l;jge7NopI-PWOrPn z`H0V=Y@D2N0kyRFzQ|hWaJOM>Ba{GXUtWlUF-mDAusAT;yj?FPzh^$|Lg}e?V10^| zW{8;@JQDGS|~f3`_tYZgce)J%NJb5Jh;FBl#T;^`PP?c|M}T)ux) z{B^LNW%cpdy;V;|9LKO@X-$#jP}Fgoejd6tQ#Dbwd9{Qd^e?UOEi(|>=6Z$*3}CKZ zR|lTWxLo#fqQ74zMI}pj^1?;qllAe5@*6~B0)*m3{VkNrDay}$^$0b7`5t0189=%v z5z7M(l$8}iQR6D#K*%Tsloi6b>wh}3$IOH%D9Rrs8!h)VWe1eUrW(WTXJTeH2pH4g z)L}a|LYL>=E3gd*V%n*a!VmNl&|g3f*`7mX>&xT0+^s!g!8NAP-YCR#91Ap{i21G5 z>TvexA9p$BRtwNcH-E}})J3O(MZzenPAXMlD2f}_`*-6cU{ewUidF$A(;F>+iC;FNoCwA|iDDSN_ZI z>y%|YUQSLhBh2^Fi~Ip!dNn{+Ufv5_ zG+2`4cn(HI9BMOo2t7=;Zo7h5$!0zaougN^d1i%GHkl9(R2mH zrjU>`gg{UPBpA~e8yh1;XCN2-hPk9-U)5F`lDpUXMuWcJBXTBkFbYG*>*$4@ z@{AEW`O9~1RPh2@Hz~>T2hd`oqVffr90JOjcav2o z)aNKhQ8zdGS-$I*7&wR(KcpCA|JE?OeuxmFl)26wI%RO-Zz2Q^Fax9-6!QgECcK|n zyoeYrc4S z7p&UNvwi3z;=a%qcz!i(*T&80kPu!dyx~US^ot)~M#*)?xYDPhq9XUL;^W}Zmq*|c zLgk#S?2bNcUlk?k`%wo8Fkirhe$9*6WV$}%CQMsI8M!FBT};wruSoB$k2Ljlb*@uy z{~kDa5Vw)L{@%TNAhy4wLH;zj7RSeCf0WBFK5HDE#dG)tPyuq+gI*?L97s(lSM_dc z9$GnB&83WU-jt=g{}M(Q3J?ww?5TM-dUAOw2r#zplQ7iW&zx}tCISQ_(maY!l@K5y7H1nt!d-Qn%7wW;rc{wleEn|us&Dg8g%yP? z;pTg%!cN^^Xl`!zgoOjV`L}m>O0A;Gw>m2`_`8k;9ym zveJgkiKdH@BZP;`5Z4AWil3h!e7X4-Z@Bjd#RkUu)x2r( zw_Q!Jj(!6q1_~z^B$F_f(URYg!{kap=L9)d|Lw^|23d=1uOF4O;5&&ztMI_ew4J*v z%7`l+Xvp6p+2V17QTiTm7(EXNY}{HQhzE}ylctiDxbSjNTG4&)fcuhN-?58XWCfAm zT|z^4ltXudUxO?`74in*$y|PA&DMOFp7POs6%WUN<~$%9+VOXB2hY-eeDfw&dg$f2 z$b+NqLxCT?R<7FEKE$m7vNUdbRwjuw@eg)TLx_oWGEjpLOeKh zNS^)-_Gbs0e~BCKZyPwEeM7^M65-ZeKX!ONiu%vg+*BIzJJ3G4@OfWK2onfuEo9$a%9EG^_rK%)%ac?iRJhpPg$Fb5p< zj54&?VJua=0?N0G4e*;M_4BRJ@gg~-U&{XSINdrr*?KwYZ24eaunf9_f6qSc&|!Hs@&=_`dLEro{m<_Yl)9ElP_8w#nFf2NfG2Z zN;;HaTw1B;cI@$1TfRYPZZ;2otw}&RjKzI4VBz)9(2%*g`OqNo13(!15J5>vNm0?u z+S>(GvilUp+wgB-@QK`As%*RlIGpk$Cik#z}iku3~Gyx6;}o)e&zNx ze*IH#xGaG!HYrG)U}ZP`!R5J^8W*{5#gwk*9zF59vT`nlX{SVNu%G)M)=!S;9YYc% zq883Xc^nlMME$tgZ&ffpkk1ZNZ_4G4`RyV$P-8UnU?HrJTJvZ;;dwbps;q;9O? zn?Kkun?L_w|Kb1jfBf&0|NE2Ja{s>%@xM>}@6Z4DPyYXRh;?%A`U9l*PA6N_nZmqb z+iM%pH5Csuj+qECGXlOfUwLt3V$w*FNfbBR(xo4 z-IganfiyfkEP9kYy^YhaQuC;+#3z?9mQ1}oxemu4r%_Mj%6~iwzsQmJ_;{!oFGF$) z`bPlp3=~Zf<~n6E$VRsj7twnGsm)4H-#j{pDXDE0@oRglTwsqT>_AsKWYq~l5KM%h zKkua=ek5=H^f9LKW^$PP?g;slH`CQ{Wax99_gSOS1N*QjpzMU1DcRb>($dnxg3IsL zXiJi5O^|vcwK^3*T!$<2CD`8_kJX@d=MdG>z7E<3D)eBF1;c1;stABfj!?PL_%bUT z_)UXD)860BfPWg(_*V5>b-g)hs-#ZkCPzv7{l0v{eg>H5u>bTU9ynl|5tS5)m(i0> zx4*wn?%aB^?TLA3F1N&b(CGyr{=2t+wZmO}qPJ+t0O#&Y?MPo^xO(A%1L%CPaS09< z3VIQ(Qm5;lymoZ|pKoSX2(yk3V{!cbLl572hrOOJN%W&GP6PpsZ>~o*tf#Flii6hJ2fCnsC~0F6BP^z=iL-yqkaxvPs@Gi{$I6A;&m&cc} zlU-fK1LL?)00ej-vBQMqRq^uFvE#>i42mfC?sxncg)p=sRju^YGp{$d=H`Ctk!+GxZxzsYM`CLn9{*mDVN3&TGI2dB z|9r6Voy~RoU~}D)o-Au48iDlYD@8Y$Ap~S+Pl2JpbBE>}^$!6oEWYg#JD;1PBPp|snLy72(|BdtGOUh?oUU&5PN7zv}ZWRENVQ@{JdHtc~ zpu zvW~9mM(MjXn6koIm%oB#{tR50mfU*4%UGM{8gjr!@n2W5mUI7 zpf-fe)z=u@+xW)%)CQ2I8hN(G%q5`f|2`ysHQURuhJt8?{*!4Z3J*FM3h?czWd7!Q zsQiLN^*<_vm!KwqlkFO+{y(dLjg4IT$s+5kFL}oQ^M3*7z^AKdnmiCRVHUB|(>Zsp z0umI|!mdyW?q|!cZl-W``|O@dhWyyU*eh|4jlZpMU** z%9EMM@Kh|F{_KsbXo(53gJ~xWs<2R?#UrPn*m!H7o<0UXUFgoTgA^r;f=y4^63&ir zl}b@^jD{QJSWopl(r3g`i9oWLcd3iJJ~u_QhpQE^j{x-Y(0QX&Q@O?oM+Gko<#5~_ z@nzmwx$gtK3K(@k4AZzZqzF#{$0rc8r{U#z`jkfG?oZY$B;tMA68boy{~g{S3WE#G zXWm2z#00@$W(xonr&mINU+^k8LnG-GWl(d%$D4_TmG$k$`U>m_Z#n$(PuoL!uGKlP z)cUUSaTX;`mdLynv4j_9R)eN}oa0VZa@3P20Peuqc)uvtWnfI>D0lvy2v3`QVI5nfFzO8^7-=61OS8m zd1MazaI+!No||Bd2$JE$&Lx6CQTVq@Czl&&Uh=57#aZsHx>4GV&hN?_TU1KkOaf4^ zAg~anF?Hiy3Yl2Rg?FQ0#^+H0IY1FW^rx)(Kq!=A#4w@7`=QYKDD0>PpHwfLxOkd| z2*|`me63;+?m7}>aI;ijTDlU54Z3h~237c=(A_Z{K3wD3wIykA`LpDX^6fnu4^A)4 zcNjH3Jv~sqvBs0sy6Yg@hnkwX;9q}TN7<%N$ank?Fu5FH#K6Dz{yK+We0n-z|CLo= zMTZLkB=oV0JOGUc5jWCWs*QdZmd&Y_diLCYU_T93$?yp=S_D7~oF-JVY1$cI|Ji>W zOj|m~?)il>{gA5V|EAd7z05;oM!kq+>q|$sLMc3h4%lm<(=xx?uHx<%xIFO82D0Dk zQ!XF;YI(pg6qa!+*%bjYbt*tYRsBUSGe0p%2L?UZ6H#uV=YvJMx6JkSM@R(`Im&rF z56(@nO5jEj4`Z=(uAa9fi~l3XbW!(ju+flC1b=cvXg&&*5NzzZny!u;%P$5Sjgsnk zKK9(M_9QuZUisq1XUM}~D>2EYs-GD0f$KrFIB!0XW{o>z#sqLe=>9ACDP$!GpJ^OXLp|%oh8% z&16NbQ-$}6tRGc1TPsGd7V66oDGX$DMB5YacdCV@i{({&I(|3b}k!p|hTd(ApS z>3@aZ-yG+I{V(`kIZOh~&CEVWpBV?2NKN{Fe4ZFQ0D{%P)|PwapitYIFh|0#U%w!@ z6J=(;cbd)51R#!l&{0CGuG}i4KG^(Z$5oNNRTKEw8$}rIM%mXnp$+e_Kqi#|lO<*fcN$**@TAICEw|za_t{-`FDk zf2z@J3c&^QD9EfJ9=HtPLwiib`L`I#M+jYVf3CR*@Ky*YW7dn5sor;Y3!i*BdBf}UJO9tQudp}1M4!n>O|9*} z0dwM2BpM3wKa{~DNyG7%#Rp~#IWMhPA+LcRKve1mu3ta&sj-m}AR2sUXrcp^<@f&& zTFL$k7QG=xd<9T9>MJ>j1%z)wvoA1NA#wD1x^|hx(A*N0Y+SgXd9q8=cnQ<01_ELSeY-75BJFhg4@oT5+ujg}OyLV(LxynJk1y0BC z_0{)aPL$a+(ZH>(uHxi4S1oIaBA0{-&#~_c;RHtxeIaotI(e$>?OP}qp1*jJrmRjS z>vwnH7{jI2r)7UVifY5tSMLaaOATq+LqTCw=8{uq21qC!OBT`))LYY!h*u30hh*A_ z6FHLPB3dM&@%lZ$N9ptDVfmH0Z;4>BckkX;&;kBfljNB-$~hV)?>CoG#@}DV!=lP; zSw$1BC@abqyi%Xtf#9-d-@a}@yu|nmS2wril@%1Ip}X%qe|auv_Y+wu@8XK5t;A(e z;<-*A+ArH|SC|(T>P+*g<}*4EQxg+g!DpSec5SJl<>iu{((A#M0Wpe{q+cBqUvix7 zx2NKreZI|icqDaHp!};|rcUcY0{!FS8bg3?%Nqllg!X)5VxsTk=u2MaIpUjk67Y}L zW06Fsq7d@}efR))@n&A2O-UMQ9pkWgW59{Z$ER%`wL{60VNR}92V6{VJvHly*ckgV z+tIK1LO+v@k*fG}{g*F-GlppEDnYzn@c97!;Tu~$iFB(&`7F)~ui@pX2j$lVeFt2D zFv4k2`T&-MQP#dQ_km8Z%`-J3qLGlIDJa|Z*3dpj*A6uxEZlCcuH8j9t85DJFE7sC ztnBK#9L930DYWJ4J~^_ijdYRP#n4xLWKz6zfe?t!{rU3)6dcgraK#~%<^aA$(Nl2~<5tU+w*0gTBXDJ`Vb>0EY(X zj5aUc0Z#qz$}wWaaH1{ga)+T9eCtLCS&)Tx?%I`R_!jw3C`t*kx1fN4ALtZ8$cu}K zji~2KK0k0uHKTszKpW>+pGoEJ#|^?ms;sM)&Ld!zK`V(OfuL{3yt)}vh3Hwko!NVY zyyo7m38U9I$iNU267sU$Mppf(fR);f8?T=|J5tWE@o1=jcfLs_<7aUqtdUV`A+V7h z63I(BcqgO%(@&Y&%wj$6Ln>^T4S+{t?%`3^ZI=zINlEE5N(kKAXXTl9^S34Do-%r8 zTc8g~07Rd6-Wu}w#T#a4Yo)b3;nW0N?}-5bpLX>XR#33VRcFR&ZOPNm)LL(`5;)}l z;Py_J+#rT81!p~t@&gr<;)mmmr61R!FA@f=(BdPV^*6wvdsp#oH)*>)2x_Fm(*88efv8g<*aj-QD8M%*>pebu~39m<7ndzISqS3dYSJC2X zUz{0$t+f!m5C|6V8_W_CF}%2B#_ody@QZ zbFEfFDG?dj0beAHjwS{AXeK-{!2tb2$o7L~nodjJIvK1{Qeg>Ti?-iqK6Z?##q;mg znf(+$e5>A^B?59p2oK)EH2XmMCKSG>J`)V+Yalvk3_N`Cf3%reGO35sd6Z zxM2!(p4u^N^ZM{y3hcVwz>?spX>x@h@*g6k?TgdKkh9<$8G-dcDQRTX3vLg(luVrr zjWm?rr8p0?htIKS0gQssf_NYC_jsDOI_R=2ilCTSqmMtkLT zO`=>cMLmT5$p8Tz&I9p(1Lp~t(Db5`>sRS_6%7$>;rc+Gz$t>O#4gcGX+^M&heH7& zKv`M&Oq7yV<{3Kd+OXDzo_nmE#7?`1^<;loF+ZVMwD@o>q68jIiESrefj*o7OGr_# z5aTd`gk`&nLEz-6xw)q&o+YDIoSmLt#JCV5gusb_3{}_F)z#ho7MvIoHaJV%j<>8@YvXQ^aZb8y#l*m-^)}t;9(#XW}_7f-ZG;dI%8vS z@klw@82t74aVyp~CSAUBn$(YG7NFT%CMhuU&mp4M-i%D|&&%?bcB|YcDja;W1CIr` z?u3&&&^h1`kOZp+{`14^g5>wfh1JZ}+P6xJG0^_wB8X>3klrrSFSE1l6%{{076XF0 zaaSKCJvOM%LyyU(I%{RLM{sH;qw2yE31bn5pccCoT51PJM~o$Kz|!mf@x!Jg>n%p0 zVRVK@tR+StW@KE$LE3Bz+HFqi1vCo`FFS9zn2~a9geDs z3UYu4@ofilp*e=q_IGOvg*M$%=1{^l*2pOb5qfuvmOx_bph*G%j^OvE(-!?2AqEB* zVeiRw&7G({{|nYt-imQ*XmypI@*3khP?YJUX>HrS_bdkOq0}8^jB!m6p)TO&qS{UV zuKw^y!M8g;V-^mVsbnoJhcUDcvs!+46=tKjKukW5fveQa4Ho?Ezc1Vj)lQa6h)Z>N zp(1bp_;(_+2%n6Csw%RsnNWPQ73>1e%tF3FF?zLUs8~lYLRO~x^JtH)MszT>*n#KXpW`3fHyL8e*fIjO(VcnNI_v7{5W9|Gz#=-Z)Zgrd@dWI) z*@uXG-&tC6Fk0ss-cozQ-l>#u%z&(4LX!wwv^~8YF$U$T5z3^6_Q89nbsX#!C_>B- zI#4%**j|U~$NFKr&6&wO76s^`ZQy7?5#qHnDdff@;KSDFfpLvv`T}%t`@n*YeM^Ks zoEgFlT>khghFrY65PD3@ALVdcQElD>a<>4MV?0dk-7|~FBz34{4R3r+-Tk1_B&R8X zqmap~Acu)xvHwMXZ%I)RMC(G(z)mzLJZ!KKb^F5+ZUYG%y#&K5^HKuSjwMTi9lT4h z;e}*rd(ykkrc!CplNWdGeqe$dg6n+r&p&EuTG$wubIs}q2`1nIuHB(!%=_lZJ{w-4@Z9NV67@Pl zGSa6^dhm4>UCNf%KY%{RNZe6OmrK&PvocwT!Ve8c1w-Hl2dI48@b zx68+i%8<3>-3+Dtzl(Q~ZshFe9@K4Xb}eqUVww94obu0jhdmM%9;3($JGAT&;Vr@) zH|Zo=olv)}RG6lZ{+wubyAAH|^N5IFlU-U*8J&syw>JBP_`nP!#g3$ziL^=is z8-tLGT}5Sj?t0dg?dbh8X@@A-bJ^7s*|UT?@S_cIU`nCB*SzN%GQQ&;inBp=BdOM!SCEg-{I2 zvc-*qLgwdf=k&#!2iZnxUFWAxN)^a|_X?ClT#v=FuKDEh-aG@?Ysc2~0tU=;#!WJ8^{*O+G57q{2?zA>8ts z>S|UNmXJn8G;WaJ%l%Z&XrC23qAhRD8~pXF8DDWxQHVpEl>oM1ISMdvJMWf$9nrr{ zK@ki&QB&->kcMAxuSdy?HV&P2%|OncUszz^y?PGY5+pE+Dn5|h_%JFeLg+~rQ+6<1 zfMEywF(DLV6+8UKFx=xkWEB!SQ}+c|HVqp8_>rEX#sTCJ{WprEeMuU`ux#L%2tFk; zj}H8JSQj1AKutfUWlxbS$xJO37>)7|zSBIpggO*Q%F2#TPIibf$SycT1ac+&F+6uv zV|K7}MMhq7b900D1*HMpKY-cgW%I_f4p9 zF}+F**aS*(VlYRE<25LEP-&;Fh08P2`$b5x*T){ zyum1Bc6s*!#vC5TBxhc?f9lN8lh{sPIK$`~JKQ@jcQ(0E>T-+B(NVyWiBL46b|8k7 ztZQn~pP+R+&dp>U5HQ@l|Q{U~*AG~)~BP_Jxkv@eP!Al zdG~Z4InuF;yf$nfbubh9jtqk_1*D{;1jCNf01dST)&+t(JF}2wu(&Ld4T(hWa#*dw zuR08{4I&IEJ}f+UOzV@P6cZPxV3ZI8U>zpXcDE+|5tllPtuAwj+^62MQc1Bsu5gye zXH8T>3buv`9@k6i7=Q3XPwEp($T(}5mrX(R1IF;vOLs!IC+7&H-@N&e{<@M=Wd6Qu z%zk{s@yGt=wv-*~_~i4$hT(_>22%|V%KU9o4EyELHC{Iry#k4HyrlThVzbh5;be_R zjg5^{sHo7LBr)wo*j$*Mr9+y)p0{Ro4Q=isRu|Dc%^ob~9iZfQwR)zJ2K$0724JHp zMU#ddh_&?^lkKqSKQ%TRbv>*T4>U7Awo1S4(yZ{g;{2<6tb^OxZ&YinCl7{&_dfYC z5<4)F`hmTpki1f3eQbh#={tSIHT5O9lnt`p^=w&T)NOM}c_KfUcPKNi*F*)yu z;h~-~@xY$C6P{BQ^na?>o+3{AJb1v$%9_@0bNFy1%0FWMc)r2WC+tRY43kx3_x=u_ z<&-q2<+=T|!D8$%lRCR3+w{E$ZlvD?55?a8w=}x`qG)Gs*c0hECR2*Xbq**Putm`t zSr_PMw2w_qO-)X&!Sr_58vY$d5Kq(Q^RvVv!I~h zv164$?j{!?)!VUsJJ=}H`K{Jj7%4lxa;j<#Bc z#ZUG!k?HxJdwiD3`A`xC^A}*RG9GCa&06(!M*CF1KbZ z_@cgDdKBbm&^RndvdsIe!Gf-pbq{L^2b(=@#q8GUes6nDl8P0VuazRoDXn^$U(x(w zC=up~IU~u#Ux67C;K(4bWZiQ93~hS;g)o_*ATm?V!L)7h9AVLGRomQtFGaB^Ai@$Q zH@p@{-fX1AHCuhtd-6N(_Zj35$Qh@nr@@1vh0vw+K~{(7YYxu9hA&@|%eSV9I#H7K z-8ri=>*c|48Xe#Dmc&O7AJ(9=9pns6?1b%N4Xgkd<4-0zBMu@WI!zpWw5zi}cp?t} zdn;94z8b};+4jDB`!C+uZY2N-BB5P}JhBz)ACYTu^^LRq3`rUaIQapY=MFFA5<+9E z-Wr>}yGji5DY9)ve_jh3_Y35b1)&H-6rXf^TKFSJ>#r2oU^$wXGZUfM}JSn;x{CKr; zOP#R3oQ|7^;YG^|RGE?}Bh}PG>dX{XRb#;gq8Wu$OJ*y@#oaxOM?dp(E+#^og2M*| z1xY}mR%J24pyU^{zDLc1jZw1Gm8^cxCgeGI1jNiU;oHd%AIh7Uz;}RB3a)j6ih>_Z zMWn{2AZ(jNq>j%I|5jW8meU___i{ORiL292E1|imlVN)%?fUbk1M2-j zk|%9r6pY;@o&>%A) zI7USFU+L~UzKcw<n zUO^qmA`2)*97BhQwiu{AOs&7!b^qSlFm`ex#;1vii2<9R!zzTP@S~N$E!_wXKNJwV zLBU{a0JMj`<2LH;j$h`~&!@@_)Q6|{|8)6_?inSpZBJP-F|j4w2Dt~Tf8V}+;Vh5F zUH&28=5<^vG?{{VX`8h`G$`h?!opDKf?c`@)N^22l3rlMdq2H2P8@!GoCn4-C&4_; zDB>^z5<2*we`v6!ke-JatxKGIIW9~ugvj%Kl5`}p#dO@5NVuYTUMFUSHe>Ok@C4gR zv)30^UKTdClG4&HTS0ZIjeFq-$xj?6?FT%D2M(b&AI)A_KdPLrNo+s{d=sivlv?u` zv`FZS(1JoBwAv2j^OepC*|+5`Gso~cqO)fg@d2*zG0Yesie*t}J7n({a~O7khjSfq z78Tg1FJDkZ{Y6ns=)|aAMs!HZ1FD8mizw$X!XdBo=;naPJR}=^?n5H>Y|gv27Ai_5 zB~rDxN>tuY{upH8R?vVN0ybY1iw?_wtl#w|HCs7|yy&z|zF!4x7-nT*=avG=#CKr~ z@WN!Sz7Dx>LP8K(a2!#>C5@#X#HwRewqe7k!0C~>ch8SXw&Y@tBzB}T2{Rsf;6 zUf2Z#>I%k41kj5{EdO&h<8SO63D{VA2>xLJr3A*fLIke`^9^|3R|dtoz#X74#3lZQ z3miU0Ah0H;rl8x=fF*I>2^MMFggpG0dj|7z))&safN38w*}0_$=3Xq%&}#CEV#4GRxF-xM%ByafX| zi){v}6o!!|r=$#1NUny&#Hd6*9639I0;b^FD>0WNYIjd|_zCxHTNQ3H-3KoXnG*O! zR2}FTKwH=p04UxKia|4lT(vcHE6edIuf79d1f?iJgaSZoE52>{#zPDN0m3W>YHFAo zju+@(7ogj*kIpQw6XlH4&?o9kmo9yg!*~Hu8t7nYum~|eZX}}(m`iZf#WfygjaCeA1~jFK-S`&gH*TSgAkJ3dEv8 zK(Yd7{s0&r+OGACrF|qzkGvOPp$^qU&y!-t;P&*p-bj zG6!yuV^bzrQV0P+!_xFK(OWFw)&as%gT&UAFFR!X@NDDrH721skfmTFTkDR#h(cQc z4bLk`4Opc2Zol7dL*&P2&xqF&aO4Lz$l`()VD^X39%dEoRJAy`=`i*7Bu)un0%EF_ zF-F||8XE%-t6gY!g@-2_Pa6{(H7H5_>JF@@@msWwaxs#F7FtHY!isLgpx7jhVytE? zPfU=EP>~^ViR9LOefQM4oyBC9iuE4zV}PI(lX3xSV*P@2!eGe6-j-eYfWF@n&`(>U z@+UP)QbZuWDBLPSYJ}aD%X9h>;87Uq@0stg-^L{~7YvDRrVi#X(OD{b&2D9l00HgX z49EqrKKOr314h2IMDoOLLG(`1v?+=BtZBAUQSXA5D5Vv2D<~W^zOAD!V;@nME3xgK z__Zh2rl1680Sy2psZCkpp1JM!-`ffv*}ENkf&I2EQxsk*6cb~J&L6`eWn^WWKYSsc z#_w*-a#WX;EXSDBurJf=_o%thjj*aMPc+A#4@*Qvj@F)-RA;M#N$TOy|7$!9(T zn+dA~je^v2xoSC*3!B7n-${D=y5HKAq~Id?qA(6TIyCfN_&oq#9xhnP7O-amr~#6q zib*@<`;fm*M$&6iW}!Oe+P5T)ru+gqAyH9Fpi+;? z`l)H2*d;7d_n3tfZvgAOpRy{XW5hDR5s0On`YN`hPiscX z+~2+r(F-%7L~KSA9}NdV_S)`TQ&eZ6cK={ zh*!e_<)sV6i-<7A8AXB}hKE^Q*XE+$MZ7&u$hw7vnb{ay7v6m6ytyNY78Su0mh!~e zHi$bAScr?zuK;L=NOK5}7Vlf@51x-R(hTtu(=C|Yx5Vyu@ffo4b*xYahkWTc4k-6P zIpO*Nry7Ige8;|_v~~K6#AlD82glEiQoetwl8a4@dWT6~R9dP!hl? zhe86Z$MdMD(Vssdju@PrY#_Jypli6VL{e6tXS}pOcx+YRj(p(tqy8x!c)i~p@Hr5L za39)Jtk=X`h!aQUV*sxnq6c`WR`|X_jX`i;TU||dVsFI`4^Oh2d!bx>xqeQ9pKY6+ z#vQzdLKhnaHT0-i63Q90rAX{t&bx13y(@N1^_2AP&!2mcOre5;=n{RiYP;A0F2yA1 z&L3mxisH>phS|=}&WwC!7m%nGX0S)E!q$Skhan-!Nifg+Kwd@JgDXS68p6LpWf9J) z>AQXDiQ*9WH^ScNYQ zmzD(0N-owY*?s$X?0)&shjW0cMI2Ir+->!9+1z4(txo+Njfj1>iqZeQimT$(D6i1f`1Fq1)^LF7Tj7{gKmgWudL2%9`rVUR%MS>hW8FS z&izszyR>)bPQn%N^f041v^=RGTF&R(0nqiOG@nvt@C!teM zV);Br##CxE2RbL6kSVPX{t?8e84O7Q;4Thw6@*G(AArCeq8yg%mv79F4v9_+#q8Tt zJi3!S^2p*ba{Hk+(we=$e>@Ys(Pt5@+sVc&#t38N5w4g ztO0;H(1!K(bv$2}s!^4Dp-v9JtCe+Lv8GPceLtSKw_kcn?K;rdfoPfvd71c^)6;Pt%KgeoRWKaGM| z3i{O(%R=nz@+qxS9b0ya5#V6$4r})Etj}XXs(K@3A8ZOxZk*D6eHHDBBGh9V5JDKE z@q-d%|E<7@2OZ(_yDOHbqiEY-=w7VNem@+3o19+nRyNhczFSMe$JnQu!)}=vZh89t z@io(hSW4L$7#q-2t>f*BqYW6}WD1oA-1ny=6*_Al%1_bQ*;IR3PRAHj)@Ju0bSYq3N|4iboIlH?$myDvzvO zn46)xS9*EL?9%$Fe_O;2G&-f-hVe3wun5u5Yet8MF|PfZU`V3;O|S0DFT#FaikluUiw>j?3aP0L5w>^MJ|n*&t@ZQ$D5B0Ml4P^m6kp8kKvt~W>7Ga`pPTU*!U&(RbbkN zW(b-8hGXhcj3Rf3zqOB2p21i2Q`1m+jkd^by_ZA6n`+qy)6!{t{ z=kAR5=!l3n2wqU2JXK-?ob5b^f*YbYB}Z35a-dL~3aLRQ|pVKmH>}ql>=TKK8h| zn3K;&ZXb1KvdhZuiR#|mn8X6WMjHUgkWLk^WP_=XI(yRuiD*uTZtl{J&3o!@+1Is) zWcqzYu8;l}GN~pj0c^5IetsaKG||OC1}iNs4JiR;wbT!B@8}BmcydrHErD6R6`mVbm{cSo3h!jV7kF35x?|J+S8DXIN-M6jEQOxC`^A}>@T&hJ?E zv$D>xJ5ora9DXd;m@vmX$XBr9&Gpo{cfff*mLi5&>WBL$1 z7+y?>jvJ@}YLtd-yBysj`$JWzDL35LKym@R>Dt&-v_&VQ1&!T z)d<(%;F*NY1fLa;$vV+3v7TKr3KKsnui}2O#hc5*_C^i;qeKd8{&c=j4ijd1)oTKD zqk@s7oF}~X85IU{Zf>m;bG24kY&`MO_N9EbbWDg-sW>NR8mcVlbRKuLzm{NWzTg-7 zLZ#R{MI+5>Q4J__Q0Px;Qe(nmhDIKu8-&&4KU%$DuK6Fj$ixc_Azx@w zYymKUAQufh0FPwoT7mE2i)Sx{dw5P{SIzpKkeqc=)8Wp~;1(P-KaD9xd{Hh24Yq=h zLlSy5q#CdChLHCU-gFZ+J68FN)>M5HCza2i&%I zDWc_Y>Nd?ZEkm@xz!d=$DJm-$=yGFph_KtA5l9rQUs&(>CK=*jYiNpT=l}64j9gzs z{rW^*F9Zy@-SO~%XRQb0GtlQl5T%M~97erQo=`cF)@85tf1=U$^f4&BSsW#C#wPdG zPd24f-lOwwhlGzxsYC=nX_1Q$`oPSo;Chga-R^clU`*`T^Vz3T-vi#HToR($t5uV* zJEiQecJ1|vL`GL3E2a?VM=VJOwi#Mn=wjVE(0FKbg+s1_a+7XS4x>B(bip$e78dqx zL^e$eG`ojwb7H$7T_E0@INF&<4C-_cxq_ODfC*xkkbF2 z>7GYh7)TPn$}ia~3|k3AL!?vv@grVYNW8@WZXi3lg6P*72SchMrl=<@ctex{0o0tQK{02F}(rVK+--Q;yL!pkf%rUSt56^xcI?qmzE-%ZUW z!}Y|eui#^x*N}7tU|6`@@V+1*7Qlvc04gJFd`;7QD8b(LRPkE9O~jzU<^XmHhc?}< zBoz<6tAq>h`zNdlhR+iNY=LG$(!gz4cJ}1SlgEw`?iGxCzz|fnE(IwI8BPj?+qI-# zc@dOmQd0i3UEmMo9xxezZ;3pif&;JJJ&8;d5}K`C=se)kV_VMYp6p2HbB}W@OF25 zD-b(O__?S$4}=qjF1*WxVAzbjd$@;Gn|=^d1HhL7atY9t5wIobf2=LEscN?e06oEU z=z`smq+!h$1vp?1Jo@wJM-5LuT!m;7rC1i3o)nJRb6YH-QGvb!FA@pB zqf}9e;WJmnucAk}aM0W!_@@cEC`WGh#*vuk?uP*cp+)2HL!Ay;jvJ(E2<~8o?m&Eo zMhtb!Jjy8O)3CbHCum~C7T&-HVZ46km)csG2kzIIp)GC3S^@+t4vrFCF(jCejiS5w z6z<)4#Ymk1fCA_sA+1Hri#LPfyC9Hsz`8?I2ZX-O)deU7!c#C_(F;5rY8)Z^9*huN zL^B8YhfHdEZmtVP7=QnZ&}m?kK)SFF0vNfgJ@c{<&}uMgh|WEDbqKfxB-m#_e^0yt zjD${32}6s~oP)L@hPb2A!wY0N4qy3yi24qAs{il*YhNQS$;!A!Mai!0dF?%uA|WG* zjO>wQWmERvL|Ms-%8X=(tg`pW2;qOOKHuNJ$LHbG6z?5ZE(EC#P>`5)b~z1?YcJ#Soqc5Cwn& zVsM#5phqC%23%B-+ybZ9L7JrFFy;7}TrB*`^IY%iT3x>edFLKS623rOKH6hcDq1Q`8v7ALk1AZTaa zd21>I`{el@!E;21*edmm4F4z82_ zk`9fbbUB!8MV1g8gPVjzzN2B&?aGy~tAmoHLIB_bm0Vt^zB6M#t4$3x6_9-e1$|f) z$lC~J_Zq%2kzgi(g|%8f#oN+bGOG1WMe3&ssBGq--x09Ya{`At>vN00f5 zt-Ct&-=u%ti?f`n4RR7XV;BNbL3klGC^pFwRnv-y}Kl$t~y z@=9>s9Qhu9JAwEujzbxYfZa&>EC5Fx^UwaCs}cPDb&iEGys4Me0@-mjZlJbM?=tjk zahvD@8lWj3Gz8q5Rn67ehXV{;z@(vRe5VGJ6W|6sHuQ&ycu+NSs2TcPO`tGBaY7JM z;cXW$#K1LPF#-uH1qH(Ajov_+1B@9!5qN~4Wta6pK`*QlD2<31M@vHF?>av`~c*iLLUz9+|UyA#(audUp}Yomr)I$``bOG;+i ze&=c17H)!v1Q66PklEp(-t*l|kVpdC2Lz~uKj?H-jjS2RE&R>vdAbj={+@Tzeb0qSB zp@C?*^mqc`!!JA^s!lI08NuR$bp!3JSVV;(Hx|NinhOJd3Lh5|x9YCX-_15qY?hRi z)LXJ>)84ljKR+dDD1*XUQ7~G23%%2T^gO9+0K6F64ir3WpaQW|Y@T)e>UgYp1}n~b zT0lpHp!HP})^>T3*QkVqJM1bC&m+idz(2a2Sc7Q|SLK~MSo)^G==sZ1ch2R!(s&SJ zaYpXVaGv^k>%PIJmh2Sj-9XN2QSE30#G8 z;UnlO;JPxr31_r!+y~+U_+F5!f)H9c2K-^L;?yK9U`xQgQ!iSCOfc46?#aY!AaOSb zgr~_`sLu%`DW`$n3wZ~CeGEP{{<@i~Yc09wf`h1%l%@m$o? zRzcJ4Y{+la)g6NMg{BgH{rzyj8ll52fG@y3?fAW5Jr#b)u{cr?6f2+o)pD8!1C&*$ z?1pL-1w}dNq zbUmSMOfNWRm-VaxWg5_f%14cSTj*{JMZ54zSk0QHr_}PjgM)*eoiEhXAvrPxz6fL? zL8854WaZbdnAFs9a3UcT=qU$c1EjGZz?0zXOhB0+IXM~XegG|on^i_5ZF?6h?hd}c z*0>`$Vc?&Ef+gTp8RNUZe`lxZzyl!zO+g9z5zmMqnA-$G(eK~pEVM@MLF9%+uIdMn z83B2B4sPxhNK5F&0q0;8`q$3f7X9nJFETqF{bwEKb&BQj7O=}FP0zvBMFjxi7L1r) zOb(oqzW|0vfvg&MUeK&!Wob#pF=9z$rMN@TXC?<;r2#A!IKPmP7=yr8=7mln&^p`! zNrOf&&^?C-DGR&TvO8rFbl>D$S)j)l1vcMf37VHLyyDTXGhEiJiV4FQK|;xk3)my!|6 zLCmKb$GM4ZISpe67l8!|%wfVW8@yKX&IDZIoct#E3NS3-!Yo5GI32k1fm{k48Z5yd z1QoH_aCj$JQDLfa_yQoQz`#MDB$5Q0$)Zq@-E#+@3|O#`f|VHxO@yNWcM4>hfbAA@ z*)wim1BZ}1voJGG#cSrQdG!zAxMN#b!9E8+q+oCf77JRHg!*%Cgb*P7{DWjOvBgsr zmf>h*50|gwnUnZ^fEE8-GKDPAn{_ZS5Us$`%k&rr{01_B(7NC~BX|+#Ch>3ehLE^! zF~o__-Db9GGq|wD>EM$w{>T@sA$(RsLZSnw<>!d?n*w2l+#(4(yA&ycmCU=}^U!M|N$DNkq9klJs29LZS%rsobhze)JMM3$>0I1m9cxLI#pq zoaMI2`Db3kerR5Xh=fTvR-?#%(g&{FnO-U=5C*OjWZSmPe%;2Zr<`Iu zH)O`24cK!j$ADD<>p0()sQcQGUz-}@ODGgS1deC>k&zo+q&bz6O2_;cPOp^nVv9F( z{1>YA^x-ZMO$J=U?uVv$AYvi+Y$$Rp&Gjcs26Syc5I!XG&+%XBa;jY0my`L5@ zRNXrZ#ve6;aR6&Wc!mKJkqtNh0i0)Gl^48Le5uS@O-|g8^}VL5ObLO+d+a-WIo7G+ zR?wY#H-6~R18xqulh#59r++}fH{s&Q!d>@zVF?w?lXiQ@Y#XJ}$yCp-M>Fx>TGzITeizqBbN{kKV#IFLvddO(r=^M?;#cUYAFScM81IA%6L#*e!F)S{-{J0Au|!kqB&6h!w@FwteBmlF-B4CPRU z%-@-Ra@H+oTsk?}*42vP3>SRgKfBv_$GW4jVQa#49aR&8T)sf1v}GuDeU~GoDPzE~2V#Zf+_np*n@!+F8x8 z@`pRiZ4*~hBd%$OLdK$V$s@?MEAh?$R{t7$}%cGtcx=FsLtP-;g zjyYU15HvH81wvSYgGUHepimj8Y~saU(5s!cW{l3@ks6)q#IO^FQa*BOA@@AG}}w;puUI`BzU$>AiRRiDg^3NJ%2m&Wq!Ii1;QFZ zZP#g@FHLu0MrDvTab(1hT;zhxubsEQ!>gmy_vo@Jcq*8g6H4X=w<*Pn7nl+jlZEF%fs;52L|1fOtalgy8kvmBto2vpru%?Gheo3a~jxrW@Yz=?s$aDaQvpjf}e0B*<0&dy>$8X1Xh z`VlZ+F(j&jq**pFlHqs(&!@y-d2NlEkrB&wsHbo?yijy_&h#F(8Vr{LyR65S7d{g^ zdgXJ5Qge6jVIeKp2f!558%u_QQYdGLjn(~V!pQtN`^)*Nd}#cEQB;g|EQUK(TG|h; z-;H!i%1Vh4iJI6m%MS)N|Nn&e{E8Ae9+kcx^!gpROMpB5fjcsWqo%g@V1GZHQKUR$ z$s|Zf9Pnbeje2@|p!qJOseoGq)f|we@DCT7UEGjOGnHU`IZj6?Fr4R^BK*IGi%^pfnYe?=PH}aPy?tB zau2|Zn$<{#k^Ywg_A=Faz68RyAY%b8d+f+VFf0JpkrNYh8P^J_Z)@8{u@4Z)M9sG} z*e_{-cH`|Q`cSY4wvg~MfQ?wU5*l+u>{R^&3U=0@s1<7GN`12?u^PeuvdmtlQ7f6O zLI=>;5wI^9IiM@iub_tr{E4+{>o_-lxX8`+=0>^KEDPisVAlbLXiyBkM-deC0G9H5 z*W^R`D0pE1J<#t2_XYhccQD$3bwX(LeB>d((XSgDPr$C9k}9UwugjpQNeHB7Brwd1 zkE(w_D8oca8J&{yuwq2=U?Cfdhe01(#pF$_mAsZ4S`v%wqc{TE$&X2IvKoqw{UO?3KqddqM+lO0v|qx1ENsn80$yssDM4K@v_YjkQGV( z3SI7?{2O2%z-}R@1m!jmS7F8bp-e{kn#7lKD0H^?uyxnzRN-UeJ5~k~F;U7EqsjnM zJrCc(nE)aiK<(kq;~?t*89~4=2qx5WbsEx*f?HRi1{Wp?^l~$?$_c<e%T2mZhIVouMfKeDq(n${yK%g zN&#aqwCKD(fB37k7rYoiH5%MDKRv1jUZ4mEM-Eh>c{EIXq}FRMxfhxRbl!|*n6>}% z&Ory~b^`ASLIvdI2#$X6lYyXn@~edu2q|-OG|++=sL*B9UT=nhDGsmaukHd9eX{Ihdc$WEn#&>N>UsVtk`7elet`>-cCly!;+ffk%9WTOMvpfE|wY^>a{ z$A>?5Uj)C{kVmE8LE$ry*25~p=fNz1BnKJcX9(KCs{|g4Hu5@*6y>&lj_wH&!mp9O zoH-G+MPLGer`=`w8|397Ma2S0Mpu_wYzJo2VQWaSrU2OHGre1vJ}54ZDCKZblVtZQ zJ$3o(Nb(#MZrFu{D#6GQQ7~5;asvlSMM=pJust|lnQQP}r)36+2(3diAa#K&^$z9} zux%*P2Xq*GbZk|q-iPcdoJWT_wJcSN$0A}hRE{efAm#;>AVY4)GvM}rfk+5W3^o+v zzU7E5n*06+TPG`HV_<@Ts-}lWEhH*|UknEb z0=|Mdg@z>VC7=+EKbr5_K4Drqp_bRq)zP-o;-QA=VgZ#`hcude0 z&cYXLQC3>ZVr~4>0|WMvR&y7~z;Saw1SE!|3A#frK&l)Fxf5wCYRA9!3O3R|&cg18 zublbBO4Z_-_P`)tnsELP7sh&`b%aK0r(hx-4v=SuJKTk{7W3A%9R< zpk$Y|_4icluB|@_ZZ*`er%BJ31BHMN7j~H zgJPyoN657R{tEao03Z-!10!e^Y8hayhPR~}@Zze$yOw{^0%|}Y)#v5qC2XHca4DY) zS#w|RL2vV2Y?bambLn@o^CRM_K1N$8Q4OpzUz0|x#13OIoO+foxlv}sYxwz3k5jIJ7c`MJ43mV*92fic*^ z44D51L$5pDagsd$1=li+9%6sCK>#S$L5v^{fgFlBa1N6O#i3#9e0Wj^41`h$URQ;a;qXE^eN+8lj--)w|C*}Ng>gi$q zWyA(grsxmbpxKAlf55c7;xYDsqX)M?fM`Hc0YGzm+d28G0dQ7eG|(agb8P7DFOr9K zxBl5$C{UbqKiMltO^#7~Iz153F%-`Mp-(8(?L4*a=(Vh~AJyJCxBt0WV^Pe!(9dRSU{1&P+t-dk9r>`@Tbqfz4?+ePC~)u15k2 z0DuDsH))~RgB52tM##4$>`!9y z!4IooOdW?;t7B7UXdR)EsRd3P7a5dJxq3L+FK=M8zV{}1cd zHF<^)KA1%~%NVpl+9HMnOn331%5%vWFYG5cO$*AvbZYUz(g~Rcv;W>EC}8|iJgIoM#?&eQ;NSCbl*DR(YJGfG2@n4_3NNMhw$=8l z{jAhD0x$`uQ9EMerwzc}@*jx}v5EbEvolGoKkCQjwT>?kBZ`h4^<&N`|-x$~O+ zC{L%*@T?={H)|mhe-L!)E%+bUi*U=2iURc*&~AVb0r))+yeNpJWKeJ!4L$(s0<@s2 zG8*lIBtfPYfU%>kkE(%muN+fAh)vP}1jL{U|6af9&ZMifqy1PDZmsM*4rOpTkFS6^ z{l1K?6BkG<=m8-$r8%ybD#>31IkA(MA?=Ude)aiKfS48GL|*Vmfl8y@u3itjoE*w# zBYEGK7ZsOUD}StV|Hf!rlwiN_zwL+15IeoZxTEhl2vR*)UaG)w!ec$I!Em8yC|vnF zaZQC6q?YFlG_k*Px|(jZGwNmR@|R{93bc$P^cb(1oKA!d9?uA9RXvyeIPC@V3!|?) z_4@wpVN#{HkM|?G1R>lrHa0#vTKBD})GZ!#p2l`01D+AE2Li^{)E{hdbmSWp7uv+; zFrCr|zzoCOxDx4aSig>#Nr5N}f^#Uq0T%<3KCm>(qfp5XCkHSkAR=f3zC(-u^hoc| z2xws9qS+~io-O^~#;IrL1WJ#d5A@2wVyXae6C{3}gMWd7TYmnfNx32JxBwm`KCz5IWdQ@ICW8Bs{QvQV?sfm)p|= z0()jLQyY5*|2TZC76uc_#}HX}B^46Zd+YYqKR_@Ml4?D`rh$3CLQTR@4Kjt2P@Mp? z2Yga??CisXq0G((WNBbqK)UFHvJSNCU7Kh)1ePO|&47tL&nfJKk6oEbL9oXkO_vK3G7AQRb{c`hzfUt0|#E!?2=E=6^?Gl5cfaBgsA7^kRzu$5CYB%iu0u0@$ zE&$8lk1XOK{K^%bXW6T#!j(I*?i`Y*qtYO?ZCP59eWrlgQ(RNLbdv zZv};MIx1XeHsEK&Z_06*1Nm=?3JR~Qc043r3eZxrZB3kwuG)P+9dWzHF}I2)PmM5d zUhQ#4)f4d7p$N+zgo963z8$Yr`yN&|Zs+oP!$5jp-NcT%@!zPws|me+T`BK>HE$#tv@ifZic z<-*|b#Nnr+GRYDG{oI|cZ_zoU8f2Iu8w+tNP!NwBkCz)YxP)-ft;6ZRRJB?Puz;qVw*(TiJ<3qD`rOb}v5BruN!9R2x6i+0#Gbx}-Wc>(gTu!!lPqv0`0|3R) z_f8+aMW{(vh07%lZ5H~gsAy{<|Nbk4G=}Y0iYmon!{lKDDbM>U`1sM-yyOjNED3nU z`A6@unpHNh?BORD-aIL9J)eMp&VL|nU+{O3QIBaHN(ZL6Tjz^+%i}^bB@ob-+HGO^H zqj5S6Q}9z%BeM-StI9XRbcg8_owB|MzH5*&=_wYXz#> zcS(Mbk9K5~rNE2l;-u-oqLuo*JBLu}6zEUta@Hi-?UP7SkpKU`XbgQ&qHL>wAfmqf zQXhZzJ^g+EfCYBUgl_P2q7K8+DS+6R$lsbpOr@yaz;MjodCKL9-Sq!^zO^3_qATU% zW{MMkYozaAEcvwo(nyrOBA3|o^>fEPM$P{J^Rf@FeWi>})a}>;IvchnE>y<}>{;AW zz}T3>Xt{DFOy!_+B|Kz^48wNKKr-Zc0R=KPCZ9S z+fKp@|C@7<#sr4Oop|fKt}9$k$sUc^F`e$r9m!bB4V@Av>=nQFsES-OKlh4l_MIyqdAR#c9|pLNE>_PN_z{2qR#-0`w0TII=X$kl@2m28 z5MxoI{xtnvf+$trwo({&iTD-R80hGvn~REq3!qs|3H71Pi^A+e?oRP<{UIul{bf%r z^|<`sz-Z~sM^~Se7?83W+Uh;Fr5?12U+nY!~9-bJE5Hj zQdT8{_cRjbN zxtb9&er}WevUlk~@3Ipbw+R}Z9zf$($<$niajx7vm1n0y;y@vgrj=mgN&Tq1#1uut zkSi%f*+K{TrCYYEz>}5|5a@e&owC;`nR%|^yTqlXc5fbBX$Tg(>CL~Cj{$57TI58! zedqFeN~IPu271NiaZDkJBK0&Su(k63KO;S1ZqH$xd4oE22%Rgv_Tui}Ur@Cs?sCjg zlF=_?>k?4!gX2(pDb?jDfCjtf7iw>Vi!<&zc?NNGB~!umzv-1f8k;;aH%c5?x67Xh zQ*d2U@;ut@_US&C5EEmfDZ5j8=hC6eM&&iwzsM(qmBgn9`QHHk`|GLc!EXD1X6xU7 zJ+%g>f5jRV>}mP$>O1`_Y~g{!kl+B6j(5H@M^@orD~6-BV5cokr!Dx$qq?i(O0(-3 zHyQLW3G|fxxsE_-1kOYMFRX>ZZVA>2PmFUns~Oxmu3cl13-x?15!r!IMU^c9v65Q}#j<;!)k|J5BE;U95sVXapQY7xrd=3HWSYMI7gGmX_KOfHY%Z!eg7-;3iRm#m*-$}ThUG#zEHfNc;cnUp;;KP z!04Em2oP+dz%*d-Tq&cQ1|ana2z$`2j|GvikG*~uvR+iyfH`!tDg0#nrr|nBPtj#p zT@UCvd6blQHX0KB_M?@=2wCKiktGeKxf;puO8S?gLpgiL5_@A6P-weQ5~LHPVnr3_ zK}2T`bSVmiO;87Pi%zM%2y7fB_927=T>5znJnEZp!4c`yHd99L`9NX|tI1(Y@^+(7!(LiqNmZe_RTx*NPPW+T?kaTEMc#wpAlOh}-{{W3-JnFr(%^PDY?vGf zrrk@g=EWUkeEBUN(A3pkL;dNNZ3vjC!o+}nj~#HKgy(gH=wy`&ukEmb&4+Ef!&5N? zeVIxd^OP_;Iq{$Bg#@t7Id-#Ar!4HF5X;{NaGHP%QB;NImgbvQ;_G3Cylc1h^ z5*_J%G#%)#9Ndlu!rqU&Ng9~e1n90qX2L*$E&^ND4Y6WW} z!1tVR((zwkF0Cs~zgQ}zg`FZeMc#5VJUAo!AI5?($$gU<_$^+vK^J7w+r%$7VVgLNS%}DT6t39UfpvYDlN(nw@ z^u9~_>+h_v6G(-R7{>FQ>XF(D$WKcgP1RPc*z0OCsYmEZ?zUE9a$LDqj->?tAdeVT z4hRB--0x8%aIBb+cU)I@kkm!N(zb8vo<5`NQ~mYxu9O7no>@H|`*te>xiCdOncPCM z5p2ByelcdHqX{9kBPC&n0xbmJ5eq$Pn-t}TZuTS85V6}#w7Tk)cy6ZYxLR_T5(ftt zjiQ!Dq3n2?@JeOIrHFfHT*-werC%@?XG@N@GzA1860a@#2cv_B8|X;TemH0ZUW2>) z!1NmlY(F$>H!bNrb(Wfya@7ttL;zjoee!vvDUu+gzc68hjv7H@nYdM0g1uG>eZmxb zj$|`@+JPXs`1v_XM~X3@TT?WzF$*7u#zN*vV#8L^mCJXDzf5g34Sp|O^Px>(eZrC# zPRQLfERl-9N8@7Nnh9o*wdWL{)xi%&;NmMW%oS!6;xI-L#D(G@vNA9$d&vYIzukh( zqKNC9Jje>#Zb)W5g(*|;`#$N+jzT)jSaaKSG7eFCEuN7sX-Dy2wMXZ4ye#vm(!=iC zyjHh{M>n)ZI}b>KoRA7>A8D zI%^ZO`r2`K>iS<#_byrACFXkWU`>oqmMM>zYCrb7WnDI|s9`2?TssZHSBNR_8W)+f zgr4PJb!u0{=W%S~$CVDF#JOcC?M$b}MSw6!mS&>Q|Mi>iU-lbqDz60>>j;%T$K4Q~%nKzd9bJ+C97tg}TsWXD zD&<|vKw^kvfk4vH8;hQ!?7Pj-Z{&hf_uRA$UO2e+o%nN*{T&uL1jal}kOp&pb%QSx z!AFVEGSU#=Pjoi@VQbFi^3d46ig@5-^cR`&1uoAne3^~!uKkg#?7wF0mb+fY8!Ic_ zd{a9riigYQ*tAjn&am-P7 z{_~4?B-^wl>}w3?B04G%^cY{-R627?g7P^X$AzLk z0dW;B@W$RmuIa43$5TO@8gYGBW%HA68V{*E_J}e+sWUWp83 zQ@&%w;FIjN`5vs#r@K)(OXU|ztrcBiKHd4pTWUVzca*7{wln?5Luk?%4sBlh6K2F) zP#{wu-vo92Y2I{P-1P=0a@`9AmP*CeLbc0JBs z%nU>&yTjjnp7@?IYZ$YayNwL*^g_!}g>m{J22$e`5N7yPJ=5ozug1)CvP#y^(kr$) zRVq<7BOV+wE>R*dQ6+Zt#49*x$4b*YpCnbOYYa z2tzz}I%!tSt7E(1l-B$z?+FY1Q6ygQjV>f-fIp8B!t87dpG+`+AXRy5Wy8nrq#K%( zHA@Q-0gt)GXxw{x4pb$DbT6w0N0(S2&B+LO~EUgKB5a3s|qpEs9v`c*F?XpmBi?2LLwhl*Y>cW|eXRjQfMLOfSW zphO7g8uxDMkyD<@L_Ettpr|t5btSXlH1Xj$a?nsyW8U#FAaIFRdvL=pe)G4;o;qH% zij=;Vw|>WknlhuRlqbsN;zdh~aD@t?75-p6eA9~*2o5sY=qz-sb)*qfmFD9_lY!ww z&IvWS+^ z-K08ICI&yDLr1j}MQNh(*txCk#v4bGQ6*?TeH$C7DeldT%3cUIBhyE<)=PYtlyi8V zXQZv@iVlmy$22p9=`RZ7mllC=lpogtqLGY3y9NmZH@*&Sfi7_AqW%e42L{ z6i(LeN}P@dy|6*<*yW=dF-%u^7=qMFIY4$6;}~M7ANcHXvyxwQZ3`tGf{g@0CxgFu zVM+8!B%Aj89|>H7;eKicPo?I5%!fzzl`x)R^Ox~Me9R&UYcd(-{$RId_Es_>`kK48 z0#mGkVzQNeiF`;mve|IvmA7kB1d{F}2F<~WkD`Lxlqt8Dh~qP(cMCm^!>AqwZpO4J z*6)nC6`Zj3h~LSmnBJT^0QpPq^+=Zkh8HElN<~NB5aD*hMMsAdprt#Emt!q*;o|+Y zuoUxwqze1dN3saAX8#lwHal&xzS&TO@HkCn?bw zwumq`R5URrs>Pp=ZSjXOQ`L)0?7_n3DNYy;1e>2soy+M^W+O-iA!61|xWv}Q&4xC> zMERMUl6TW#rkYxvNjVVC73e1~bl4dO<~1Ut*VOL1Hl9PrqDV-YHMDQW>FNIYE=hQQ z>)q7MmBj`+nv||Fq(hIb&+?lYzsa(_3S)min-^?|7ic!tT%qfW7t}TGvhFQg=GGvn zmZavBPx6Qwn8h7xrK2`o&LaJTjt;k;Hm=XC3(WeYm0P$z_yDO}q0qOy;o|DSYk`K2&p&lkqD?H@m`8@*1o@DkdMJp zS-*=Lp_I!iQ%M#`z?ailmTn*Tc&nD9fg=2v07Za$f0&3nke)@0kiJfaK=qR3JfMDv z&bg$iNs4G_+m?(#NOPiGxN)T=Ffr)yvi5VK+K?^HfyVi4im!#H@>Dq@!$EvTvc*20y6vlv@aLkM-oBSk@_`gF zjq}oiYqn?R(cyNZ46XvgkDiqc6Lb7P{z^mpzLtsR7q8Flu^)fTNPUeX{}wkh;>LMG zGA^k?a$DDuNhCv8=@TNxq{$*^u0)~{fxsY4rBOLiwVk+BXDAtHg$4ZSBBr9*8)RMy z=SBcZN!NnXM&LE$AdHtr@z9~mL2O6W$y3ouEvnIhh?jwDo|eCT|8_TqS-Gfm60yZb z1*eob9Jg4dIQQC+MplX)05ROxJ2`gfplhF zf(1pUH3$Jo1@jJB{r!k5gkHf&8e&#V_o`s_q5a{IRJ!l4tg2$3Zvw&h#m+hpIV$?` zjY_|goh_*XAdZBU&K55eY@tS#Eg4zv>fzBV`{)bN3_1bE~jWQzwlu?k7B6z zdk8wIeM-HHOgX>nw^4GBVn@3}u(sRpHHnk9NuTNL8^#qri!oWRhwtedJQG4?zb$Dm zcQ}`g68)rhxf`m`6xapMUs*t-*^)lJOPUUUEloon-DGCLhNKq97Z5=@D7GgAqqvZv z(aujVuu78Hy0AY-Qe_K&Q4gKvv?Gx3f1yku{4)A`b%jowfz(}aQ-wK{&;e*aO7etK zRw@*}jEEZtT_PoZ-D8dF&+O8DOyX-S{SrOv6b;YK?f-~8e>E0<&txxw+D0o$Yw7Fv z9S`}%b#+q1gCmZ#uqP7-%QA#hK18K^9E&&OJ8U`&GpQXK6EN%cnxB7+hsrm6@8CEh zE~`H9KqdGc_FAsLp+VqS;O1=?kst1@20reKv{WWvsLzu!+aqY7!8EZ}S~be4aSo(9 zr>?N&|HQ=!D`4+gGJemzTiX%4H#MWLU0ZS6CXgi3D>CgVfe0N#Wabw_FM~Z?0O)0? zZC3?vo7Ar!o;V&hNF_>d2J>`6enPUj3Bkd(qacINick2M$I5b@{Z?DR)0WZKTl|EN zuNN0dV@#2hzr~3Vm3c$f4k#4Af!7MckM+U(Y=)>;%j z8NU`0-d$gx<|+>5h+m%h$_=0GY%$+m^t_AEjL1Q|ytY*| zGUmn-E57BsA%UQJ?av+`zTM15==Yjtp>g~=bm}fs%6pv?)hCO&PcL{DGEWbk#XHYe z8G(Ad8CQAAv&xI3@+K6$hYNLLV?BImI@}n6I5zmKj3`mx%u?_2&CQveScJ!gNRRJ> z&bwwtI8rV>nh*r^(2MU}7n4?KLdxPt3E2mlCWImI4A*#NR(5DA7Dbb91@_M~)t^WHd~5Wf`a0>w__5rUwpabp7d;1TN-RU_Ahf;&#Fjuf2`?3Ki8svHk~=* zsAnlWCD4EU{vuI@QGYcw0}^}E+?-@l7H3*^IU8rH=bpK7Hve_XW%-6y);1%jdXZte z(A1)&g<+X($>4;`Z1l@DmD*ut+L#0aR)>YsvjDpT3_ygN7eX6#EHpZUiJ%N7in#wp zJJEm9vI;*e?vvPpym-5?NN7lqNJfVZ?_J+dYdehtabg~uw4n$E3u@W5tM{qZY)h5M zeIKbDJRW}jIJWO92h2wl1NMl`ja%uFGDP6*{Zm(MvWra%|ae)V+ zi{DkkHt&4Pb|jkM9!vJj&QCk@5`}ES*@6y|4%?J-=G3Ncrj@!P84BL$xamYlY^U5lQImv-l_m44sLN;YsU+2pUx!$Z0g%9WmFlkX@h=cCD@r7WVCA)_R| z%JBWy#qWf!&ZE!5vj#Ua2fHhb9QH9}aoR0x77uQPw-tqPc7_&>)0kfovg>-BAsKo# z-D<_S#2|aB1kt>JFPQusB}Zn;dFDXd{#&vFAl$Grha&Z=Vv7`Gk&kMN{|HkxuN9s1 zf5c2FS+6zsl|7d0_NM?p^F57FKj{>zcvq_*h(3Sim68bYu(ts^vTbVz@e^ixiDSPs zKgBwE4FAYR;``x`*@i#Lz{I{#rpUjE=1XMF{Qh3ovB;FSHo#{fDCqBUo-re^XO22L z9!)%tD?l7Z4txmLQH-LC3NuvVWYd53BO;m}g~>t?M%*Xsk`7bo33gl0yneKAoPF}= z&o>sIpCSTtWAZPCQmcMdCf@oSz>xL%p=L+5RNa0=8}r1EG4Ij8`|&)YPCMm-fkh9D zK07OoB0bCAuNU4OKbo1oeb>`&sJ*?YqWicx^kr(f?)e9mvWr((&N#}L-;vlXp7-52 z67yM)O*i!V6egM_c#%zfZ|Pm*{;{!Ds`tT}E8Pjm+%PrYhn?@%CAXWL-ZZ?T4L_$E zZ|uDk)6)Mr%?)bc|8W7%)3jbyP*u`;B1^z?){4b*cTwtZ>uO!0<(((%vFATHe9gU? z;vPslW*@pPwcXyJ`EYoGQOfSPzF5Q9`73>=&m3Dl^((!26B{B*az>l* zW-L5<^J^lnvQmNqVTeGIokg?s-t@Q8#4SfWUeC?FA8^Ex;TKeMk5ESEqOebPh*(mL z+Ve}awgM^#B_WiQIJwDvXLZ#=$r>(+&nUku++W9^;P`6sG=9 zPhGVl?+^16AD`PlR%Dqx9wSY^?fUtaQ~qK3S&_pvZ>ggp-Sf#+U7kK3 z{X-46O_o>2HW#mSum92LoML{}c=XfNw-$skofF4@jGe63t&dc=A6h-Czt^rvNFBi0 z#X93I`TNgE%T)Uulc$Ce-MMuJzSUa5Pn7RmwkyrJvU-Om;q6aRC@Hg%u;`d z==igg*V#@>@?WR~oDMV2^TQ?;e_uOkN{+nD41avsJaL%jW4V?Udt6uCEn;*0+Va-w zsMO|HmI?R6BdG)c)+!Y9P8>UT^Gzna1}|8>somN-yS&rO*eMT+y@kCSm zr|Eggy4hK$Z=&XD9U*Rt^yxmEvn@_E+zFCxTKj#wsgdG4U0W61AC9+v2NJy&u5kZ- zWpaNaRcd@=xSpPtjBX1R@;dtt?kJ+u^4nqL$@IGKQQag{0fpDfl5M`r<;mzn-<>XA z6OY;Hc<+Vs-`%PFLgf{M$A@C;CqLOEucnFAKiE$MpYkek?_7(j`Re?2@eg*tE7FZz zKX09#f3bIU(#vMAd2g-Zq^m!^q;clcv|?bu<|1wNaeu1Raql;l^Cm7IO+SY}9;|$P z_$N&;GX2QjckdNJh1KfDZ1wuzpA8feHCtV|F9?Z(9ujgR{As>ui3rw2`D>GYzMMPZ zog}Z@P*M;YLXgNWeZz`9NBmXTSm!t|S7#O_ADN=_0Xaf<#IN#VtWLSg%*5p{+w^K- z1I3OG*1UOl2{)Q9t?V}BT~t~8b~|q+d$ALVZeOO-rXtB5;|oePW%A@D%&%{MCb#)H ziM4s+d)$21jg*D~?syfZdtsbN++Q!c9JntWkhS}5;yf#}i@z#vJCZNC`!l(;rv4rQ zLC=h4W4X6#U6tAD8Ns>qfy>24lESO+r+I7E4oVJp8{a#9KYo&UgRs?T_0=1{w-Q5% z`~uSeFnb+S9OvJvh_tUdn%LYe7Te>NbpILjrpD3d9+Bc+%1oEb6<+aqf70t8Hhz8R zwJb^x<(k&56XogDH0JaD-N|eBLrg_4qp(3-v~0hM$tvxMQEG6nIh zHB(n1gnc^-X-kX`+kYolud=)tD(eWivmq@VSQhw>_1DGL{C&VsaF$yyw)$4hw!Gk} z-3WY1n`Y$1KJ7Vo{_k+rcOFsq%~sm$>u2<*f`?4g*4OkX>_!fz71RE1?A%Ck|AotJ zpB-5$`DZ5Y>&{t?_YYTVqo?QI(&eo*x8&b-*a>fRbN}uZtL(^TTf+4Eob8+XmAJ)c zRYzi0PV>L+tJ)FT;Sg3{lzSD2jC;tN^|{0OrRYR%oQLZoS(=9}llRKnjLJxsyiOq# zbqt-kLSV5eu@*YFj7ApP^_b6UM@f?**jnZ8u>F~%P{^WVN1!MLZ*y1@B4o=0x@7RR z$tY!3BCXZ9)Q``%Nd@Z=|Ixdo#U^InS&m^Rw=<3CYNeB7cNsFP!VTh>v zhWa1ht9ca5dlHQ08;DC)@+q^4&2u<}@pp#CrH)zhC^bIe(|R-f@#i*YVmSXN{{SRM z6Pc{FVSw%}t0uibQj{Ulo0p=FpKXu}oCZu0)5&Y}&qg zZ_<8?E4fbgT@Gn+<{4U7T@HG)JsT zom8Bh|CAs|$@u~&rPH{gL84jYVc$=oHx2R9|tN0tMYa1bWLv%M(wo8b7G|ryQ*GL!iY`tUSbnijJeBH&Q z9}1m!*T#1Cd3{Cp`r1QZ@v<9b9cV4?t?|&R^FAmOH2nA}vBGNZ`Lvb==964vqRZdM z*{eE!vIUN8cyyE)Hfj3?@6nXkKT~y<#`6T-mh3|KLxVBzFr3uce>lTt2ri1=zol>e zn!lBeGNWB=woFeJDwjy$J#*d{>XRoc=zOZ{rKp{qmyp8sDx`xLfj*tbY$)vTpYGe zecGNVIDNRMuBIkD&)`n!ZHltx`ZE+3J=)i=an#cPZH2+M3fFFQYwMSMez(-m_jIGk zQtk$Vi;Dw}7}V<`QP%5iL|UR>iLFZPgHp;--t?o^2_nr1_aW090fQE4$sy*Qa|5>Y zNbr1-DWaJpI5s`w@{JjjY1%&Gp6KA5mz=E3M8N zznnWzrzvK!RI+o`1AVns4nIJTs68e+*pv(%LvS7W3GoXdAV6&%CWFr{OHJq%^nH`n zZ0|WeRgM28z;q@N|Ju$_yHW{xe$a#|lZKtQtKMB(qD0;u#a`UFKPxLj)r)6Xn51;I3oqbem zGv390JuE;aYyQ(L0qe`NRVYqeVn>BmR-EiTswOHuethcI1(Ghpd-fvC<_f~$@TvD;Uq0d^w@ZXMDO&)Q(&D=}ebdLrMRr(q0{xru*?)*qk zv5zh?xG;1}3_Z*+E)j({fA95{*8BRf=CY#qmJjjo?S{Y3;OvS{EUBpKs(c=e6yBY# z?I5m~Q@6n~`WTrW=mbULv{>-}Kbp>ht*tIvw+U{AUYLmO^jURsd-LQyxEEDRl)sl(K ze?G;7gSTKTa!-)1(57^j&;<$hG@%6C#-Lm-PWhCl=s6WCp&5t+rJ-6u?P$o*30uH| z#`-#6DT$Kk$6gEuq1}7?$X|2N+V{ zd1T6YSF({KWME*;?b#)6%W=Ef6v6gg6tVa7$?y!gZoe6;RDjr zcUbRY-(jS{Q#m*fETC0dByiSA2L|S~Rt;UN;K z4{+j0%H?VB?hQL(`273E)qb542`u8_tfHO;qDZQ;O9^uz0kD%~!SriY!ZN|sjVskk z?eM$Ue&*+$k>;&gdUQga7=I$VfLO4{dc&gE0#}nLvOXV$L@-O~pKu}g=7-argk8Yl z3y7=13TcEGzA?duC2B)Wn42U)FDqI|9~#5e)jX@p;7%=EBc*@>FoDGl*-g~D(H7!g z4e3}Qyi2%N67svuS10%1E~^r}J0W%OGG>7#oNZ(-Z?^6P$rvxcB$BQe8DDs|zvhtp zKd03AJ|>Xr(|&k>nHO{Z{dv2&kAK}xJMh@QHI!sKBO`TcvV8XrL)=0SW>!vrd$wEc ze!B=)^w}vDdQDDw>Gg}ZU%D9ea#bQEaZFnKB9GfOTed=KEZqZ!%(^t2^kyO(uiRWT zjk_wt&X<-1eF@6+a<6~+Qgy=5%_7gk;p_exX-(spA{^MS*DqKvId6O9yq#^`S{Ny7 zUn&*2KQf@H6aK;&T4O&8{S>f=YxUV9kB%6aY|)gUL$ydGVDCBA>P|5Kcr zIxh0{^1^M<(R7X2xv5WYFo&DZ<&b}rJm5h)UZfKnIdk+PsUKZFB;fkxTxgzTlY{dC ze5oaG+;u#`_T2w=Ju^|v;6SGEzOYsjr@S72lt)90Q5`-Nh!O!}6yr%7zWy}I3B>7h zYb`v}$d2=X@wAFCwwY8fhK`eeSp)boE)oE>>h^590s+`z>o?&7y;tf4#=mZE_RtBi zcs^vgz^M*>*bj_+P^#4XoTn{kY8msn8FIS%cHVXK2HO(QT+D3f2oH0Lm$}@I8Rv?E z>%jnsml>=&F|W{qC6gQp%_Ixw%RFMbkQQQh!^Gh5LQp6$z@2=!-bKCYt(~jq&(qgz zjxP`Cb_A2@HdEh&%F87QV=PR9jlypJ9AQWnlA0B4K11JJRzA~Jb=o$f#PbZge$!>a zqU@-4`uX}5(_vbr;bg91E!g5OV2ZWk)a=Rsc@{P=*tpl{t=5NKV8Eji70Wiw%alY^ zsu9)60^)y3`7(eFlw51{xta^?Ef_0Vce!8OT7v+FPZ5;T9h+bSUTf8|3Y8zLT$+Se^%GiY$}dS_-{EhtZExqyj* z@lc;kq)iYo(xKZda`h8n;IrN+fuN%)O=#w|^4p6bC*Ta$yEqr|bC9>Bm!qc&`J-If z<tn-mg#vBK{|NY_7YWHvy*dfqjO=Trk6MEo6kvNmd$y%RJw{8Q^P#@SD@cv1-&_UVO`XiV%2GGX1Ow z#K$hO$g!a#1BZj82M1sGbGrPdVd;^db`+@pu-tWVBP{5$iGdJMa|K<)#Q~v>17{vG zS20z$nybzfU=BP`;oBqII-{#^WI-1k2xUNAlQIRI#&Me`R<;5Im`@10j*B6J>>&sG zNl<=}=BZq8EzQW7iJvzG4)kh3w1kmE+>wQlzA8yGInPKfNq}?54sOknpwWA)2y=Z(Iqrn*r7Kfh4n+}!@mY4BTnefX4i3$ao0s~ z$x)`1YmI=@a&-SUJBz(345EK8#ETo3Lp#b2-hY#|jf5Qk4b}Ifv+94H_w+Q?D=9%@K#bs&DLx)n9h3p@;z+zKvpda5uWT+?>I(q12@xnVl*m9b z8lkiCTbU90k6KEMv7Q*&o}mL;S)+>I#p{3V85udNluEwzw*5}cGsT#YLXc+1&;kGv z(y&)zG`LChs^!=Hw4+~Gi|pKsVSpj(`xB_N5TP{27hW(3LFz^X&5xZg98Xl zph|Rqocd*>o1!@$h0;SIRdvCU`_u7Mj1tcTAWMv>sv-)Y!iFcL1w=;%no<`A<6sbS zn1!Mh;Ew^1Z^39hovCA5luf1pyZm@-`rKb5nCh5Psz?;T;6RGGiY>Aza3Ua&BA5`B zI!2G!uuS5^l$b}@b)Exhmd`-q^`s%?bVj{oXnnb@myx-yZkUbx>&@+=)?!sPaA4u# zm$X?WzsHQqX~4tWpuQxj&0-H$BP~+-2p|Zgy~pjsYv?`vG1UMroTUDpMM(Z(%*RTm zQOoR)Ew+Y!clF;`4agFrBc%>@Ia4&NFcc#%`wk`E_FbD>KBa?5^d*Wv3JCi+Uj%gR zaTyHkz~Oj!ogDY&n9*u+52mWf~U5ws) zI>ywGD+vOvq@!sVySQ0jC`Ktxmeb17K92QUKCwrS+u7&N6S>f9+C*YR){Ojwo|>A7 zm~gYo*r1pl5}RN*STdU#X#h-_b)lo2dJ!0D053^y(p|0a30Rp5{DD3ykv_UmR&ER7I|WK21qTSg@xHhm z4((&dUrcCb=k;G89t%X^#3|+9%R;&4pSJt8r-}CSxyPJ_`v5y!eXZ(11F2{}%#ZJs zB$ue)MP+dYi9U(RJD z#^N%+_0pK%NfU`<9%`UQB_v1UOZ~1&rWgIyQ*NCEg5v_vf6;d)VfN;UhJ(IOM$6ldz~IIe%V*wjyqW-of)0__#%qiCtat9TyNaC`%)yilC+^ z!Di-(@fd~7~^ezsfE~ zW0mr&T!8WL@xjUCin6iy-qdnPESy%2uE%kDBkyFE#CI9e;X-*=XZs{s>wW$kcM>7@ zE15}uNNvNp{QbJqkOBb_T~P>>^;7$OqeKato90gJx0JIMi&0UT{BK~fdHU$Loz0iS zcXo^G9VY{+Mr)mK55p}I$ z-R7m|ck_15)w;8&q6P?8w4A*JXthI`awFPDvE2_V+D+>oCD#|b%Ep8T)&7SC_ctCi zI)|UWetCY>_8{f+?f716yPV(dxKZo>H@KAN2lZY>955EQmXJ{P0E=Ff0ssWTan{j0e>S0FrQoRlGKCQ>#!ipYQ!2dGU!tLI<^HZE=@FC0R?C2cI*S+ z?a}K_DjgICIIEi!X6{w}NEO(>al3nmP*r37uzyb$aJq!8EQ;@WJkw_<;^_^2D4JaN z@ClZakCVek!WM-OzGp;8hCjfg21o`e)~>U4UQTdL2R8g43jhhIuUQzQqNMeDy*OM{ zHhSKEfoyhNh10josUj>adX=X|o}c?ZjqG*%?LX$(4%VzeYQ)kU7aCmdxt=zBPx=Xn zaYS>qMkmOH-8@aVb;gB{@57grtHakZy?W`B3Ym$jyaJD(i68 zC|_;8+@S7vP9 z=SX}Ciamg65+z#NPyO&>adP7xFmxec%V#@IOCYt;}cQQdjQk@VU2h zTANyKHTx6JH&duLix-KJJ)%uacuYX_ru)D<2NSKEXBX;gYoA= zK1XK}=bJ9qmK9WVfBSjwyDsL`<$bJRE|2`tB$`5D1R$nxjg|oHvqsk}Mqg7!-bM(z zFCKl~v($R|`?p>G&Tu+j^1mylWXq5s>a_ahy0T#l#pWxeh?X-}B=mgvAh>hW!em5k#? z*Db8Xi6gbyH=Go5|94Oq^|8V-Ilre`jj;lbSUpy)NG~p*xrV=BQ;@g*`qk%5r<2x0 zs?1s2GJUe!Uo=&a%=KDK9h|lDIS!!Stx}6yvO*AiUmZzbSDntNl(* zH)y#lj$iW{t$gk3IfA7+Pr|GjrU$8sDXZS#V?F^T0^retmL$e5^Q7t@0s#by8kiJN@{ znCp^#*kH_%?CY#J&TGs(nbQs6Y&sc$Q$e_XxDW-N2qjLHs~My$xNK zzjor2m7mb(dW(h+oxa;A{f!mccd71NbHOcJ-z1|{bXu%868;Ph zEUxisoSIk3NKcT%Jnl}uudW=b17FU4WESnacdFaZTz+s_5Claz8T;7r7zuiO@!h$a zSIy;fHYIBGbk^l@fKQ$E)-H^;tXd{4;1lpT+=iLcg}bkV+6it~Z$9ZSHMLaW@&r5* zPm%}r%i!Khpj6(D zIm}(VUFRDA>8j^c9!XFkeg7~eZ)5kYYV&!&fQ~IwxAuZ(h@>zL^*7~Q)E&9V%Ix~( zMV!OB#oai=xxAfI2LpS@bHShts}k(ex{Kh7t+hbl7#AGW2V?$yC+g$XOXw}Pn()Ok zc*rrOFCsAr0fC_)J`-$NfDpSXd!HU68sqK&M?D-|uNJ!%dVf_g>!O?9sGA%JPMkt( zEQY#Da#fUi4lSO08$Qe+go23{KnftlMnRYgMF|#nqtE>*D;q_7XS#$dfF;&PE%(F2 zhBZtUh^@+SWS-FB3xofb0>=;1JF8?UHQ}K1cop@WmCl z755gJ>L&uwej)zR6+L;9{h0o*be=E|A zf7rVNoGGFbf90X8p!^YnA9N8B5D>7l#zYRMVC1C8gM(Gl`2=^TA`dICh#~M0dxLHd z&%59=%y&t}?rP~Ol(u4b!ZjZ5({3y+zF*#c8|Bw4OSK%D`1-mj8AHSOMj0u&q`1^* z5z`k}g_^sa>V-A$TO+BZd4pmb!{)WqV}DSU_`hvFpKCnG!S%|d!AB4xr|y&KXkm;W zH||e6`R>UKz-A$Si;BeWnMva8Ly>$F)SuMnipL|QK?u1POY$)oqVzzbDK6{=wZ*&o z?}f=2($s-7iIBx4RMgVrTZOvhB0A77lVgJ~*y83iH~wY#!4xc2h*jePa6lWWkS0#} zpz5OCMmH+leDN6sdNCc@{!8-)u?4Mdgd-wE4U>*Z#K=lZl&WMh8l38k7dQ%|<|k7; zS|k9TEvkz3az6kCBvFBZ!OewSN`>n~PQvIA%cdeqgeNNVd&t+pP6*QHgLijGht?`*yX)2t*)fygxz zR@G5?uAP?saGu9)#gG@R3Z6>zFh2pn6rMJsa9P3E&qx#2z`a$a@!6TWY#wCoxIM8T z-CZDF^!I@JxsGrccP2tjWQl4@C-NnV48%1kTh@>fJ!M#YeerX#9*Z_}?SvXmdHDiq#WjP>rZjzKV+N zkbam8kDZv_OGBgl>|E||b7#`+iWJPsqzN<&{IIN`?sATv8d}lFWEcMa_V(_~>-u7Z zMjrV|em5FUGO^s+p1VFeIIeyoLl&Hcq)E9D;!vCb;s@8fBSazk=grTEc$v4AmZng7 zCqSsS9m2#1*V*Kn>ocll80vSPMMRYKI9lRyjM7|f@Gp!-AE}Wwb;q((i-Q#A`P-`h zJ^wAbOox;o>Px@PH_|W{k>B3V<;30TF7!2NUrg$KfAZ+wnAdry8c*nVpH#7-YwkV) zYZnr4F#QKW5))hzyI5L>fbGl4ypUn{Z9>+j|6v%HHk~oQ(A9QSf*Q?hpAclT!Tjt* zM`GFt%V~CB0{i>VUlb^N^cVnYYM30k^s{InoVcC7A~M1h23nv40D(0U0Xq<+!v$~_ zZF9Usi6#=A`)Gx2nIx(NP{E_XLkQ0ODVl^C9twb?LidL0(fdWkfzwQu0Hh=n3K|Q0 zT^XfZ;ZvivfP?-Wr)QYsVRedk>=w5BVXKhu!ZP|R8so?1lw6P*S`1l`EEo^&3*{yn zlN5EAktA#b0jc`@7B%r;$@a(MaU}yw#$dMBey5pL*F&1}q`Wpu3f`? zaPmBKr~mqAM`Yu6pZNN$MMyQ7+iv$@q{wqVnppT{h>GJ&vPu-*M1KOBR09)$=Ucw> zHF8_P?W+%2$Nh!`-2|C{$7^2{S5226Oii_nRcSN;-s4129iJOlV#GXp2Tc#p_`Sym zB*)ReBTH)fq5e^iPmuPI%XYlp!e@i8?PR~|2d+8+tMXdApIul8cwM$3^rjQC_E@*- z_|fJ)kReve89_J!w8s#d8HQgEmQ>RPa6}HY^`K!3(c(!VbXlht_N_bs^ziZ=#^&Im zq*pLC|m8 zt$bZt)HJ5(d~>R+4cXEZ1y!f_Ncn1sjU!XQ;9A>hlYsG?dEEa5I^6~s|D!%iI8ITZVc{v+Ij{=;3zB^Q1~THc^rqpm6DcEvN)O{mrnj8GX2`o z<8^qz4mw@6LM9*Y-NL0hvQn1c_M?y;68XUqW9q7e%71l%7)oStU|?w9qS~Lp-G7Y3 zAEEe;4BPra}O~i$NOEE=3=>mR~zE}n|AebalC=w#9IwYs~`8)MQ;*9y0u4D=jK~@hDznX?* z`*uqcE+5br2u8u^i564Y(krL>btk@hxeL4HJtC&(H``plVR7MNgQHQvI0=!F2&PWl z?}d@2yvXEKO$~MY{^Yw8JFdB!yiH#+x#RP8YLu@Rx!j%{s>d>=3WzrhDndTe?uSpE z`i^B64Pp1wcBy26Cb2qPCo11AgHGR$34}XsU)SnJQ%PFYth^Ssrpjia8HBb!@pmN( zC#?=I>n^*_s;l`}qiG4p2<=-(y=L;|Mm_=MyZ(VDqATV z7x_H*p_a!&@U)Sy^#U3e66SGor120we&rByUB^+8~i8-u1TgCig*^?e= zWLC#R^#s=>gOC-exB7x-SqJABCh_3Za)%ngW)dhtOSn)4aqLJW4I%<1bn6{#be6Ec z8lTmHc2!9UV3pi0$~d#hysb#NQ?a_kw^@u zH~SI9XZl49s77i1s>^8hpKGXF0Z6oZmzbo=W5OA?$ z=;Ojuyq4@m)Xlw+*|DM@_3=G?Cn-}n0h#A%kE_qUF`he3b*8Q5rq5Xk-9$DK*~w{a z5)E>m=$EiU(N=D@p!D^5L5QdIW)LqHxnP(5a(%Q`l(T{kr|taOU-ZEZpR2)1MS?t_ z2KwLKF!X>|SRUoE{w5AK)^7x{FDhs#Y5bu8YBDd{LdAm4M%RBxDPyNT-iu66%0?~p zZPV-bSHtR?es^iviMov@N`>r`t~gacDV(%=tFpQ5{>&7KEI+LbDG1$)ik-E5RqT%# z47livs+$h~s93@J(azZCWHsPrF~HBu-azt$P5Jl0&IJKBG*yAfTDHKT$ZGjBQ8cxQ z_-w(K$=CUFzqc?$^=(T7q;xhz5*sDs(?eFf-&-y2>=GdCDhJaaTX1>r6nfQ{Q>Z5+ ztZuQ!$vm$HMf_h*`bWP)C5v1qhZ~eXJ^gS=tki9rtBu6cJEmq#VBbBQ;cuX{6TUx* zS2k|@^f!0FgSP10@99$HpU9hu{YfUw3@zgQy!m|D9dLYbIIKX;z$@`}|DcYQ_}$&z zp3TZDeWT6w-&<0(yeS4t7W!b=t~@i}x?5RXO=32)<|NpVTUGT`ak!X-J-S$jGXp_& zVIZi_t}xElFi8T3nlyuXcj9Lz#=x{2cC_tz%;`_HqOUx+ab1UM+FEC1c6jD;Uo{-L zKhQGlC8Vj?G9G2J-kJ+F&l|k70}h;;avv7(^h(Io z*ww%KHma4~j|m*-VoTxB#d2%%zyZ#MY%&DNGvo7Hh?0`pXVoV0)dgglrq_8XM>N{L z0SbT7S5g%k&a2u@>I;$$j>{D(A*hB%>M?9Lb--HJ<7^nG52ZZhXp(r}7qHF=gk>ae znB%66^_eKXpnrh3Kg)2png2(A7I55XHn?Bi+1uhfUirGJUE^;$+4c6Q+|3B5XGiL0 z9D47l!!%73f)@(Z)?bP)!V%+&lo2E{_XmqN6Vy24ey*7jS?P0riWry?g%nsY> z+a1%Bx*-K3v*+qca)y(EUT~6MCuDOdnwulCx+SmM`+g;Z>PO(Dt2q)o+H?boZI26Hs?SKg@KXWg z?(}gyUYK)jzR_=X-|5r+40*tL6m4kWkkNk9PQ24bZE2;S^-3HooqbYcrNabz;z*Ms z@!NsEOisZ4y7GEc|Nh@_xxtAHrI%IAqL0Bim4PsI!MUn0}4Yl`%rMuYmq$kdF#~Ac%!*l!ttXMvhDb2$Ol#2$UDHOJ zb!`sut?Vj_?A0gfnB^M7Hs`^Vcbfr+$pN>q-@vqd)r^MjXX^JGJbcZWSIM{f3mx7^ zC**$TX+(3ZXwly`g3sG+)-N*8WI0;yGRt6XIes)`tya@oN^zcQi))na&+5vP%hInW z`Z6BmzW3W>H_y5ukQ#$JvzJ)S)lYtxzqQGH{w-uQpLEzLTF<#BTXqNv3k!SOY%lDM zhS=c<;I4AvsvAG;7eE{h+FjPeVfy69gi&=YA>YlQKQfS0zjuHIX1%M61^q=D(k@k| z<%!W--?rH^0ngn%c&kl8pD&)JkkvK|tQx&JCw}K@2e*rnG2ZUCn{nc1ZokX9Y=VF7 zBi)xy$D%$haRBJ3$Z`B4wmLV5myc_BE|D;^^pJ6KNW)@@nJhC5! zy^{wIht0~J&KFB*=w=Px?T|{NHiz5#);rXmLN41YPCIu{KFG zg~^a-1kCA7q3vevzPK`9L&pDnXIHZ()Xv%5o=@R>61Qskj^*L7i#I-tjDyFB&&hLe zANGlaDupVV`n{}P{fxZE5>q0{Zyx+ z6D{-J9EhDf-{f`oTEkZy-P6~qVZEL3z8i1e;PYDn))+PT4yJ4BL+>>C$FKBK7Ai7R zufrK<5Gt0(#u9sj^m!}&%+6n{uJ^0bg^cmt-o~5VS#+LvkDoR>oyn36Tb&m=j~CZD zAYx?~L`bGqe%K9E=4NAa8tZP+eE1xQt_=+KZW(^G~=bS z(}|2vXdB2|t?T-Bgm3rHJ0ILU(6&Xj80lweFl&uYB;qzY4j zH?-e)OmIK=iSl;?(v$!7H(0u9?7b1c_p^&Yow?^-r+lh|ap&()4Go`aSUV;Fwx$VE z4g3!Ce5*(?97&|ocKz%7VKq>EGzL0^K`#DJH?2|f1v#x&@`GEVliOkEMs05LO&tBzLVV5&up7SlJo<=vGqG^r5vIAJ=~JwCMQ4VQ9V1#>*a4w9k=U- zK342nU-y1LB$Eq4zHFb=O`fiClxU2&IyHX5IE|?NzxNFdW~Q?9dIU!jq6U0{#(f(1 zruq{$=}Lh(z)ph)hvm^9a3N?M9l6s{ZCHy#k+saz?DJ$r=7C7i`(u6x@guF7R5_71 z3eH%!=k>~DwSGTExp`2?t(aGhuFozr`Ehlh;Ns-#F6n62Xsm1rr(kA3SQb~ ze(V>PK!qJ>4-pPjfWs^bkP5*7`8odCpR`|s%Y?0(Y^ca>axeMK)~qc8F1sT62~h%KvKz|!rYaRw zP&Q0opT9mO`UnZQUgQpXSH^Y~v~gz1wO;4ayZ(07t(hL=8kQe81jLJ!`dM`v&~ST3 zD-cg6%S~x6wTxJWFH!t%7m?UZg5KBlXyA3iqWhIWEx0Qo!m^RdBTjKE&eB0$8yfx8 zjO@^lj3zbQPCZG*F1$-B@HQ3#;mlQC*=59IM}K)ik7yc8E7(E!iOa;A6TKG7@N@b` z11$R+>eTu-N61ZIXgtZ8r0;uReJ=r^{8WDm*1`lzF|cCi5@@6c!3V)j#lqc@2>NgT zUMe|X^1fHh5MaDquF&pkht97%og1@*9M*kD-!W;6Jk8DS{Fq&r@C(W_dVsl1$wa(7 z%zgj->qnnSn<$)r)^TPs#Ze}@T_3WPKeb#} z@5y_s($^e|XF}AXSmjTL`tNzFjIOp`$kT8&Ge>j$U&8#_jYZsd@-v)tSiO{3f7!0} z>#(AwO1yXbdh(o*%#<2%oAU+HLioI@Qx~nRY6bLz9%G@^d?dG%-x3O+=GhlIFlQ#vW`1<*9al`X$J{5}LQPuLL zH(C1b?ym%7tz|cx^jC%&;Mfq8Xxxp zyo0ZFwfV1ZH5lOR!j|MG;)1vl<2q+?FlyQVb(9VyxV9=E<2wxNq*`G9M4^}cY=;tf z(z_U2tEQ8azOX>=a6E2_CsU^tR#CBrr9Gm1Dwi5Ng=npy?I1ZXw~yu#rWt)5J_C>( zixH3FIB->@+-+O}p_!L82yhnqsk)^)aAo~8jy}F+xTM5^wO2k;)<%N90mVhbsOd>u z#^+AaENS=BZ^vlstV+HGyD-~GVlwg-6qKp3>tW<~&TfHdGSZ^+BVz%Anxdc-dTan_ zP`9c^T+Mv;RysfpQwdyO*xO2b2)fFbPZbTMCbT>LF{`T4ls65MrBT2^yxiZ&w;2Up91e%!YtJ>Z`EqoVe#^=g}0lo z_FxEP)2K!wx{^+-PqA*M(DtRfZ(>;$Mm1+!?Py?_@l~knQ5!5%lOH&`!@$m zdl^m}YH=qTT6nC-=ZF7>NcB_hAp>4j`KO8%DQ78Y1O&I2ipV%wpplE55<+zQ3>E z{K@lp-@ktm-^huvB)jY7*#h z%uBs~{1aQUAgo2}rCQa81Lt*+NbQ7Y(85>#?~^2BT~VSL?|LRMENVLT6IGRpN(laY zz@-f(eW@rYxlV@yNhQX}wYv4M-TPQ&S4LlZs)`s_OgI4Omx9)J03a=B3LU-?FtY?nECEr9LKaO9FYI>__-ke;1!W`+!dB&lxkAEx@_d?k8yZQU zPjyoJrwG1iTQ06W7X{|`^s2PuBsi!+AiXS5X`qo!Ri8X%dSXv669|@#te)T~%W@W- zclME9Rgd8-t9JTG5hHp%1&F;KOA(Dx96r3$lOa$gv2+B(2m==tS}KY$=QpB3=un6P z?3JuzVpr2cZL^$}rY&3H-rYbfQmjn;G|ElO>Q2O4Kph9y7EVy)OKVuf81Wl*@N=Rd zkWJLVYZ3N9lQ^fL;$tINik9f8u!l+)czoIY4IB21%%fS&;=w!f;JGuC6MCPo4PTa} z^><3Za6U5rfUl>D$F^!DLS7zXn>|w}d60OLuZ8IN}-`$5-em445n%C8v zSIAXevgfkxrxiCpm3cOtR?*neqQ+Kj{%=o6hI|zg-0CRX3g>3-dTEFJq-!^cIUM9P zcAlMKu2^Ajk9((hp5;1j3%R#H{3+71bqK-izM>1@FKK{WhkvZlX3NI4!^|t0ODMUW z!%yb>oRJo{gXfo*gw?+m_u5sO*tZa7St_Z`YS6{U>3#1YI0f&*j=*~DS8O+2=>_{U z%3(ed>LfJ?7Uu+7G2D^G8UOV5xtfOsd^iG%G0R&q+~)oocmY!j2x(_qL#}g#ot^J< zo)xtrZw|x@8}-&3SG}zGzQZe1Ln8t>))Ce)vD`jENYgjV3@nbChb`Reu0Lq(I66`= z>Y=g9UCk0pG*r%x)PNPNcMPsY){yo&Z>353+36_}4dO?@j*|PFZY5dRI1ys?`?sJa z1^C=g6)%#IQ(LKg=zz1PaU5N{7Qj#u%Rvj-7{JB`M1X?Xf+-7B2YGO?!7g6dneh&V zjo4z;FzW%>=a5-jg?hApVGo220w!R0IFE8_-~~#n8k|+4g|5uup}A=Z!hDD(C3uW> z@DbdjRUc1$6L?_b?_?-{A`-P;AcO67kxB+oKOVdAPaqB zaD*OQp{VLvq+!CEiEAQN7{v#$8AU0Z+)hLtf&ZKhjkF$;MUg95Sn-)OTH*pAeqVSp z1^Y;+_ zeHy>GgJuDbx?CkXB30<`WCwc?PLYJOnE096aD|3|O5`V*Qs(dTNFc5p{F4s0 zNZA6+uA%F>6w^sc4xR7E!DG6bT+A2tjaqDilis zARs6~7l02J>57CJlm-L=gZA3Oz~#&U={hSJ(ck%iAb4y5CxG6}z$9AXuZu=5ka|}S z*v#4&90p>z!w8H-3;e8(jYjd6l78+tY^Ycihyelw!CBAH2YzVy4WzK$3sa?%u#Q?u z>5fK0Luo_<6pYl9d{;=S1@L}L zU=*8i08X&hIbC5MATJJH6u<^Jk+R$AgAWo%2%-oM%!QK|HD51(2*pN+jV|}M#Dc6M z;7Wg)F!?0nqXh;7nDc+VBST@Kzzb^@NC5N%0YcLP0jdZTP!xF_1W_C?W)SG7kgW*- zDHiU7if^rSt4gl47%Q4qDS)OW7(@-geLog#@(bz9dq)_6?I8Rd%&hwZDrL_to+}Qn za3KfNBp^cR{0M6W27+e{YDX1#N@7e(>ah3cmC`${&&n?Agz-PZVcgwO_er4dclg{X zG^}wDJ(vIe>ynLz$Ppb{g(K>LQHoE2O>~JTVGd8f$Sk&l3vq0PtTs79lItzi&a4X+ zRSeXo(!$5A04JS`CWZr13uv8@6ebDsk_!drR1b9eyzQ%wLavT(=Lu9!v6%uFXNTk( zcYb$4Pl^8&P{U#%YbpXjI>WD;P&vL_3$0)hus9k+h(uP2S2nxuk3y;JFX<5q-1-G0 z>C6Rqk-54S=I{iEPJaIiu*USYFohezTlT#)l4wMp@rO5oYTbWq0^r{4>99ogR%Bkgi;q1|kIxw;#a?v_ z&U2y{>0TaOk^ej$o-Wx!y*rVfeHLxAUV(nm5BIN;fTMp!yCP*=)vz5@NCmmUIDVh= z3&pdb)g|(W-fq{_tDLTXlkRk{>tsG}fY%;2G{mHiP1-k^6({#|WQ-?6!6+1fe5uIqBgy8q-M&XR zhrZLX?saj`{6;j^_I{cq+mL&b0ool(2O#81R!i@yn%quU@ z-?JUC($IXZ)X3fsLdPZ-2jng-NvonXbu@zDAvBkj6En#T=U-g2!aB-J{oV6F$mj)) z&VcZwzZz8xst%_w5eR>mnUMIapaxd!B@k2BGEayz<3x{uvg)*M^W+HK_3adB)6v?F zOYxveQANuc`2r~WDzo)9!fT!RRX>yH6j{07y_-A}@_+7YDq=bwvzgv4n&4Ke1Osn2wx*PC$&0(@}OO+Gi2Z@28$>10&I&iS=!U266u|W8KwT`n@ z3-oF8Y2rb{kM?@L)STtLu#-sWe{;)z9c+6DjM4h29oj#|k^(BM9;MMOE7j zPSd-chmVmrpDu}!w3;>|211j);?}lRw`)1fG8t7Epv8u(awx`NES!DA0IWErf9i|BuEV1b{a{3MuW7; zYOf=?rrYBng00IX;D`VKQH|4MbtM)m%_{tO<0|qp z{QsDG??5X1H-7x!;Fukv4k3G1W>#d+WK-EfR>&UNdvDo$3uPv=C@WbRMJSX_WhLQv zou1F{`~CXs={#rL_w~NU>-D;>`~7xAeF+VD^4@;B+O$rHAihSwLSo%L=ECpFKSie| zZegCEKIhF(#$41WIf^b6YgLv*Whom`gvfI$ znvLoaV5B8@uvJ_2cw{HxgX>iS&j|P7m9J~%mD_8zo$gQ9eRn?bp#ONyz&68 zCB6IL>J87eKfS?=AR6FarBe!@JSDnKIY&$^fW!AgMifna=dJ8{42`IX1hsylDZLzh z+22szsJqNU^`3pfTcvFaSvPhT6kPq@(2_CZ{c+#^+*QC=_I|#g*Nk&4-F$qESa$B2 z-%4_V=aBJpv-uml^klNqWYTR@@7pfs(ICO;k8;~QGuynrwNpPu$OMmf4oe*NPGCyPRvTsxUT|n3F(7uNXzc`=FE$(l#%fITMtAlyyfxS zsuk_nkFw60?|kmpW)V7|si~tw&)6%N^Fd=ch5Gt!3lrH4S_|#TGzS;MtxrAwNm}9NZ`yS(Sn^;b=5mW)i;H4GPT>{Q9Y?hCSTG0j}`#} zJ`=%ux9`*#b}W4unaQ81dfZ0dp|RtY!@ru&QBM~p!~Xjd+LE&m`LWbFCFR=DSoJ5@ zDJPy!Ef#m4KFI87bHBDZT4<#hPMUm|!epYjZ$RwREvdgF5!pBGb67N-7McUnw{s11 z8SM_lo$r|#QykK%UwVKE$7krlntC5W%!j}&k!HdV#6eo{>6)X@S-P&ptxdbyoHb|; zJZ}}hW%dMjL>e>E!YFu&t*W~~;X(0d6Uh>yR~ey8TtvCEjn0cig>gL65kV|-Ir85V zhUw3T`(Mb?y{%U)ujsA!cA$^mb=G}aG^kgT<9^+GRrJH@jp?6z^SN!UwIl>GA?yeINgfr*uKr3q8e$y7}F&{YZT2 zh1FR<>tYU5nDx>!GdXwd!wnM{Q zF@Xsci=(x2vsq{}e8ISVV} zg`ZRy0U2WvzdyI!C3!b0S&1hTGTp9Yp)z`3P?f2~+A3j*-zvDJ)+`2{b9C!_Q&v?< zd#d;W5sRTxBOv=H+c}uMC zJVXWttM*PbBWU>u3V+H`t+Fj|XGum4k@EerS9Jkn(J?$qq7FC5gp1+wp&}zGabibj zaNJ5MWw}B#lEv?3Rx%diWmXCJ3taG|Q^L(?xrm3i8bQ=I=08YLfL5zm8cb8%&=vTO zLTHXtXmhhkn5PnvhNCpM%IW$j#3Q+w@WTtAA$yIIs<;z^qIg0otJKa(5QbP<6%S=l zVM^?}bxV2N)q+@Lj)Ua;BdyHLC`}%$Ze(l(skh49#tmlYXR@!V8a#b$q;4Sv$2A5m zi58A2hW6rce5bi;{3tbnrht(q^m?V21dEUXCm%bJxdLu*hUu2B-UB=zcI7GEH<#XO z7UZjmaT=Mct={5F87QGbyQ-D($k#Kos9Di&(XzNj7OJx@V%9TOA{mtn2F5e!Ge|>d zYWJEh2djJWQ@C7~2se+%d<^-Q4o!`eD*W$ZP_cPZGy<5%oz z(h?a<7150J941?rmP8BgcTzBh%4^b6i8GEehOdSsQ-<*qNHZy~`E*_mbcsbsvrwce z2I2Bg;FfHJ5*X_Sng!B(k@h@)Wq}Dd&tRc}(-9*gv=S&ok$jA?IC#M`%Eab$QIw>i z-JIsiF*I&67(`sKxQD8piE5NDu}slKvmQGlxa6`eGLVlGp}DpD4HqGUqEbXKsv^*X zCHTeia&rO{uMnz8JjEhP6s1f7*#&I^&EN@K95!M!BMxf;GLV zDy2-xr6BP@vl1L3Mdc{PB4nx}3a22}K9q=>77-O+QlZaBEK?xQH{q$nOjf2MLWLZq zM0}8xuzgd4V2Py=Vl+c4hn`%D5ct2hg^`yCRlLbn3fZF=pHUgXrNv!S!e^jNWh+xU zs$ec_rTJwgC~QwR@W`l2nI%?!+)2A2spRKsn6dAD)>b$5n z35ptlDWnJ`S5Q_L`ZYYs-P5Q!hRZ3=&rPf1O@s_$eOMwbUC9=x#*wdrkfxBX`9Y!= zDVw5%?tEkv%D<|NxGIaTP=Ml`B{7qUp?FrWP=AgTwZ!u&iuC8W zSa4#Wgu7x*{~usdYA!0Klkf>%<6v!(H}H~icrqW6^M_MyK|8<#1$)mkK5niK!GZ_>6J# zsj>)MRa@3z+{88iP0n%CYYGP9L>47TMAB(~Ne5-HP(ITLLlKe+Hw?kTxvj&El%^>X z!qo~yI>S%E!Cz6}DQ8Azp^SiIR`9L1@|`(VSW+mP83}%2*ls zEgbzj4 z6xEdZ@W2U3@bZRuF#iaEl&t zT%4gw_!3R%KyqTdZai~R<*4p7MvBHngR;rw5Jj`r?(!r?w8U+uBr|DT9|WRXu28DW zFsX;E1m_}-rnq7_XRN?@QoM8_8#5{>UY=_dQDWb#jB1iMC8k>2KBuUR^MzB>hELLn z>ISzQkpT)plcEj#GcE^73@-ewoB7FYoRVC7!PH$P6%jsSj*S8#bS%HNYE6@Nblxp4 znF#g7AzcCaG}$GtJH)oyK~$KRVamDjpOO#-i97Ug{L89n{FFFp&)q8*!V9Nnb|q@A zYi_2dA_|%=$c_f?7K~K|$)gn~tJ)f67FF;IlUD6&lH0J4d5z@Ab&xw%P zRy+!knooaJGDSTs{sc?COdH7E7aruQB-KVyPMxMzr!|fp#<)ET9qD?fN*W@oiZ)BEO}SoKf|liCv$rtpdL*&o ztF`e45bZqX_Xv<9eg4>y{c$Ma#BTrPw8jtp$X(F|RUL5hxg#-Rn0esx^ zV*V9t>?KVebc9<8PvctB%w{kD^DeO}rXUJE`bf_Eb(YMJjTOdSb28FLxlC6_lWLPG z-B1PNhYG0~>Q4#77`^<^uQ2D&*I8!7_BDhsqM09*P#7RMRp-VEg?l-_sW8cuwsDBK z>0KfH#7sOe!bpJ=Mj@*#^+>aY`$E-6>n~g3p=v_E7A9Pkt94G9Yi_7l292>m_67S+AIGz#KB9)>QRwm*CnqQ2L3~jf8X7vLZaz|yc7m(Qs|<;1>`OmI2PBHy8F^0YE@RSu z&~ecfBYonZ&dJwg*EV-Hl4VzJ$-WCO&>lQIxqIc{-tD*{@v?DuJPviaxX8M@u~RjE z3!Zd0cWf@uu*f1FHL~E4DpR3Vi>)xB{#TghGBmr%QW#&~va}>nLHEBK8+t8gKiB5z z6z%++e@o)Z!b+#>5PzR&{0BHpH;m+BvOIt9kBTXh&Ycvq?}cWVaI*IV#79|leN65b zk*^~uSi(s!RejFD*`vGoDuZwDqy+i3#U(%3`1qR(-*PS7R>dH0Q-c$U9B&u3v zAEq8$X<$6Mc}UMBfA3!Aig#n!lin7_Wlxj9M|2U6-#T|@wXCoOZd$s~2vyx{|SOLDgv2}SMK)_W%qV3{A>})`zi<9 z*Zp@!fWu4=2tva{LzICBCo@RZ)>lge2uAyN=&75k2%JJ`$Q91bg*mub)q%#R>CCtuXOD@Hm}6u`NL&pB}R(d#J(;4`~nLtQ5H0h zStWW)ChMR>Z_YTEqc3KLC@G<;-y>sb9a0^^53}(%>8UZlDXxu+;ae5sw~)54!E11s zCO>~)|ADXytwn`Gy<5pU7JZ&w()UGs1l(O5uW*oTNKP_1dZqiYB$>SJb_Q(LC1%*d zoTdHFmoOBax1y)7KW?V|9PiwkXRl(sv;#SV!}3o{EV)m))+FmJfGa=KuWuInM0>y> zj!@GOr!9Wmq6SwtmWnI*7V2wjT~$@p%qYvfwjbvV?76g14E(cG?*f%yd`48^Yn%bZ z#(jk#M&nwd41yA0iRBN;T!+K4z_(Mmdo#TjE?4oEHVOB>xzE4OFrq%TP~qXqffZ%OJVs?^1C)!UtC^c-{E?h8RyooBamCh2?l z9_9)jTS&{t+|?9k=t$J}y4&}-Z(`oEYk4`@^eB(uT8!0JjsS|lA;gk`UZ7H%+s^l) z*ROv}9ZM%V=X?_pAF?!RyIJ^wL##24qc!r+L$ROrk~etPxAzjqHQ zWLS!H&3dfIGd-CX3l{65Nl62BpPMpWJ{C^h#KHRZKm6u<(U#*t$CLS23vW2#R*VuQ z9s(`9i}w4*rxkp@q?BGUI4~@2kP#8M>-OJAI&tWV27GhB^tg@1>{-mL$9r5`>f`m2 zN1}CI!<3fZF&rA-d0wR6-TAU05La_zt{;m67yIdQ$~KT|&^c zmy1%8kZf54<&!-lWjPVHFLpU6{iqNqo$?^;q3wsG965nT; z&%L^FiC7l3?tC$v>3XCmU7ttC(t)R`xFf=4VU3m9RqaPLmg@a8%|!Ov`}J)@yY^>u z-M$0zDH0$4X913f68vf>A(2!?1MBhF_x^i3pOSEINeXr8vQF&(^O}I^>T3(9|I{vQ zAu*3PbAQoA$g6Ff^1pY1elzs7YU3clal`u8@BgfYB{tvtFFdAuGVtFE;4&F3=j?)& zG=dom&RT2jV+&zM)MNEOtNeR={-4isR=*=>W{~*OulDbD|0#HM^pAYm z|DX3LUscjTYpJdscWMt}ic=SBJxM=2`r((a?!9oxr0v9o!u2U?3RkA`lw(O#)#4rH zBQ3`3_Prj7$rbc91Z#jONEe*#EM(I#d`sdcscYk+H$(2yUZ`c>&T;L=xQD@>ZN{gU zy%~3}u$NNFipI-DhxO1wIG`R%pl)+Bh3fUgO&l-%K=Ta+g*aRcw-seg8Ss+0R!Z8F zhy=yqgF)Bt#Td}$iQ%Hf+7$)+3>il9s{oNRl_MnXOs8X6+l82S7CkOEs})<2Yw zBr?fKj0pCMlFvH*W6T*L6|1rQremu)<{8DwUJ~jWsoHy(@UIOcHy?kpO4oWNjIgOG zP3^__JhVwyYUR5?O?~z5^H;*jUpe19^{a5?!h??Nv?^J$672u`zEHBU`n_pr^TlG>;H&7iqt9TwlNsJf1CGpXfwIzHJ~E<>f*2EGG;Bg$ z+itV>AjEx<-}LcP0Y2`ym+6g#RPB-t(fPFhtS{|2r1g~COES%zmZ7oQLayFnB4txNDx+YBUZM=C?FlO0_> z>d`7M8s8)4HFSDNp52?N#=ds&lRD2NOLu}dPbuNw%|Z0&jD(usy?5`PmKH^gk;cBD zMP0_#MCDxF)1L_eKO*^$Q&dY41&xiV-$zc<9vAuk{u-g%-lrMhZQRz}-cE<8Z)mX1WJKZi zIX`5_CVNv7OxbCjtygn6{EO_hG-2TGh?FVnE2Ks{h;BAEHtoTYo5!2Q2{(y*5)HnR z(Tk@(BUPhc^)CcaLq$aeSt6W$V7}w=*>3)sX83$E+b!ieu2KSWIuybjlg!@8|4JhH zzrg&X<@VfZPGTG6S~A!H(BOsRT*qTifu=O=lGUPv7yJ)K3uJ&cieuB#M2nHCn9H(q zYXWB}=a1ymO9_4SePafuUSGrDTX%+=7rtbZ{}ZTShvg1&zaQ(Xuw?Q2%EP%}l4V_f zNJayX%2DE_x+}xEySux^w|6lF%p}1wXhzsHH{U7j@_QaimjTP>Xe@2v`P z9$q?#J1BnSsl6e7$6tQlPB*8GjB|{ox#=sK)>&|VVOL_^BreimBZ);x*5Lzqa|nO0 zyD^v5NS>r&lO6S>|3Mye>E`sa1tN|dG!mzD>ywAKktJL+Hq%K@&>z0G$RK#U9bxX( zOJlvfvSMhT{p)AJRG%#T=sH@@Mpq=PezW3tv@v7BVJwC}xP)>4b@A3R&-WyVJzgZX z_~}Ryw4%H9Wf~3pr8(lJtM4^542#Ds31;#dvM^3xTWch_))L4p7{@OZ@KAMSv`}tM zvU7(7m||hs$|lykpnOdF=w#T14=-VnL5hxyLQZa`$Qw>lQTG^!BTtV7PA zH(ZeJ^(I3+v3z*As8B9q#)DQUre9~e)9*N*{>He+$nL62;}a;XSaq|K(DveqlaOkP zc}BR4T$%t1xBfXHDQ2`p<^0I5??QQc#ozG?t>RGh1X+SoY-LDIvaG+vv^yagt-QkZ zElMV4^2;}KB;Eg)!c~O`6W)tLJxIJ5_LpxZ@9{MvvFLgo)wfGO&3nRetXBjUHp!Vw z+o4QWdX>eYaROmM>dOJ-VC{@@92w)z(!BI)Af$&+iHGW@(%ev*_SF0PA=}`W%6T-M zw0x$KxqQN;C8k~e&Hcnp?e7K$Y5B|$B0|>xm3P{p7iZ#yO|c@;un9m z?6+bd~*rb?;y-U2vpMC%n0A+SIy#B%o2 zC@s%{C|iO#Ey`en5k(n=jB0%yLa381Aiw#cTm$y5GoCJeBjNE~@OVMK-}7Qkd2l2i z0qJwU>-X#Kf>TP4EFFQ*U~v}m`4fwbaF0Qr(ub~8cF|_8rPUvcG3w!;0^AvAHgYVn z)4doeG(6k`nbi+Wc5I zVdB2rpVXUC-1)Ss14T!#^u(O}^**+Ut>5|X_th2Zag-iMX(I=@f*^y8D>`(SX%g1qomv3)hYWER6% zX%L)-1a)9-TtPK6KVL&|g>yT^y8OaPuP!%r%-g#_hOmpV=aJVT#!tHYo=JovS3Ylr z#v+zqDcZqWA(yO9u(#21?oX`XFh;;Ka^FvdE1_CV;xU!7j8=M=+$A;)GHAuS`Nn6h z&EfhiYsi@(eEgDN(vJLA5t`Gx$9f?K=P?8%7Nk-Zjp?Vx_CapxtkF{{yr&9hK2(=4 zDic{X9=Yp39L>x3ocAtPj4R4#34LC+p7g7&1a{4R+TrjsL9R)vbLVj$A;mM}MydB> zgRo`TRyPiPO!592n_6Nt{+{6<}H_D)G}v?y0?7$X8pTi$wMRY zh8Cy)t)oirP3VRB%Jql48hb*Wr9vvNBwc;t^;<5yQk$FmN2>O0vqM8&nQ+7w>W^{b zt|}Kdh3}-^9r~HyLtYZKO{YJ4&iO5HRJu}KyjQp;Kb|#{dm}zYjXmLhxjrU5Gc&Un zQ>FM07}Y;UgbT}g)GW^fhE#w#28uX zl&hD@7DVt74n43XkkPz**X!Vub;_w&Fmm^W-gNE8pH7W4Ho^zYNutq)C^d*dfCozY zacut@7)mucEX5q8a*hFgd<(mw>oZOEP`NhlNG21oj9F=Dt40@ZY0k#%yhGkSAL^^!S?UWzI6 zpeYmaHOjVQL)Uy^LUzotWV=APkcB{326=aC(De4Kgy{MyNbVU!KLY;vk{d~F<(DoATUx$F(;q?kh0k6yO7Yg zH0JswSlGcc} zDjX@*_(Fj;!Ul7-hmUZ5u?MKZevI)iYr{Bm@)xct)oR>-G|B=n;g-%btS{MnGgyNMUBXhs`pkPZ(eKAhm&?0uld*YT)fML6TjcZMlLs;LI-ug!O zt!a~4!p|7Fd4qKWnO0_ogv-c6D;}p$JL1u|{QT1jxk}w*b%^fet^7yjNsGSYUa})~ z#ZV$~6t`t{4j)iput^tXPEL9W}l%0&~euX}4BDh=mw(r_jo z2U-sF#$AdayCiHiNCj)5q^zr_cLJ{NI9Bu)TqR(TtGw~yCjnmGoj2z-9>QeVg`tEzT@+7vs0TyPNigoV)q4Tq7U8a5P!<%7rCnp8u{H(QgC*XiQm4S%Pd0{1N}EI3C9qZOXQt9)(;+x zQ!t%lSfHc%mn3OE+R#GxPgW#C|I_62P0;Jy1@ zA?89H)NMH8Cgvh<^MIHB+9ztdr|8Wm;@dY3Sq1-S3n`|~gy~cQT9+It{w?X#5cjR2 zFkCZRQTf>vMZWOyi{XRt5bbDkM<_@7&rFQ9wd?JtYk@#)LomP3y3X7A`@V_EJPB|6 zbL$ZXi`c7uvLQ!SwFWaLD|%THV@vk-7UQ=L%*M11{1z_!C}HMtC)W{jOmX9y@Nh{` zm%8EF`2#&GqI4)m+H(?+b@EsIJlCIy=Aml805^7}+}TK*L#aQ*Hbbr+9v%`5`Hv3{n!~a*xw|D7IGmTLM=j}EE5(OGNuWQq5)!aYFA1565 z+^?~Tf34JJoj&TaU5HG+Z8pCu*Oth5Eo6cla%ZJ#vNwtgniVVNaGv&6c*Jb9LSA!n zs8i)BwMqV%RJbLSw4TH0p|-g_rWSuq{3At!A4_3#n#5Ll?u#h-MXbMmZmDxPc4T9& zaV*j1GK>zt2#r*zoPfSC-wn-TosHA0)dU6w1qF+z#4^8JzkXfQ(0qZo1{m1w48B5( zzWAe~qx0-)ciTK1(8!-&Ia%MgJ~ga#9&cabzyBtRBTv+BqT-^dZ(V(T@{oQjm9DTQ|hrR!7@BcV?Zs{HAM-g_~kqUtJ%ve}*oCUl5`u!<9T2Tu@fl>pmyX zZ2oM#bLZm4i>4l*tl%*ey zbIk-n4#;tbGe)}p3cR=EW^eR6J~-N4QF@o-`}b!bklz5XhrOMhl_=USZ>UaOE4N6HoC244@IGsd4%PDmY}E?iJrHB4rS)^~g9dof0@%Jh z$0Ztlf3DSC-rdqDLxoDLD2r$Tf3EhEmz1^ zyUk+@NHuYz>&mckhtEFLi5qUKi76>S%CZHAMMFINVTZ|SlgC?N*j166XMcC0-nQ;^ z9uG_G4psPCVZI;FZ+f9HW&TV(Nyk`qohb8^>e7SQmwV&4uobzzy&XRK9sX8U&SChz zfJ^;_{W=%6=h{-3IwAR#=lf%M0@n3Cwm-iFYCLTkZ~`o@4Jb3bLKE|Ls@C{M!0F$2 z*V?K}N=h0V-QGr1Lo_&RX^mm;^-f5@+3|u?*U15hB3+Pppcq{39Kwc+HZJ0UDXXhxz)QT?i*8E@Pl%1;6EgRJBARRgH1WNK_Kwh z{K#+7ODd0b{CoFk?yVD+NA`auP}u|1=KB9xgL-E_R;1wQ=m_5ov5gIy!NI|&wXIe6 z8XmCjOa1-P({;N44Ev3ek3DQ{*C3{afPI6%5HffLey##@a&vKc{~F-9b?cUh<7ZLp z;T(^xnU0^mAk{^fXQ-Aw7|N)#87ngVyLj>GooCmsUWKXa*MT^A3;};&JB>eDh-TkoCWTQ9s;8ZVNzGYhHafOZ=jDTw&A8Z{i1f0S3La3+nnx2BxLb>V^k%R$>*SEAgH-CQ#dHSr=2jT;Cvs+KDh#h`*g-llox1+)Ze)rODvI^{* zoFI-0hD66}+`0#0;bA=OoCEg+X4!}HfWVG>M{o_;ObLk;tf&PEYJe@B3WAWDdMvUA z+!rJWfK`SqkIca=;BFQ3n}FFI2+Z{KCgFm66E1fFumIlG4Bxs;z>z8GG~XT@8=EO; z?Fc>$=?0s02h?lagB((3APxFOzU z|KDE?9bd9th)Lq_upCH+bcwBkj}Ny?S|FB1&AUS(B}3fC-}D9T0VL7o0Tout6!zOb zyYEGSbn%p4;pH`LdGyt`JlA6>PNdmxk{FRC?BH{DLRx(Ti5BgTmbmG5(JywH2954GYk2%R{L zEG)&IJM&na35jj$nW@GfsZ2HfJ9kq4-UJ7S#CY9yyu?dlTXY!0Fa4Ua&zQnRW9PTj zx3h$ZdY;3o0hP7}Lbmcg`;MNT!uA!zI_z2kc!X_;JpC3lSSfom071Hg`XLuVu0043 zU%by0T!Bby{}N2H$|+($wF&>AlkoZhIZx?)Puct!(>%DquW#@AVrg8VNG~rhx71>H zpv3lpBz^YoJ~xw5P*4CNHU7r7s0%crA*PMM2LNEhjb-07hg-`Qabgg2DS3ZY;%n%6 zcJ&;uaTN}x`;dNnwKK}n_0ldAvQ=j_)K{b86)dV?i zuEiO|!=GLf3<-xD(@wvCe0BF>()4AIvqmFJ9zWh&tpk_976WZn7x$SV6_9YwVd3Py zle`N#h!No^CS~5FTR}qeAXyR<6QiN8ZU<4cyE1}pcYzXUIm^Mg2%tyAVMfSqg7Xhg z{dDEBAAk#HY`g+`@Lq#61H8Xy!U|xO3xEjNj12SPgV-?+a4^t^;Nvg$wd(8ZefC!Q zAt7XC(ORh8zJ0s#R2A%WzwRR_)bLyuBhxfXzqg_@PsH((MR>N&r&7ykC{N^s-LM{k2FQ!38yzRhK2Wd+4_97_lBaGzl&(ZGUx=ZmqH2d?chT5w3`*<`uODBq+(#*ap^-tAfBZ8uh~oGMe0)PV zV_w)!^A8D;8ZMQuuFX~E0FAK0-vN8{L2`F$|4A@$pd0C-4}(uwm22^*=>F(zgEbt5 z!^5)yFyfM=kDG_b0mPCMv}gc65uIn()z#IMxp;|>%Z|xY2Rs4FjB=F1bhx_c*U*Mx zar=YKPX-$Rj=(;RfP?}45FajO%&$qwY0SSn1_S` znwPN704P$h)c|lriFiS?9DQ8L)hBp}D0x{_o$HD^Vs)bO1K?#SxqA2R9f7!*a7knv zTg;)H*{W*3X5cYH1V)Fo)bf zTs;>efh82!3%Kdym67~~u7Ci_iao>tDxYP5Qfj}704GExw-W3vzmK2Lq#{L8+;Bn?`dlbK&FA(VSoDf z2(Y&%P&2Tp9e!-u2dZngTp||*ZM6a?(o^f+}0?K&-?C; zDS>uwV(oEnl~ZY&Ytsj(BZ$rqzD4}tqXm6mk~VAvz%C^fu)jVDg%$pwvN%Ed1pK6> zm9!)Z_@Z!~y;;B-o>(Z=hL)%8r7`EtR=h29U~<@%ZgE~(Wk{YqZ#S1Q=7E~xQcB2M ziG$W4=$~w*PQq9RDhwu&n9GH9i7{mdw z>Z%S=M~wmUxP1B}g6B@HFJ$J2J++@de+Hx!02ouZ=BAy8(yYoYt^~2~82|(&03CsL z?{m042XacXYH5~;Q(k^P?8|=E1`XKiM_g8LQ_jxLa6=F?Yle;387dDBAjGNQT4t|< zK`7v$jKU&oq@2FKKER46SMEWyVzJOQ*}Q?vW) z7o@*Nw>9m-c_gC79TEiO)@&hLm(R|9W7h1HM5wAl1PuI5FZuUNW$T+bSgd5k)m<)<@4u10LquFst%IRK>`l|Jo)6RA*9!& z22UufJMFu}Sl|n3lL4IB9CNVt!5T~oCA$bWkF}#e+rdy&)46~VB_JrsMbCdB=DPjV zL%?)U>6^X3r_Nb(7-GV~)0qj&jC~4{m=sj&vT8Rx0F2DoKRcNPf{BIp;K>C#EZpq> zO^!!g^q|R$2sS5wdj5k)aM>9QObBomt7AC@8J*}Oz{CKc*-hoavkhN3NhITcu;(6t5gY^+HFeX&PcFZf2Y_~3Ud9%K#>Pf~JyheL0Qv%>`T>zW)9Kf? z;*D*JFAt<(;f3Icgdhh8Ap%Mr6;eh|k9wl_80dKp)Ow)8u;ug}aQ6K4bZfmg_pEbE zQ?vNYyP-T)h`*hxG2~Fo7=?F%5j2sxajW*y1aYY)`2$H-VTAjg$6wC{WGJ)d`TkP* z^_;5|+%GP&>*&4He88Ds7PVpX!=uS({*zq+XZst|P~%Qd54(0i!NJ;Jo|z)tTtNXW z&ja-m+#yvPvLe(2UvN4=SU_90k56Hhwp*6sAsrp8j)kONQlag0u2=*u3PK%f_zu?l z?!S$O{HpU*Zg608^67Lejo|68^sddhHYmX`%mWEM7jzJ;A8_p@4Z0-Xi7T-Hnd1_a zwSJa_zmQ1b@I7E5U1ujd=~oS>Ds{>MDg3I!(kQUA;De#n>1UVOkj?hf+u&f{Kt{sJ z=~aF1+TTtpY8*swePlq&01Uoi0Fo0R3P<33i;MSbnx=e!(sliQ%c~fRsdJnYw@_nF zDoC{Wg`DBkcUjfD0|UMLlPrp{ciX-A{qWbm>Zpr_WrclI`~m$HjelzULS)JHJLF@a zj1Who8$6_rysLHMxfMA}vmj7l&gkSf>=L^e#R1son!qZyd6(_fdBh=gL_{-X8D#!n;O7H8PJmJOea`< z%_2f^^2p`$Cz(WTAj(Gprz-&r-pfhvIMP2(%baa0)`1L}k`%FPD?4dGyutB)lO#?k0X0)B*CZa+Ic2I4pZHC5%3t?ie; zyCdb_Bl1?pl(c?Z>FZA=`0o`%K+U<1NTzUTlo3nk0Zg3t#;S~Dci;E-Vn0xm? zxL9=sZZ!kK7N{Gc_2RatI;!RLiUuB$4E-cgWQg+N6E_q7$ z;=DYUWLnkpyYCf`KSSSptXOH`Q4iTle!$IKKS;{vm{V*6V5X64LNT*F(YV3p!%OH*lKwgWV#KhSBzYFLm_ z=tUoWIXezGbAob|dOl5=^>nXX3X)d!ur|Vt-)+ z%=hS5cXv0FT=+-a*ph3|rrvUpzLPMVd&3h_J;*2kOsEQ#ZfuGULlp!NdhjLW9LOA> zF(1G>SX=-qTJQ|Aoxsbtl86B|a72p>>02-^0$pr{$^$x!&#OQjAXn`x-qS{|w?UT0 z>RnJvUSV|Z-W7$*3J%7l?ScOJ*0X?<4XoM)bOI<|lheX!pVaA3(C{wByj?{=xSqf+ z(B9iGSFl1B+|u68Lco_-L4biNDxGVtue}1=ot)L1vAMYkfb{faCxDlevwvWq?(6GF zaNjeqnG|SA*mfgU{sO5Kd{K%)@Byj9<8i{7k;2G6D8s=0JwPRZ2{|LE8z6avpSye$ zCKFsx9~SZ5Sw6mW<-o_g#br@<*WceC=&W+cCqD#YmNt|D1`5tY6FI5-@23&}DVX~J zUxnhPZ9n(Sv@3?U(+ezdAXkx5o;KAuWhO|V6pH~FC#LJ~H(sdQBt2O8js^5EAaA1) zsB;Mr#04R-&za`yw&tb#T2?L)z6{(cu)Sv!fB6GBuDGK_w}x@uZxT z8ndt@c{qOlxN1&a#U^hhX@$)0#9%L!nbl!(kk_z1W|*)|@PNlA>(d}7dH}yh@T^9> z$*DjEbE5V%%m()U8qJ@5X}zM?=vAG|eSFawClHoTyWE|f^8MY%7e8RN_CX zWvjHNW=W@`o?4Tvp;6shJi~P0q(ZD17Ux%qV-m3GMIa*`5tvg{Qn`vwx%q-W#e-Z^ zf>o?QdHKWFf<_S+%dtd7wz!&ivL6OcnXV!~swj+g2|X(^7I_#qXp^aW$;uADYtm)e zBiwJ!XzxK5lfJmY#cOM9>)K{4DYm`i&&sNG+s;iLVsb6q#6J=#T8Hkx)55_-(>7hc zwLXlItIKW7_36}Ed@89_ls_<8{;%Z%<1)S^6(h<87HK*yQqWZXYA&>Na_U0QFXP=)CIM^gE z7KzGn|HbT=O(nh7U;p@IQAk92V7C5r>gd5abVpqMFB{cSXD!vSpoR{ie!K^M_dLiy zcGM5PfATE0^R>sX=kYQddd=hg+|qxp-5}bUEy^cqqGqV@d z-+{`WMztR8ZSCO5TjlEMRQ5tjCmhG00}shYp6&)6SZo-n6fKx=FppK?{w}&^N7h{y zMQZDYISh!6FP9W5@mQzZ7Vmp8OjRYwb8z-#HG6|jX9K6U;f{N!^O?w~zoOsEu_Hth zX{&hf)hh18e5QkuV)ZY)IsV6IjjR114yQ8bO@-SJ9Ng7;uqw^NKmoOrckL(nf}|hN z&uR3V?|qVa`oPu#MFCCNpSb56y8e{1DL=&wZ1uAIH|=#q%X#6cx`-u=-1#Wq|0H`b zMpuLPm?fRkPLe6r;6e>^58s8smXOH&mpIKI%&=o3J-$kDgfM=VLC|}8q(Io`(`8 zWeP%ct_jA5)yq|Kvoot_3VZ{oJzH-@lJIZf3iCaC#t?LdG8yy77){eQF9{PJ9ar>V zr%sJGj3D$3HWPng>7HQ9R8yQ?3^VU9Z2#A~&TwM-Axa1%T2!eM^2Wb7^&5bc0#YRW z`m~s=7#?Xd+!{K?Sb!uk(L7u%)P9mp^WSV(Mq^QouuOffwYMcC$;J;CZ@##zV&NM7 z@Ok5$&76JXTj9&)Tg{85bC}y2^;e&-bv366o=jih2vrtbg%ocQFIJ|K!hT>;{Jz>D z!1_4uKyI^dJiEA5bYrvX9y9&or z3EL%-ewzu=V`=lQ9Cmv4M&XI|H1|7wR3Av_iKwTs}3WMjvP|OUP?DTYX zg{%fsuNk)*LI1S0v@{ath_ULl2?*6N@CUNnG)sbnww9I*fykP;JS&k*{2P!Rxpc~M zfY^W#4&aVt!Dpj}5fzG-L5s$-lwRTHZUwOd#!&(C@d5S%&T`jWdaw{DJgcpCap3@<=Q0eq3#yLCk%=K~<##v)2kv`+vd%{4n1qLFE7Y1m?i zf6*v0J9`#v1|1SJ(DV#opSgc?`Zrc`T-i199=^My%4G_`13(c7d(8LU-S@9T>k(`Q zUojVOb|Ul%09NDUL&r<5w>&S*MsZ}SfhJyqE$o!aGMwBf!eb z>jVW5+Ff4UY0$_V7P!_ABM8)+S=JeN_Y>-2BG1Q2ng||@AdRg5S|RJN?z@>pzb z=+ptZmNH5n#1NfJU-lw@W%B)y-j-}Ai3`*!?}h0)zxDMGDjkpaBW)xVz}BRTvrok^|4ko_~jJ00tx~I(i;GHc+J3c0GkE^g6;{ z&XhgYoY~dkCOZdVPf^=(p)NsW6Oy3rFvGuQdS-55boKsIFNL{QgSeaNh6V ze+iDfgH&*^BJy}vk~Q-i-Xv=^xN4%(jeFt@&)hnRdwqi2tOa3<0aMn?&LQJA;~;6AWg(Z&{afF&+{g zy!V$EJ6yO+%`bwN!P17~K(Bot^_A(qLgQRr=sB7m18@)sZYoD5jY_ih`EyN8O(=|s zA1v;FQE>_EGeC_kR8$+^htEYuM&dGmL9yjzMf{#Gca$|cGO`eK+NDeDSk|x`Mae4q z^+ShU(mMqu#hsfsS$KFFPqxt;u>jvu*HqH6V*khy``l479egZsAsQMQY%fWUSimSl zD05hfR2t1 zWd5@n6XURzp+!pki|0>%X`bbVl#6sL+Vsw|)E$aTPeB6K;_7 z^4>SzWpyK|)Gjn*7r+jlJb4lv>kvT%dg8&5o5YXQgJ*mQoF1=)MdQWuMXGn-wxc}+1+Av4 zN=3(RSYo+f!w5ylV}y5Yqnm)*ysoCDafP?^JUH2gYg68nqL&BSvgUNJGw@mf*4P#A z-(Lp%$j8SgXpjNEvEN0?GJ`>*$F=&+6>X~|BWrSz<4I1bU08*(esM%u5Xmfv6|sap z0<>njdegdGy#Fl`GkEz7Iuds;+7W_=3ln-DpIk=tni(G_=@=_3KP8k*$SM%nn5gfj z$nS8J^ZjPy>N*XG;@v$J^2wKYO9sgjd}72e{X|l9Ya;OM8#l@gaD9L3Ro!svLc;2hgBQI`>d_a?r}hWcXzjol&Y^8!W6#eX63Wq-b&~v_uSA) za>CVsk7Z`=#iwHL*Voqi`}sYpt%a><1)ot~yNf>DwyX@o90V`neSCTzc)JqpWMpLA zN>|p$!glhn5>m46P-kYn#jmF zZ2$Bs0O=U;a(LnkyiKVg%MI5aUewfl{vYj%D^oWLc?MkD9rzKHM?xZR#ytA&A5S%o zAqfiN&DEm>0!%#lAS#QfBoS;8hq2g{qjnjwWDf4usjx1MKNT_f>=32O!jB(678jdH zSv@W*0gubd>sv!ULIg^Kav3!KlG^f>AiWQ@&7Lg#pOb?B~zS?Ce51Om#QRi&qyH zVLkhfT=~-Z0P9hY@*bBpOqO6YCACacq+`F2adlhNJ5FAs3U z7R=-d=>i|0LA}JrCP>|kHGS#Qr6P;6Z=XM37;k5+e}CoM$RRsByL0ExX&Bi*YcW#m zNgOo0m7X3uct``n7MoF}z9}!q=)F;iiHT$f23)J<&^aACq_U}C>yE*>?|}Ekt*Z)< z@mQmsun+L|5YYbsrak99!QPj=m^X8 zETKE8dLmOH=_ViZInX&tBSnKPG~wkPj?HIOs+q;*<%gXsvA>H<3ynRjOq`D-UQfPN z{x%+uqVqY~<|ouooMy|it7)QJKaG#yOiOcnU}GWzVWw6yeh1TiE_u#DCfjykx~z2+s4o9yKBKw?!%W*Di1O3)};=@jc?nhmHis|Bq%s|>YIy8^VW2IHdfZR=u4ol z#)iKH<`VHG9aJ^;*NfZYah+GlnNO=)s|nuNz6?~lu(0s;m|Qyj`Et_L2gX-z`NqxF zpA{OLm?$bLI$4>sP>Q)wXc}t;{9NE`@SqPT{}^pXx8l0KvaqFShRc30ud06!5AUzZ z;GbgEZ#rMTtg;lP3f`<3wI1)pNeSzGx{oK-gaa{eZFooY*Mv z;7h;fYM?#(>Fj*WDY=*r)oHmW0_6x_yI#r@JQuXzt0B0Ng;;Vr|%$5>jSH_OY<{|okmH98kewQ24q z*C>`E0h~c1XplLBb=Q-$e=0 zaYK;0D8xwLTrz~hbSK?;3yT5dMbjJ~D4Q=@q%EV+6q zl7uc0DdXNZkF$=8YGR*Qz2uHV1|uLK;0uZ#%>xQSX+FNqc12HeWVVQlmm&Gs)p^l) zawx4qhx7T`{y>qOXCVuYE4%)~y|!oHKKC$FX8$oxSDWL(Rj8 zA9q2s%f!PI=N^1lv$)?Dr6GzKmai!Z3Fnctan%md>GAblsR6tc+{YWUgtl==5h7AV zp2?%Jnil{;L!OD`LusL3uZXC+un-X&``B-hpZ9|;WG(Co^b1DVq^1Fe zx1GYPF356?tE)1cMoEC8WTN}--Q;8;YE^6NcgT%sf#EH+$kW>?WcJgzT)6Y&$3XN` zC|Ls6R)obaqTIZ8?HahfTjs@GFJD5z;eoyT>aJ4Uxj_`tBKQTt}-gUlw;W3IpT*pJ+ExvHV06hOaTu*H3afw0pM` z9x@t>0JOx6+hdepkYlgN`_OF+BJJSAj_f*8*za0q`*;n-7a$J{qnoInKt_E=K*0ji zn%v`RZTP@jmb{02iWRYQ1?~H*RGE4FwR!PDdHLViLr}bWM>6epeOn?t?mnAy)(@Jc zLTHBp_ig8r-E?XR>&^L98c5bIJmalF3!UPPctJ=jlh_?Uzhk*TO4r`iwe8!PH+6I^ zEK~%sX`A%)bNr4lVFrekh%K~Z7skfMh)@J53n5sj`vuxw25xRKYBI-Ek`8#n(-4v3 z8yHgZdZ*Uc*RS&^;k5cV-%+{js#O+stqR(y{WI8=jEwss)Bvw@r^{JTP|zwVJw3fG zmh6 zXYk1CATEJI7R{(gRFG!x%qpO}(@0TE>RC^W{&d+(goK8+K6|EzyTc=;e(`iZ@z$+S z=V#`6OMOiP@6f-Y3@rmzh7Y|-s>Bm^aBx_lc!KVIpLLb&rJo+CC*xgnQCuV>Bmfdr z5;llzJpuOmdcW&gY$|8xydIZ6*J`vIQzNwp>URI~E(~@^6(aG-mDkk#0BZ%D0naS6 z-*s$Fnw<_#3zs)JG!J94!cVfDK?);CE!@GzpWmOG?+t;(9-E&Rr&fgm7v$y&7FBoh ze)3Oti8%;NHD?C&ca6RLXJ{3c8@KxE{IBr!H@=Ko@GKT8o)NgRqn@6gxHOcvJgltd z4Swgn<8$KT41idmtkEBSgZc*QF=&%Q+nAeDZa(DJrCKdXD8Z=x3eh-@gGFGn@j8^y zwzZ7GQwE`c;AA6tEVde5%7yi%J?sYd_}a zKYdz4r$^eo8>laOI@-`JWA6|uUcGvSZa5t%4;njE8AiZPQ3@-!m^kh^x}TcwxxRvz z!aKJitO^v{>RMWmUudyt1P1;^+(#f|X%sFh?){;fZeDCY2N)nWGExVUP-^N)h}8fH zdb~rEFJ@ikf~E;5Up+1_KmQc|0#@(Ixw+U^9m7EMJz`Iuv)^VC=CAWQX=SV>TuVy} z)bLpZ@)1$GFSjU;%I-#*H!G<)2W>doT#q+wv;n(^|izsc{{3*yrJMQU=wy75K!#q;zW zJH83LiTCn#kxMga@1oMVo7;8K^_*k1YyV54%KGlo zsYc#cA3+L1$llS|B9kd7?cF@@zVWtYK4PG~Jm{mwpX^aBKoFobb+omUQ71vTzO;UG z<=EERNU^CO6_%nN-+BTzQ?h@ZqI*3jyJLr*mdva9%G@Vf?uw6Sr$%qD{C-<#BDing z*~L$-=v^s)f0itZ7WPJ0iyo{eyJ`KnUu~#^?TZDHN5q~MmOk}cXTpr1tFpx8k(edS zPP4_!h4UTO&@pVcyB2(&q-VKC`}31fUcxJyT=nY42ceOwVvJQ`feHSUZzYZ^N%j;s zn(jM%{)#7G(HGXCPpa-#)FbjKzaNoiTbp;hsGu|0(@f1M8MW)O7ZYC%)m7WF`~#!o zQCab%`j7C$N;BuxvJRyXPVoE$9v=Wf!!*Vf)R{JdN!Lgi_1T*oqyO*4FRO_~VCyl;u+C?KSly@^pBV^=q>QA{9 z9xpd*j;CA3$lIJIz2v5km|9(1qS;Sp!amAyG)&mf`(KT{{=m4tp`4u7d3WtQA=y|i zQHhGvf}H6p?fb&-y^Sx=nEIR}!sl(j`35bMXS8AQR?gASRY#)ePWZi?q;n0us?_hh zr6;+ueDh^S$^D59>ZaVYo-R~EikB!a=}I&?WZy_u_q>$Iqw3CTsBIo|@?75698@=e z*kK`BSzZplv28CUA*e^)sl%4=cUvpn>kU%kVsy4eLAsx+d!Ey5mAam|zV^3|KrANr z^3{m(=djccEd3l>^77;x2&5L5ak`*!>Z!l>u{YgEFEfdq5b4W29J5BQc-2%g;j4U@ zu;~JMhlF@5`xj07WU@>5;!lOf9MR<~&_AioS|lgP=eT2>E2UjFgYJt$zVW&6;FRL~ z8=~WKdka*9rz{YEaSL0_#Xc7))44mOPn?q}=Y4#x$Hb(``-<_0q^G5!MX7|g1L%*TXff)A z`-fb`qONL`8J6)H@`QbiaivpE-APB~7tpi2K%i$r&Rdatbt$AytB_5;@0js}N|w&e zlQdrPrc!Za8U4{LkF1R=NgPw_vrkSYH&YRkRC_wZJGBnq3oldBwXAE5?#s-gUbt*z zeMC<0569ml4&nZKwsKb$_*}bN=D7>Q)NigCRC6+j_kFy-k)-f7^TgzIS+-Jt+j#BK zfXt1L>$g?J4tr;{D%fdl>5W$Sp*?R>|7GW-HeG}2Uv8cAlfz^m=_WpXV&dk$o>TJ6 zs75D4Y*FjIaG;YZm(IoSlLILS&zNr*{Bi&LtM|;k3}qe_tv}gX%8Jo{+yh^I{Ik$6 zE)be0!1hdJSs#}3W96G)NQn2C60fO|K6F>}d}fc!=GSl!LjK;5+E3M51kMWA{5M|0qVS6!QlP??2)zR-dhKCB?5fhUw4tT(oRMfa z_09*E`LyrQ=ouQ?nejoUGEI#!!(cVwag%-d@SJm{Rr}Yw|INy1AS!n2C))#Cis;!-@UUhUh6hB@V95H>fOZb@W^M}Qau8+p^x_f3;slVjj zJDexPo|jdCR;7vgO4(u3e{5twyBZ-ho~XqoYGxZ55tf<3ZzFrkxJYyAA{rP!P;G5D z)>?2whCe}g>s5YDb8}YXTl_l0W&!r>6J_-8Mkwe^MxSq)2T%R=q7O+&GPSEt`tHqe!MU-=TFIR8I!%T?uW`d z;p>g?kt`_|7b%YD*50nVCJ-?GT+ibyJu_Jrrd3(0a4k`&1dya8457|2`TDl>+hg^byh^(w(7P* zeCw7@#hkDHevZkFGVT|cCG@VT9lZ2Nn0?~h&I*R@gup1CjnV&?-Q4xEMtT-u^>qFG z&R4IVx3>IolHxeJhdJbKkIT#UcIBwQ&2i?%8hN^Yre1Qpin<@a+x!q=8U;R(-k_f< z45t~dNWFB1zU_eH!`2hf_^Qxc;}>3VljhuQ1xQvd{grd&d1|qLV>m2C7s_9~INBr; zIMdYQA|;(#ii&C_Pqecvnjz~LgXiALp}FsWe>eU`Utx`!2q1(YO6NPa*`oF3rDM+o zt}VLu1NH&XqQc34{m1IGVBl?3Jl>P9o17~#CyFIBn7p#!gE%*jRZ>T6_y5dsD7Nq= z6SQ(jZanvBc+RI{oHxlfo9PsbY1o{D;rSK%Z(GTxR--C{#d1Gt7_kTn=359A+?xy; zNw+pVm{~w2_Ni8xBoZkXlF!=zyH(R>+TL>S*bB9P;JodFbRuzNkgK0kIl|i+WLp+^ zJZ;Rnl=aGv)en4bkJVx~$Iy%yTzagaAC=W!5wmhDDyyM6I)6iX_+Y7dag)7JvkLQI zi}1KyRZmyc!k-iAES>z1tTGICPRt+8!-`#&+#?7iclpvo`R^uU-2;8D7A%y%v+*iy ze6;JyICr&D*$Q}THKkAmUwiYRLG=ftH%);&pfCyc4UO>XX)6Aw844W!mOYlWyl zHjQy>gKATxW?qxI&~zlLurlLb%JvbHs{UOSJ;ntG*yK(T9rm)TTm8q&UDyxl@us`y z(L)}aI2drJPb1~QY1$qyj@Ui&@|?9&9mavN3VuTF`U5d`<2wT43%KsKj42=fW5Fr8 zrj%?W)I;sR5LG_fRNB;e)Tpb${sm&k2Z(JborilALNv@X;<1jqb!t--+HC_Lt5#0B zChS%<+_B%}n`` z|NpAZVmF@t_bJ5ipaFJo%RR&+|2GE_U#-Vz6cCl=u?uG={QEO}Cktb&VEO-hx&L!j zEebqLGMii0_c>a-P@;rm;540hlxVPh{cFy&ZpkIIQR3RCRBxH*vJ`| z6{e&l_0nVkH-cx0$SUY}Ej8a8OQTUn2>~@22m$IK^J3%^{BW$Mh7tHdE*6%MlLeLq z=Ebd#fW(S+f+H&K=QrD-c2p!PD@#bqcR_&|4~%ET&PBhaFTG_f-pMMFG$@qplKF|G zQ!(VG>V9v}M!#z{Yjmrvu z07tf@R@{F=;+gzUyQ*NYj6iK=Xdc_1s~oa?UkJjcN?lvrj|t=YcM>)4y5cp#@wG{S zsY2-RYg8hDH+UOh}>IG&gy6=_InSvrkS<0Th-9 zh`&(ga)#ZAh4J0JB>qIw>1yj|^2uG!;VswRGEg)jxrQgy?JfG&_4Sx6U|FAfMSgzO z;(ovb)%G}lrUTw)C7@?Vc?e_L}apP(IuA%eSx3Pr@Hy2Tn z2We)jlsFq28mg)Wy>|~^5NJEzV>@ZICAar3AbL~*gm46)DPz6<`7ld?-YGBY>#t{4 z{a-EYQ7d(nOrcQmK(rn|DTuWgD9dx6S>ol#>M;hdoZhKfANg5n6$T;E-i+uT7t$~# zw-TRk4ULRI3yV&lv&@Le&)YU@mMi|ueeZ!+@D01rl)z2vQ~w^fmoOc~t2_hNX-m(% zd9j(Isi$w2eyCN8i&R!m-$jhPb69F2#s_geJ%c!&YruQ*y3f;-3EY*ENec;%8Y~); ztB-c?%$rncAsaCX;vIC8=GZnF8lRd{SP)<@@l5gZT3<_xfT*Y&;4!%5Yli0lQMIx< zjr>Ian4O&s;N!GpO1zmy*}&eY6E(x9ix2pU@X3f!+@Kyw9r>TxmSk%Ay(mhwWh;kf z5#RoC^r~uVQ;iJSx%xRe7d=m$JbC%@<#~zyDujlR_XcJN3V?~})7P(p)IlANK`B8gKauk=i=h_? z+yBN3wfBw^Belu+%9Ij0I;W1?%Ud zseT7iiA5s?_6rm-wWaJ~!b?vZz5Z(#X@Zm!QY-~pt~*6MEh!QGppOw~*Fw2D6fN@= zcnIkq**ze@fWM4bb_)v=GY^7zU8L>+p)wLy0J~Uy#$t7}HTJoLUIN80i5(g=w6vZ+ zKITNHC-D7RUpgvJOHp85r@V3Ai^=H1(-#ty$}TQKZ<>1anFeKYzChE&A>$qsOiUa$ z32AC()occSl*M48CMWXgq1V{Q#D$DeWNJY+@N{bfxi@Ohc!yALj5R(--7ctS z)(Ka;&cTx&%F4={YMB1#=AUgxEgSS2Qwq}cwd#-BcX@pqv0|X`CNY&+9>817?1`g# z3C) zUO|;ziX)b!lO^&O0mf=3A50U!?vN~_ zK58Y(>Y|{Nh=2ax9WZB+etzZf912pr98}zGk_gTJ^Y}xg(7#QS) zF;k#c4Gj-3*09fD!{2MXE@#kCVJI=*%imvZUE1MzNA^7b^yeYBhXDWI&H0eHoKuKH zkcfvOjQ4DISxrri?>nk=40wq@_Vap$%MyaDLzF~?=+>Zny;DL`?_H#lAPwp5H8Hvg zWc^>lMp8$LB}E=1CPV+*A4t1N#gO;VdZf<@nzuQhj7xlVTl764TAK?1GB6M%$!X`8d5T+| z`o;ZA(hZFTNy{smlc(HwPB@Xz@lgl0o)~-U=e`o4sHqTh<)<$kA@tz_A|lg&hk3Hv zt2Jzk63f!Fo(nPu3X@dgBHv8(?aCew#wL{qwD})>72BB{PS=B!3`ta`mY5|HwJ3%LK?>`Zu zpC7C}VJ1QBfd@ykU8>*Vg8)?9)p}BzMf%;p?5?7^87hH2f`V;s(t!(2TS^u)F0P_{ z)Jc4Ogl`$_#c-LOk~>%4(_ditmIso<^%=JEcJI-6k@f#OqK0%mAV52oF2l`!-s8)`?I+A zg}+d!;YFj4XK-E%@7uX@=lxCYX6EcT-}1-T1F88d|g zOpH8%>-%N&uWi3&sTooxY(TSfV&@+dh7d^gAYC0tII=E<_5K0=$xSD#UDl%1WX1Bt z<9J*fk@X1bWXL~Kx}0M*4|t3!ztaE%$7QJMfwQ!A5<47;)B^&f$$s>?|F?q?h!}i6 z?x1utGc&m^KWk{9!~z00&o3ZgVr)!D)dHxqxuvDniI&SMiSbPAzK;r@*IPFVg8 z;D=DiQmQ0F9s$*FhgJBF=L$@B{yh}VHjMsJ`aKJSrJ#X9H&`1gDypRtLtbT)z=cgU zUoU{uN(0Xbu^HG^4K1xkh-hsXQv3_oVW~rw2Gs~y;}@tmGIH`md=A&Lg=nW3ylIbe zi`(wqtU;r|pW7{Cgl`b+U#a;S z-~&GMAC7|&sS-Tb=U{7NKhC2@p^^+CA|yS#=(Rvb;05*|>}M*Q$iHb{Mk9D$lKWyB9tKih+hFY*%e@>Nc%d}YFjjYAOVNt6JM`)N) z?ZJp=g>u5)p7-EE>+Rd3lYQKA@*&0d(H%R{Ixg_4R7PgGJg_9`G*e(u&;iWy!qPzv z1YEm2RmMOuT|t0?{t%smW6Nz-tt|EJAGDUvSR1~)z!VUk=il&D_mI_&N3%+?Z7l;m z2S5!HNl22OvL_{P^v2S9DTtBNDAB%{P;1}D^kd4aj=%B1;cnN*brH-_@_e1G z5RPbG=kf=a2azKZ=gSPm;V}=x+b7lH{Z*FeWZ7L0qpHM+hSO4a5TP)irV7||)e{p# z{gWhH)M9zMPX1wR3iMDY*h?q~nA%>}8C?8*snDtLRnB|&+oZ@a0j9@(;myK#_g_yK zh=}@DuJw&FpDHFv>U|8PnNUeaWl>O4VvS)E6Vsm?oGA{;r@DMcC^Xayk0j!F6#YHp zZ{I%;IV-`AYD_b`)^G6yh-v*aS%=CYaD7kgo5+k<7FG1RyUU&LDVE<&6=ed5Gx~I^ zcFB6@Q&*Rs0q4pw`!$yP%t!jF{%*w4v8)>J7q)yEP2$!zYrfMo{m43DqvzM@HPiZc zv>qCFmxi7uR$7W`Ts)<)v!righ1}@S6hxTFymw{KH=lSw2g2)B+M)8so-eZG3?{s& zt2Tq2D(-&=FB}r0P9iaZ0#9s*xGk4zC{poaHRsA3 zn6Ycnl}+EAEq3`}m=m3DcZ7Jn)6SWL;NhmPcXBuI76e`W*z8>9vd8&h8~-3epqU+^_H~+ga=Gsd=mZa z)YR!WE>h$E!CJ=^Lk^!@305;^pvdlt@Rcn!y(UUA==Kn*y+F)FfF1z(%YRMqii%kH zQ;CeM9ym~m)e5ohH}LE!TjL!g`hP_yZPs8O z6R@Ojb1Zvn?fN<6ZL;v1_Tych&Xo>=G+8E-Y2B~w{oO7{m`QeqjJ*Hq>J2UF>A>hN z=ZoJfYD7Ezld1v-IIVa`KSY0@@LTh?*Zrg~ygZD@9Y(hk1qVb2wU7n8er@PQmHh4} z4SFeY`m@r95#S*16}N3b>3|V`at_TDH#$h`zN5;Ui{#%Khn}a2Q@9_JsPjhl7oAF| zK$mmn!ii%866!drI!n;-)-&fyXy6>qYRnzK^l&0)RXrx9!Q#7yGG~TT;1eLL&~F@I zrvnWHAH1rM&%=Ny^*_o)k&nzHY+sz%<=k?KHwwxCX6&A#-YIlN>+nz?ba{RC`$3u_ zJ@Oo?ztk0#It+B@8i27K8OyZ9Gr zTH5U;UO!~^K9Rg`Z)d}O^tU7(8-S2{o2c@u*Xo}-S7vS_up8IbKi4ta4!%?*S``%) zB+3$tvW$S*%}UHRJmNa`2hP0?5sZR*8)_1;^mtntSwc`Aa!J@AZoWZUm(t zE<+@$0)}0PplO3fKYijac(LGd4B#8td@OIH^@a22JN^v_e+noI+6fnzNz^V1ii%^W z)Y7(_G7R;0fB2nAKk&f1G?8Q_nuHL7NkEiTRBz#)MhyVnf~@}%Nt$N;{*cN*r5QzxNH)kQhI73aV1n6VN74eEW9z{3mr6a$W09%p$n${refeLlqksHuuRx zR#H+D)4e|8ANTc{zA!T>e>i~~K--R^26IwUW@m2y||V>ITF zhG5i64TS!uPoFj~_C{?1t;SAhaS63nE=|gh+2xT(=dHpqTSNp5@Y;jHaTsxP-h?O3(FzBR@9sZk|1Rv{ zJ)tOI1Ve66ANoP8g(QCo1V4P#7(oHWE_#$zXn$VbwMpf=s(PO%u3{IkL6WSj?Ed`; zTxSAv$Lj)q0ArNJygbO5u==1zi?;|%OOfqIjRiLlWSM%k%6Aucpm4m%$LmC?BEe2a zc{m?MCrV!=)y!I^rNel;)z))R{NsXdoqA*THznVt=|CU#EX^e}+{LKCTt^-) zVjd2+f?s@cGCL0sG-y+!qoXKz=ib+|Jygv|{8;tki10CzP5=gkLb>b3kvn6mwf9R; zuB!V>?!#n!KW54r@!A3J3GUwA6qfCF@~1YGZg81|*lZWfoq1`}6?Z9)Wn9OHJGYT} zX-9>LUH-yH@AW=wi@8B{0qsQ7EOi>URMUaXfYRTBherDLU45=j_XhU}Wai%UuP7FA z*2J0{_gL4M?aNAePQ}{ke1kum-l)j{J4Q<*f9MdQ$HIbzj&u5O-uLd}10#ojnDubm zt1x_n5CyLVLl$y?Z&{Wi4smmHV`|1E9uELlz~I|HTSj);RWY}O_Pgeu3VEpZ*ND<+ zRj2Ro?oLlk&;oWS$B=Fv9Q3Atrws$cHG$JB*?XF0Bh~Gu$JTs{D`|@q2Y+cbtPhl2 z`E$wpukG2tFDt*KUa{d2Ts&oJO8Ca{3Lqk>fmugfTwHhCK5EsCfE^kK1=t8;^n;;` z??F>qPYeF3hvvn=53oTnFvQN;*%^8fxZ1+8koX364sGs!(5$O*?t$f*YHMuuy`7#I zk%f6h47&M3x}mf?@-XxSYCVLvOg(1Dm^%JL&H*+e8|rJ!x(PwC8#z>=fA3FdSST>eB)daqw|PvxmZI+p$yLVqs%2~2!On_VMA^=Y_wH@2qiH}ZuZo)u z8+%nwuN-(pSEZEO*g^wk-0|bbv3^9xshTEeF0Azi&4+H&E!5qoyh9#Bcc~A!Zw#i+ z>v!$EwYLT#2x)lraF){huxAp}P4S*IpL+7>mZnMZQ&UqBM!ue&)9>qlAQ|*uF0ohS zo6gXq(Uy4Pu>P##wr$yMry&<9G1~?|%s9U357P(KQuys7EK+2Y*>}}5*fE7sFY%Qy ziAZsDVY&g-Rem#X_o?hqD&y`V#`*$RwXgh042!@}ul3tQZr7utU_LAsiURTqmk97v zCeO;w(FZU*IY2-Kc!n53X2{U2g0cy|4=lvqERC(_&dnpe+_!7|aNa5Ri!k-5_*YBS{DJUoin=52dRb+l>*dUtkPM7}yAt-w3QuER~ zjg5aXz4i93Te}GeS(UuG@F&NrLAz%a%^nsJRqfBVSP3vSAz;G##m~==+0;in9VtI3 z{hJNM@@9uhQP3t%O6Sd4XSnFwuv>_B5_TBq!-;WwE1}PL zWYS2#r@_(+i2B=y$DF5+-+O|GhMffQA+&S-7{h^R2*(J}sDYWIdwPihOqkmW-8q0X zpd5no@~P9ag@2Bt5F#Y{+qQZ8`kuqgaRBN^51l>M5k&0tW)~pQLjWce_JzhyFhir37D!onM<`2-_p2zNE6G2wAzyP)LSiD73DRZC2>?lq5LZ78?aVy4)AT0L*)O}f^7HuXNG zfHxp`#f>F3*%LCg5E^F8xV^9@s&K<{EGjOJN5(xZJiHBkHr`)!q&=VwYy)74I)FHJ zbyWjWkwH!tw6(57;ZFEIac|JW{rUX^3%e6b1xzz9CH>sUmE&uI=7$!^_Ex%X5&qBs zLm(321A94SR3JCtbj8*_uHXc(s62anTdjguvPo+!8Xb@|OSu@rgamL?3YL(V7`mI^ zVF@ttQ@M;6467kVIDKDUp6SVM1Nt$k+jl#h@jm#b?fNIX8y!-B9gvQZ%U?mWiJBfyJt_+eIT!5$z7oH7h?okY1&0#>PsU?2 z5J8w7FQKqOU59Oml4SkQAM{6}os!>vK;a)uwawGl7fN7U`WHACQ0}3Lx(mtffi%U7 zZ@aqokx0)52H3XT#0aV0-UD)S9OoZS+buvn+tk#AFehsFq@kv!CN(uRF0T6;`4%_n zV;d9u#_tU=9?@jGo0c|$Cx&~dtF49fmiA}}?aqa!qI#*8^;U=Y4KrWq6Yy)G&Ju$h z5y^s>p*nv|H0kzbGpS40fIY1J{(UhZ;BArFR@-MN#o^NHT_#I_FtiH$Y;N!YIr&fg z6xt*UT*5O=1H#Y%Aa+%z^2w zqa$4sWjz8HCSUWt6&5Fx8JP(e?UXWj&BegRwk6^7+}s}wn)*c3ae(cO!XnoN5~SHG z8b(+?M#bj)u$2%r@CM7Ect`(0{VsF94yXyrNX+HArt{9Za@XNYj{sE|85sdhmUV_! z8?j4u?P&EaO*uX}xpy!wB4EOl<{`_4S`~XwTv0&*-UYRziwH|N++hju)XH3hY}Vc( zybA1TfY6JlfKB3g5sF|83wW6aOU!9}EBI$Ox03hn7|?^RXA%b!;!UEK7)E@=igm_I zmw{ThePF;B0RdF48Ov?}lX7x(*bPz!K#4|rdzV3*+SYpRPHKVi7)}P%DoPQW)SL~N zRCyMg5AGAn%{$rH2Jne6#`MVjnIUu6-B%7!5pe@OlsWbrJT6czuN(a(<+jBgT4uY= zG+JqVteaigO?nukq{@rlU<4yd$c_74S*ObFkNO+?PX915F_Cc_d|i4>MpUG>t`0V6 z!aMHu1y^vczi7w0_lguoK@cbnidai=`3n;6z9n!(^?hs=Bb}k22U)NTCsanM!*xkV*?tWTo@forA@w zL~+f5m+OUen+q;-+%Zl10_qlt=>aT{_{7%vTY;`(gByg~?*rH1>fbdL#u#+)uv9x& z{`so(H!>zh{r()>Ki|K-AI3t>aC?`m!grzj!IrpB_qb{~yQ{3v0*9CxC?iHVUPM2? zWji-vV9yfT*x0~J$Dt0ws$qm(3Pvh}J5q)C;-9E?;)mQa;Htw7AT@$vV5dXQF*S?R z9UkjWOG`u6M4*7Gt`0vB2|<6qH<*1~7IxlrPj+~IzTj>_i4?uT4DgFCcC@jK+P&LP zpGU~UribmI0RQuoI646)np)&20s%2AX7zcEz8u{YLdV-;3u17lW;Wx;Rb)H_RdCs- z;IMvV{n%Csm@J|(j7^yP@Cw2SwQO(nP>4H^Hesg$h=60CSInqvz(m;RMn}%T3}Yr5 zRs?Aji2Y8t?QTbGdgrCSs12tJJLY3>vA{Wi>)vuU(bPg%y)P|*hp}b-w6=ssMGrRt z$!i#4DugVWcb&xPx25%fupomU^>cfYJH9cQB`&;}9ngL-wF?Fy`t94HjnD6QeT?@< z3=72nz&PuLm5Ac^7D@QPfn`Ab;IGpqooIdbWWR_e>A=0zl%dEJOC6cBvuVs@ln!-g zkx4%Nx7%dqAN{|kqeWBlTi8?|v1k{e(AKsn&Oz~;e7DYf)Ab?q$2o(itpa#2@T`dJD%P1 z)XoCNrC3cOmc2c8uA?F*CgH<}50)m`^{lov#0#&J z9)7KKF6SZt&OmqmWgDVAa>xvFErb&=#;sx`Al%;`sN9l^A+^BJf?fo4!kbxQ*@Lt> zJPZJ71NR4;eO~oW?OpH8CfncVUggaNwfVBXempI{o=uy9IC@Q1 zUOsN;f#+>)g8clSaC0mg-`@?5l&d>D2h^TDo1CAIohpwJ-F)M$&sv^y4kn0KtUYab z@U-wt`@SbZMm=L5#JEDtJBEc{Lc#-^8MqVsF^LExF;;~D%AXO17sVex7onQk??{Vr z_7iX^qP^$^2#$Ic@w=t?B%ug}z*aRt(2d5NWw)Z@t}g?89r4FC+bv8sU+gy&4102% zMdPupxXv43N2f2aIkl7i@>OTvdlwvj!;tcb^|@w=Gg2It6&1z=-4!g_iHZtp4~(Sw zLF5@u&LjOtAw(K6ckyBQ(-H^^{cn66^PLQY2Zeg5NL)X(ysHPI*i$?j%tiwCE2WmwBr0xkpoR2SG80d{!L z4dK0e_oAe6ui>N%!0IfL zI0?M=rqeIDAu${vIDUpd&&$w*t#{h^TD?}^j3oOSI!Mhp?)0Rju-zg73wTuU@1s9X zzjH@dIIt1D2AXSl&~d&Jr#KT66HrJiSQWM0i)^*rHFmy;k15M$(PEhhArW`DZ(mn` zznS4~wY-G*CAkv?&jcW=TiCNLqiQWI^QCKbUT*F!5OAoRAxbaqhn?jVz!(IkLc7Kd zghQ~(WUJIezo4+eTHPlsJcZows1PweHz&ty{zH26-oD*|+7Ei=%Z^_;Zk*HC2b>dq z8nM$;^q|o|dDlO)>f*RW$`)QoxZU$#Q`{ga@u+x4zHslZ$Se#X-GTW-yLOfKxL_PZ z14>|wvNuvcFZyfmsG@JgR;v%_P3h_BGxndPx+NR@7Z?fMBdbu^cCE?bsFVoYyy@JkKlA}w<&Oy~w zHjr&2I^;0Daz2O`L&zOZor1)Y{TQSw@ZMDXMjcCmznjz17Kjl_44_u9j3(c_ z8B+hDF)*;&wLhK|`$DboF$Ig`-U3|}>LB=8iE|B5mq6C}0H1{V5jn9cJhI|{wE&8+ z%<-j-_B(Cb_4jx#!=HVMijR?V@l8w`4^ZNu+gn^(;vd#9yv31SpZziP%*Xw|GIJRM z-0<_l`q@2%JdH#e#}pA(3I}kg=qR(E{b83rtr1Dpa(irlUhfG}446U9hlyFQ5y83s z9(UJg2!U76wA6aX7(4RfeU!eaNHcrOxpTO;pLec)rLvhS;N#FxEn+TO2=qgeW|ve_ zUZXbyI#%N9u&SFLYt>$Q=o&c698O_$Oh8RgazvHv!#NP2QLmtV2k3w8qfT)@hD=wW zqr%34O>`26AW^JBPY>|F8;FCuS;>WnrE^C?&0R(s0;jiMTJ4a zpg=I}_Nm_9JYj5Uz(MfM0xL0j?5QgffAc1RW>PFbp!e+ga|C^pe)-jLt;85niMp*K zoMzwxfUu+=y0C|j?^;YEP6`LXkB3za2e#@rcd=xXU)eeKI_$BU<91Ds>xhPS0Hy$J zx!%}+`0xgJ0zg$&%PM69Y#^|Z@X`JL9cbL}1~_Zu55N$&4rljhc+N2a&ekyxdrod0 zJ1(F&3GY}`4E;wkp+7pv1PX|7?)3Hbq047$meY33Dl9$git@ZW{GY27auN9O&>5uO zb(x^t!V@F0u<*1ubVGACtWNFAiK$)9RoB` zb|Y&ACG3NLZLB#Is}AQ$MAp~WX9=~}JOBv+Yc@P$_Ow3{r(w#)#@CvPM%@aG`PY!p zEf)8;-Q8t?E{G||AQvQ@pq=rC6Aqi9$S9kNQr?i%5O7E@zZW77BbG549B|P5F6H*^ z+bH+&VNjPMx?nS-hJcCJ7my56bmlj*D*~cJ80b}kQWOKPTd-^;5@C+EOw568+~$!7 zPOlQZ63Iet5dsV$DFDSVb+%K>#Z$DPgtF9#=^@Sk21s zt(B?_ox?X-)U{w!02|{?DhmpnTt&5g(74Vp&J0wkJo$O ztoSWjyuGHF!hjI~&oMv;#lIyQ96-9bcSRW)8T6y@v0>QF>SPbOFDgeAnu0iggNex# zQN(Y&eXC>T5Ncj9a*Y@v1#+UUzTN_+S6swf7b${(M>}#__{E6_%HloNoMih)A!qDC ze*~L2%6uI?Jy@xEF0Uj2?#1o{I0TdN5DHr$8$_#cG*)FtwGIRW0L3r|Jv}-35#Ac< z3C`vK4L6Tg4}&-Wxu5APSbQZv50G=q!LHB|iHo#j&y9DPMOkdm34L7{syIHKCRF7S zd8-T9$CfQy5ItZW#&E(D7!2I!z2BR5w&Wyxp7NOJozR~(9q*SlPxI~2uzDPDkg4Pr z&dothHR$!D{(@T5tI#T);3Q6B!hd``p&Y^lmN$2H?XF>15k!&RM3WqH#a7d(6s%+Lc^=E!EkA>P|;3| zVgNH7JQa49lt^+gsh4}+omuqMz1kYbu`HuHxQs)H@HP=@*JmrcQNu{=1q~A1w1AVb z1eR$ZZf*XgGW`ltR1Hnd4Jw_@f#DbyVOs_>5H8(Q zy7gBX9!9ajJy9=-8rjlv5NHh!y9p^WK?w&s2Klo6zBzUOF6noL7KH~nx=@=Ds9sbS z%61GJK=CAWo4logmz`mhl*!;8t62%A5lt3`ae zvYk2=zCx$#(Co|%aij}I$hh55^DOxwdH8)mEK?pG^8!kXE3jq@tiOMUM%Dijk2K$ujHBSqTmxK6-k3 z>gwu5wy-GsfNcvX;oeK~#8Diy1F+>j$~Wvw6=7R%d0zSG4o7RCQa~{j6coT+)Z^Mv z2fx|xQ~w7e@lS&k0rb5*af|H(sxQdfk;fWuR|T3Sw` z`JJBmh3pSO<(1`$qu$q4Jb=hyxEf$YjEcfJRp)WIlF$xI>Y3&*;+EkR*9ug4I5-04 zKPVOzw#FS;{?w{eDE>uQU<3Fhp85xL&4@In7h|tCX#vRpJHZ$5{b_W9?qz{#&jb(K zFT#qtTZ-=rtmee$`*B1i7=H2MQu7|{)96R@`6l~UnUcX{T{-f{Iwm{P_jPlrv`X~n zZe6x;ysUZ9!<$E$sib*GslS?H>Kg_=i~*OQni@j9K%`XYXPe4fx|HOAA$S8#7gcEI zlbonBgzgY+#&y*TsQQ87^0A&UIv{9Jv}x_=R*7-7bViD;H&~-7n-r?-b+%3?*A$or z*X3+~MOAiP&OpXVEK~Hu^cOvEDNF zwmDog?r&`PcwCsB2NuT*I8mwGBn`tyE@*K z%_SiKj-Z>0U5vx_116zIXI|@}SVp zJ%>XzoY-ZAw%^Kk+n=ZBts!iDRbs3CG+);q*Z)J;cgJJhzwKZ4Wh6U^vNN+c86i8a zBng>CMuu?7m}8@$KBZvT$e*@#@#_QA+8ZxS4&UFhgY(Tz)3`UhP0qXS z4}Z4LY_v(<$YN)od&yCxe($>D2`vd`GnbzWh$@J6Q!3>uqHGE}IE3b({jhC|r9b51 z(ITIwV7HiqROZJS?GJHp8lK;JOZPmNwt;uzyk@yaiOM&LRS8Qb47JhL4u?CVk8y=J zMYd%$qU%3;uulJFX5ZdQc~7(xM0O?S1eVb4{sOWRIFWE*C_5m`*r7G1;Q4l+GPm;= z)nE>#`qL>q2fRb~H0@7+8}h9o=v05+$vyTuvsX9NJQp`84C|@8%S;n(Rpl((clNqc zf5&pz^3?WnwfB5qCY&}uldcVxvp-&$uE#X^<@T?vXLpKrR`9g`CCF|Fe0Xmjg2l(! zw7ru?h2djC$3P$to_G>ud#EdeZ3ti>s3BH`l2hN z>^NYOH^=)e(s<2{wu0SQhw1Voi7zRqLh04MRQ|dC$?C_E$>LwzK5s9GE%PnhBGEsU zzt(IbJGXItoWa85Qs(;rL@-tbGrcjB4eFF|J5SYbG2GeZ&>eWqr#W$yve0<%Bj5%24gDOG3B4>q}csYoyW zCXu&0!ZcKhs`<+g<15j6A%gF|H2+x{M+xmxHla{s`tpzev{KK3E$idfwr#jxIE88p zFAopTmMur_tm$Gbt@at=KhsC{g!EgmMtA09kS>vV^^6h)Yo+O}d5juwgcynHv(xS4 zvN5Du55j;U?N7;s?~KXU-kdBJynC1W>Lp>dAlex#lYD{*&&K;>W{Ye zGRxWg!jI=aT>14P>^&sEKeTT;QorB)t7`3~k=4YH#WYtxzDxFHV$%v9f0tQ2ce_dC zn&hj$DtGCOndT1lrW_mY`S^o&ljz+jBaxcwBdk$ht&WW_-u}=$OL;%-v7;`;Gg{^D z6YuKcK9l(T;Z1<@Lg`gi|V<*_x{Ewb?-!tO;R+Yt!n4 z<|C*BsQGpJ|LPH1D8K!ATc|TJ|M^Da7tBlSHr-mFj1gl<{BM@0jjlbfQ~5MRDYTe; zq4|~QWaCp#lwz{TlaCry8Z*+3sG*h#;cDRNIc;)_DLPuz>lkyPeNCi#o6SyP_DyH` zl_~qwsC+s&O{1^$FzG5zEc$F>X%+To( zGM`i!*}D31cHh?L#U+XoDKV^7b~Ft8uU+KV5&Sb0Z@j-$A~jXC4Lnq_wXVTk z%6ZJja_jvKRzE|arbx{8PI>?A@(?sX4i8`VI~T#SoKP~*Tb!V}Pqiw1mQYwi6N0-1 z5SCZq^x^-{e)%$3F};fBi%|6_0HliLaN1%qPa86T&Jb*&h(1BHrG@ zn&2HLaFK3fg`29NV8%065`Y`R_5--OcYPc<5T?bB(@Cpss9UqXr*w6riMgS0CPd)o z5c_i*1b=w;9&D0I9XX%tLcOH0)sQXPCc5_b&swf?OOC*K2%2Jfn^^0u8hto7CHJ=d zy&MnK{8IyUPkHV$tET06*lnRmodZ&G0E$NNk&`#w86pI@)#SdP(mWc*ykEsLL_pN< z_)3W8{y~>x9yNn~SGEs__>~0?9C*ez`R>n)4_<8-nlyje4m9r!N*l}7-n3ZMozGOw zvc2X{RE0NFe(A>iGcO4_RNMuJd1ONt7gVcJ`>eU6Cc|i8CD|iy(f05D}k|M>rJtZ zz87T|(?_}$UcAo#D6?t6(>!e4*J9RD)9+-oda7S;$$y#aM^cM>5eWF+Ui`T z3=RZv@&_$6%wQSr&t#bcYYp#F=)io#@|v0qab2nD_H}LiS?kEdAzf77ptC}e3ZwaS zbp8OxQ2QVZ#*vv%T?J>DJ#LVoBY#UY7HE#X6 zM@)BBq7~)re>^?I#COLplx9Th-Fe>wE#VLB8uT7!@mL&kv-I<5t(|kZ%03WQmBu_e zF*r2Tb>!@a^s^u8W}n1lM%k85Fx_*}6f-$^QZ&>%)xD*DkKN@l-KX!XsD3N0c?upNCf&D`_D-LG8l)N+|yALH8cyvXE6jQEuz+{}FWY2mDjFcxbb*1_I*yG<;(c zaCUh%F(4nSxGwC_$8zVL!ci}JxpyCbS`o#_vz;-{Ks9Dt69htOZ*Q2+xNuTT511NbKPy19m8Z>l*?>4y|7DC=lye* z>Fl7StmEApa1d~*}jf-LtNFOfk<}Oa4-oi87?ab#^Z|5+VqI z)pQ}G>(yn@&S}zKKp0});Sdy_h-ESP<+G}%DNIdD0~WY%mBt|qSc6?wxDnTtDj=!jZ^{E zZ8Ugob7E)AA;@aP;6rOmK$m+V)r&=kjzKSUGjuR05`-paxESbW;E#}Sj|0&fFmZNt z)W&c`oC#!yR{;gUX?7#Uxb}7*goM#X0$u@T=mkO`_!}zX0AGN%)o++yJ*CWtS)pIV z&N&jI=a5O?h5Yj+xC^uk<}d!59_>YpL#X+|EO~f(7GN?rl+6qR18?3+3N5^YR3Efy9DYX9+!AYtj_6QLq&+HE@N_H63;qADER`01T=jDcZblR z$0)!`TiRT}-pJCMV6TCG5nvm-(2uM^W#c2FfS1R{{Q%Ms^bJtQ(2=}Mi2i{T_iW)S zp%DcDf_PQz+F9&9;;n$!t=-4| zHhZWC;-oz_ zsk#N2?i<(*d%<=9Wcv*KA!%tJpx)U-S+720Y1O<3W8+yh=P)t=b%Ljxh=I+}R>PkV z=oct>D-DFu^xz;xGapb6AsGUg=MrbdcfgUT%*DQf;6yY&HOT#R12o-;Tlnn80{M4B zrR{~!Lm!;Sw}V<#;d2DAB&KZtNIRHEvt6GMdA+uKg~9(WQ(VQi^YY=7|AzB!Eh11Z zAZmzAUwb+03~|u17vZO41rQ*s0q#MDgRQ{I;b;~A$N=yPVpKi0wEk@s;v1yu7z4S3 z0p;MZ50@)pH%yjws(BFwtDr!qc|wNgK882qDE)!@2y{k0!S_9Q5KKH2Ii2mM|1&3l z;CxK3IJN~xZ4R*CdqJXffi*moegLZoYfdQj>3_5Od4GL}P>%3vlLffjHA2A~YYj3S zRAt1%j1n>fJXz0;Pi{|da|6c$+CI?d3jlDH^EnnJkP|I*8!kd12qM$YGCWG{;UJ#_ zuiC!cql6TFO;|WT7}F*V+zo7Op2Ak1T58)csSQw>mU}9D51WP$qjBOFbTV%; zb@Yi7CmJ6=((t|l{N2^&2UsSYXB?0jh}}U{>M(Cu6d0_KKE4k%8xuW$*fC63CkQwg zyJ~gh1U3~vKpFU2|1!o$o`4$m%vd9~#gthI%tZz*Y%+Y=Qig{R?1rr8Q=pva z{0IjK*Pe$u7u?6s?A=!PuuC9erz8UIZ2WNLDh989!TElwUx+vrJP&Qa-l%*kw=bYv zhiVgM9~YaaVWG7@>zz9F7mnF#P8Z$0(8!&JjLpPxho6rG25%<`jJw|)0fW)(DCf6b zo7Y2c%~>qg>8}*o9br27)SfKXmL=1mEaK9zE z4D@z;0H`F6E);ekD!Kd?_$i)l=G-@gWrUbHI^W>Z;XDYXD0J04LSy2&>}>Tk_mq-s zQSSVqBWpMP9k^&pZ-I%{eQVg6&<{yTNgFkmZKnXwW{l$G<` z)6gi)==2Hq4kE0;n)Hqzkm14b{2@p%!L10F`-1(0Q|;?G57W{NHVRJMN9a&@VanQL z)KWM3-+hgPj2q+c?JfE8_R@()94*^Zz2dW#Wkz*N9UIt#Sv+oc#RIHtxN=?z!8XuG~s96lUg; zA&_KrxZqChD6s~06#ftlx*J6HaADo~mjVCH1yJj!7pTX@0;GInUtNVl1$GmGjM=VT zMJhf#B*RidE_3S2)$1R?cZ9G(&g}>AB-bHPgf6^rn6MJ-D)=L}thskV(W8X`Pexlq-1mXS$)<2x2)}P3@$}`*-C=&m)Yxi3{vg z?VV7IP)n6ES+RHf*cijv_chZ?KVaDqM)IY15Gpf7y(xIU;Uh|2#Bs8>hqQO~Eq^=< zhRb0I92^}lW@akjcB01)gQOH8e81cnpdJphgd~*^{>3fU{yuTkY1q=z666wsH7{9t zk(z`Rh1SajScvWTIMj+%`BM7|byf*c@z?R2Boc+i#E^c}R8@Ha3pxGs$pMMv^YaY= z(6&iSo12vAL^BAURhQ?0mO`|S>{qyV9i?p<(9$DqU- zF&<)$z10r0tEbRUin@dr>To#1eD1h~L-&pz>c^$MFpT)IBM<{>!*KIa)cX;s;JdMn&Z?{ zqYaRVSApu(pe+wKw;x2N;lx#U9K;#*-jo*Kf{JWm@SrJzcBukV#1&jjSjv&c&^lSl zFuXBZ0j_?=`MOY0(1Z`-=E3qGfmuhZH^QOBj_K@kS%=$iqe4?wCMqIQiobveXn}Hr zSNj6EtMrXVVyZIknJQ!N7OPv)i7i*?l?xGyUPYXT8mx^v|27#J{_WxFO|J#Tf-z2I z^hSt^ntq#JGRf@Wb42x!-k~Oy+iJiH=1}Snm@Lme^?p3$aLCgW4Sx$DSAo6m2cwR7 z50t5}t9s#+leM17mYa&RVLVQv--ocpFj{zg9Ja#1_KnC7B0YF$%WYvs`INnC0;i4p zm#eA>x%10RvZNo)2Y@z#KY+Sa2;xu-YD1SQURY3W0FXZs5rFju+lj+}#<&!l1+g8} zya-);q6LSE>F>|}(-eMYu^Y_drn-$xLql28e5uaR?*=O-7&6F+6VM`7SWw_M^!2GG zy@n~NZW0snCQaTW4M5QnFwN;#jiH$)Gq=b6H-TgC`AVXMV?4V*Cg|b-t1af-<9c2e zbwVJC(nCFrGTsaYkTRH(%8NnW2q zF~UK8o0UrJ&E##rP3wGa7xRnmRv&aOnN~03#XDeB^#KH>#4t1{k$(V_5gZg$i8nTG zYZ!`SLz;OH47GmTJ(Tri_tnney9mZVcmt<@z28boG!!lqGCfYEclhuX9qIE6t*_F#y&wQ`~Cx4mdXwU>FjdJ5yKBc33$ zPy(NbejT6h`0YhFl8;ED5Z6K)NOnA4+4)Ztm-R7HW!6%A9u5R#?CG%Iu2`Z-X!)+& z#M7hLeO#H~E~Zhu*lWND?2I?|o12+=eOb|#<4dJTxZngLW(|Sn9q2mK zIL(A&0GeNPy$3}d-i@^Bf1Y4v=I_`C4-U=3&qU|f^>Nr>NW6_)i+{GY>s*RcRvu05 zoafct-U6*VC@kVnD}u;q0ImrCGfVlfck`vERnk zoC{c%KPY8E1LGLnnD55G3z?HAc^#r`5mumtzlPxVB!F3%ryPv(fHwrU=kau4mO=|V zH#?j<($_p9+XZO__QTTLJPfkzfL{H^=uzMmi*x5z|6_sOd3NLFt4j?5U;98%AUJJV z-{w1yzB-j#Cis326HPNB0D`rTyas+3Vc2m5tov}vh?(ISHNtmp+uf;XLOu~N&mE+a zMAU&1L`dF1{u8f?T^l)JwBI3E2pOt3)XZQr7&-!p{B3*0uaS72!)hM?n*2z;hcN7B z37b*l(ZylNujtVkvwl18H8_3d0Jg(*n|TKK`O`aK{~%OS4BOX)=mb=PDvnL`2h z8JQuvSNuViA%@!h7q14}&#UgAnKdRD}5S1X!xsHzrmn4%-L$vOjqpTuU%KsfY|3-q)Cn#+mA2m@Qxk70!pM z)p9=1?9y7S2cHR)zM^Y~mBS;Jd)0`Tzo$p^!hXzag9Rm&q!30DZ9OU~-w?}b;9(`Z z;rsi`^^?N+s+F$z<$_cdw2vVYRvEbKX+#OwtdjJBsrW<~soV0Jdt|pJ9IHJ&DB)pL zJKuoBv=dnc!m+h)7z%shH9=vMf|Mzh@vuQrtpULeC#obUalsj%J$H_Cg2ae=1L+0Igtk0*3duPKR zP!ZjDctIby&UvD*8XNEtl~3>fG$}s^c5~SsyDPK5V7)gZp27B_&2|MQiqd|~B`!&K zK*O&i3`hTZ^REw3fJB-JVaac(uT+W*iMl-@DH8M5wD>|7Zw+6Eq9o2WkaiqMC!*>h zduXezMecyc*jU20ixmN+DojTN^6(90l73(#XaM*N4hkHkGn^H|n`=nr;jhYi9fzA> zw6`HDhPRe3Cvqd8UBr#xS~9V000{?)I__@93)<`wf4uaIb7%&$1PAIeVmnv>yrnbZ z3iQne!NDl|?S5WS%v3%Mp0$9|JPQ9wRT0A&sphKeUqo#|$_Yr1MnKv9P- z2DT#!CFpJ4mo(6^1J{qi5Yt%R+kwyE#gOe?1bAcgn@I?3NnkKHu(IeUs|#skNqD6E zgJJ%{Sr-u{TR3e*YpB5zh6#-fPcb6(;{>eTZ$$Cy{r6_lN^Q`6tKNsMTWC(4gcK;| zZ0K+?#Tk@*da%}9RfSkSxly_+uBH7#1QI!TDJ;mPt4H|{A(cZg07&NgJd(FtSUFg< ze9e%Edz?jErBQQ^4f}K{h_M5;*!N$>leGK>b#JiFN+T^_|T?^9WG%#G9o050`$2tk?NE0F#iafIxFIz90O&J{0qCD8XO9TE?JS zz$~UCJr~r{c_{TS5bdA9YH$Dh!~IH^xkd}Z3&POXYS?D&n=CYzr=302zlb>IK451I zqrtbrdl5-ZgnN;%DqZ}~107uvVFi{ZCX7meM*yo43@tvUg}2mxVz#Ym1Ud#OnvaND zi;L02Lyzqz>>`Axzz=-c7RjN;V~A)Kt<|GiuK2C#~`$-gUiK)+T@%+#)9sBeBl8h}xgzJB*j z+y-a$+3ek5YZ8P_NG2n=bA%;)arAMn`p(BFLp0%d*fK|T*P{{bK7tBdn6iTF_uifd zAcFZ!3%Ck5fFa`VgSB`DD(kO7WGo27BVglTIfxbP`_)bN1X-@+unjtg>R&wd`U*&< zWR|&F3V`78ZpljGh>SV<{DGz}n)P**l+J!&hHF|u*tb<}t9uXZ4bhl{bbjGx2N1vK zV5cDzvMpm}$I9q{zz3`z45Sz-I;3;hD{zPJB0jx#Ev40f5OzV3gY!yc!cx>lAusmf z`aks0e+^{m5zksR8tQT;%MV-Slx4Zr_$q(va^cqcb@kIKQVL*`mF)|tlF0DXiS^w( zt;kS1DBztAKY>Ul?Ti-z042Cb81*kVBP0Yxq7Wt$7M*BqtG?qc*TJg<|Akm;#GoKi z9h$8!?~jeOe}KEf$c2URH%mVtTSxTX0P7hE3x&x*)~5wG3?CiVzVQ$X+9zP_k6r)y z{lS_OUIWCqajlnDrpoWprqu{X372Yf?AS4+yAb>QjGJ6Jk>TkVdDH&d-Mc3ct>HHL zBW84Veg$x8htY4}Orqg#9dKWSJ+SUX_Y?fn=Jbvj&v_7Ujv`ptf}9!|3ojHTA&~5O z19s^F5&2>;9*>;!MBSl&&RyC!fn3A5Ju_S(W1;%-x5K1hI9(IKo>v&qKt#9{<*%GD zQgh&Gz+MHS@{zOGSp!^h#BW_zJP#i1AGF`OmfA556qjHxn^gj0TE{~MGiZKFfG6P5 z;_%717rnFX5n9#P;aXdn<;tG*<1hc-JWu1_9&yCGf4RaUKL|NA;SyozVS4RrJ(Bze zPiRAc)+#6mEN~k+mT~tRNRg4yZz`+7H(+t&`fK3*?r5{x_We_Ol>z~&{fm! zg3U<{MNLaFyTT_cs};if^yBP43a$iQd;Dwkp3L2IwpJg-FtL6wTk~YwC1nV`rw8Hck&S`C}Tf1|6F^r&;qgVqka3%XB zaM~Mp-<)yDS$rhXc(yFDx7K|0!nGTv-`><24K7I7ZqpoYcI)8(B_k=kzjmU1>+aeE z`)eNO%1aLSt=tG6nG!VqbaT&_h1K`>bg07IzA|YvRaR8cuQxj2%J8aqm*l$E-~g7# zxw~b)BI_h93mOZMMU59VPqfjZV(dG{StIoEfkvWD3!`Q$ z#E9_^p$5eihm`ds7(b)NuZph8VpRXG(yMH5kgxUi_cO2_{Zksi@@mWDK>khsJI`hm z#V5y0#+ zp=fdc*N3a#g6o>+0!F8pUnmuCRV`=m-ei&MRu^aN#fDbD)lsozfup{!c}~U!T^ey0 zzBJ#UY(MJpM^x7S<86Hy4eQTCwnu;hf)OrpM4mI}4y&svoS~soS?`G^f zFiI}14Re?$YzSg}0)%37L-7Gdp`giv)d2IB>0UjpJ$$oH%d$&Z)>IO;9UQt838H~T4#?O|=QGH1G)>P^{7Wz4DjzQILEpOU29JCuBE z$GPoZy5`C9_esJ}N}MLFIjA)q0!q(cQPr=Nk&Eaqv}k4cH6W|^B!6S+QwbeHwHI?Y zH!{T`=G8=v7@lq987o_7Ld&1C8iGJyoC64a3d1SP&CSuf@|h6f1jYY0Q>^Cr773FG zvf7VpLVag6`Q>Q{i@cu4oufCY=}+fyA9)sk zeV)E)TeVF61vlQ#b;b;$>|X1VjRpr^zmu=2+JAk6%SieV zDJLt-4Vs(lx!rEM%SEuS>njU-f6-ey!|FNTi>d-|<i2$k8}k-?K*j+dyfM`n zFv2px`ePrSb$!$tI1noWJl*b<1kFX{lb-Dh)i!isT$cfK1e3Z8B zyp!NG70oHz`{#vUmYsb4LUDZUDeDy@^1{&}Ry9ACp|89A{Erteo=NC_muXP9|G_bC zw_yo8iFP*ysVslyqixfH!y$2OuLJV>&ipQ}vJDJ)A3)wvd~7;DH$BrtbaOf;^vq$K zmD&kl3c0AggTwid@6nN!8^7(soW_N%!3WgSl)wl@nVm8l2|OMqd@v~AU+n5ORylNV zh;o$dH_x^_urGy7%gVztrdJAm4HmsSHUz}X=JmJL&I@7&m za}Amev}Xzix&}68t&|SFdf{R;>3K*~OMGB2ZR*)zGiAl`7lQ2O?xi~G`j;{Bkm&i9 z4hFXRjNfk&Is+tIyS!cC!v!>sB`&29%Dt0%7+C)`VRev)Let0fOCU zb9gIrbHT=Vjf=rdM+Uc48TEikfJPCFm~@-`jvOu&V8ggZJI`~*c9)t4X15*sz6mT+ z*Ne$Fql8u0zBRK4zSyfY(y7YRX1p|7B>rQ^$eo9{Q6EfYdjq#mKrj8b*P4R}J6-fhgu7%VVh#N!Me?rEDhsrCx>$eqe$lo0 zxcTOFs@XR$qL;j9+hbiCmzr-juf9q@_M4G4^4NDKYW9y^z|WQgKG}V^PoF^s~q69*S!_)_d8&grLUknz9kKyLD<4 z4|l5^HK`FI*}Vk34YU|2Dq?IHK*)&$U9;vDQu{Z5EiF7csYcT3;kHD{%`OP)2#8BT zTuqH=7zAcC2NZCi!(_-+0&^BXE1{Y(OBM2?^HE#>s`LjYN-nt2mza(Vg5&9!CJ6Wg( zxEX~Dj;ztZkwi?3XKpMlj^a;vA(nlMn);@FqB``>5xhPRc?nYjMCaB-P=ejK>OB1; z{*=FrQ7JPm_UzRmps^eP;txI+AXZPzW(Q(^Q>@On-R8Eu62sxrmcPeA3Bah%r3iv^ zf+z%wzS*dWzK#-Ds=%#bH5k94ZMX@wVh{}~6~s{(1$0Lse~Sm6h&@52#5L-;2S?95 zw}tg>)bCK+4MkNHH3L9Hn-$z1H<$NI=G)&J2#D8+%;?CpoLLNYhU|e^wf)UY;GO{Q zF*P@zNB=176LS=`UH$&R6XmyDq?Bx3v+UZ5DJ!5zq$r@|^o5`XsQP*>KN;^yZCq@# z6;*!m^z8y7bp?zAG=x^iQ-THuI@G=m^cQ}fRRKW=czb~F)6HgSyTndn+|@GT;SeB~ zly3C)eO(wmo7?x)EBp7XgurdtCcizxkNE9hS~oSLeC$57EFe}E6s4Z1#r)f+1ox<6mh;jHM>9Y{KLNoV|L}})rB7gk1q<^<+C&XK z-^u1C6bw*$D9I*ftRd@wtQH9sD97RQ!j1gq8!K9AH(U1Nx>J!HL!R%!1sZ9l6N>(J zf;V0xmU&a(rF(0it)3ro8GbxNO)!-vFwg->bm5#v+HP=33*?3JYqr}z>d3u3o9n^K z;h`+fTo|I<-P+hC|@aL3Z$#&KvE1 z`P9pntgo29x@q?kb^0*}tYQF|#N)c74vVu=#X+SYm7hotyOwfVV7`eby#qsjtZi*Q zq{RZJ<$20&Wq6MAcZ9sGtyR2ltv&z2^JE>2k1p`3{w`Nu z_-k}ZvoJ4x?36)Q`#TMt(BDfP>`T|``huL!T|1^4``YD+cI~s#BR40X@PJv1*J$(0 zp7>CDEzkG9yJY7z=l|vcti(|kM(&D8{oLa^Hh8^yk@2%!D}UqPgL@a1MO)=6KfF$j zFTH(sK$UZ}+shjH4Jjili@Gc8jq+8yly0VOlQX%8L~z-5%3s@aipHJAlAdiOX@;bI zaMFp?zwFgzJ~~pR>O>cQYcaR+%0Vgm@fL}w&&`{d8rvS~lsOuORfkA$)o!emK2gK; zqD<_O05Oz5?Q@8vTFViMsiOU*b(yiF=ZZI2i*hKmXB_?1;(T{N&0)^s#fhF45ng4_ zqM;LBG|P8a6>cYFl&2|k&rX$;4AQ^Ne5EyFti4HNmsz^=>#UT2Aomr<>rP%-Q?ty= z=FA7oY7N#xobFK9KKiq8G+u+3R;^KjKAop`CFEmlPqV$H(LL$QA~w&%hC`$u8V#-N z`fy$KSoUdXR;7*nJbz*8`!yulLz*vdCW|lEF_Yab5F^pWE~;|ZP_+nTUH-9TEy-O! zHTueHvg?~}y2HZ3s&xUyO{8%#2}2G0{AHJ-^$P;qyC1M)-Bf*BR{d699+-I_^^-e) zum7IFn%6zo(J(Rd`N=^KE1MI~-0nv$(%25PtrWRTRz7u=BNb=A$#s>wyJb)$ z1Q^yk?$rY)4UQD+D)h8G{2oC9cc5iM9NSmT)QpzCE<6gq9=|_z{OD<~*KgF*UO4zH zs;9BFE;k|s$lH`~`7YJVK$4!1WzaUv>)V{}Qw^Aw>S2h}xYMG@BmMv{mS+wL20~c@ z6f+@O;W0ls%5evuS7c%_@rXI>li#bKTS*$_o&^~P<1wP}H_CfGT~JR`Xy-Hbauo<~ zm1p4o;7u`ew~*ix)+)^AU>C_Gr{=8?CC*!)zfyIOxJmn zcgB#+o@7}6f?_6FzIYKJE!fvWYp%|_l(-p9wdT*5PK$oi>tFVDlpqcV&Ztzu!_sfc zp6r6dB8nyO0NnJ8awBcQGCZYL_7sX+?~@t1t+Ck3#>RuJ^o4Uar%21wxqZ(z#q4A9Q|9`U6rqwI zqsB|W>RiJ)Hm7V=+wflt3&2CTY_wC`VBYsja-CJ6hi+7vO8P&+9@t~zYUOZMt1xQ& z7+1(^U${D;8Nlb>8IktyTK>B<7Ulc{-=F&0z0Yjwb6EU$4&-|>nJRza2WS|`w~u_8 zwGEKrNV0!mIT+^P)9u(_&IeEnUWIt%-AN3=l2no1=gy|4g)2VsJX$WVt@`HQjs9mU zD!#l~JyrAg-dt#Q$@Z$HcMmYqYQpi~75--%E;phyxr%^8(kSh`=t|XL>ZX?NM!>&E zkN)q!gy`Er5fw;Hwc|Yw_8iJhdkeGotIce}o72(KSqsiSu>R3oKIc+j5DUZm*2Ew? zxz`21Wjz4STRqT5jkIa?zMCDJeNrT)phiwio0FE3l9H8GX-7E{uHIi7AFQa=PijGh zW%~E;@R6p)Wj$pZcE# z^{m7QAFh}=b=EG8jzAm;{)Ac|YCR+imnqc$%+bG-n`d@LL7bnp2ynLnxx0$7>*Vov zUa7cqg@r&%!pgH{PZFwP|4s!S>&v=#l*84iRT<`d>V}H~z==0VR9x1LHEQ#&- zkL|KOma2B*vy0+nroehqio)$<1WAcK^U}z@d&C3&*QS{YDLDa2#$qs&Y$c;&FTQXf zqj3sT=}7iX|FPcx**!%A=W_;$Ky3HJ)(toeC6`!}*>`Ea7d=@y7kc}b#{YgBhSAv+ z1;CgNK3M^_oN}AfcMR(8Cckdjw*Q~`ew!G}T%ZI4sDU8JT7s5@dx@*0K?^UL!y(ah zMgc4mLbHIkg3=P#x1Q|VLY%-L!O?>$-cK*Z$sRkDl1U-zxjiQ-X1D+2HU9IIlxduV z=$>E#|Aw)({rVf}apf1rhYJ6k#nGA8ZG@=SPO`^kk+odNtK{YyhpN2KL9T_dG`r1A zzb$F^yUP*Fh@ZXfJOk~k7U1U^6#8IE$*wamG&z!#{U`FAHyD7{R*d4K=vvh;4I+s6 zuVp`)Ay1+wk)8~upUsnCD;Z7;5iF?+Gi>sOLvi~T(lZxIx~!fM zTbsjp?5PLu+ktJ_Hq^f~KT0rIN7@Neu|!gHDVtCo)}y^l5*3uYe0sNZX{G`7!`$lq z(A23vLYjJTK-T}&wa|&=gb6mar=QLXc+)&Pqd}D@NEgkf`Lsu2rzW*ywT;xoGCQ8| z?Rq&P6V`iJhd?0VgaiX=rv}M|jnh4=xLoCMseYuj;GUm3YPug+y_BgVInwk+^j=gs zmzp`m+g>vM#)tA7m*5V6lSpN+6yuZY?~LEj{?&X$nVOo+MqNfL6ibTnB0W5K*~ZNJ z`0O}Tm;Rl@9-CA>HVJP*112FF&g3?IYO=^fHN|)~n%7Yld|&mbzfAY*npqo*@XBwG zrlR_CF>Oxj^~F%*`_D}HnyBfs1F~(+)F<2?d?CB=GsI1oQggXHWcW-9mmj0b&XCcM za#1d(l8^r6MXWzzg?9eo6@ADXBf&;XO_qElDHJo4;O)ppouYrhN6uA5NQqJR??h=v zaV#}yIFOx+H7$$tlRQ>KH z`iDw=UJ<^x-1~IyoK@f>m0A4Yq!v8avRd7q?PXmoqHk)=AzDnm7@2E*kd!kYODao` zBsb4(oDRJ3&ty|2Ky5Z}N5x0wXc3Z1G@F5jRQ=nIOUTAmW+cAqygw%?R94ESzsi(N zD=(qm)h%b>$zf2EF&9eG^X$D^R<5n^LBYhXE5>7@biSea)6vpD4q;5RBzH$PNmSAItp*2hL)4Hvz@Rsq$HRb1V z@?Iqo8Lg4Z4ke@|=BsmSDo=8M#L);W_&PDHhUHKS=OoL08EM^9KCPzfDhsQqsPLs` z%?vs0R?+UWTDkflmz_FQ!HZukPC8unVpZY^dgnYvm24hyl{phx5{c!+_JDZG|7@y? z*`-hBdxatu==JO@%@uAAx<8VtbTIBsj6PwzX&2MZZZ^uk4N;NNTTZ{XF_Gsh=kOxY zGG%;i&|jD5Z++j2+%h1&a^v@px^x3CL!p!`3SY`%Vwg{NI5h6S`-^w!k6U#445 z8!A)GzUE{rZhLcISW?G0B~4wD$&J*UWqXr7CBrt%ddadEt4TzWZ@uVosc(jG446F5 zSZWz44!`mcpJCbTP|Un4Ct%&_Wj+r|-=+Ko%nL(?qt) z?TtI{%39b=!$}|Tkjy5S%HB@LLKPp&X!_x%-W67=l&OZ=|5@t8E7#J$H@cDPGbBiD zucYK9=dDSHj?Z+QIZ-CB&E_CZy-3o##3qrG`6AaMu*_|;j}U46&(YLWDP#+?*djrS zQ=qot<=UQiH@A?DTAux@s5Qxq^eFxJ3F|F3ydvQl^z5-D%+=wE?2c^pIM1D9vMM4! zny_!0xMBZw$VvJgx0`r6+Q~cgk4vybvS)k5*$qCJV<*Lyq!0btUu^hG+UO@^OxIC1 z!SB~Tojq-Nrf){!^!slS%{C-~(d@8vlE^yVlLBJVu`^mmt;4&-J>`mZ&dZYpsVDEx z6(oIsGR2-Ua#Z}Q1l2?5urC(!OB17+kOTS|6>)Wo*u9vUr5n^OU8sTBl*q-mbxaF&vSZ zT-6#W{Y)EeND^V=mo3W_EMuom5wUPtlsR>}oVM)uH)9j;6hle&6nP2K+4JpWJ^9GA z7}H8ESCYb#Y|HH5{wAwaWnSgxUmli?TZ^iQnvgQc*YzoO^dx;gl1PLI`$Gv4v1q-d zR<%fDyz4`gY~x7LR3_u%Y>BSq0kS)-6PFZi2QTe=^B8J6UeW+Hm)WoyNBP!N(|7zL z?CW@G8T6!Ry&sbGsG5~EFZ*Yg$cTt$N%mP}(Ue+fiaE^fJIusns6;KwYch7rnwL#N zeo0@?J@y%OJ&8;3p@d-vFJm#C%Ox$^=~0U*_ER5k)H;$Jyd$zG? znG&g31ohApA}eHVsw}I>Ixld}{3pFS*W4KYAsr>0M`K(}F08S9TtdgII6*}+ zN#fJ{D5mkfnb!T*(5utzUcEbA3=IU&MynV|Oq9ln8c^oN*GC&rk8*I<+EKszqIvj0 zX*Q#oOlJ7{kJSyc&7lEVvZW~|^}3OEVXP)w*hNch#@-|*sfqel=Xr(7+l7dbB1h*o z&B|R|S-VT8-#%#gtkRDqCYpnKqwDVK0QP?gIB}7C^o>cH)G3PXCX41YBqsfh4Ax$+ zy@aS*6pW*9lpDLoW@fONL>f?w_nyg+4~PM>*x=0!_bsS5T0F9}i!C}{Q z^U7=!*7Gi&Sr)c7B3Jo-els;=V=|y2Mbj(0@JFQ?GO3FyiHkOAdJfhe(&J5{klI8K zb5Y0XXH)BmDQ-6t;mAs|ir?<@Qc^6>!@u+K(ycOctC8;R(TA}rCMAaYZ89kq^k2oe zDr;8MG=03IyR2e#<1$RyFK}IrksK3kg<~Z;m{a%*AI+~Kyu4RjGdj~D2*8a1O zhZKJ9{Y}H;LKxJ4A^UDqHhMN|(j`3D;@~gmt(Pjp=}3_?s+ZYVG);IkY^5&y&uo^= z49GDgk#fSb$m>P?D(HT2NW@!i3}BI%c%n5xmN$@6rp~xDW-Ut7Ps@9mGn&cJU>m(* znu)`u6q1Og@Fb&|2$i)c^<1!U*8`TvYEm@a8RiFD6L%gs9BYv+XmNLEciDMMj|x)> z5&g@?dXcu`uidVEH@RoXDS6gw1I;t)_=`qDuC^AjBVuw%1`I9M)O(bvACl-y%`9&w zhiSW1i&rklm~t0n3>K#d3vBvv%;Z-opWbCQu4wAdWrSq$fBYbdXDXW`P3<3XoR?vj z7tfH{9+d7=L<$ysJ#{XCi^bqZhImWyJxMCcn|0nI%$)6a4WDiNV@gsV%XF!K)+Ky6 zTdR%4BqFxQ;jFMw*gF3JNb*F~WReXh9R%tI#KC=P3}HWvFyW6#)!u|m?XdGfLqL}j_oXH@Vi zG3Xs;H1;CN#=TlzSJioIP+ymQl|j)ukLucx*WiLNy{3@0o1$DftzWEAzd22n7)e6! za-7A9Flu35n&NtC8?(Bt(&FO#8TG{$JUo24s>)ScoeNFxhEN_+@(q-eI5{P-2c_K6 zDbl0?2R_9hsj`|KlD(TH^DX=ipB6N|yqiN-COXuy)1|7jhmj;vFK76sp0i6Q^$(-9 z376(JYC8GU92~4o@B7~i<+C_dM2_rM-t&( zgsi1RY^CmZNt?s8u>s6i9;QhRWo?*}S|oGcf}L(=D;= zi4w7F)ay)Dru$X=G%MTx-(W_Ix=@`L-)GSLc8vA=`4Du*M|>82Iw~g zy8f<7VeH@C%zla-{Mbd}V`VX|A&qf^;=xPC@9!qAc5e{!j?J#hw&~tGNX|47axY_J zC4bf96T1~GPut8?BCSJ?nfBrui;XRfWp)r&FEl*B==acTV{{@j`)e(ZoKGbgY3sdc zf6#}^W^?M>QX3ek(~C*XmgtM6W^a$=x*jd>wNu|d(!E|!OkZMPFs??Cvay7XKh-s$ zjE7ZoN;)OEh9xGGNnpU3cSb7?7EgoEh3Kl^Sv<1iabAYAx~#Y;rqHrQIbL8mX+o#rnI{5@(E5+IHfMumi+Tn{#?WL zB^xOd)1)7Thk~`aOsV#^xj8$o3T7)vu$4^df`wl-6Ld(Py&l()8=c(yY6 zs_LJwoy(kZ4?f79K0F~Wt1`3cMtzwmMMbvama@U+481D8q=m$f6tgOmoHtHdt?vho zWJwWno4*614iq&k6?>gQ6G`D+_ikfK{@qQipI$iI)b}K}@$IR;oLYBXU3Dq0OZL3V zhm%&TQfboKi=htj*_nsW&BeuLx9Y#%h)DaaMkSzG8r@VqKwE4cBc{2Fu{dLMzet^WA zP=y<1BkLrE{+#gL+L>X?DzU*PHk&iOO>dK!k;BNhrwogw>-Su>P0eY~34TO*>>gIV z^OB61-|mSGnZat=)COMFnC9y}vG#pfdhOG#@z7L)Z``O+@Q6wi_Sv&+fp`=!aSqNArC9N6VUyyr_@|L_}}o801)IjJ|l zX^h+-Wd^w+RLi)i;jzY6VG>(xvOQf&j@+*c zsehZr$>v`Zg@qN2Yx{W5ikgb_Djv$;@mi}exv^*C-R88!nnOt!J-zQMak!J*=vD3b zlIlz{BSf!@ay4HusA*T;wC<3MlGdSt$n-du#Lkd@#&e!yBKnf$&%&bmrXhs1} z6{(W!MIh7(Uj;&=IN>pEN%4BE^te2wCk1q|N6YARGUl*%t>S46+|A=J!1WgFZgP9Z zOG0}ko!Xf}jw7%9Zq80d8;Cr!mb~#pEix>|7*21q)_N%x92|Y;M@JUwIwC}G zr&v4nw3BW1hu{%<5L*ogrY^XkTL<=ttt%4aQe`SKzH%Xay&!xS z&lBtf@c;vlHCH@J-+xH%@}jcmdHo)AcDUE08-c{uA5{{y?&DPSzg%c~D=Uaq!!*VE z&`(8Q!$d=>Jq?~irx|IlJ~iayIEfFw0M| z8P~Wcrs2g8%p|P4E%B8{?h8TFWvVk*)5Sxq*^=pNdMK@k6FGA#a&7V4b78A8_c2rP z6CQJ#&P7+c+AtBDnHWnWv5)X{QUs!#pYzynY!>1{Hx$;waYkLO)Rz{boaK4d-@&Fc zIh+nt4B@286Ye%|>xkc4Mh+ZUE=a}2MZ?4`KPs7bAmZFe@oMtA#-tfTTBV0Ml62ZA zKZT>2aPar)1-DP+J7f_YeXehBxT}wlW3Z6-yAotjtZpflupEU^_^MR$5Zfm#CDTUt zn^$9N9w)U?g!IFbmvQ3DB+W+MDG_>n{9i)qUYoGh_41XO2NDVi7@+Bvi90G`NSN2L zJmq~XkF>BUee_fvSRJZ*zrbHrZsKd)f6oFO*8CcmMYqQAV`gu70^pN63<_{4zm!#m z1qV@ygUvu!lfak9^+Q?`*b!mCtzDXJZ%}Q3Zu4$f>V$GPKEK)U*XkJm`5^tLuI|i!HrBY!6N9t? zN6W@S2U{fuHMGagPu}-ux~yC>yf^7Kwcvy+ND<1xf}p|&9~Q12PR`zZReZ>6m%;1T zDSr^lzj|tB#UwVj`nHe8nP&nt+R24bHK88*z+*i z?WELm{p|B5$*0#qB+C8p*DXt`@5a$7nKgVrL~pisxHd)oe_+w-|JlDH5SrRuJ2WHD zs9Wo{x$@Jtl0s8-`5N;;r20Hskk;3F;CNehQ1Eo@$*zI>Y2y!ljbw~3u2Yr|Jv{u+ zJGh4$t8`5H{dY1nV}-UtpHwq_Voj>MPG>1d8VP)#q;XMi-_}x;1 zk$sVnGj{K5UrDOy<#%ySrlBV$IL=!VTZLsl+1{5mSXpzLl#X__Yd;V6YJRaf?#thb zO&4y*X}&yvTPu3J_1ku``g6*{4{dhGXARz8BT|oPxw;r5?eRpKY&JzNm)@7uIzEcx zIH(8W{Eky1RepzN?=v{Y=5Z^dkY^fo(<;mZ*<%k-e{IYgFAtxI<1GLmvN zIP~%(DnIZaVPm>Sy9b=+%@}*S`PBxy57u67y`LS3@LSm$Wj-O;>Uljt*y1rctJ>ID zqZp2@Tk))EIe8rHGy3nK_puToISDtv6}!bAttDL0`fp)*h)yYID&Cp#*u7r&>+@*( z(^;_U-}*8w?y(1MZNTNyt89^jpDVp5M<>F67JHA&GgEyp%^cogbjp}HHu;>XW_iB! zAVU-^EX>K$=(jj*zaM()e*SZvDZZO7dSV6f^J44ZMD$QCot*Xf*eA86(xRO<+hZ_D z{(&{`@;HJ2%Sp3`I`Vn(h0)^`jrA7eZ$4U0%EpLVYLqPZG*;T4`iRz9Ef?B%KK3Qb z_P1GnYpeUCz$(LiEFQDXx&l^^q;Y32N#g~r?rObJNa%Ss?$WUE#Y*Rp-=^bhAzJHC z9azLQ9TPfb6gMV+Y(_PcRF+5WzQs_B`s|09tx)-1V-05foR5lnXgsrj;Irem_HC7U zNXV(m*5PN3Ef6_L^*<+3TxnuY{$fA5RwjD-Ya`h<=8f?C^iL=@5#V!v~zaa+Iei5hXguIo)PKa32LR_`lK&F8GPGfq>M49liAGfAlM}1~q z=8-`SxDRCZQh+{aD@OZa_T0xmUkNh2&lA4MC*ak}W_vq)lROc1`Y!hS6G==L1V%*& zX)^1{ZCY6R=CVR_Iqz7vtx0>e)`g$B-qFG%B%w4U+;E;XM=PPaDT#BO< zX7GEKKaN#Aod-HeR%nlMTn00^===Qq=gm}w_FK&iVg!A^igU}R8P7ky{O(c``^IA| z;9{W%-LI#;MCazzIN<#2t%sIb{!b|rCTq5yUSBFE7AjqBq+3ym*n0mM&~3Wz^a!~A zo*645yc*b}X`no$jq%a@w=LGoKLP&7jgnR>wA)cXZ>ADOeGco^9~z%8<+igehCI|M z_dhyP4cPlMN=`f9oe-aUvEVWU?y93}hM%WURYQo3jBYkk@a|q8sy2VIo}hw%D?IKL zbO8Em70q|>MSq&iLXGbKCtkEfP}Lo;u?TEr^Ao-_?ligUR~9a8Iu}GM{OgMurh)TN zx%_~#hb@(LyJzT3T86C~}J=6Cd65 z7Wnm3^ons9x=q^6I`uDx(Fz~si_a@ZIa;_LQ@(eV?OUB}^qp!0k3159;3fD^^>wd$>R}dXkJ;ZPJhK-pb;IKc( zjhk7w!Q-<>^cU;_;NV+#DC?F;0C%xd>t~a_0=Eq{mzk#XNXwkpWM`QH^Uzy##@XD& z;0&MhB3Zm6)u?4g$yHYU{pp>T%k_AxZ2Th^FSjRVWm%t`t&zkiK2^?M)wf-Ae$Qqg z%2j3hyEE){>LGS;s%15hj)wOKTUrvxowqm*)2hCQT6^@Y&4+?RJE(N+=%NSyHn-vM zqh#}8(Lq9Szf!%;N%z3Xqpq>cfUiX^=XX0}m8iB3W{1DFckk`!&Q0wHTyD=xWBxI* zN0>uz{mB!2y>p3;MdQ6kKd@?icCET|ajn`;6wxnoG-XEKpOHoUZJ}o*YjCeVx`MjW z$-($xPrW^M0f~_3{`aVy&U#(r6GlXa06K0UDPBSj!^)uFWzTzFyIGOvU-OG`4Z>yd z)A*lvCiOszRmQ0)ZA6>?6!~QPxqlLzcEuwwd?Noap!XAHoq6}8NIIr>NNl=r^+2&Z z_wPs*1-q=Ve&eFuu*DNteZa(yH<`v!>3EQ3-`@O8!R5=^&NN76HVtSz&kIH(*6ipM zh;K2pD;BCedT_tUPEUTM^nvf*BJQyjkH>X?fY)idps~MK=MrTXt^d@0SsIb90`*sf z#WD)Z0pNB4==b53uu^(>PKQ9h*u^ia3E$|wqdrfh!;j$(! ziG@3LoRzuls~~q@+4|QZdMpLSi=>P|CBg_If^;FDZ++~$KL=>Grj^?(D&{;-xQD_J zwS}A`1BsDrzh`b09!5vG-zB3F-uyT-stfK7syfzfmYc=!pI&uQyjsd`K?e!OP&BW5+I#W| zW80H=^A8F3!< z4q`mLCkOez2L){Y+<*6Xh#W)X9eFA9MbaG?77ei-XKq?Nnc&2uV&p0D&Oo*Ry6PI zbYv;%w|Wh7#~y7tr{od1Qo$**Tuu0uIpbInN?SZitNJIiyM#c zPTu?$_Bf&Dc>d?pdW>Nor1tqjt9YtMYcAXahjK@!Gv4`jRdcWmf|4BF0R5(Bd{+i-?bRmFQq5 zP%a|2SDeF-4T{L`!x&s3_xq}>V=d7l>8hXeAm#3JNKm^`_0VQ`O*5xtWN6c9H^?U%ug7dF2!!JO76V=E z7U9C`a-~Vqwe0pV`NrC3igoOXJQ%S)0v5{}yo|%0K;t=<@m9v@yS@@m(4wA-NlJZ38mv>6Z1GbkN5hFNnjU0yz~D7$?%g zIrY_P1U&{5zTL_;`26B1oUg(37JIaenMS}(4By<(I*S97jsCT){FxnYlU|8wYL-R} zZZ56_i^%E>)6a+bzu6lO6J9s_{;@_1&djn1O>G6tN9k`G&3+L++0L)SdbaiU>kTv-vM}ZDu42?XA7?wDz4i5yaxMXP(@_=%ubg#;8IRbcqL&jL6v`379PVh8Vaf!rtI%6kCO~)?6aQO zS8?Z5*jOrO@i#6H91q&7x!ZZTLKXw>86;Dh$<%0)r9DmIYU3D_n-BPzi@Ii1O@8GZ zF>7n!zJZ(d-;vJ;H`>e@BQcfrg!f}*sNZcBkr)0C_V*Hp95!_l3SpjyrRg1i8v1DK ztbPx^*n213vqb*VV}PCJx^J_k#kuxmh*eUv)5$!!=o0*l{VE1!>ixqMtbtjeI1diJ9B4EK08nAp0{5B#jX+S&r|u(j1x*E5igqj z5|~eCxGj7Fy7YgNKilGG`pD5fm;55CY%oaevPNHG?77|*D^gdbX-}K+(QRY_y`lEX zm~VEkEa3co%sr@L)Dg)SB07^cib(8A1D*DMdimn+7^ReaulEL6+(e%OABpv*X$a&z zUf&Ce)%$a~5zx3BME=^;FQGa9G0klA)u!m_-26>nivz8Vf$i%?O>wf(?m}D@BX5_k zpmf{IwoG+%Q?X zo-HzvU=t^3cT6?&;&Suqq^Z&8#3|rLfaj#C=9*kpp}Pcq%AHQw-W=)Y3%U6V(c@|p;^@?&yF|fbuMPR&+Y5JY44Z_0(rPzl+Vh*AdHUXdv%l&1P+U_{p zz5lDO@%-Mw#m-sJl_-M=kx8&7Ikn6F@PU^rzxXIpyE@qa`72@xx$lP-KN>?Uuh!<4 zM4LS#GUi+58ppU#e!rk0bBBYW+$dnq+q;r^h5$4f+02T8qVIp)9S> z;V)*IGDkM)w22q2o;M>siQ%R{Y9^|})U;(-WYQj+P5fcba=l=Py;=NYbX@8I&OGVgr*xBQ!&%Cj* zUz3X(1q<|?3DFcsh2PeXPmciC^#Te1+g(u1e?tP1g z7`Kc9wg$vWlxXfc$^!k1A5$O@l<0J0X*FHtsWtxqKGlk17L=a#MThR9SvkogEk%9evFk z65HAX$weteYC!Aq>Pyndp>yBRw8m$w5%$6 zG4gP8S|t0)cHli(YUdU8u1~!}^uLOImO46<$$gh9$#q1|E?orOcd~^2_O80vMXvYS znHxHsS?hi7=;2DO9bh=aa*=TqX`*H;E@jQ~k|b8D6g-SHrqkW^+Rjb^^Q%L`R>y}n z?B)7b=OqS(N2BtuZ)dvp4_9MiCKh*x;+dEeNyUC8j9mV{&YeQ-v-NwZeCmAVSmk|m zg0hNcxd5FuQage1_BSylMQdsIxw}y=SX<;Gz8k~b%)*Cb+;=@{vCcY88{C(XgQiM^0!QRg%Ptnpp4qsS0157nTh$3jbO2>PunuoL6HAd&X)BF~}Bp z-c#D#jFs(g*R_)=JMh+L0-Kpi*uq;Qne#SVd%%~ywLB)gtIJB}N&C66gpYgOXYZ*3 zF6lMHiFaghI^XEwsji2_W;7fwcb#W@9=3&85l{;TT(8U02tpZjEJ#dh@*ax%?wD1t z3hn=_u4t*V7+G4m%)=LTZoBlt!d0hGW~Ab>*k8^*Z(klN_w--x#ScY)f1F*j_GNUH zEe#jrh{gq=RW+JoNUFYC?pFS zq>As`l@-ER?4e)celB-gN7^bI-}n13mC!UTI+En8BEK=YYiKi)@g=soBWIIl`j^g$ zU6WRAN~yezT{RSxrYS6RgF`-P%g3di7}&V?g*!>@wVG?lzoj-4%#nytTMm)4!4+XA z{>t-NdLcu3V(Y-G>kbs3EYAjSStMK!kGJZDr-4iylfE{F!X1pXn#yGQzQD?tK_vM1 z<$~=P5x3~L#iWQsk!$zu-(HKE^Yf+TIUVL;)X;L?%K7ke-fqbRW;e>j!IkjD?xJSf zR@+2SiBq}hL|$9@Bk$2Y>|0!LN_tYRD99qc9K&7l87Ag|W{L-+v$J1wd!)nH6w$|8 zJ53^B)IcE#{6Jz`IaaA;r$D&m$0ZdE-NZlT^(PZFN%A|7qq@W9{iTb zHCA<%e-s%rCp2xLCu||-Au(HiVDuxkw+zP?K~2A>8094HX+LKO?vv?`2~3j-p$e;- z#SywsOo}mGS(SJ5V;&*HMR<>x2=-%+>hkoa@wwvk<&H;7i|e`uRECZa0=X@QHYRFQ zkaUh`Oo60Z1d3x|{$F*TEx@!J_;(ja5@{WJ@N9+&pJ%$=AhP=&cHJ5T@s^IN*z`jH z#JdTNbIPs`8FEL!qPMlvdwwXFKU9vZhC{Bz~=6Sh5&KAEJ zmgZYUvF9Wh6y45JxK!%-*qD99QX85nM4da<55BKPEp3Na7ggur5c^7`1kzW%>(OHs z=b@A8$hwCEr@({|JK;vr$;d4-{*j(!#$)Y6yT>#^cE&NybK0w)c##3&o_v+*@L~#q zmljScwnZZKkSa2-jPRl3lr$qfFamo6<1uZ&dQH+*A*kmh@=CcY;T zMarP7jr__)_xzL8gxb9QH=$1{}VL^T+RCwLZ ziId}osSlw~dIobE4DEG6Ml(t;q>=lTT~jC?W)ZbQ528Vf zK*f-_5XNpwC(3;|nn?i{W+q4cudzF5;_X2X@0S!mFiiOp9?i)4F);G$mLx6xIUFKE zA;tJnig%58vsfj@i=)m%-tNvGQo3O_-@l5HF(_D^4!-cZc-CEhl%o4PF;NJ;m}SiH z#e-VRI0yzS93l;4RQCAqNVKcne>eM&8eL`iD2@Fm7O5d9ots!pTn9I%H6@)wQ7PI5 z>}?JU^|hF}CU$VF{EF|B;M0*f2NT?KJBt$Hj zE^rR)4IwS$@ZdhXeKHKvkzPJyj4`m#C;~fNcMk%-xB4G^$r$(}3txew^b%c>)ky+T z@gX1IK_IfG#3rwlppZC{qK+Uk37$DZ>^BhWYQ~c%!Lo7Pu)tyQj;TpI=OhSOuA3=8 z0!JT#o^{XjwYecNF3cIhsXVRrL{ph(j6LBFYl(xH*$C@NvZSP8SQW0=;FFMa&Zsp; z(>ACy92bh9{OZ4+sk%v~Lz(>t)-5Zapv0dbe^K?x zKt~2ws@v|tT$kFN*TFJW(;d$GXz%DESc0YC$krTINfv}2PozBs0*&NbH36g*H+1kF zrwIkNydJ_u?tUbZS!v!gQX-iu%+Q{vw>sv0NL>dhrBXjEDSjn(%v zW%<$INV$rIcC+@I^q@hwu+bpsfzRm(!{Kn7H-K}NKafI4lBUw2H2Nvtat=!>f6SRI z5P6>i!pRMnP3lJWbH+V}(80fW>`H& zzF&m~Vfy%$#T*+$y7e`jp@XGO7taZslITM*Vqhz5H4{B-Q&7Ov3MKW-xW<1;4cz zE2EBlIA;eT9)t+nZ0l*9TzQfdog~6G^dm7X2dP>?S|=fcXX=wz6uuC`&2BXXDUl8q z+)%0T@1zzyIxsth+Zd&BAEg*2i0DWqo|DoQag)-SI%y@h1&gD}y!y)NWch49G^bJX z^cR=%+e|LLNNJuJ7Af&haBNr=5hM&((KHtZmEeSQh#_wOfZ*i*S$tir2p{B^3^#+t z*i4&n5XLj)X@&Rb+>VO=+DRdC*nFrVU_}%hsAZR7%L6roQMONgFwQxU@PR&_|&eQIrzl z6NM-f@8+dKU{b>rJpJ^cNN9$nWGf46{5R;2PwHV3uwj0QhYRSks@7#L5}n+TYPmf^ z4h6JO(%uJd*mT@jk)d#@&Wqls20Bnk0&7`Es&;qOJzE%sx*9|eAqznxmSXsgneQ;C zj3lB9{9@T@K}y6V##N+P%#|elKHg&DURD!lxdXCGoe;aNg90zkEj+YI4h}uu(IJ6| z5yFT~0|`SuOGT0qMG{Itq6YP8g(1$2Q2D6G_&-8m94QiT{GNEuPP%Vv=yBq<#T4Bk z_rzq;7UHEjFkVSd)=4RuuXIa1Brx-1k*v$(daxOVsuhSpr`@4MUvAF zZ>0+i7RQYfhau_Ua4|KgIxI#V0!NCWDMBEUX`GM<7P_V=b0{(Hp+}E~3kf!xw}V0A^a4&0TMyq=##_WwOd%u?K?iyP zEf8!X9P}8!NioR6!#%f9@sC`$Z8rX_)+R7Q6+_{078Yy5Rv9Q7^f>}EkcAkdb?eIO z4zktE%_)~o04nwz9qF(oNK~rH$N|^mo=6c3@ef&x%qmFgX4JL2wATgL83s$7M{omAJI0mmg@R;aJT^#yvBT}j+rF9BV#G#AQ&tN z87j@yoF;?8PMv{u_1N9Hcp_M6n$*T^a+nxgOhT`slN16W<$!m%HBUx?eQ;Fm6}D%; z@ud8jdo#d5O!%(SE!|A_y8z`zZ4gWf8K}3Bz#E9xf&6WCl7I5BbY11YPtA(L;4OBU zo$?l>ycm+Kf6QkvbJDNu`Kg$3>jtrqfw`aYfDsxXg>-px^(UkwQ1N&xY z?v+PN)bVwMnJ@^7J63LNF|{?Ge+x`RH1B;9gh3G~kBBJ{ljv-!+b!!xmDHwHQ=zGL zxFz+PVnf+mNGB(+S?o~z(>dF7^LMSSa;=ayCn=LfIjWnh`DfrcFKB&1o~*GeaOsg9 zl14ho}8r!DjZvQ>Iy|@^6Ub;BA58oQxbb463o-zI?G!trXuQD;`896!;;O zU=XFRu*Oktpn| zI7AKeVsF$Qx`&93-isH;kdY#C4Ni9pZ`+%hPccCoAwyLLb^M5D_7A&icpLpex z<71KNF%s(x`Z%~!p{7s>2JGlVm&X;{T-sCyKmFc`psb+#yLoi%#&I<$1}+*lLy$WS z$fi)|g^uQ!ZaP~KBP@Mv9@k?rJJxy-9tpj(g^a`x74OC!RZZM6qdWAH@!q;Ub5T`) z$$eJvkbaDFH&p@ie>M^}D{JSM;?WukO`}lHuj)B?TdR)^GaO3fKogVB4LPP2?;s3z z!G|=S3|Ll=t`o*{GIdr?(@i`@^d1N)Yg)3&pJ!8On?S_YF^l<~c`+H3j+iAF5n`|^ zPT23mE3E&v#dZ|A#K(zOaD?}+rrFJ6%Vk|mpCFYog6Pkjfo(b^5z+9|yApB<`J?Nf zo|Xv>N$3Bt)6p(qIL24a!1U9;CoeGp5sM-siXJ^E`j<);ozw_~j?q$>Ww@XeS9^7v zO`~pS1TYsDD=YEA{wYF#dkbf>=*Fy z+}$+P)z)TTSw}W;(}#Ks5vfb@JOF+%{eF#@x?pUVD{ia^9YP3v)NBmHu|;0XeJ~PE z6h^q=H7xLCGEs%Iv%Xv5>W8;q>G@~X3?JRviFO0oWpCOd{FwjRr2IUY6QQF$KGQcg zBU zkm{=BPvTbhMu3}HK4J9dcziE{`bY-J?ww)qq^F^ z52DiCzu)-Vk^g-I6;baWsf;PtN{6OLc2j6-Yr~fU`Ka_gVt{O)fCH#CKfgP^dUkji4mK-ivpNAT|X}q zJo0nP2qk#;Uszep(Ske29F4#7b5?027G`Z@MN;hG# zhpN4A5ZDbWAJPJ!_*;$X_u1bg!4(NY2_z?%OXi^jeB!BPxvt&B-Mx)B4^cJxd$Q|= zF(cyUsO5T++{m--sclqI2o?9F{vbsN5(w9xP1H6Y0fFW5aUGO3K4%Y;G=h3C6FLL= zS0F3Qzgb$nGMMS}6`Q#c=)xiS1q99sZuSUJ(yu6X82Gn8Tl5BigNk+SHr}C(doi;a zbk1f3UbXC|odK4}#S*iqO&K0N|LWYtQ4BKejQx6%{d%AMMnka-wMjNP<|u+v*aedJ zAx+ADV-bpbvVbc2oybmtmI++R3XZs|IFo~t$h@!>YI!2rma0L{TOtOjjD$L%O!$1 zR`>`C^3P+6{Nj;}@>O7g39-TUwN#X&vx9=@j~VTSo}-GYtkVCiI*;cGaq6azU5O+c%BB0E+rbt2-!b{yph>e8zm(RP9b~=mdpmX+LiMk%{!(GNUaqSh7iV z`M-xg6@E-^W(epJ35*D0p!A_wz$u7;%vK}_WI-Jn(Hr*n)h=E{H(35;gB?aD^wi$Ptk0^ zmiZYT5vnl-rpIUYii-t+JRU?$YNO2i=?m%qtLu14N+c5K`SWt~-HEQxdd0Z{e%t9v zpQz|<)+X}*8lwSPq2d8q$hbJ|5(Oe+M3iPKK(-Nx&`&&9{pTx%8WokDH}aGA*=wb@at<>leO-s1ZuedJEzrX@p1F&zgfU(YI3JN zZN-Y>JbF4{^ntr`?Of^q+TnNP+YfWf%!sCslQX8e+R2|MC>Ri+@x-J4fRYx8l9`oO zXa6nQivSBZ(APIk#!jo!-Bev5U}$j&i$KZ(!VrA~)k`1*4iVE&v3WDWIrLPpc?GpT zQE+@0l|^Z^1k^cfQTpy`8SQ3EY1ML7uv@JFRh5ZJ)zMEZI1r9bYudlfiAqL`{3K>e z8&8HP%p7|x;5oH-4uJA`Jpg>5AX%Uf?g5oW^g!0WjZOYlR|*gh|I@f+O;J`+MS=^^ zz|Xv$rvOa$%xgJ$6;uMHuqu;R378D3{`-k2h6PZ$G(1uNKKy?c)y;j@^v%IntEA+8 zDZoVy-CPc#C>#K)mDkb|0Bk#H=rVvMdfLV)kK%;g0-TfA#+Qpg@@!*+RUiS>bnF`I zsLT+xl<>9xDCya5NO5s^L`2Jnm&pI#offQ&@gkMu;*$4cLo=Y`Bc_3tJ-|c< z0NmqUGvLdMNQOuCYq>*yJ1$aM+T*9WZ$LF}d;uH-s4rK`Cm_3NuZC%#0bm%wDTsGa z+eGFH>AIu_x|49)MZB<#O7J}H`Lgc z@b!%=ayFf~LHh~6g0kO~Ir^2%Y=;wuhle)c;&BfpvXbz}{Qg^<5PNrg=$SFLHA>WDGP1 zv8bHHcF&uhx%_@;KaqL}Hm@y9L}NJJ1u{|8V-%<7{b)~>os-iZpb<0zxAqw>XLoxRIis*z3a+782+DU%>DA(u@b%b!Pjy& zfEpA+1CiO+hws^&4o84nJ+%#Z>>7zYX)b@y<^SBuk?G^0V-q-AqJoKpp!iOxx(Lpn zsZ`Ld0ub*@AVc^9``_g5uZ_;5QHWX;z5z%iRZUzf9 z!rip54RJnF_f{tNj&!(OGP?SV*ay;@MlJ)7MK6C5lzpDNK*^wj-Yg9CEsy?RCv_Bc z8_y}J1$L+~jdFY6fQmyi0PO%!Z_li1P$ah!YQXG2B*>jd7a8MU3d4=Lx38n3qi=FSZOWUfJ&cOTTZ z1tLWG09?EVzI$$8bBDHNcLzl}0+9i*Jz^}Y(^t=cXcS71K2b%Wi2T<^SYFeQ79;Ug zBUx1T4w6GuH=7n6GWh6m%aHn&x28Ly>cx05%28!S&(-}h0W;YjVEC@TM~Eab%2!yN zIdVUaHeNcLGK=;5eRtjyXd$NSOAQKamI5c*2LPaT<5Ww>zb97mdB1I-3Ua#T~r-_SGHWt z?gD`+L#YuSVE{vIIsRNh4HzO#fqee5v{5sJA3z;!T1Wq$qj%{Cy9M$nXdOU6AE7e( zhFO&ab0D=1_%&yMs4-O%&ec3FF3fg3^J8w};ZI^SrG$L)U$1h%00u+z*??oYQPcEO z1MP8?H-g}y7(wH0y=(i~?BAJ`ztya{`9v;|JInBSrFseI$p3knmK6bpRiE%#~=>nYX zrN044NeZMf8xNR{Tz{Nu+-q6B_r^lM(B|nbm`1dY(T>Gd`!hBvd-MHtYImD_R%sPuunub^8!N znvf$U68cte0h{vzRUANS*x2+vuFh@(Uqx|T`us1%J4=`;WMyShkR1T;1nT9M)lYbM zT*tL_qv!R~R=x6uDO#poF445MOTn6(x6XLr`@gqyQi}>x!RY9d&De8l(}aRp0!MvT zX)2v!A+7FsW6@kDCQq zdrQ17el(Y&-MO!mkIl;(h(V|r^(s2;L)zNiZ^3w5&qzqjc5%>h^&n<=rhK<~G)VLH zAkz8d_eb)#s;(}~{QKRiDCQZngT9^g(;5XDfQ)Xnzh8Kn2HeyH>Q`^Ltp)*p>M>oV zLcz!fv;x6bIAjmBSX%QSv1mdMv_7cWC|{#tjj`*+deftJqUE@CUu(04PDsG59` zFZf?g?zD|aot}Xbp}toBj3iP@qiC$Br)PB3W$NQ|rK?Ny=$9R;1mo6YrHf@i`mBFu z<^m9Qz9+4%t?>gLTyVM!?S(!Ol?Es~4jIngUn`*=@@5LZNUIpYPf+}gx|h9>@77Fm6+Pv6M#9-sVfKKjwrqdp97Tyf3kw~AXZoDtdG?j zK99uyMn~7sPL>w1OioLi4LbdoE5O16VXqOGb}Cg4l>7hJx@XqG=JaW4h-!OyKfnXU z&gTg@%iFWt+uNTR8YU^+>yRIR@tDQ;V|O;OC?$p`s$ToMuM8hyS&~XQ z!;dL)f0uv!xCaoNP$+b-1td&BKYV9r2lB-F^DpCw?||(f=zn>7usW1}jvWNv(9zN9 zr!BI*V<~w5RUv4GWL4aSAXBSKJ+5@tM~@r;HX5?M_t+$iGCXH(rv=AP?C%o;zW)Bx zYUfmESfBwUL$il;i?lepGTMKQO-ukL#w758nHhr|HHy1;f%YMnh{)XR>@%js${%*G zcCKHwei93Rjv~4M{tb}IbOZOPbJVB=-TS|N0}adukg9NubnimtQ)nGuP)g!ouk%GC zCMMP}GQywE8d{y4n2`95t_KZ&PKqNfFW&>;ukQ-OMJfqy4J@bwU+TTVUXwKOHow+m zVM*;nM@J{15z;d-C{bfMJUS8<5&{VIQ(qAv?%9XIIV-h11fwBZ`tuGgqHmc7lwy9q z<=s26N2x#`{RLp((9qBTxLT)#KFhH9TWRip7Vqf>6e@r*x&nE`kLhUvets5G9N=uX zUuzo}+@+*U&&r}9At50qPKb;9US_~YO-+5?0o)s9;Ff4Hig0nlmw;sy7#Ik!JRla} zM*x}rMc|B^o0}omS|#IgCy5FLcD!!~T`o3*{Yd#)+lGdA0mUadIhpmgA`2-1<@C0< zqd(_0*Tg`B`nmpXmHYDQ>gs@J6_|qiz?vdF$X(Dk8UXDrEtw?Ii%9>O#+dx`)97_U zF={}e!NJAt9~dBe{mqWo2hh|2)QyLOqg6zhhuc-_WS%%(sS}02jgiPPsnmn~63f>p zij7qj6ALtal&Vl5BO?R)%<}H)i zf?0kfB_%28^x}e6*qe02jE#+L6)+FoHncnk8PD+k_UtnlZX0M1pu8A(H7-~5&9a*Q z0}2NQFpZjmiclKVhc1QHOU41I92X8pzJ9IwAQ>&l1jGwag_^1=30SVygCBOhDn35D zEG`dd3GE!TSV+6&(FruoWTcIZvcU9CO^uMl;$&^u3?wap2*pOa{hj|2>X&`F5;8LE z%*;Z#wc<5y`Gbs6+Rg3p6RTvLzuog}9>dOrAnp8x{|E=&6P%C6b1eb$^YfzM^zt`T z=Q=}j@>F1ind#|~uBlH6@$tWQcWJ>OoGX1ROk%jn#{;m~0jMZwo0%j~Z6*XsB+HC) zaU8PkR2pIL{KCS7_8qMUWU*bEEToCdssP=bA(6A-#Lp9VZXAX%L6xr;txXi>7RR8$ zLaH`OfDwe-E(ECbKvxp1m%NUR1$`aB#svM&T|v{9m9h29y&DNNeg3=>L^wbIM6m|q zddxwW26I!u@@w$B;AMSO&g3d>+K!3ed2i;h2sQS+s=;R20Fxa|c34CW_#l(U1sYJ??%rMycqair66mT_>H%!oF@U@| zI|oG(UfzPm9ztKBe`-G#3X>orBO{}rprE0_f1D0*U2nOqVt{SRsrjKmn6*GdUEntO zWi^{e#dAM@3bC^je9-X}$})UpRsBOnMTLlnNXc&oqo!FC3_8HqZ#IKVX~M$7L_|cu zLFI*)b%u{7`}^%cpL1|0?EJ1;mMZh=@=!b(GQDSre0kH*!4dBkv zWoM_4dIKa;oo4`T0m#h01Y`rqcG~%h7cDIf=q0UatVy`A(8%8XgdLNXw&LEpb#Qb9 z@ZiaP%f2G>0|WLw3HPW4Tmx}v^QQ_Op#RL?V_B&O;tk*?0NIqG)sSa8CF4LQpNWad z1TBs_`aj;E9gf9%yX4cS!|r$nPypQff}c$&T3zYv_8iPlN}wF;Dqg_YHO zLy>2DYs=KsluiQ6?G%JMRE$Z!u?ez^t*!L{eyzuv(zguaIB4w*5Gf+(TR(8%wwqRV z(@%f;r0PQ_@I;x$y6P^|G8z~z(7~ByFNS1=Fo|C%65wFwOri4KHw~!hO~ytp)g2(E=H@uz5w+H z<2|4es9jWo!+2os_DU)@;6j7*A@cTS)3)!@r|c7dG)vOEcX)kuB`?v9@d6@@z6Sw{JiKIV*bdE`Q>?+>`6t)+pJ?YjVaBXeR8sb&Tw%!Ow`1inT4f$XsF`D z2RYW;wbsL?ASMES^2p?*WB;vATQGE?1wm{v{yZY|qlbsK@HNWfN1*S9)iQhv@%T0K zXV-*nVVCja^Xeaf0m(@G>$A-}c0At?&g`dTOEb{CuUgKhFYs8WPs8hqi#L{f5<$25 z{Q0vTZv&771;a6j+2OKf&=%)sAFmTJb3RZ*(<#ZBC@e2m zDbUb=`jm;8`4%i#b*t1SZ7}xwY=CCrN~5NJ}c?)8jrH=#bAn8$|-h}ObmTQUB9b}%Z3 zEMv@v5f;#s;1-d!Y3!f*QqhQ6Zg=C}ZNzw#e5u4CN`drZmwtQ}z30;YK*3e~&aW}a zn|y_W;^JZ;FfQo2MkqF_k|{8d@njSX?OAv8d3r8JIB2y5)z2De9!wCKltGhKJI#il zsvX*F@o0S`L}c*VPlI*jFNQm)rTr`+Y@JBl1m1>=^Xi)y)?)WtN2MnmP=R*JdOifEM)h^_$2Uu1YktwLb$U zGeALr90kzVIgfe}OAbLhXiD?(@b@k%xEK|sfI4cTt{)mV!umch?iC){z^TE4-Ii^>XL0!$w83LU6~$y zMvg=9BfB*SHj6W^%;R5p6_`;Pg65}yN1xpCh&U2P{q zWn-cW!7#8z6Z$|cyt~t-?kAW-g85)+5X=O-!ZCD};5M|CqnMnVyE;?QLj-7x1L~7P z0T&yaJxIj>*0<65H>SxmU;Mq>ABqbkmMa8*IthGd&QUG&!e$YW@;;TdpYwDYFcB09 zx(B)D4wIlK#Q{{^C+=HQfQT9?g{UfONIySgmFRAXvpo4dcjtnHKMub33&@m+YbWzY zaEkdP)JKZkeh|R<4rCwbaB(`qj&I*UJ_9CoPyVKPfTa3>gM$McWNHnB!h^aUgw^t* zP2k+Xv4p+H!0HH?$pa=F9RmZpGpU~GDdn|vU}!hixG-Zp2Rv98Ulx;}_t&?4d?~|- z>_}s*wOcE7k_LAqVfZ;{w?$r+q9J}45-Nn0k~2Z#FQ1bj*hM_c@XV8=Pw^S zouw8^h|a%O*ztnw`X`u#1DYXdIgqP3J3E6-{5M<{3U+p^-~GQfm~&BnX3)A$c^1MD zBCC3fTU1MgbwPL$!P~!LlYGC!Hsr$(=8yB=U%1p6hDo&j{$mLKJbTvW8wc&OET-)~ zq;BVMGS-s{skqcLp57t~ke8R&*VnhOxVPW!r@;0;J1cO+yi%{ez8*{;vi*)J-3LY@ zB$q2-u3{I=_wJpYpU*XVkx+RE3O0aX^ySN!ceWTTX!0UzqC6_-fY|m_NvR*KEU~h( zW@Kc5&gy7o#Y`NzXZq5`1jK=l`SWJ>ao^+xKyMuVl{~ zcUH1z$zDk%QHZjVSx7>%_a2p1A1g&vW@wV^WEWaQk|>2j#_zbF@BjaKJx`zKN!{am zU)Oma=W!h8dF{T|jq`o_^ryx~b$j~{B!L1{P{d)?VJ{y!zorfFLp#OI%*!n^GBP9( zK?4^jaFyMt*B^wmbNDRSO4HNRIDIMTH^=Ma#?){LLUxZrO1o<6ThwrYvbeNnVFftfBPkS zn!9s}veBUoW@chqUS7`YxkWYV1*mILUe}ae1yU%%fI`7Myb_PcPWCTW=itm@SdHfvN_Nl+=5xQ#n|EKRztEG(MBceGeBl;eWpZ*dTkiB>6B8258!_!Y zcR`GwJ+74(SF+=>V{8;=W@cX#?xA=yCd)j#^ofiOu{ZB)tz|OJcJ15uuCGr{UENxe zWk_^sCEh*YJV!{e*!*eI+Ld0V4>%0O&jmIjFHf31 zq1mc5ts>~24AZ!Rni{SgUd1x#rezG7D)hfmFDEjq@!Xuo7r+7-8W>D}`OEIfFZL(?$LmMz{PG)@apN{I8RTP8(c)XT zsEjQ{v(<`qrEPbszdl%Gt_hflVl#?{dHnIE^JmV0{ERM>xL$p9E!wcefV}6@fFLco z;;L}YBHGJ+XjNNZCf}2no6F12KKMLrd-sX^92^|eGc$-DxEyw{qvK9xCDS^Y zm9!P`|KorKA+3;{{QUgPOhpK9_%hFfR}w{nsX6~gWnp6=qB=P{Fa7>KI5dRn7$xWy z?g8PUAm`y+!sVk*ggYHy{Nk8+{ZKyQy1f-#;nwDa(1E)m&f$V&Y&#!E>q}&ub~yq@ zhekr2yDYaN&c+Jyw8~qQU+s0(4&4~V0VDD6cq&FlG-(~U0D&#FXfQdtW2)USCD zoxWjs|A>ePS#XEv&fy+EamFKHEngIbO|W`8$3`c|X5x}Yt|PgMU%+~x5XPit@NC$N z$lVXCs^rzw-VO|uS5!m^vGb`8`SF)ql$#zrc=}0T#()3)ck|}Wyu5WB5uBuG1fkg2 zhvz^2Ct?(bjYQ2jnI6ls6zDSdtho3yP6~)`>d*`nymHo6%^yD86nP|`XKGU<+x{r3 zv(qHkY-VQ3CV9YNt3>o{KLUJEdd z%>Y1$OM{U2wF+4O>&8u^vUZJC&K)fK_U(I;0T!B*oBRCx#%dsP0QA1Ef9J<8K##=H zxeTxsPEJ`EYIGXAG*1PqbzG7Iw+5}@N?uTFCr+I@Ja{l%oI9y4z0$ebTCZpkm$RL$ zav*Piq01lgGUrPiwbJFBZhe|OJlSMkr5PL()Kz#|NQpf-8i017!PUrg(N8V4icLxf zkt}hiB(7z@b?a7MULH;`I3ZVj2ardU-MeG-$juk0xCA$BU@w;7LD;Ov>f(mO@Vgth z-_{I)_s}6ynTHe1wa2#q4bhv0N#&N4>EXk#dwcP--pj%;2zB7*ACT; zYt1k%{q^e?u(pYb35X#+4L=ua>l{$5Is~^HL1!%U0<;PDhnn5fAEBkJs|@s(ku%f3)*jh}P{UZ1O{9W)p4GWFTccZim{D$F)ky%D(RG^tpJ^ zd+0W^!Of!J+OX{{1qB6s2uU`T6+r^7E70oQ7L{g0MV){`>)lP*hZe+qQGmeTyq9 zz>^ct&N`C2hy_ZF#?qc(VdD@`iBEe3V!o+~nwAzwXamn&L_`EnKX3o#huPUD@>RVj z?5o~~mpRftYe-J)mXMm32KFil+tQGfq}!@-YD)y_`K+^Jy)tj=GwwUSTK?cMZV`H% zmX>CF?_<5^2^*U++!@}-MybT_n4tS~F;KJrI6Ye#B|H$;dOmAJ4IluyO|`!hc3J=t6Nf)QunG+0Nd|j$OtPjzEilXzJZYguLCg?*QLb_=w zD#GyNN008P%W*Dcv(y9ISQ!xe9k+!oPAcXySy*BFk*tgKpK7u_ft@DECIa%p{E#W)ORa*RgL^M%|p+09VJE58U~^ZbWL^^lpt zku}-<`2PJJGM?bR00O7PlmA{#h(t+VJF<@u^IAEnZ7&o!5N~GUwbj)m5)EF5F0CB| zr&8pZ8*^RquW&gONz`w;aJJl%kB4XW=g%W=_>>PnVydLf?g79#Yhn^_ErZDX7ntX3 zZ$523KN~&uBZo(kw%`9geQ1^|j^jSNbf9T*l8l8iB z%eLZKxKVfiu3a&$lQ;HW^Z;XO%|?AY?}mSLh65MpJq|M!g7ZF^8#)AJcVja%ru<%T zX}*^(J-BemxjGkBOYx?I97(>0J71@#U6883e&y!ohGHTtn?p=* z7IL4r(C=sYYENLRgfb^8Dk?AE|KY<^JRpE~Xofz#^6YH9PJBTlCg*$`{cxMsA43A$ zt6U`sWOV2Rs6le=WVQWg&4GcRJbfB*kL3+xZ@LblaOLPWBe~RQwU_EY9OO?Az4^0y z?6JRqOHi*l^i8?3(QTT$8|m%MVrr#}d4Uq8{pHI_>*~lhC-09>)&PplMUEH|w->^3 z2N}1l-QwTBP@<6w9tSOnFJ7E1I}#qi#&D}RM$dJ@L`nB`5zrg}Q19#4v7xI-BS2yt zPW9XB>*W{8SkG|^h{x{&MBg8}k<&V9maod}_P%P8^DI^C>CTpC!yNAS^dFc@5*o-3 za~}Q-X#`AiqyIPdR(VLWNQ^mMB(XwSk$g?-#uvz?cv9esGU9Nm-GNVj>ggls zl|J`Hf?}Gaj2LGQwZ!}ie1i0cLNa7?Aa z=%UZhoFF9y1(e7^D|4Iy1r(u_M|Pa$CmdsJ6hlE7y_{iDuB@v113L_u(9n>2Mi0Rm zvf>^YnL>_RcyGi4{3@C;i<(wJRh5O2vEtr6PKFp6uAa_L6p!?=FLXDk6+k1+Z)MZWo_X%-`~+S9{BbN~J^uZKlNlc>&pIEVtY z)2)SR6=URq{jAp9w7O-;m^LR*UQoY*vR;SvREd=UZsxPJT*ht1QXGl0_KyOCf{Ok# zD51B}vehlz{FvH4&pdk2{6yrh7yxSg*<;6)a67u6xi@lWEp4Dr1=&LLn-{MiR#%TT zU65G5JTdK5+0gRhF#9fxfy3cI$Sq%6%_XmwAuiy)X}mf>-TCuBQLhh5{OMvWyn+kD zfvEt7Wb7X)D=8f-GAFD1hkKnyxuq5>--gZt=^-JHjEu0g!~THiLdizW_x|QO|eR8rj_2%gbS2H#Ahs;c(dhDhQAXJ;TEsih=U`6C8PV z?#%iLKP$8dJgFGZs`~ncvD!Ni9{dCfEEKIPD|3VU0{)8R#6$|EsDotOtYX5$9vAKH zZ<^cnN>_#{MMZ}|G}8$D4)u=Y)S zOL+;rSrQ^Eb}wQoBH`WQVkZC|78Vwu{#e!sz2mkPThASyJDdj_SXEPFA)AeY(%MR{ zv2@_ZfW(`5J0ELZbH+k)ou;*a|0t725XDslUWZ+NE~xHPc=v8%&zB#g)lrt$8e1l6 z+?`5-+}Uq@O_dasd2CVs#AlL%DSGMGFUPrmg8dIwox?kZjjbomZ{h)<3R_=azx?+{ zOfZihJI9joy5jp!DHr~jbo(*AojhH|Y3^*uA9qkkUpKtujk+Oq*e+4SN8yd}s}HiX zv!OSdOTK>|rmdgcTR3a~FJ{>R zKv|NmY3GD{+Ox=F)E{~9g3!{^o;-PSRjyL-OzjwIM+C;p%d3N zZMbqBVwsP>Kk58`dj1^G8Wjx|pT+cA`GbXM#(%g!&^T2f2sL10A|$eN?(Q0hPpDS` z<@0lM!HV1mSp4_*XMwW&ASwr**d26K=40^($$rQz&pW2NcobK(k=0d)3yf-yVUwhkhtzIg0%j?K;`t`M{&j$5~C~+x;r*N^m!uxZNA%in=-vA1$Aw zppDFN8yjA#Ok7F+b9UBbPC;hnyoun0{ojixnWlbt%<^YlX5uoOI66Xtx=?*AhzSM)K^ze`Za-H!Z6@gaH1%q zCOsUBnW}~rnTFt^JI)!&5sC%}B7M8(RMS(F0>gNF;A?##ejQ0mjSx7BrviL?ex8)CUGTv)=# z1vlT^+ndtn^fY8`u&2ip$QALJ=43d7X;g1avUa9^c$u~`1pqm!Q_yfa<)8gA%6N-cb# z!x~kzCV!0k$*ZBEV+1x6V&>xFqLG+s%s7L-ek)#7XVXy0mfKI0>^Ent@2b)^ITrGpMQs*YyZzVKJqu~@apOA$Yv=1zWdkfg|5b@rqGe)QAjf462LvRlaZ-wvH8 zchPDQRo(FLVI;)IJ4=&!I+8K!UT&?A%`V#R-l+bVxiR>+CQ$$DsaASk+r|ptPLbnh zk?+9buCK1X2N%zEWuiIa;B^^aAD`xT(RawB6#Dt2It;)6%`0gR{ZBh=3swsFGa$t+ zIzEjyru-_qHRkRi5b;3#8jY8UdaQ}};>UcC_`Hu5`}3sPN+$gy{zN@bXB9rrEXVWY ztl!3O+N;f2Hdv*^59N`rc@HyJ{L8A`2NwSG=g&sTJic%svR0M{+&`#qEZDo#{k_V( znE3br9JMcYoZ0Grlq{^h1y>^MF!0)JYo9ds7RVwa zQX!V?-!HgsRaseC*qMGKroXO&(UzZ*zD%~|y4cI}>g;jEHLn{7sa^H@PwTAQ?ww_M zG}8O(Rrt7wmewh;*B?4n?ptoPFl4%Bn%P7VckP10lgh951KVBtTKAhbe_q5eq9#U( z&}t$bo7>g(V*J~>{&jYS&I4hG#m>c9W-%#D>568AGlxg>_=gqc$2i)C(-ON9&BUY9 zBBwPqcL&Z}|4A^*U%bSmt=r0@b!s{~{CxCv6SD@V0}^)6?PNRBQ5)Elo z4P=gfH89uOmZflUkBn@1ZbV>9RgGIXx=py)*nAL}pk7sv%>%lS%!P>7X+rxWC73Gc zn@mGGNt)!(qbURP%lxhKP=W9bUcH)se*31Qr2^YU`IqzQw;zShN9oXVbY=Coy2cN) z)f7%%)?J$TKJf0GZ3&Ykiy(irM>Aba7`QsI1b+FB!`IJ*Hh+QifBiaesf4&V&E5+B zmOeDpl-kKQ)YnsApPH$cy|oZ7MmBq2q^>p3x{)zLhir$D^)awQTwF&zvnnW_$ZL)} z91uB9v2A#L^_d#S)?{;ac{!Z56f+B9t}=BBqNyy#y1L{AeQ$?`lvGrxwPVYV+;qIv z!1x^mhL8rg?im4ZtJ!?5V;M$sSNba6({oIGg4W^~iva;>nT!YM| z_hSPXWUt%Ff-%c^6(N|Do7)5n9w|h}#@38^ojmytq;^$RRgr!ih3wsm3d$!`j9O`E z*d~x2FwnJBkT=VB+tb{7h4HK4Rjt@Elfw>;a&$^1H{T2lv=nkCgs{yxo?s#{EFK>9 zQeE`Ov`*3_xY@E95)@w^7Fi{CK#1N#m^)!k4`2JeME3gRbRF zGkcGVV#>sBJ5HNt75gbJ*3yl4k!zYWL5#h5)85C&2PzW~WsIItS=l0>Z^i=CZAB=>@V zv5D&9_3PJQMqsD}yS2Eq^casgT}0o6k%1@P`SrWHBEP>`quUG^RFFwTw#kwh(MW*?9LGL z8JG}c?62RyyI;RpMDF~Xu38)PHu1gWVTK$=cT54VSZ!On(AMUm^ zZsp9}YKYzL9=@|;!c4i&@KnWH{h?_oyKztYn4cu!ES;-ZrFNXgb*7AljpmH#SDD~o z9zKkHPWEHHp%hw#W&@C)K24e#gZuU)dFDXls^;mwt9y=VZ>G)Lw1r-rN%OKg6n{)! zDS@0?KFH_!#0KHHf2-K`>6Pae<@1B3j9@0ErPn(SmZvzg_v>Qu*b}C412<)SrS9M1 zx{pHZ7861VZJ&k1HU=OlL2`y_^YY~_{Wul?_&BF40z9SF_fuN=;!0Gf{WO>kz0osH zB;FzaX@2C$5$S9A+M+XW{p1Q5_A2{WiYy+rwOyY|(`Mn3ClCla<(5F;=RQ4y+#3S? zU?&TTK$?RgGcQtkFvafGM&E1hW1slLJ#LEpRyDh_#`b3Ki{9dfj$w(8#TBwFbN2~z z`^rJ8nR6C#=|@<#87k;`B8~HJ+RhgNK>VDSwJ?VT)n49~XSyz6Hg+=mBN^#;( zy(xySVx|RwVESwKt^G=LGj)Sg7AuW_zrk!577`d48S8DYd>br9uz=+Du&j*kLJpr< zk7eEoGDd4zGO2pEfk=_SMLts$@-XOzZmyiD-0wL~6F6Mz(>tMdkeCU>8}mC;KklqH z4pjXb8cnd4p-p19O;vy0ZQi@u6BLSyiul`qetbxB6l=0$adssrKZGz1yq|sTTG40f zn2iW&^~J)~kY}Kr-1KA~dq=OJ%mnT<=Sbw7>UFa3U#=RPA0M|3bOOh5OZ&*1`j&?V z&MjY;oSmGKQ&QkDkLYFOl(QilvkZU?ja>-;dN5=zx3}P*P`#$_@q-r<4W-S!2`Y8M ze>|G~AL5%;{@UUQUeuv~k%@2tFhG|$<>t(^?x9~Uw65mkNM-=hEZV}u6FnP`A3C%| zqBsFnwMoggeUypaYe$S;#f9rI&i&!X1z ziRu?k${{xwo>`Yqiz~f0+GQkal$n$5a>r$>bGetT_JdEg$wP}lIuVno^TeLlU2eO1 z#$)OCTMqP}kL6)Mf89kroVKiDS;e!^Coj{B3fRksHoB%IdA-qU_Qva^qTmctjnfS zq3z34M+v65C^3q2$Af}`jvwb@$&jF&6Xx+B>P+K^vgoub@nuq8H7VbCm&l}+6MOau z*UhYFS{rX+-2S)n{nA7;dAa2{$^fuOZ55>`|DbVt$;Ot$TRFTRq~KzObnJ%P&I?>7H&;lUWCZ zI8sgtHmC5IzdR5;{e09qiX*fZ(g`xvUdPIBZ;EYs>k@am!YYjZ8Ye z2pqqp7%_spiQFV9E&uuCM?&A#_K-bhol~C5SII*51u;PxMq!&P+)T$2#O+cfc->n} z`Ndr-X3xXxdq&eMcQ8dh{ZOTr@Wi(!<3I@;Sv9Y^hDZG)Ft!jEmX?=Y=DxQh2Py=m z@~}owy;xzbV0rmReW~`>e$f=0BtF+2Ez)<-Daw45uk25Mz_QR7E7Wd$NK3TlTlM4? z(bL%1v&*GsaL^)U!9X!F<3BPPu0cD6m66|7E__TQ(;uGx{rWfaG(jS!JyxP3NJT4g zT50N6APytw+dtT4lR}=Jo~NG%$EXT^w@DY8q3pX?G$4|%xW#LF=c$>nje~o}7R>Fz zP+`m)mgdKl;veW=q$TV(SI${))st}%14V9ad#Kpde5mZMx%LY;ccC=e^&L56Izi-h zQLo6>KeGj{?v}Bz+@ht9;;vHSWT1YTmF~vB-*#ShA0!4uC-lgFMO4c$sY7;$h`I+d zP{&lpg}z+zJxBFJ4A+${$~k_pxErQNT=&m6DWUFUuG+~ip=j_i*`;r&@wB{U;BK@9mxtyr1Hhk1s$i#QhJ0z$y?+H|xll1G!5R31c zrPOB=4!<3Fi$O?j-uT5{>i!efY^m!Exy5W-86mcTHx3+^xc!We>p%Y7zeYqdZZef) zE{=43;*BQe;+^RRifT?Trgx5>2S2$wYa)}9CU{R?i{bXOK+dc3n#wntXe*d1q85DE z9_qX_6t7=Qa!45XqkB|{w=G;S{`j?59~4&VO8c2v{xOG!fAmW}lRm?Du?-CM+)yHExHVL;qax`f@plc#`oUr8jfe!J69IjQoh@fdjITNzFLPA2|ry+1KobAo~^7-@c znO=Uy{ugfKkGVM)IQ-}!XHct0OiIRAw}>+_F!=fSjDmTtdIgG9PE|Dk){ACkYVpbQ zI}U7CWE`D-rNbe?MmO<;ZICbJuWA zkWK6dwFc`s+&?~mE}|JGr4|eDyng(+1%JAAF~#mA1?L)Z+VgjPGifZf&JhwePRM3| zotcrvy+ZBn7`(29><{_fWsdQVhQMJ6@>pXa8V@HYMHnWL3ETVt!>ea~&PBGXH){;&Fryr|Q7AL{4=5kANCGnh(?P9{Wdi zP*{L85tUZp6_>v)#+3wSm1NXGb0hRy5~TqK7KRcq+)PL3!&_={a&iE5h~nak20xa; z9e^y(Ih@h+1^))4gY5?hD}bg#P%xI#q}CRc*#X;Io9XH4r=AAeKMUc#oWse`hQA5? z11h*0$P8rc5r^mBW@mMNlZ9ScnHxd4^!E0K77w)qYe42e7H}8;$7iA$S2n?>)Q(HP ze!SO^9HJhof?otOuWkVM)xPg|Jvs6?mC7{0q?D7t#k75pV%g(g*1VZ z=esdbI8h<$#mv~=Xnn-^SIez;FQJPA^2x1ILG-0nRJI;mq}<3Emkp|qw8g)r~H z@8hG?cqc?_8$t}UU@0jnhyM^NRL;H@fTL%5{^-pj<9BsW$){gR7;u|y_6zm*O!o)G zb5k&gO5`e19Tj3>GybtlM`qDTVAOPdIsR;C*Nh8?@YJtDE4I!IR&(iVpJT|ci(lq6 zxzAy(t2h=T&#p!8*){RB(ZWlWf3$Dng0hZQv`Nb}>hWf;MZVvs7M*>^6<_Y_iU~hS zP-^X@NbI`@u?9u@L(wPHOVQS>Lv`Y0we>Cv*y>9?!sp!&B>EI;b+K&rrCv^z`i3(6Aw}As*R34OWqm z_zLU_lWnIo(`X^W0T^3!FQE=Ee6KEWI54mgwe7nGxx+>AiHURYA3@$O3?SQL38$sB zTI_;TO*CWvlfy;XYp z`skkfi>=QjtR+zQ7emf;w7h6By+{-U1nS!zD2kdi~V|!gcHC?!a zWyOm6$d7piz;b}ML)O_XE#3U&#m*>xgMTd3YNn;X|E~ec;dS$|-+%uCKW{bI6Y^UA zt)_~-p>c@e%r@~_}| z3Geyd96<>P{e84rOvAdQ>tH^538N^^?Z2u(FoE3zxk4D;F#J)1(LeP0en2xO%m_Mi z5mJg}bGldVF^m1D^7-tjQ-rg(Nn=brwFIxj8k@K`+jB=6A$k7deSy5inBH-;&go-O}+{S(ANSB!cT4dwfk+*D1v?>i=Ztja)?AiXVvI_>-`Ywy2Wk*Ue|o zwqUy`fZm8X2u*gUtgRan=wPad1D|OvQz;sCCBE`5U)w>D65&ikZ;=DcOia{a7uVI* z_3)V6{P!0IG#ElA0-wQep{e;ECkQbPj#}trFmnzJ4Cr)AWOap`Qq6Vud$fK;r)!Kw zIbMX0g$1V8K!1OK9IE5T-=HPQMR5#oog4f^*Zf$OAuWpl4>z}((@VNbm;ORq04D*$ z8JT4p?nON6E5AM)LR*3T8AqJ78#h*cT|z(q3WTtZ&M#2d&yWqkTH&M6cEBU5rmo(I zKL!LbHZ}(53|PgQx;jnN1E3OTC1doC;a?@CI;l^UtXNhb%=?NkH^P;e)+HL zd^-rq_mF`R0N~<+Xd47U80s^>py18iT>2t?^D_=PCb1WoSkSqK9q2V&b`-E6;z48J zuVORtcTX>?T}@Cl__sH^r@o;f?f)Fi8W&t`ZO5bOcLJT@alxgff|o^9oS&b^90h76I2H0rtatDIYlkY$(t{uSQqUj_|>%9t<_8Iy$lgX{)Lmedr1BU1f^@<>0<-qR;f z9--yL*|`=Yey(2SkhzbZ06`#5=xey?ic7{C>5CS94P`a$HsYxNYifQY$YFZU8DKi2 zG@(r-CBnz3rGJnGZ~$#jp8UJ;?h;TZHhuh$ob`6jn!yLRZ_gls<*Ity0#SnU`|$of zx*U(4JjtkQ{N$1s5swl5TWATYf%5V2;i+0zbhId5-2`uly@c}X^y2{LH%DPTwUoy0 zMoSuab_E0NK2Rd80_qOPZl0cizXLcLg|Synh{)=jzkB5HV{Ny70?aM=fm@X*h%*Pg zF-R$rqYj`e1QQOhwD2SB;N=~wI3X7n7WUq@N;|^*K79!d@g3C`1HX_j=~F+0s{v>o zQ&JY!Hn3xWaQ*RE5y)Hlb=8^6PVqa5!tvgk^2GzIR9sA98b~gec;cf$VAxn7RO zP}yw#Up%jN0OkI~e__FEX^8d8HxO-EdnCWjy!U~+04ZaEF3Mc9Zj^j642h-;(`j7$he&nWW^73+Vq0-<*-$_;$8kKL}xY0Swf9rUaH`C=?7&Zrl^%%h) zyR_S-1_%6gj)J~uhNYF2%HK`#tS$sdxjYOpO0XLn_ofTz{1 zMvx$(9Uu%02*&TpL(Pd3YVbK@kD_}Ebx1~#tKVR` zrF0wpJVH0N5=x7c@JS-}jCwspih?~1dH{|Xt-lPLJgjP<(9jh0q4sQANr{+Dwe7vb zrl!(+P{jF{r=&0wo#9`2iVihAXi7WUtD}HhoV$;sgogndQaBIow~?2_Wm1DeAFNOk!1@a&`|Bt+8b;Vw>yf>FMgWV9V#T#$$WB+4145dz*(Ysn zgHdVX`$VZ#p{Eb;0#o@|b8~pFD=js(_oruqk75hOzrvu1p5useC)BzqND$MnEX|~t z5F=&qWj-U@2mhI;H#a7*;faz;azU}&agT8g=U2jUW^VF79IP~T)Q=q-f}b8kNcKT# zQdV9D{QyEk0D&6PKI~BmUTV`s8tLAH4y@rycaK+)ns8tyg1-mngq26$0rnfzwfLgp zL8!ei!_~>h7YtMiF&Vbua#l*bGQW_>Lg6lnV$-S3;Fg24gOoPUF6tG}xZ{IttrYe@il-A+-=^3dY z^!Kkr=c;LGBEW>d|J9x^a0CDVP5U(gc<`$GH~{w!&^pJfy5BHnsHepA3cT0oD345r znK+zbvtzYiCHiA&{cWnc@%(V|Nfj5>I-UcmC=34uKkD#s9sFo;^&%2pg;av(A{Fcw zB+dw<7#F#~s?lb8dMk5dzosW>)s&UJ52`7hi$;=#c@(6Mb$$FUBAoGD6gDl8q8w`x zPU%m*n)ERc&3O8B6Zx~JyBjWcI=Tx0G$=rn)YKZPs&pza3ZNF<#Y##YDg1GB)u@i4 zC7`icFA)~bd&l9FYw>GMkXKX$e5|~CSM;lelk?StgaaUn(B`0toOR6lH z%&`{bUIWE#$f4D_oE_aQE&3l%b{8M`@?8AaRnsrXQ)o0&aeNV7RwkKX@Oge77)F4D zgNnzjAW<(ViYe*y3z z%ZB`(K7c|187~&hm4ERurrbkDy-SP>#V|9o75HcPchD^)SZq zVtfUP4X8`lj`8u$mfD&jbsg9YPf_hdTSZeG)K=JmQOkj_nVOnXusdY*7>yu+VXGlq z_%6SH|AtnI&Z_3AU#Mr&tN6buce%)@J|d&;!8kZ+X=zNpIE8sW{QQqe^BqyNH~GcD zm4>~G%mi-u%GO2@sv^{l_=-RXaV@J@CfwtP7==Xl1zk?l)0iuG`_UteenLOnrMcm6 zD7{Ht??5{R=!pqg^BcD9^m{Wc9)839u%d;-2P%shd8Q$7pkM@`=mh~K!FGxahLILf zM;@a#xb2-w!`Wt;m!utT9NXpuxVeCE3J(LSa{wGi1P?~Tm^r2UwF=_>) zL)Pu&t7w;*n)(`T6W9vyh!i~ zoOdEsEalLJPv_(7Y-FzE>|#kVx&;pf@J9s}Z?t|xQP)v{V`m)mDF9c?@7&2wPhZ41 z0T^g8PpszABR-)WHq$Y+W*M40eRjM_&>7ofO+H(xKYn2TkwJ*zIR^}klQQ05K%Z$z z3Fei@T>FEr1QI2DWyQ+f{Tuq4i&6#or*pJZ^F6_K+S>~j^vTJ{yrhj>c4r#kI)&}! z%I%wlc0E$79Ev|+8&qls%*^UwzD7$52pp^xy1kJpW0`m(g;+HD$P&vYyQ`@YuN{r| zh9I0qhRgL%xc}4@<$a_ub4&Ls?RQ8I47*;NH?ibpiv+fcESg(ekD~84rAve;Rn;CF zUZ$a;o+L0twU31MjvQeX5$#emHu|8vI+WkD)InROK+PY%Tj)vJ)(CU%vz*{m=45A; zS44+T99nAQO!F4nnm%3mi)OejgfWC@nA%yd2K!`a3iWk$Nr{Wc3cS^)dH%(34dfAd;foq{ zL&18DF;F>i^lGVHX4d|*0pTevU;H3MgHccaE^yTd4>K}gI=o$0oh#`K##kYup~x&7 znM)Pi2W05#>Ixs~1Zu(z6QW{n<^B6Cm4!NlMMRC|<(CY(*y#_U3jrBn2U3j8&CfqU z^BVdQXTE&V9Tq;fGgn$AaYtT&<;>-;Q|`(65@E3v_Sm#w(2WcY1);3`g`de6rXDC# z`U{6Ld(+qBT=XPL287jkOBJ|}ik-PzM9X(dWbOH?`znQnWAWV$YoE3$U_q~<+qm@uP&r18;Q?c+ReD2ZHJ90y6)G;;3|8SARN?WB<%vm2 z|2Gq0@xAwG)g;!31n%72%Ft+cYv05yTJkSL@WAr%HF-*s@1oRqIVKz+S8_HvOLfHK zBGe{82TbxHy$&-o;>m;K6~JQH68;x2;&;&FFmbKlJz3cn_{b%m>cZBvjKB^0k9HeJ z%u?MOdC7zpS3&=>@F`289upP)jA|2A643BZ>^p27G)Uv2pr~!Y69u0FOE1aZzW?%@ z?rzecKE7IV$7+BB%pB1_Y{P?Ta9|bi2~@;Gnoq?r92sPeVrFX6UG*uP6zOu+5MZ$^ z)ivQzZAAgLjR~S?L!JZsgcyc63hN-292Wdp#JAQ_hP%2cVreu<^Nit_qkF!CChlj1 zELG?I?oEGxddJka@88i7G>eX!@85ycD1Wl(%B7wSKWrj@s;aBYQBO33&Zc*3C0RDc zW4j>o%xCq>3{v?zlPIk~qKv~D1>Y;II)HW<^`PUM5Rl=R1HtL;U1{{$jjAzs#6}*A zIV!2niMosG%NbYKH}JIr4(bL{`X2{z;^A=@METW|gg(~cA5rWQ`h2~Tk%lb#66eW{ zg~T$XG$N);0yRd*?<;7~CRMf2I2$mWWzLA_(4tah8fzG%izOG7QH(LHu_0{I*jXWQ zgGto(8m&S}i;)lr?x^+gzf&;HGH~?c_a~~{O7u-~v5o+g7)#&-whjpQXo(Ru6%}fQ zqK03{g+N_M)X*9NozXJ{kxa#XkVvPAt~3m5JBe=95D|nFMYLSccuAfGlZD3Xw&KS) zqyc!Cjg36Fe}RS)&4jjEqeu995fQ~Ed4w) zYOVSIB)&yvqz}D$!!_69(1#ow08Uu~(Bbg|&G)#IL2hc+(|x9gs=X zl}+wYc&T$QEhpKqjMAFr>Yk4rscU-b5tkzT#kZNrbjFzzrY7Tc8`?-ip$fD}#1Mi2 zIs&uEDKI7kq|NI3I>yeUBT;+LoIl!XKqV_zpZYd(FKo8@2U$O!Pnt6XlnFj6KXSaq;xz z=j6PI(~i$dSdMv57d)!7nRdahh?af7*At@T6AxKa%KgGM{5#c@#4kGbV1(!yAW4$s zjhO~G5EyHq@83}mfC-Kd-F%p%P*qzCMlFUzlJE#^*teev$l!qiNfc%PcLJFL#eh*x zS){+$we9?~XUfU$({{lhE2;8a_i+P5$x>pSNW#wU0CS7XO>1dAf0+aBBGaRW*PXc& z{kx4bIrJ_|FFgL^?s0o<)A!2b(7$K>ZnUghqRPmu{2?$+~n)sC6((CG!ZQTGVii?X8f>2p0Dze}G^!U*uH)Y#^0I<~$ zCgU^qj1SOLQyF#338hKw-pyzq(Ah7`HHE(BlQuSOXy@+eK!Z1+3Aj_#`pc;C!Hr|U zPa@_HB(+7#tJGOXuTTviUu9U>+w9xo^6kx=<4k;i`2s)Pk05`=I3m`mOcom9-hozc zG|nd^Cgveg7wSfZ-@!1~zu(`=VUCfC3g=7{dL?xzf#Zv&5)C}ayPHoPAWLSs&qC*O z(8MHJKtmCCqJW7+`~?IDdO|`7gI^PQT*Q@b<30qNldg_Ct%m7MG^X<> zvSUWOV4>Nc|0CFkboGWS{{jp;n{T~GixUD2IFkrHBh^(3ZLTpQ^FO;VYF5$P`BCQ+ zj?fb-Qlt{0LoY8aL5jtM+eT1?iHY5aCYT$GJemOPQ7NVTAr1jPPRfPAWL^oL{xMTr#n5vhlZDlrg$n+lZ^I) zr)LE?+7LR!D>?JbNB2qcpeK)+o_=6(5FsHcIT>^mBE3UB?R6e|edCr2c@oH>Kma4-~@#P$Cb7qHra-K@T#JhsU8%dhO5 zyfr)DURYJ3G&J_)91U+=53mQf!NVCldlScDfk6A>Bk)BD`H{|XAyjAU|;LW;)31IJ9*Vgbz1iiZV5mH`n&&%l5j14;?c z>kasf&%~-IpZCftDhvNZUSuYJ;U=G$+T7UqJT=wAL#9z&T6*p3RjQl|&3WWB1hlB9{~85u|I>;z;Ef`&p(3^orR1d1w}3U3}p-=N&BHVcjw zWL6Ava=Rk}IZ95hATKZY>uW(WC&au6mcSfWcMSU#75)AF!E;v^7X)ZvFVGj4gMxDN z^RusC7k$VU6hJt8tG=F-%mLO1%mjd~7q?9oy4;5Vf*wPNQy2nle)K5$p=)hUEjzKF zaZG*!+@n=1Rs%o|tXB;xWw11Cve-Y^%Fuc+N24>K>JzJgw~jSAHILV2MFZ9}Kt3G# zDbPU4d@2liYN=4kw71ueV4!Y70)0Q{G=G+V(wZE{fHr**o9|B@+bc01ksmpFkDOpT z(0D=8_pq56m7TbxIr$HWEs!c83CYI-*HuBzf;8fSiAyj>$S9k*I4S0u(3U-LC{lI( z7A{LY(&cazL_`N_2uN&bl0&sJYmlqr$rb(wgC#(+Vki>O1f)J{YU-jSL9600!FP)# zOkU46EDUmV)KrOPFTSlmdF_xmyUDp@2V^ft4-bYvL>|rADsmf>>(vocSsQWz#D5Hl zQl}~S8#nvO+Hc)N=L@O;8fxl@xstng(M)K8*8AZIlRs3I8=njxu2RKts?e*OqgGMo z+k>{t)>bj-VhResu-!3#47eD~hgP7atMoH7;e}p{?b0p~2BUY?V zpH6Gf4-eP5a6!q9AG9HfY_qoqGhhpZ#l9zZl1A?XWEIS$R#I950LIC_jG6$xB{b;e zn28T+EYotcu{Gie!fu4ei3g535+xYgq~QQD)xp?tkT3S1fq?;O{v~`CI7=i3OI7s` zscJ4N!lwkB3U6oGO(vxbq)tZ{+smH5Z!$wygqAEA6FaOimmePt0xWPl3KO86I@eyl z{y${4JI&M+C0(1>dCAEm+S`qm2b>J|iGK_+R&ZJV?O?#M+KOSHAOpb1AZll3XOo7y z!*CA68YZp_Ji6Gjw>59#TkCB1*E2INVR~NXGxPHy$laLBe(BPsOipd|qoQnp3nZ$R zY?wtNo1eoed6*q7{zcb$nhh^61XL14;@bnZWfQF3?Kp zqQE#D>pHgq{AHOvdrEKJ(h-Dn3_BS988L;1&Z`vwj{j*~098JNwI|IuQ*bsy3?0sm zlA?2Ohmnw6nCqpg`L{guYh%Yi0d#S7r6Jb==L;cc1Y|7#5=AwsS_#7}@Lv=9KRExW zQLsdX(7Up6aDdMb$IMZ8_j1$(bwxBz{Qv7=SEPt=(sx)b0t!npI*F16Lrd_Dnr&mf zUocUNh!o*;Kgg;c;cxk8%pf|?#mD2*j4_Xs&1HA*;(P5^RK)n(6A0iZrxW7iF@F;Qj+ zPDDv24)*txsgI)!Oig7OqAmBg#{w4d6Y4e*)#RgOIP{g7=&x=<<9|u@-W4s?aaZ!0qGgOOh8c^8Lp_7 z!T~qnL_$>r7~<^?kL`&pF!PvBgb0_ow@|jMWUo|+RHU-A3nkfG zq{ylWnMG7qDA^LCj7l_&C?m7Xtl#;$pX2-MkLP%f?)(1uc)wq-Yn<14p4Z>Mf5Rfc z!9v9jItgOx{nXS@DxE;`@*m_U{XRDIl9H6uMSgLTFl!=nM6^WhgJjiyN?RD^z`AS1(m5iWLiV3*Jw zW40=xbV;3o>JD+`NIgWXI_VJym?15G6`fX7goD7PXzn`kb6UA@sEyJ&r5T37ot zPs@94Np6Y-zy@&KboTIonZe zfNIi40v;xs*gEp{E7w1xt3E#XYbau$LfQtypPZZ~T=4#WMM+8em{QoLfB*qc1$h7H z_(XnuZ&wD(B+!QLBqTKcyo_-Ms&9d6e8O0_lN5jon1 zt+Ivb^*JdeAt8GV=kYfv`WJ}6%ZDG@;0rJNW5*!q#55`q_aE65fGUOeDGQ6q(NS4| zDKE%xwqg#GhwzVLSx)ED>WI+$`EaTZA!^d$@XnvwTVQU|GcW+X`_$8egaE6vrluwg z34L=rvPN>YYe`!Vc34-n^bsP(ViJqZ`~=AVaj3tU_ALqO88AtV$E~M_W(W<~oXThQ)^q(ZV-FPYg96*6iKe zJLQdM>uD1-m6)DhjPZMn+_+BexS%vPA{1tf@QG!vFBx9mUmvn=A(mw!z(9V)(wBIM zvz5lM`5N)#m&+&ZI?f77j?Q{I2C^k3Ea)3>HC{BBA}XNcTkbAQ3A}b^`#&wKs91C1G{ZApvq`{OUcM zJ;p6N^`FIljJ@=&^18exnMEFB9YmcuLd)TsABQ9pb4JSHVDytG?l{5Ly!pp{jZ+D> zZm8Od04>nd<0TS3_dj_Pl|2x>uy1ki9HS#6VMR=+XrNan)W|O{KMW7o2JiC)Lx5br zwETjU@Tm-CFFSaD0C~b6q!olzyc3}taVOQ+3=gS?Z(2Qftv`-#@}A^b{k&cR3&UF_ zx#Og%X<1d3l$coPO-%4nv*r{P(Wv=^DPzdk^Bu|vVkjoiBvC}jOA9K9?_-mzCMdrFpBM3p%f(Gln{5O$Nm++GCtVLlI_?oL*=25CMP2sn0R8vMRv2 zOeGWe(;FL^NpBT&)^G$GAX2;f3X>Fkz2d^c9%p%c0M_AxbJ~=_C>!yG`b1UJ@sV{G z`TGddfG5D)8{LDYIf&riDm+#lDVN3mj|*UiG=cqBKr112Z;%YJv$ggjog`h%sqB9^XR@a9 z@?#=3JS*15w*wTIPt+z^Do<%mx_r#p^IlZW|BFi?jhYK%()KQO`$q+jkEqM6t9sI` zSy6Vg_zMoXoez8_a+Yg9ggYVV5X}Dp#q~u ziH$esc5Q;;v{XSUdW0I3g)>m;;fNzzfoO@?4{1W99l|pnwKf?8?+6-YJY>)^1+V=D z22b?(-*QCZB-aM2Da<%2Md;)7;ctaDPUtf?$BzJ^4z+{xt8yksN8bV$n}-|=YDT2T z#zq^ES-^hDAFi&c`SSHEsKia6x}&Rt_xIlK@(Aj(vY@@5I(EzrBw=i>CQhexY=8Hz zvb-D~zFqI%gZ{P%#=yDr=YczRO}ux9P1NP_7@&eEe?c)svwSl)wmmO1HFa`s4s%f( z&NxL}aon{Bv24N3juro75<8qab&8ZU0^|j7k`L?Z%A|F{ZFu2^;I}zA7)zfiCyS+r zr0dxI?EiEJD_|`US`%<40oLJ2fmea1;LN#mbXyGIoDjTo&CMs~=LtN}(7rb^ER$pa zKu|QHAVNE~0JsUX9Z$BA$0)C${CkRv`S2lB^trEJ>n2rPaB@0y@L=!M66RqxMtaB9 zwgco>)?RBo_8a+y#66D_{f!K-0PQHj0;%NS;@;+KftKgd^PzQubnAcYSS3J7;G-sZ ziF$Z=fK)C&;j20XE|H78C5mdu%fT>2MvRDv80Be5cxil}12G0STgd28`D?hGJEIUp zVF96a$UJ9ocvu@-yI``L{|SjKUc;kKC)L(#i2?f@jpYNudN06_?I6(c*8Z!Gn{_+PaK!;+K>6T#H5qGS8PYm zsvmeU@oe#_q_xD&bMp19b1yHbkp>0s{7IyFsgOVS&sO7VcXAYk@cOB4Uxi`npY{*b ztfQq5KARYyUk+VbIvSX&2aMl(Wp22chF@#p!pW6D?W70(Cqy57een9<)0buIbgBTW z{*b5NzYip&!lsD?$XH67TJf1|vI_tjc7!GR5A?sSzJ&LLdINQsD(^g@5`nyhjxKU8 z4RZ{}rj}vY;lQ^$|Jk#62V1aK2x!2egzmC`Rx7K17eAt_GQKZQop%al2s+0=n!PSV zODR2dWAl{MXo--v@vsA2RqNb79a8UN7)~cYkM(t9V|kArA!$r{*W9?#fxdigW?b4~ zEYamF2sD^}kJO>8#?m6817^6EC>PK$XzeH5901moD+AxYfdxM^Jsm4xr_P{Of9Ri} z#(F!yHDY5|ow=!P2?{Ie*k2pP<|y!T zVs@-`@8~)o;=LUm>JoDOI?2NhlShWy0```i!=Mh#MavQLcp}uzT!u=w6Rh7m}r~AViv|o2reXr&sKNY+uK7@fyN8QHManG zgeo!0-)Obd%91DBi7XFhVoF4#edq37MFj;AJo&};u#^)x)~icbK81iv(}$8DNgY`r z7-Yqfsjq{BFJHZaq>g35ru}E@;qW3m-Z1sghqiY=O_|S5tgA9`Xf7em{&J{3k2pnV zC5ZS159HcZR$#$+s{l@zg#e^Sg~62vKV^PqT=%`l?gl=~qv>lyY0%ad{W(r4 z=C%8!OIUNIi};G(4`EdB5!LNB=uN^b%>soQjZq|maYgoou=oqm9(qc26Cgt{(n*eN zI(S528jL8b)7shgR=P1V^n&nNhU5|1>~2gZv1Krn;RsC5Fr1{KLTbdy`ws}iK%+es z7_Db1)f)zm(D`s%^ove1)Xs^-7WSEBeSAY2_B!!Zu=I=JVV)TNX=|AXZ6Td;P%s|QBU`a7vZ&$Jxey&NZHg+L_;0$>rc&DNme+< zv#=y+ehLX8QXez_x8l}^!=nH#K2t8RKlZ6w*1}P#QA^yttpE@1&V$J z18~MHwh17*p}Q2bt`XLfL!AgPE&M)TV-snlVI&jfzFiAXS$aE1k1ZAa3nLf)^!;k+ z(&_AGvP@53-Q(*+y@w3`XE(&$>m)yWd+2*m?Z zAqp;VU*Lh}0iZ!j%F5ch`?K}vVTFa#ugp~>J7nK$oJyCn#D8c;tLCoi%&*;gD?_53 zXW6=OCB7DJIwD4{7caKjd^!9S?wc}aotz3XGQLsnG1An`Mhl17hxsm$V<0qG zo}}Yo<<5-9OL5WS@!aXph@%$z?Lz)vsHmyIx@NufZX7R*X`zspOhk4Gmxn6F-eN1hrB~t z>?x2IU{&(+^4ZjkNh+7wZ7u-?f+`BE8BCx+nFJyP)+Wd|?2kt=JoXO=us>9P+sr#M z3T!_B#h4nwE{K^K`{nksp7E7-k0c7oe&va^IDi1~>nJEGdAPWkq6{!G8FBlvlJ`e8 zTZx4-t7}srg!mpUPYjfx*BP zP4dUQI>#u6RzIvv>2M96ji6i=%xP)RC2kQd&=OMV0T4NKmZsHwFWqPC-Hq&UfNblf zsLfop^_B2f4WLu1Z$1RbxdSpMur-Ht%jdrhzTg{fi;<15ULyXsRd=ewfu46IHK2>w34(QW80IyLMGQe=Z>{En5A!s%nqxg1?7{GqO5&&fV1&vV->DVNxp$ zX$*VlVI;FV#Z)~}U_fo80mwQP6_xM5rG0m^(5E1)_c_ah3ySfm$KkVUx%q4O0>Ga` zPTVdud6=(W|$8s6n^*sz?Ek@s3dG{M<;%IU><_6fEENZ*RaP8 zzd38Isuy<{LbMF`>}*_BdAIYBl6-RueJQXIf(%_#n5Ox5Y9VzS^_SLWtyYrK+w@Lb zub5QjRfo*qE!NaVAqNj`o|@m6S3(R9aAj#_#fIKw~x-aKQ4m>~gRA6NA@{-E!MkR^3rrqndiOJA=E*XonrJ&f z{_G#4&e;%t2|r=IxE|w^=Jq8%Y-ILrr~y&xSd`On%1$_`+qV)mZdw zuXi+bDukvqDTXdx2lIoTK2GBUIa4X|nn=u9F>cBSF|j05Ih#^+9#n!&d?s`RbXr1! zp#6mI51|VkG!7lA1$6d&%Ulq#paj8hqWz#-^sBJ5XoxZ^r7J5&_Hbv0gSs->Cj2Kb zK@|{iadX@F_wU)+>N!jipkg6l?s_~L!GW*?K;u;?YokxbNs*;SOD^Xt8vt}73=Blz zZD1X(f$NSSG6ir8vIZ!pjZ@jC5)v9{q#aL0h$uxK{tkKVacCjM;!2N}|s z=-U847ohmUQjzOII9_EK8Dr)#vd&Kqqu8)Qb?L0=i0;G1`9p8U7B#)?czJp@F;>HH z1MdzSgY7&WQ3a^MR&{vT`q(jGCWHyb|5TPJDBL|fkam5qUR{Qpri>fUMVXU(HSX?c zQY(#E;@UkdD6qdT{(29^E^cS^g=i~5I3a4LVPPaWemzi9;&JQGEo++ycf~`XgvrxP zo0*B*GRr+LJmI@%c@ zP%#kYdh;ic4(LsKZSvAm;1DjRX}z!u-0hVHQUv}0BBz=n13wgh0M@YRfgD8ND4=1K zPFzWS@hQWCi0^K8h`jJ}*MHu#4i(M4;t!=QARz*0RLR5Y@ZmOuDF_+tZEeG<$2!ln zX{g)B?J*?RZ65Vx)Ym(HoIsJm{1W}`?f7_tA{kiIojac(X99rA#FJlra%TPm1LtgD zJ6XOXscqkUp-9!WK%?D)iN8^m5j;0%zbKS0Aq4Rc#V^}u-{bFDl=bP{dV1$vfmZHvLVoK_voi}I7po-A4e}@A^PF(u!h_3 zbs_rt?PGzbl(6d3oL^G%T~kw7lZ_!J{TdospTCpx+_V9Q3A3J&f57grstw9DoxP&Q zoe-gajmmiPP3SAx-^!0Vj!~Zz-bJk+^;vg4*KxOeO}zY4Y+%uYS*3MOu|&0)bpp;q z2u&bA4PIQSOWtIUG7PMIQkoxf#s>ZlcQP|)r>2mNG5v40k%3|qqL=pp*2hbS7O(jb znm){$P*j5jxe<9py{h-%2x|cT`1(Rj2q24-iwihUV>S2+1nzFk2*fA|7|DlueF*!9 z05{4WH~`Jc927km*kP*}K;xmAiX=~sj4)!|)qJ?+JG@SuOANii6Tqy|&+p*8$F+cs zFt-JhZ!qA&sH!{dKy;JMi<+8xOsc^k_f}B@D^ePJ@6LlV54m@82Sg8Zn9{>1e)KDf zkjK#FR3I<^gOm&h07w%^UXYSQg+1k6Q&zSJAOnm~6S-z}oYu6I3z(u1(37=7KvZ~8 zfMYQ7#(b3`g1C-Akq>*n&Z!8i21is6NN?z-BcDAZEP{nE205E%@T;mS0uBfM4kl%B zHz74q#uW1ft>FNeZX6s3LB~e12PNkeFfOc`zdgL-p0hpsab#J4VY}frqe+!mEa>zQ z5h9@_qAmDXPWt>aK3~Az78$-V8y6Jx9!#)MK_JC8z9fI9)h9lTQna^Mt15+>fdLsf zBq*p3v_2qdn9Shc-Q3zjcF=Y_(DIjGMB&rN$rc1}M+a>4Nr2*3gNJOYoq82|tbvN~rA5h$)Z? z!~Oy67R-O~!uLr_6ATRHIq5HpG-!!ZKKH~XJP>T4sbDy*vK-IAK*grx?1krv*r9=$ zFh~IeGlg$2Mxg|P?|o6x(Uod}oLH=ir}!6aa9c#T-A_%0xT>=9$kC(WPBkxHtiiE_ zyq7#7DD@Bh&AaL8zkmIz!uD#sE}2`hi>yhCUcp_*BXr$jiEdoiq3qVw53)Vf?z3-= zl49=&Gt{600%1*jfeJ+5XE}rgOan)ys2&>FJra=RcOuFX>lbWRpgK**Up61t-6$EH zIv_Hb&SJM*noqTl`u*j4M%<<|zP`Rt+5`l=0)&f61xPo5Pvhzged~huX~_A7wT&4e zGl3PYxnMopk7tES4Jq;Xv17^i?qRsif3p=T(B;L&$0a4v-*3gl7=U@RYnP&&9El2A zyfYwoq2xeU4zdd9qTqniv{6n{_6=oMl3KqYP5KQp9f(d!O5hu((9?n7HY$bEX+#7t zp(>ag0m~dCe-U?qX#nl>#EIyGhrv%Ei73J_NQYP%xeT1C;#aQ@^+1K!gkJ$CB5e8M zU^(1tZ-El0t-Wnx7UBc^0s`PlLmA$JJA+FY2&cG) zh6b>G@;}=h7BuMrgu8*2dV6kSW(jO;1?L~0@Df(F>|Z#sL8uvX=@+MwSb**7>%T!0 z1fZpG=ZL296D_@8S5WmeHfpYIAa5mA=p7Bod^Mzkm6BKL+rl8HXyA%}`zQA59>=_0ng5TseJDG3`nO4N2e9V`y zTtNwmZ(qLb2Y*^nFx>wT$$K4VT?2zj{9JVWkO(KGq+omo3oWEnDth`0Wfn5Cpxh-V zCBb?Kd{okS*4J7fJVDp`1#|}7kkFYdRlg+Q@%Qdc%+BIa8Zpsxt(|yQFHraJ-n>u_ zY4#PoSzJey9f*O@Z$SG&Q1Ezr^5dX-^lZ4G|NFg^#201b^0jM!Q9 zzGLwzwvpp+_U?UHSUA~wlMO)u@#Yl>=Y?K4Ihv0#62veJl^-%cdEGxiZOgt3>X{NmnRrpi8xTg}mqgBVf_U)vZ&XF0mb4NIYj8Dw9qdlr;Up0@ zgB1&SMm8;>(y9jzeCX(SjN6A=9kCH`En3>meipq?pFd*}iBLG7O0U36&R@ilqFph0 zH3CyiYn10U9B3$xtUDYqOmJ`(3=f>0o(`wE{6wqyxs%~*?G`$v`?@aSf62YHpU?T~ z{uV9|PwD;}ewSByAMUR$udji3Tcdc3{SJ|WV(NR!Kx#!=FEh;xO+5KxMbDlQ#B3-gu`E-Tw_tdF7;I*P0!1c+R!nU6$#G-$2 z*pUkWIALNVBq+FFTpX1K3KFQVpdz20o8x6?UqjPuBZm#8u(1DzgO17%UlCrzckx0% zw6H5P5gWTf^mf8i8NU$7&S*nIofvoTCU~eKLlgW%p$Nh+0q!3X0+f&K?FNBCHbOSU zgu)Sj%g>*UN($tvefv7zy^~Z`-9+PtVGwFvqWwd1LYasWS!?ImYwS2_7a*>dM-%w zD{*=emLXKaAOYwdWF@rn#(yisTY77~seJBE&%P);MPPS%OU$rruS1k0X$ z8}S^D3ZW$>(o2!R$MIsU@o4d#K_(m=r4M|b`jf$x4;BU&FB%;?2I}pZ`oM#6`Zz7Q zz0T-@(-quchWHKT=}4T)p+kf2E0{76XvFv|Z~&*(x6#6E%c08Bu{Md$;wb05!%R1JSo&wY2pz$jZ`<;0q`s{kVn zMXmZc-^6#p|KkFjA$Vn?$fu%$YXeRnW|0-8rG%Aj=tA0i_!3ln691W2>P$BTJWZ-6 zRW3k)M1aH8k|k^}Bn|um0>rL$cqfQr?9L_N5_w^7(Ob}n$^=R)aOHy`HgEOVyO#GUK zsI9TR>M+VtJk4Lk4zw>^ut_`hHPNL_Qf24Tg*$?!vb|~ARaC{O0@&Xp1VW2}dKe49 zU;=<`a9;a8=||jmq(=U(%9V!j`z17lkFj5iYqG&VE5Kp$Oh6S1TjQy*u>-LE$__zq zg<&n$;v%n>56&Q6LPAg23wU3FR*(X{2sqxtb;XR$dv6Pnur_C)*1)a6$t3vsX@mnI z!Er;xz<>!OA&?i--))DglQQS(^VF%c0uXcP9ug7-*J#flo;Cli6y);x*~ zcso@g)8b?QBNSnwWJ!KLfgL*CK%6UkpECXc=Di3$FFY_(v$M;^a2%h2Nie|sq@+GX zG!W7Vj-U7MbDF#6|F%5U=TBg1_F5R4cDLL6`s_?^D2so92yrz-Dpv^1D<19b$;4+~e)4qcNnV8%DX z_zTo2_};dcMH@Gumd9IT(ZjKXogbEB`4j4qSCiiV&|>qC5C<|82b*l@#aK#Qz&w}o za`?a@14B;_fz#xrXGWq?Nx$ap6H{n7lk)RXrz2Stb`u2#s>)OM z0}lE`yZ zuY*-_y)`v8@vaa~6RlDHBYwcA%ILoQjV2p3XR>LAI9mW&r>CbkHv^Rq;8#a;dVSNw zVlRj{#l>f>tr_-DDNQa3CW$A-*E!fr# zTSr1?*=G>7+{R^-?5UiA!-1!d1R-_=%laZeJC#{L837*q_0Z5p(EW4d$h?nAXv4s| zJ!PL6us-nr(U9fO%(%N3V(jY+8Z_y|A(43~gbZf$SO zqk5^B50Zc204o4N2cKca&t*B8snzqOgi#=; z##9L-6ny_tEP2j_ml`U3OcD@Y=RcPWgXsd)ick$Vf#qF>TaR3a#~7Z)mVt-(2%rl) z8AUa%r)Y{l<1ne}CqyB{|e+2I7|(0|hI|gSS0B3*Ac`MO^%xpNk$n50}5PuTcx^yVW&Tr@O_Kv z{0Whn=IQ~?I0~DSrCu1+!-DMD)29z>{(i#dHXM8;7b~kF@KUl*B4(x;7a%{tf+6MZ zU4%+xZk&T3h(M?X&^7=UAW9*cV-=Iz;Zx<*G#D8GI)bIyy&pcb$m^jh27)~Kk^EQC z>C<Mrge}Kcjc9`T?iy-_q57asyD}T`Ft`X*Hi?cjLx*T+Y`l$0P7W`a_U5Nf zg>k}>NlZ#AzDVvKv?HbP;_w_I9*c`s1Dy^ z$MD7!>cbQwfA!b)Ak(2%Lt%v;4gZU}6F(0B@_jJQL4=cakn0<88wq+fr`FyGPBgL} zq-1EP+%8?JzcLXIZ6iF7LN;cV29DwN{Lh%_6+DFCwMckW0D=(2(LLPi(39yYqo1I( zz#3%s>okW{R4gR!q8J-E)>Fr1_6fJ)$Y*usam}ulWTK@5pEAh=ky^#Y0n7mDq^L4N zBm!xVVC-}16g&?v?2cv@iPU$>K8mc08^+JS0P$7Pt0Qa{U~xrE5xB)n%^nGlWDo2K zI*4Of$2-^H!k)*#-hOAvr()0@HVdHbBA7ug3wV@Zgbn8>ugXomJoirYet0+>QjP*OsF2V&wR98B=Z*Sx&I z|B9l;1BUZYCB$&3V^D_TTKM_;u3_O~ivV+X&mf@G-&0eBHBfl^XrvJ@@c|`gt0DE% z($sA1>nq1+qHAp==07_Mj2W%O$!mS)Xs=+I1$5j+p0oBd??2s!yx^it;rvg^ViRvd*Y}YOkU;%lpEEy)V<%MqfBgU)&9$_o|bv0 zlv?%+wh^aww;1<5v2N;VHW8inw2pqxzt)JYxWd91c`Rhm(9%Z4Q1TEF=^?=Zj0g%+ zd(FsynPi6C;W+Rp&QYnKsE`M(WRc>D<%fhZrVXXn=i!IqS8iFLtV*=ZUP(wQj)^-%(BuI9VcQG z!W#M_FkBENMwoYIF6z~@wNbY36Z?YsKN%mHE65R;!iRc+?4q^6Y^&GU-Tw1341zUX z$Ziu+v1LQIq>Tmks3XwILi>p-p#~-f?G(!F_c|errMR;@NH!s#=ro_<%~L-aZ$zEV z3%I%Tx$$MfojZDmHP{Q$78u-3<&{PN_;P5_gE{HUNYJQQn0kj@nL*)|^5;398#f+N z^PH`O5ueq|%X`r;Be}~DWzWy(y6UYt86e+J} z@gLKSMN@PYV0&;a2xvD%ZC zJ`cYKgwT$U!m6OY!J3Qo6bq(Voy;-qm7*U3yK{*R~U-k^_5Cf2v z35&K=co#zwpIJ2o2mR{efCWDA;EA6ETMk|oZvzt(Poz*Vsey0-?M9Djj7Wq2*3WMp z1N1c#a{TyC;4~OCBXPpO`8$fiX6mCxMv@>4#l}LP5)8#A=KA0j!d9Dj-5i*fk%7Sg z@HVtFIF=w?Kr8NrehL&-b!&>)3_NLIW}UcIh?O|w3JO<2+JjFIAn;rRN@+C_B> z+@R4x4hU7L^FlxYUyo@!w`1Y+e6jtIg>-efW6V0D=X2!>wiiPVgnp~h&|H36CW5nI zOLVqi=Nd&SF%`cq6KjFBWl3ld<e3dZj3;nhs!X4JrmaXSj|L{s8RnSL=UvUR+rCwOv`N z;V%FYHqEwkO10rAQNeiE<;0K`zYFSqRHZ;9P*>vl0bn6WGEeWx=E8gc0&Vme3GMBy zVZ`CoG*a##ONpt9(9|w!Xs$Y6x^(x>9rCa2GxRT*oVC!{i(@^ugalBKx82=1(cSOg ztA}h8#BF+}c-QDFg3&+#2LnIgBUm7S@8L=qI=4;QS;EjB#J@i_7m*HSHv|7e{w-O9 zz3@Sy5s;aMCX+u09{?~6r8IU#WrB4@Xw8UcsCq8i+vgzvi=BAmgStA`twRTF=zUL8p-iOlfIO{kD z397fI4x;F%uJ^vx;a^ zzBb40`wfR4sR(whH2cYG)ldG&F(=LB7&+SX(QL^-xHCwbaW~_pU)}hYsjJv&bGu3g zkyVm^S>R?A6gc6~1EOXeLO~7VY}m~$=RTbJy?Yf9lyKQWbRNMg zq@pAVC-Y`GaiArGc|knl4YlZbEiGFVJy3)p@8I?mAgSqTl7~;B9YcQ!z23WbM#v_} zoRGz#4MvZK+lV}sdiDCie(bb7cyJJo5rB9wG3MSCt)GWgON5>G`}Se_rwa(=?c4o8 zHgMi+pMo-!3S0!;kG;K+@HOxjK#n~J=|O2Hn14WbL1cNoiD}hE7Z+*)5|~jYB|)$- zHaq(?FOPJF>FYBhPZH%&6bfMA+|Uwz-4&^a(TFqbC)QQKhrsp)4ULB5zg@TJckR|B zw@Pan{RV$Cj2l4OK_P~>hhH%0&-e}CI(GjOIY}v8I)ryEr0htWGX|yT65Zsyuw|Yt zzLcy@u70=QjOAfY4m36!Fm{MFIH(hdGDZv80W>ub$zG>F6r09;20`6-0CHroP57;u z){cNYhSSEm13=G{?Uq$@uZ}&%lM;;&PMX9-#~2La(E}D2H-HIs%IUe}C^;0!7@Fe< ze1Y_(X$MIc?F}xCw~r6WngGX}$Sj?NNV39+OJtBMqS_}_nV+6^y>tnT**hq%fq~!a z1on=^jh7PIg7y)0Xbh7^Dz_Em)}2rh?0-%L>_u39`~JPup+j6LSvy*%h_5t_G@$>) z%L3v@b~!wdxzL8}unvj{v_W|0wuv3QsSDC3vMb1!p*%>?StDnChu#4sA#`GB_D5pNBvtwgw;MXJ}dsI~PZ?adY z@gwo~N5#eBcu%>x;T;YqzMl$gw86W<6le#nDRNEIcT=4=K7)Y|+N@aKH5_WcJX-Rr zzIEG_pkI`eL-ZrPt&Jwb$EOM@1HZqXDXLFEg(&|M`i_{Mgu)Xk5vquhGE{tc4G{F7 zID59!u>y3^Ah1eN7$&^Mc{llpIeq$r2fOB?F+l)#2Qp7^M(S7ZGzq{q0Y{F%~DFEgq0C-wr`p#H>6=T*>#BDbE{oyFBv80ZprJ_Yg( zM^<^>G(3%=yh_PuwJiFXXmRuTM%obu za`GrJUPVPk;e3JIh9QkJWPHebNdEIT77b#P=b8RqZyWnLF~PtgM<%z%eW4hI|`Q0_S69zA`E zQX&nHQfygYlU#WodudRxK->>w3+Ka7zJl9bgXw2Z4zUF|7~#3c65;+Kc4e*zk5m;MRL8Xteer#a2S3l|yG!NJyk-&uGia*J6 z?B-qY)NQf>4eJC9nXv2_2O-LQfpe+|FWK(~&E9z>Tm&X7Ap_`6dsz zctdPfhaZ53Z4H?i=!FexE1V)0Jx~P+b0gr0fJ;eF39G9Iqn>I%0=qPGbAo~X(yupYc0thWk%hqr8!Ic`&S~huGL1s~#`oo3Tl#D(=PT_^7i4u$%BPwc>SIMk z3h$$ncfa-ZUB>OfL!0Suv5|qtF(w(X>+eVD@%;@$9Q6*IA8;ul)1cjs$DIXe_PVXjp5jnsVxnyGxIwb89LF<;K6Vw<0ETF& zFs~P2yWMIB|3~4Q1wM!f$l&+|Mt!7y zy}afSyez42)4s=0Y`i`^nl;A4(69@ek^!C}%xdxxaaV)!1_IPbC)9Fqe+E{oKl=_v z{M)xQBaGNYjy&pzQ5Betlfo5VWBO!|^TdG8c%o~>xkG0W+2ye-8a66FXJ=u~#-Dwj zOziN~Gk9;KI7Xg^n&&GDrmtUNe}*!Tpr~eFA~4Vq0Ufn$`u6D&R=^-FVhr01yaAaF z5GBO7wcxq}dEG65zmEd&;&~X?DP}F_EH+E*wpyARaF<-Y=2iaK8jmQ!w!Nm`zw=eM; z($l$4mTTP|!D1Ccyb8RGMg`BCFc!h8nQVU$NI2epwb>2YKd=XgPc@T=P{<=311X!d zAd*c(Jw>ol!Hb!6!$gz7>`=ZB)&Q(ywhgnwe&Z$LlTeWn^rN7ULVr>VKVIYlln<$M zw$9FLFx1zHX&D?`N1*?oi@Il@z(c+#=duHJsVG;-1MiejPk>&_%|no~fVV(R)oQ|` zfUXN4*2qDea=ugzQgvv(vAF8m>=#x>M$M~EVey;_u1(?Om@&G#y3+2E0EZv;X>~Jbk2j2g+JU<+Qij$6lwDFm&DF`1Qo0E)CrmsiDPg zG9TP|)c1%ADgRA=Q!z5dQ^!1ZfuzeX^f-ty2-w&u4<*iJSc?pO#Y!IogBX}m@k<2w z`-7r>AkEOEqVX|VlTKT+0TpxXHPGuy~5 zev8ipi#WppO_J=pVGo1#yH&DwxaQY}G_6Y>ES4}VJRr#|9dw7mE&#Z;H*btHRe-Y= zC@YbZG4D&ZFk7{L}^GT9dBGhwtkOR3j9Yc zsXcn8s6Gh%kxQ52Z{JoraDW-}Pt_>2*r#2}d;_McG@N($pNm-Nq~rW5A z1ySR1vM5mi0|1`l?%v&l)ixlrl-laRSO(C}!U9OD$lqKwmSE>dTa=FA))9Qic5RM+ zIDEZVjO5{%IJ<9PQSSu3J5gu2421(TS|e;R!BEmTP3{6d8B(rPIU=bDTow1B+A~OP zND_K_;B!faDpJQwij7lD*qfW*%gD&UuZIU@8wCywwz;9mz#As=WtJ$$zl`+`ra)be z9(9F}DyVpvyi4q%jZ^X56&|mKF%@DZhIgcqWG<_@$C*#lk&EYh!AlyC8aY`e%}_z1 z5}OP&RQ)dZ?eKc^5J@C`Q!KL)@W@j??$U@mbJ>&3uwyg)w-8c|&jW{Ic zPWBpIcJ65O_yu3Buqyn>K{CDp6@n;K| zy*SImJdkVny!x0?K%0g}zQO*r4m|BWl9u^^V+#wx;3i;#BTb~)Y6E8&r-#3bM@L74 ztNpt5UHgy!zayY^bPx<7Jo>y|XM&TS8#o)e=sXccHPXkyxbP+Z*oo(fS6%k^=E!iEI(C2W(he@R?g zI+_6$1{jPXYYVnW=a_^{##90gLlY`xQOXbC#DX5nPMqQ)LR#;`ulVHYQ?zrK>Y#Q* z3;`)#XFtu0P9o-M6jdSHftvS%r3Hu$4|a9`yo?&K(?$kDpN_Wv`gavX5vse!i?Ml4X!wh)s3Cy0@y%D5n)^a@hb6+SWpWx>B*@jhHW$s;% znTUU{9nf!5V(3WmJThF&vV79FopeJgWTu?|Cee-(vnEqQ6))@iEPoLQ1WGT*z7urZL ziYuD*m!GzAoa@RQ=9|C0dhlh$CA$=!k*&=p(w4ewmkzFG{8jT1e;oeC2SXzyZn4x` z*On`Tg$|{RWxh^7=kodWgWW?%zU|(B|8&hU7ngnUY-^K))ua_Ur4#nwITyXS;`BGU z+njw)Hmja0U%7oalwq(l@^AHnPYwM?_Hi%ZR)g<=p|#)CdX-U0cIS`BMQ>Q*Ta|hr zMawpgI1`I2jWCn@(DmnVA6RcJB7H)s*(Kk9`;EOF4Re2R%*_*}E1^-k%JC80B{tXI z444((x%KkGqC-zJ?J%uBLuQE0JGzzT8o!wio4ZtWM-Jb1eUV}Q`?}Q4`j+SCGfrI+ zy!_?)zUaN)agE1u@4-yQ5{+TM2_91xDD#IxcDB%tVtA_fD8_#Oz)4#CJJ>>W`q{ZN zCMHCK<0zCCp}RmNgaokV7MWEso3FIapGo+@+!_zt$LV`3JM$a(VtYE_>xjiy^+25= zZzEvHIVK?b!-C5d!)V-wQo;8$bn#;-#DGTLhD3>vF9epCT8s#Rge6B%ORW9-*I#VT zFysYCXpC_QM9!o3T2^uZ6cCm%9MC==F!`g=jI)O6$w!jT=RGZuP%gex8b(EWaB`0p zBOncQ&)Aw2fI`o(SNNEGcxD%HJX~^lgfXPkh{NcIyS zfEY1ApPip?0L~w$4?cAA-Mdwg6Cm{aNZ+co`F@1zE177>r0X_U;@%%lX8z%R#3F6n z%y~CgC=FexuI`eFBcmIfB#$*?GpwNIZCH?2ej*`5t&_7qv)kqeQB0jv%h4t#BI!7z z30g{ro9VVzZW4^GvK*(g&0i0fEs(}DDOdj7f9{o6z>B~I+E7wXI*MCMW2x;b5^vl5 zm9pcustx7J+=Xx|%UrCY+3S2)zQ+8^E^-NQ{>QQJJ>DSAel z!kIJ`;(Wg6j9shoe~&*oLzzc+PFbCEjeFanMPyXiHu&a2^FbDgb9yyGf&K1QdkorW z`t7^AqOZ6+PYm20;kL@U;`nf=Vn<>1_21H$?5bz9d7l*t&h+xIIJu-w?YhtNTw_w% z^MLazzpsoBiHh<7`!DfQ`k7AI8?uAzQonDZGlv(F-@r~O9F|CT&6)8x3Fvcz-K zN=y0xtt)NQg*_e3UL&u24nAQ0R7(F_n#P0wV^m1xZ3;fMboPX+ru;5WW;dmk_qN6e zd74GGjblY8DpIiAj}&}BK?mve{e_zel2cTC0#n}DZ3nt2gK;BUNw4~B}-B?>&n){9+9ao=X zxbo`40=t4M%aY5Qr|qA%Qx29V_TMo%P5Vy`A`!H*_ye!1#$495Y~(}jv_o2q*?cXB zS{}7|dwMRcu7U(T4>F0&oAWs)pva?0c)v32KgiJ>fdNBTd;0*Gwcj4XvlpNpZ~z-` zc`okoYg|0u`{=sgtjDdNA6+KC5S25NdYVl1!#TZp^^eEO1sGVVgwtCU*nHaGgz-MA z=Or#Ra5jiO+~ zSA1c%@#P`jJ;!%D$-N-EeOU7b$#7I3%W-Pjb6ae02{+W`xah1Kd_@9rvi!yh` z8MOgwUR`FJ`({+T%!@xUM#bl`p6qRuXG|T-q(2i`Ntdx&evH-m8fbSGdo;me(UzHeG((lYS${hPDJLOP^wN6lDi`sumc{7rq@k!ijZqc7t(2S zUnF!$vDVIQbKd9qYT{W*NAK?}uHzN;@>(`u*h(0e&T4F@;|!SRw-Z?6}c8K4Ikb=CxLsVJ^Zhg&|~ zMNNI=_;Jk3Jkfun+aE^6g_I0^mE8&xJGB-60@fX|!;f!z+8>P&MkqR0&1)H4D>-*7 zslu)@o3oqAFmJXZPlW(3uyEOxUungoX2K_BuRqi{zo|VzV`MLFWd< zmk$f3QHd}42LZ8b_%~e)B2hCPogk6y2bG#{n)ixL#IS$r{(}eGLjm)+a48dh5V51a z!%|j0%M{7z@0Op*!9L!esp!V8GNc?`Q+Ir0;B168f`mkKe}$t;23M0>SYBdH#TkCf zq~b!VXz8iHjsJ9%k6rglR^aIP_1os6eE^XJhm%|yECzpnDyGb&usG={$^K|tIWLsO zXl<_1_RPabMQ+c1Mc(QWQWUB4#M`eQi+nqveLwnuzlj z$;uBz(~W2(FEbuMh1>Xv`ATOQ>!&k$V&0+d@!Z%TL3>@5QD#BZxY|nGS)tW<C-FKrs86eC1AN=L45sH=UihkHp32W{~86~a^+8>DyF8Ua`VJ%U}z`n=6OQt{buJHP)FEuU@i zVVjW?ID0H~qcZFIa`FE3nCuV48&}tU*XuMswR$tS5M5OPYujZg(pgsnQm{Wtl3l`5??2_fwaYyaV{*n08+=h)r=4p)kxvEQw3%`DBypJ#K-#Y&AFUQ~uiLZLUd|s~@ zl=p7>J>{IIeydt*E?3O|b-lfwQ>jIrEP1)p_(5G6x7pQ&R<-?K)#kobB8JlCjzM5) zwK{zTzbY=#!T8SZZZOW5eGl3CIZph# zVS8~$kLmV~U2#}>4B_9#-ivdixFrGttm=-$=rAE7l= zkya0X;-qQ5XE1tZc1zN>!R)ZF1T@z`y7|X1eFBl8HE$}l`Ov@tJHG72Fre-j#`?m&qa$5M)Je2TKx>ZXyQL)-YG@=o#g59p&IE{u1=|P zKsc|1P|oR^V(|A2lz!H=Js{^c|IARiN)u#eeQ?Hh&{Ri}z3F)1iE>H-t{jKGDuYMz zx{ecz4wN6QEx*g39$!BD;a^bMgXoG0do|P1Cq*WuM)!D#tv$J{pAA=Ca`7dFm@eh$ zLyV2TWQ0`bmQ@Zh-@QC~6f{AGL|y_bMOiU)i-mb6>93U$$z_hFv)(vn06YJv4#TLC zF0z$e^{YgnVeN}~Qjdp#>ySj;QCW=K!k88~$35wWP4JRaW(^njjZqm%zmg24&1K(~ z5rDa+^xUYFZwLAJYxy`BDtsYIz1Pm@P>-K&Z^|ZWA%TNd1w`%o~D(0oZs)d zyGI%eTgawaZ9hFZTHvg^9Q5>wsrQGuv}W9&jNGf}eUZUxdiN26|> z1y6xrzZMat+~Gq1%_!ZgObe5u%p4r+Q1HG(cG%yA4KEO8N$=Zt!+vw5mnW;ZbR@B~ z`tjgxiB1i3rh}o!MoL`jUQR~~-_nQ->u{FWHiLD=OmAKrfa|&8hWU{Z8F+gFzQQa4 zR1o*S@&=zu$#+F*_hLYu8mwi=^D4}}F!#{uI$x_A?afU*PyaeJ$1A6p#fnevNAuB? zN_w7=B7#YQC?@T&6Ql2s$?3}=OjHcg9htJa)aQ1E`GOBC!2%US%Um&Fh2*FBjHUS% zQ|=qY5l0+782<_iiw=iB3k%LrTe$x)$a7T4+#8YisMk5t`~{*cBvRl&VMr9tPhhQA zbgRQA4%kdsmwxJd+LTc~Y6TIi*?`#O^9$9sTl>%K6mpWLep7>b+>HR;eRa;|cinLetC$+YuL%#H z&o48cKkq&?v`-ga=GUDi(v)j?F$feEM^EzdzMlN`)7aB<-w8pJ=>n^b#ZmEvQU0Zi zkmW&`lpy1P8kTkTf{k#2`HQV_3vUBL_6f<;y*W(Uh)D1j=nyEIu#!fD956PBuY4GS z1VI@}WZp*oebL`4?tZlh9Bq@Y>)=+5N5q7Sirm@`dcs73M8 z2W^INg38hwT4fG3ph%EmpfeAJtNZxtxP}^Tx!GVfw=Cm_*i|q{*9A-hb_Uh3(*3)5 zf@pNLfN^j#&`_u;)6~-;F(Pc>#o~4s&vL6nK!Rs$4aEd4H#DOA4$SQR$RLnIV`|GX zC*E-4&18PE?}`^1?#L*8=f1`nWPk0v+XmgSueJP{wB{rMa_KlpzIWh^YKpqellMJ%yG!Dnl_Y_D3FMq^uq4mNPT>Jd_7}mz( zlwOsOe|67&uJB4X&bTQ|IG~G&ho2qVCr@)ic}ov=iM80B_4Xz_@LTQ9qVWVNO3>dI zomAA)bDBAJ!tT^5s8`@Qy%5-z6o0$SJxwR zWo8l!M-t`1tvwIaGHGPidl^0JVzYbT3C-WuD&{?Uv)Qhk*7V-7p6`KG2aR8N3p{XT z?g_JHwg2nXZRWiC2TiFR)LQTfCThCYYRZU@i7<6L`x!uTrY5 zwdd20?lQh!&e*vcfUM;|zq~V}aY$hIN zMWu@HpUjrZ;9+otTG!S=GnP&F>rK{yPitSM5sN ziQ7)TU!F^FnqK>aQf;wOX=Mt1XngwdzQQ^b|3(o7AH1(}dh#}kn-;0w?WC*&8QdER zKmoMBtm`J47_Av) zBOTX8-K%&D+*FvKtqgDb1uN(D4m{g-AhjTHWSDZ)JUK9Fg-<1qLC>h=sKwqmX86M7 z*gNM84%g^j8!o}Kh_(O*=V(V6f(C{CfOYQZtoLW*-0v4sGU9YHVdto!t`1XfOyg$7 zg@uEL@a5NE1uBhIqyGDA=XaW%l!8kf$SJ6ZZ}C6t?A(JU18(txu%PHw<5kDZ^54+5 z*~_df3}3_3iY|ADy$tSoV2`eqvqpGQ(I_P`&~oVNiNxHvP;aM?xwVyVoXErg9yoJ@ zR*g~wBMsQ-a8nZEmsqL5;eCNMG@L4-1B&fdo=N>qZ_o^cp#f&9ISoxrY=hg`rv%q# zdNR+o#egxD)!gOMmkgTC5{shM7H)~XUuT$%1i;C)C{9T9LyD`-u4JLG$WkU2TW8%H ztv=Pdn=yX4&39!Fo+PYg$ujbDj2ZyaXz9^U1|}!cUS5=!*8&-u%L>%29`b`=B<|9L zK*w?5VYX53#reVWr-L~&&vPvP<#?T6Gr!k5&|i1}pe9U&rjcKr=DlkuvX}cRc$~3D_E2@&m^(RI-Yeg0rk6@+h1yggn(-y8pFV-T5g6X( z%MQ>Z!JmVpI)zj3r6=#v>9yvQn6)hr^*9Jm7Lr+pIS5uL9N{^8W6{HfwV<-^t0;*< z1)^2>b^yy()&B}YfrZ78!bC+~SS8vh@EOIeTUK7~SUiAFKD@xZ=IoOnpAyiGUWRZS z2Qx{=;UxqTc>ZXZCeeeLo1Z7F4cAZ>Kwbr5paYjUXpsPcW#%uZEuirZVd>w<($G8{ zN9!Gb4N^JDs;YXcemp0#Z!f@o0UYw#@$v~6N7eNA$1$e{1z`yC2k_lcT%!m8_Cllj z*Fbz9IZh|buHSSK{3nd10&v|$Ek-3gIT?E8%6cXytG48qOKd&U;%>b%aXLsSiR-t& ze{#F+kNcUle3?%R%*h}|;OzQq8r@VbY5pnNQ%7s82+!w6oNd6~VQCEa*A5-k+Iqv8 zR_BdBeW6$qb7pxfJ+Zo zB`8%KYPZknbpdZCJKokz>d(Yx01GG$!uFqD8SE8Jxx1vuwQQ!q&R0_m(#H)u7 zyYQR2-RQ+5t}1g$+CAv008JTksM`lFaxYI{&DpkXBUU@`mK_=-s;WZb(6AnlD} zoK}QFXc+~h6Q-!#RH385-fk39AQ^Qbzpr5<0aj=uuozPp`Ma8F>Lh z3fN9HTc-&3;ZtoeRH5UMehB_gL4l-O07yxGS2PM<+ZURsU*iM29He@U&7L+J$MJcQ zzM{!aUAyj?SC&0|Xvk5ILk%U5^=8WqBcp^$nKY{MTJ|x% zPiQT}0qg*78Ax<+5aE=m^Ej6qxZW2m8qOgoIIKM6^<_s*AMWW&4e|KWyI-4fiRG(X z^)uScMF^^XzPq$70DH`wKg#wumD=btw0hNT$0(mp6sdLeiHfz#A|r%@kn40hXnu`tP0F(%)^jM z&VA{2L?{8%1k^?l@Bn!RS2!#m2(AlW{y11Y6@;%L{yhd7 zp6*?rrG>%{d$dG{Fpn^VbsO0F*o+zPWsPkY31?v(gF0cP!322`bYrlXi%rD97eUd} z1>r5oH$zE+0s`=3`GVfsf@H&U->2O9PMd$UY@ALMKYV$x z_(1$$LrD7kIiX?11yLuSx}D+^*mEdwo#kLosyHRNF2c0^?@%gT1ozjoLD`vK2OqC| z*z14q5P7TBDJ?eva^KsHF=RngpTHx1Jy0B`|vI;>dew~*d=jUhv>oyHE+H^P&7bsM|$S!YPfzuYjb z$WY|nd7XgzX+;?&sw>&C$oiM+LD8Gn0$fx%)MUmBdFsY@Uzfczs}CDhQ3`;#cTsy2e1K{z>l` zaz6-VQ@WA0-)l8D!=V|}9NQvDL$igfsY)>%97IbBc>FkIawAH=O7Udkru5&i44pl= z1gtD9A*)_l6~YLPOd`>Y*WpZqBaVY_fi82zFexL!>>h5BwoNB5Oo4QXZ+c$FoxirU z*Me{8+qXdw$B1dYo2AmA??VZTL}%%9`ZcgUQCn~@t;qt*Pb08q2=N7X8R$GP&npJs z5iDHXrUdfOXOiAw!P17h3Lpv|QIKiT5u=reOdK5;Sbke%t4#>O!#8bb+X3>BqGAP( zkECqCTth@Un`NjptKhMjs2&x!NR=w#`#WqOi+#Q|pt)Bqir?_O(|ggmQDf6x>s#uB zms!bs$X-SKn%q}IdXjRk-?V(i)8l33%vZ2$?4~I@Q{u0iT-VMeZF)_is*|52t=gkx zTD$r}W&o+Z-Q>9f#Yv<@!tWyQr?4QxgqNs(0U^MFHRR4Y^!wmnGy#60ZFAW28v0QY zi6iUNJy19ir4~XiCdIh{TZ7I75mxuekxgnF%nmRynsnE4Pc1Yz8F)-9x}G{UKl$!p z6aRW$1xVl*bZex%k{XrXEx55uy51EEb7PCq+KV`bq6{|`;n9cfsK<4UcX7hRgkiVX zrwb%B+)Oa ze7SEnFX)tB8v$F4EnoZ?05SE>eVK=r#ctt-5=`q@+IWTVBIzSb~*?siqfv zMD#(e!5T+ywR@1BK8)O4P5-HOG{5FOqdEyFMd4;8C-(z8gLN*)`5=0vuwVpP505e& zIS#tKLbAZS-`gEVBS>-Z-2)(KK{*&n_6VBEmjZ$CA$YduFAea4`K>p zg!En{!g4?M8xLB8RiO+5Bc3{_KX5}@l~XpQ(yQ+u{qSMtuF~>oG?pK53Orco0SE2~ z9xlNuf_S4KCU#|bpJK8IyQfyhMxA)K7oUf&dQSk#!D#^r{aIU^u@DD}gh8Y)IFH!l zY=dketuPWp0Lfp2jm|RMM2rhn%z9(b=~h{k5LLfc7J;8YkOnOS=yyt(ql&yX_9c@_ z-1gKR45=cqV+VgmA5mH+Y!%Ui1XO& zJmI@d(n1-ZIaMSO3^cf^CEmDUBe|J_sUGPw0ww{AV^`4-z_KE*Tn7GwM_Gd5F2RcI z&3{boW*Q9A+i!JfV`E=yPRkL#r*faqH7U_QNyod#=p#lJ7Nl(C&Fg`W{rowWk8X$j z`SB|m86+jX$^$q>s?33RXSD-JR2q{+otrmipI&CimLpdqb6>T4;D!1XcrAW8YV=^= z6DAu?@Rbn}LHTxt3v!1&pVHqa?&@xxi_@?1zn7Pnk#WXB#I4gz%rJ1d}={k96CUpciq2bp3)#}XiVziOkFq^0hdctNXTV-DWCOMpm|{vW>`-r==6rEG@(p9L&@o9toG0q$ zTD*nN5^Qw(-xj4Q)ms#sH-^`L2lfghl1#i+Y?8RJFwn>zz%Ll?aQvY?Mgq`2xX|~6 z+7+smapwH_iNW&6H5Nj`!cyEUa%Xwo`93R^c{fpDsD$X=<`zDRxtd}t8(5fw-(4G=|k zQz3LrO*+nbTd?7gWp!-J1^%!dAIhGl$>vek%dTb)*%qJ^EE>Z)jbP9vi$Xt!B6{ z1aNxxE1ayCh{tj19(4z_6d3IaYgMpyEi6)sJ*_8lbVjeY?8J#XG_-+^V(7XTOjgKk zz97Y^Nyd@yr4}O+39YVnWj}9u&qP|&!BJ!$X(^N~I)@K$-D7u!Iq8G%u_~c5NgEa! z$>ZNyZfhfL##hStNo+sdTk7iSvc1^x%op>9?I$s$_0&u+f&9hClmOk>C8 zr?7o{jfEsMC~b)fgsP06Kge1niTHD>;)x@XYlyolq@@D|upBTR)Qb7Nm~I1M6W!Xi z_{VA9wO;~8yZ|xzQwze2DQ)VJ{EXD>2Yj*J4CKF~E*b!diL`@zwIwzZ)fIhUDgpo+ zn17YHrIHvX{Y;b$0{*j=`p1>usx@sgFf)tCE<)UCWYjQSap}_9g+>2PQWgt`$7HHl zN2s&;R^zy{*{uQk7ozwnQ}krHX0!`o!-)Px>ONJNOq!U)f^FSr*uP^-R|O+pf1@X{ zehia;-8iNc%}6Spyg-sxn|Q=6krDr@_xuH6iVFS2?-Dui_m zti!01o4cs9IL8N7RH`4}%q{p{D1D81*S~kYOCn_q)O->nvJX6Zl#0PhA6Y2Fz>VQ; z6y^xSg$+&=;8(719^~<5d+E69r8VZ^MNF$6txx#8QDqcPM7Tg^p6{;uJnLO-wv4n} z4rwb8o!EU3UzV}pz5mV{7}B_E8ir1DjvA0M!q5YVgSKODqV7D%f_}HB=jK4mL1(4F zR?d=~uuIcw`B3g(TWH*bP-r64!}Bzajv)kn{Z4$pQxrT^xnCL6D4a|x)yJY={`VAj z?J&2Pqx@3VV*wW(9X_-=M)v8Z>bXz6xd_Y^NB3dB4WC{Di_A4~4aO%!rAU)xgoQ`p zUdnbw)}|>EH5WovHQ7YE=I1BloyT_(??18{e_$aQiiJwR*n|Zoyww3Z6`MKZChZ8N zvucx9ye94_A)05bt$c9DO}$&3=QMcI`8APrBGE(U6QGy@!P+_S#eu*!?Lf{zVdI~~ zHkiX1X_W8;ad1GH$DyXr7KF?dgKq~L8#OWv3L^qi-kZEVgu%j0!D4r{o&63EJ&Wg( ziwIm$mU#+P$POtAvQMa?v$Zn5;IRc~4G8};q5t_4Qh5i5a4RN5T9J^jjwKRTS_icl zxGa~bnn=v9;-k4KGxaSQq;HbZ&FFTcIsvqi**hlArH#dh*^GJwFXP@;O(IUP(J?9p zkV1{uH?0q>0ifFyGx20m0y;5V;}%a6An5_Cortb}Je$Yb6*j2qew*22!)|@1O4pSD zJ@-2HAOvAxHX6j(R-kJ{a!wye$u?vP@T+enj{HAK)s)C}O%BPo-#{kZz8&58bxgr3 z9QC-d(U2ing)ccsk4`90c)XP%4~Fw=0(tF0(dE+@a+30~#D?z5+cp7~hIP=KMmjN;@$?vc?%r-1On$aX;KwNY< zZkTNc2+gXnq_h;WHC(4|ylbytWeTQc;#1C0C~^3Zq4{S|_ZLM<&M1BG;&a#5*S}s_ zxxa0i`0SFF0g%TTk2&kvhj$_-_vXW9gNu%mVSrBHrI3)?ZvhI7^{tvO{;ab|%((?d z`E3EKM4%hPGN35Jluk(3bGre0VXRQ<_FN)!9xmAI^LB-Hw#HziV|J^cuW*RTzgFIIm2Vc0E=9J!zNbKWwO>h;#2XPb3-HU?Q`D45o^AYG@>bHm@~)G1jwBExy( z$dM!DcTE5Db|XeiU%`I{sU$#|buYruJBb4yURl|%---TuAobF$eo%Vhv07)N;hJ4S zF=oSvAB;{65GG30$7M!>)|x;gjVmsZDKd zCjkN3*$MO&0c7Xk=9Y)aUZh(|KEGxZfBzZbHKrmQif5NT5>ME(XUNPI+eBlUQCb`U zlJb3S&hC7E;=9oQp0>1~4vKLt){sVj{|@On#I?sGWziH(*zZGF-bsaA%`NbIrej0) zxcZgT|Df=R?}V9iXD4jF1;fzb9fida98QqEsObmon6P*fJ-FldV*d`_eK)gm4e!H) z0z}tg^5)!|z(`|bOW?a5`V@oBm2GV9BqwicT=0r-wbP7pYFA>{MHjwKlPbd!v~kB&m_%%(T5^N5y@x3laJ;v(<==4y=lul!yiz8W?%kZX=E1-93M?JB8Rii0k%oiV1!zI@vxMs>0&FbKrH0-JYN| z0&o-&6im<&(C2`9?f}3!u>EhXQ2%VIp|wpW*)%fgnGL4HT0=~&ufL(I6`JFCv@W3% z#*ki>)PlKJHWw);Yco2X$kU3fJ~gtl-zh9cd0rVrqvHB|NC z%%9Li-I-M*8OPKlVq_cF`Uz`_G6FCdf138I?;q zC0scdl>fZ4a2{`fy=-`WZ9@SVZCSffN1^vw1|x95gGRY)D6o7YIwcs(u}{EYoK@fz zPC@{wS~&I7Ya|eWS@E7%pWFcb^~Q}av583|Qtw}&nbl1_^MW7u&cE4Kyw=v86vymt zs(Y>K)ZB#cF9qa8sH4+_FqIPYEevborfy7m{WCC5SMM0Q&DH?Zao10Jp}C9<4r<&M zYGbov-*w_L`}alHjq!`JT@*aqOSd7I(NLKQY%RI{`!6CKP>TmJ^wh@(>wk62o=;u} zlB#Z>?*E73{-)q&C%R$B9bCZqYc$}L%d{X{}l1U z0d%PT=%zGQ+1ma^>wnMn2`WppzhTFs=K>WkGb1Ca!TnCG^!v$Kuzzzz90wL)B*Xz| z4Yp+Ho#Ur$wKJ?|*BDuzxe_h-=VXVzy`*E0G1(ErxMEdOX~uZnhZNfg_6ULnV4h2_ z6VN+M!p#KOtb-S)69L8jciWYuq=ga|vR5e#=Zm;JWBvHjgzd4D8U04T-}7%2iLxY6 z@Mi0nAgXO;7ypZ_wtZMfn6AJNjuf_|@iZPBygSfVk?NQ|useL>1aDRi$_D}sH(K|I z;yx5K><5;Ps7(=(5dU-Rp5{^nzDT}ea_p%qkngLumvMRZNc_No6<`OXU#QTL;bY0s zt4m0Dg=2x%b=`7VnmpY?p)Kp=n8lUIAE6und!Gd?q)W3d^Pe1&WK=Ijodc^`B(2pO z0DnI;b9Q%^36<~r3REDnf9S40dEpw!-I)G9vZ*4)E=wR z#fJIE4ZVd8@;A;#Av2)!jn@$F9^wr z`%K60fb-{55n=8>H|{?_^!t|o=iC3}ZU5hI|Fhq}U*zB1=J#v=zrOw6xB1tq)Pu6` UKV_T=p~07?ny%`76^nrX16qgKV*mgE literal 0 HcmV?d00001 diff --git a/docs/source/images/role-scope-resolution.png b/docs/source/images/role-scope-resolution.png deleted file mode 100644 index 5605b906a926cea15522a20e71d1f6253d846a78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48730 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 IS8ebA9~a{ZcmMzZ diff --git a/docs/source/rbac/index.md b/docs/source/rbac/index.md index 7c8b08a6..a86dd67c 100644 --- a/docs/source/rbac/index.md +++ b/docs/source/rbac/index.md @@ -24,6 +24,6 @@ Within the RBAC framework, this is achieved by assigning a role to the administr roles scopes -tech-implementation use-cases +tech-implementation ``` diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 42092c9d..652c5e3a 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -16,7 +16,6 @@ Roles can also be customly defined and assigned to users, services, groups and t **_Groups_** do not require any role and are not assigned any roles by default. Once group roles are defined and assigned, the privileges of each group member are extended with the group roles in the background during the API request permission check. This is useful for requesting the same permissions for several users. (define_role_target)= - ## Defining Roles ### In `jupyterhub_config.py` diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index 81f7c693..a0c5b42f 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -19,10 +19,7 @@ The standard user scope `all` provides access to the user's own resources and su - `users!user=gerard` where the `users` scope includes access to the full user model, activity and starting/stopping servers. The filter restricts this access to the user's own resources - `users:tokens!user=gerard` allows the user to access, request and delete his own tokens only. -*Note: I'm hoping that horizontal and vertical filtering are somehow intuitive concepts, but maybe I am making up words for things that are already pretty well defined?* - (filtering-target)= - ## Horizontal filtering Horizontal filtering, also called *resource filtering*, is the concept of reducing the payload of an API call to cover only the subset of the *resources* that the scopes of the client provides them access to. diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index 66080fe5..a92e614b 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -1,33 +1,49 @@ # Technical Implementation -Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `add_obj` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. +Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `update_roles` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. ## Resolving roles and scopes -Roles and scopes are resolved on several occasions as shown in the {ref}`diagram below `. +Roles and scopes are resolved on several occasions, for example when requesting an API token with specific roles or making an API request. The following sections provide more details. -```{figure} ../images/role-scope-resolution.png +### Requesting API token with specific roles +API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific existing roles. To date, it is only possible to add roles to a token in two ways: +1. through the `config.py` file as described in the {ref}`define_role_target` section +2. through the POST /users/{name}/tokens API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). + +The RBAC framework adds several steps into the token issue flow. + +If no roles are requested, the token is issued with a default role (providing the requester is allowed to create the token). + +If the token is requested with a specific role or multiple roles, the permissions of the would-be token's owner are checked against the requested permissions to ensure the token will not grant its owner additional privileges. In practice, this corresponds to resolving all the token owner's roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared and if the token's scopes are a subset of the token owner's scopes, the token is issued with the requested roles. + +{ref}`Figure 1 ` below illustrates this process. The orange rectangles highlight where in the process the roles and scopes are resolved. + +```{figure} ../images/rbac-api-token-request-chart.png :align: center -:name: checkpoint-fig +:name: api-token-request-chart -Figure 1. Checkpoints for resolving scopes in JupyterHub +Figure 1. Resolving roles and scopes during API token request ``` -### Checkpoint 1: Requesting a token with specific roles -When a token is requested with a specific role or multiple roles, the permissions of the token's owner (client in {ref}`Figure 1 `) are checked against the requested permissions to ensure the token will not grant its owner additional privileges. In practice, this corresponds to resolving all the client's roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared and if the token's scopes (s5 in {ref}`Figure 1 `) are a subset of the client's scopes, the token is issued with the requested roles (role D in {ref}`Figure 1 `). - ```{note} The above check is also performed when roles are requested for existing tokens, e.g., when adding tokens to {ref}`role definitions through the config.py `. ``` -### Checkpoint 2: Making an API request -Each authenticated API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API (scopes s1, s5 and s6 in {ref}`Figure 1 `). -When an API request is performed, the token's roles are again resolved into a set of scopes and compared to the required scopes in the same way as in checkpoint 1. The access to the API is then either allowed or denied. +### Making API request +With the RBAC framework each authenticated JupyterHub API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API. -For instance, a token with a role with `groups!group=class-C` scope will be allowed to access the _GET /groups_ API but not allowed to make the _POST /groups/{name}_ API request. +When an API request is performed, the passed API token's roles are again resolved into a set of scopes and compared to the scopes required to access the API as follows: +- if the API scopes are present within the set of token's scopes, the access is granted and the API returns its "full" response +- if that is not the case, another check is utilized to determine if sub-scopes of the required API scopes can be found in the token's scope set: + - if the subscopes are present, the RBAC framework employs the {ref}`filtering ` procedures to refine the API response to provide access to only resource attributes specified by the token provided scopes + - for example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model + - if the subscopes are not present, the access to API is denied -### Checkpoint 3: API request response -The third checkpoint takes place at the API response level. The scopes provided for the request (s5 in {ref}`Figure 1 `) are used to filter through the API response to provide access to only resource attributes specified by the scopes. +{ref}`Figure 2 ` illustrates this process highlighting the steps where the role and scope resolutions as well as filtering occur in orange. -For example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the last_activity attribute. +```{figure} ../images/rbac-api-request-chart.png +:align: center +:name: api-request-chart -For more filtering details refer to the {ref}`filtering` section. +Figure 2. Resolving roles and scopes when an API request is made +``` diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md index 0024fdfa..b792dc84 100644 --- a/docs/source/rbac/use-cases.md +++ b/docs/source/rbac/use-cases.md @@ -4,7 +4,8 @@ To determine which scopes a role should have it is best to follow these steps: 1. Determine what actions the role holder should have/have not access to 2. Match the actions against the JupyterHub's REST APIs 3. Check which scopes are required to access the APIs -4. Define the role with required scopes and assign to users/services/groups/tokens +4. Customize the scopes with filters if needed +5. Define the role with required scopes and assign to users/services/groups/tokens Below, different use cases are presented on how to use the RBAC framework. @@ -15,14 +16,35 @@ A regular user should be able to view and manage all of their own resources. Thi ## Service to cull idle servers Finding and shutting down idle servers can save a lot of computational resources. -Below follows a short tutorial on how one can add a cull-idle service to JupyterHub. +We can make use of [jupyterhub-idle-culler](https://github.com/jupyterhub/jupyterhub-idle-culler) to manage this for us. +Below follows a short tutorial on how to add a cull-idle service in the RBAC system. -1. Request an API token -2. Define the service (`idle-culler`) -3. Define the role (scopes `users:servers`, `admin:users:servers`) -4. Install cull-idle servers (`pip install jupyterhub-idle-culler`) -5. Add the service to `jupyterhub_config.py` -6. (Restart JupyterHub) +1. Install the cull-idle server script with `pip install jupyterhub-idle-culler`. +2. Define a new service `idle-culler` and a new role for this service: +```python +c.JupyterHub.roles.append( + { + "name": "idle-culler", + "description": "Culls idle servers", + "scopes": ["read:users:servers", "admin:users:servers"], + "services": ["idle-culler"], + } +) + + +c.JupyterHub.services.append( + { + "name": "idle-culler", + "command": [ + sys.executable, "-m", + "jupyterhub_idle_culler", + "--timeout=3600" + ], + } +) + +``` +3. Restart JupyterHub to complete the process. ## API launcher diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 7b267d82..85129bae 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -371,7 +371,7 @@ class UserTokenListAPIHandler(APIHandler): except ValueError: raise web.HTTPError( 403, - "Requested token roles %r have higher permissions than the token owner" + "Requested roles %r cannot have higher permissions than the token owner" % token_roles, ) if requester is not user: diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index c46f7e19..eefd0cd3 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -223,7 +223,7 @@ def update_roles(db, obj, kind, roles=None): % rolename ) else: - raise NameError('Role %r does not exist' % rolename) + raise NameError('Requested role %r does not exist' % rolename) else: add_obj(db, objname=obj.name, kind=kind, rolename=rolename) else: From c03ca796ab061ca915ab2bf4a5034a2554597b89 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 19 Feb 2021 14:07:25 +0100 Subject: [PATCH 068/270] removed recommonmark from docs/source/conf.py --- docs/source/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 379c7761..a53fbbfc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -19,7 +19,6 @@ extensions = [ 'autodoc_traits', 'sphinx_copybutton', 'sphinx-jsonschema', - #'recommonmark', 'myst_parser', ] From 5a15fba8b78a7f29a1b01828c3cbb8e250cbd8a9 Mon Sep 17 00:00:00 2001 From: Ivana Date: Tue, 23 Feb 2021 15:05:41 +0100 Subject: [PATCH 069/270] Applied text improvement suggestions from code review by @manics Co-authored-by: Simon Li --- docs/source/rbac/index.md | 2 +- docs/source/rbac/roles.md | 10 +++++++--- docs/source/rbac/use-cases.md | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/source/rbac/index.md b/docs/source/rbac/index.md index a86dd67c..ec0a1557 100644 --- a/docs/source/rbac/index.md +++ b/docs/source/rbac/index.md @@ -5,7 +5,7 @@ Role Based Access Control (RBAC) in JupyterHub serves to provide finer grained a ## Motivation The JupyterHub API requires authentication before allowing changes to the administration system. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, cannot disrupt the status of the Hub. -This system is functional, but lacks flexibility. If your Hub serves a number of users in different departments, you might want to delegate permissions to other users or automate certain processes. With this framework, appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilige](https://en.wikipedia.org/wiki/Principle_of_least_privilege). +This system is functional, but lacks flexibility. If your Hub serves a number of users in different groups, you might want to delegate permissions to other users or automate certain processes. Appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege). To remedy situations like this, we implement an RBAC system. By equipping users, groups and services with *roles* that supply them with a collection of permissions (*scopes*), administrators are able to fine-tune which parties are able to access which resources. diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 652c5e3a..fbae1196 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -9,7 +9,7 @@ JupyterHub provides three **default roles** which are automatically loaded to th Roles can also be customly defined and assigned to users, services, groups and tokens. -**_Users_** and **_services_** are assigned a default role if no custom role is requested based on their admin status. +**_Users_** and **_services_** are assigned a default role ( **_user_** or **_admin_**) if no custom role is requested based on their admin status. **_Tokens_**’ roles cannot grant the token higher permissions than their owner’s roles. If no specific role is requested, tokens are assigned the default _user_ role. @@ -24,7 +24,7 @@ Roles can be defined or modified in the configuration file as a list of dictiona ```python c.JupyterHub.load_roles = [  { -   'name': 'Server rights', +   'name': 'server-rights',    'description': 'Allows parties to start and stop user servers',    'scopes': ['users:servers', 'read:users:servers'],    'users': ['alice', 'bob'], @@ -34,7 +34,11 @@ c.JupyterHub.load_roles = [  } ] ``` -The role `server-rights` now allows the starting and stopping of servers by users `alice` and `bob` and the service `idle-culler`, and any member of the `admin-group` or requests using the tokens `foo-6f6e65`/`bar-74776f` (providing the tokens owner has at least the same permissions). +The role `server-rights` now allows the starting and stopping of servers by any of the following: +- users `alice` and `bob` +- the service `idle-culler` +- any member of the `admin-group` +- requests using the tokens `foo-6f6e65` or `bar-74776f` (providing the tokens owner has at least the same permissions). Another example: ```python diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md index b792dc84..da812d79 100644 --- a/docs/source/rbac/use-cases.md +++ b/docs/source/rbac/use-cases.md @@ -93,6 +93,6 @@ c.JupyterHub.load_roles = [  } ] ``` -In the above example, `johan` has privileges inherited from class-A role and the `teacher` role on top of those. +In the above example, `johan` has privileges inherited from `class-A role` and the `teacher` role on top of those. -Note the filters (`!group=`) limiting the priviliges only to the particular groups. `johan` can access the servers and information of `class-B` members only. +Note the filters (`!group=`) limiting the privileges only to the particular groups. `johan` can access the servers and information of `class-B` members only. From 1c789fcbb5e664e789967e3bc2567440f0da5d38 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 25 Feb 2021 07:30:41 +0100 Subject: [PATCH 070/270] Removed database calls and made scope filter a callable --- jupyterhub/apihandlers/base.py | 119 +++++++++++++++++-------------- jupyterhub/apihandlers/groups.py | 6 +- jupyterhub/handlers/base.py | 10 --- jupyterhub/scopes.py | 23 ++++-- jupyterhub/tests/test_scopes.py | 50 +++++++++++-- 5 files changed, 128 insertions(+), 80 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 7bbb88d6..de89c8f3 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -2,6 +2,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import json +import re from datetime import datetime from http.client import responses @@ -9,6 +10,7 @@ from sqlalchemy.exc import SQLAlchemyError from tornado import web from .. import orm +from .. import roles from ..handlers import BaseHandler from ..handlers import scopes from ..utils import isoformat @@ -24,8 +26,27 @@ class APIHandler(BaseHandler): - strict referer checking for Cookie-authenticated requests - strict content-security-policy - methods for REST API models + - scope loading """ + async def prepare(self): + await super().prepare() + self.raw_scopes = set() + self.parsed_scopes = {} + self._parse_scopes() + + def _parse_scopes(self): + """Parse raw scope collection into a dict with filters that can be used to resolve API access""" + self.log.debug("Parsing scopes") + if self.current_user is not None: + self.raw_scopes = roles.get_subscopes(*self.current_user.roles) + oauth_token = self.get_current_user_oauth_token() + if oauth_token: + self.raw_scopes |= scopes.get_user_scopes(oauth_token.name) + if 'all' in self.raw_scopes: + self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + @property def content_security_policy(self): return '; '.join([super().content_security_policy, "default-src 'none'"]) @@ -64,36 +85,41 @@ class APIHandler(BaseHandler): return True def get_scope_filter(self, req_scope): - """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return""" - scope_translator = { - 'read:users': 'users', - 'read:services': 'services', - 'read:groups': 'groups', - } - if req_scope not in scope_translator: - raise AttributeError("Internal error: inconsistent scope situation") - kind = scope_translator[req_scope] - Resource = orm.get_class(kind) + """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. + Filter is a callable that takes a resource name and outputs true or false""" + kind_regex = re.compile(r':?(user|service|group)s:?') + try: + kind = re.search(kind_regex, req_scope).group(1) + except AttributeError: + self.log.warning( + "Regex error while processing scope %s, throwing 500", req_scope + ) + raise web.HTTPError( + log_message="Unrecognized scope guard on method: %s" % req_scope + ) try: sub_scope = self.parsed_scopes[req_scope] except AttributeError: raise web.HTTPError( 403, - "Resource scope %s (that was just accessed) not found in scopes anymore" + "Resource scope %s (that was just accessed) not found in parsed scope model" % req_scope, ) - if sub_scope == scopes.Scope.ALL: - return None # Full access - sub_scope_values = next(iter(sub_scope.values())) - query = self.db.query(Resource).filter(Resource.name.in_(sub_scope_values)) - scope_filter = {entry.name for entry in query.all()} - if 'group' in sub_scope and kind == 'users': - groups = orm.Group.name.in_(sub_scope['group']) - users_in_groups = ( - self.db.query(orm.User).join(orm.Group.users).filter(groups) - ) - scope_filter |= {user.name for user in users_in_groups} - return scope_filter + + def has_access(resource_name): + if sub_scope == scopes.Scope.ALL: + found_resource = True + else: + found_resource = resource_name in sub_scope[kind] + if not found_resource: # Try group-based access + if 'groups' in sub_scope and kind == 'users': + user = self.current_user() + if user: + user_in_group = bool(user.groups & sub_scope['groups']) + found_resource |= user_in_group + return found_resource + + return has_access def get_current_user_cookie(self): """Override get_user_cookie to check Referer header""" @@ -234,24 +260,12 @@ class APIHandler(BaseHandler): 'last_activity': isoformat(user.last_activity), } access_map = { - 'read:users': { - 'kind', - 'name', - 'admin', - 'roles', - 'groups', - 'server', - 'servers', - 'pending', - 'created', - 'last_activity', - }, - 'read:users:name': {'kind', 'name'}, + 'read:users': set(model.keys()), # All available components + 'read:users:names': {'kind', 'name'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, } - # Todo: Should 'name' be included in all access? self.log.debug( "Asking for user models with scopes [%s]" % ", ".join(self.raw_scopes) ) @@ -259,24 +273,23 @@ class APIHandler(BaseHandler): for scope in access_map: if scope in self.parsed_scopes: scope_filter = self.get_scope_filter(scope) - if scope_filter is None or user.name in scope_filter: + if scope_filter(user.name): allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} - if not model: - return model # No access to this user - if '' in user.spawners and 'pending' in allowed_keys: - model['pending'] = user.spawners[''].pending - if not (include_servers and 'servers' in allowed_keys): - model['servers'] = None - else: - servers = model['servers'] = {} - for name, spawner in user.spawners.items(): - # include 'active' servers, not just ready - # (this includes pending events) - if spawner.active: - servers[name] = self.server_model( - spawner, include_state=include_state - ) + if model: + if '' in user.spawners and 'pending' in allowed_keys: + model['pending'] = user.spawners[''].pending + if not (include_servers and 'servers' in allowed_keys): + model['servers'] = None + else: + servers = model['servers'] = {} + for name, spawner in user.spawners.items(): + # include 'active' servers, not just ready + # (this includes pending events) + if spawner.active: + servers[name] = self.server_model( + spawner, include_state=include_state + ) return model def group_model(self, group): diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index f0dceab4..c179e9fb 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -38,10 +38,8 @@ class GroupListAPIHandler(_GroupAPIHandler): def get(self): """List groups""" groups = self.db.query(orm.Group) - scope_filter = self.get_scope_filter(self.db) - if scope_filter is not None: - groups = groups.filter(orm.Group.name.in_(scope_filter)) - data = [self.group_model(g) for g in groups] + scope_filter = self.get_scope_filter('read:groups') + data = [self.group_model(g) for g in groups if scope_filter(g)] self.write(json.dumps(data)) @needs_scope('admin:groups') diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 422794c5..3263ae5a 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -81,8 +81,6 @@ class BaseHandler(RequestHandler): The current user (None if not logged in) may be accessed via the `self.current_user` property during the handling of any request. """ - self.raw_scopes = set() - self.parsed_scopes = set() try: await self.get_current_user() except Exception: @@ -431,16 +429,8 @@ class BaseHandler(RequestHandler): # don't let errors here raise more than once self._jupyterhub_user = None self.log.exception("Error getting current user") - self._parse_scopes() return self._jupyterhub_user - def _parse_scopes(self): - if self._jupyterhub_user is not None or self.get_current_user_oauth_token(): - self.raw_scopes = roles.get_subscopes(*self._jupyterhub_user.roles) - if 'all' in self.raw_scopes: - self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) - @property def current_user(self): """Override .current_user accessor from tornado diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 613935eb..0d72f1fd 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -1,19 +1,18 @@ import functools import inspect -import re from enum import Enum from tornado import web from tornado.log import app_log -from . import orm +from . import roles class Scope(Enum): ALL = True -def get_user_scopes(name): +def get_user_scopes(name, read_only=False): """ Scopes have a metascope 'all' that should be expanded to everything a user can do. At the moment that is a user-filtered version (optional read) access to @@ -32,7 +31,11 @@ def get_user_scopes(name): 'users:servers', 'users:tokens', ] - scope_list.extend(['read:' + scope for scope in scope_list]) + read_scope_list = ['read:' + scope for scope in scope_list] + if read_only: + scope_list = read_scope_list + else: + scope_list.extend(read_scope_list) return {"{}!user={}".format(scope, name) for scope in scope_list} @@ -55,7 +58,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): user = handler.find_user(user_name) if user is None: raise web.HTTPError(404, "No access to resources or resources not found") - group_names = {group.name for group in user.groups} # SQL query faster? + group_names = {group.name for group in user.groups} return bool(set(scope_group_names) & group_names) @@ -67,7 +70,7 @@ def _check_scope(api_handler, req_scope, **kwargs): # Parse user name and server name together try: api_name = api_handler.request.path - except: + except AttributeError: api_name = type(api_handler).__name__ if 'user' in kwargs and 'server' in kwargs: kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) @@ -147,6 +150,14 @@ def needs_scope(*scopes): bound_sig = sig.bind(self, *args, **kwargs) bound_sig.apply_defaults() s_kwargs = {} + # current_user = self.current_user() + # if current_user is not None or self.get_current_user_oauth_token(): + # self.raw_scopes = roles.get_subscopes(*current_user.roles) + # if 'all' in self.raw_scopes: + # self.raw_scopes |= get_user_scopes(self.current_user.name) + # self.parsed_scopes = parse_scopes(self.raw_scopes) + # else: + # app_log.warning("No user found in access checking, so no scopes loaded") for resource in {'user', 'server', 'group', 'service'}: resource_name = resource + '_name' if resource_name in bound_sig.arguments: diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 8539f2e0..1a70ee32 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -54,7 +54,7 @@ def test_scope_check_present(): def test_scope_check_not_present(): handler = get_handler_with_scopes(['read:users!user=maeby']) - assert not _check_scope(handler, 'read:users') + assert _check_scope(handler, 'read:users') with pytest.raises(web.HTTPError): _check_scope(handler, 'read:users', user='gob') with pytest.raises(web.HTTPError): @@ -103,7 +103,8 @@ class MockAPIHandler: return True @needs_scope('users') - def other_thing(self, other_name): + def other_thing(self, non_filter_argument): + # Rely on inner vertical filtering return True @needs_scope('users') @@ -161,8 +162,8 @@ class MockAPIHandler: ), (['users'], 'other_thing', ('gob',), True), (['read:users'], 'other_thing', ('gob',), False), - (['users!user=gob'], 'other_thing', ('gob',), False), - (['users!user=gob'], 'other_thing', ('maeby',), False), + (['users!user=gob'], 'other_thing', ('gob',), True), + (['users!user=gob'], 'other_thing', ('maeby',), True), ], ) def test_scope_method_access(scopes, method, arguments, is_allowed): @@ -403,12 +404,47 @@ async def test_vertical_filter(app): r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) assert r.status_code == 200 - assert set(r.json().keys()) == {'names'} + allowed_keys = {'name', 'kind'} + assert set([key for user in r.json() for key in user.keys()]) == allowed_keys async def test_stacked_vertical_filter(app): - pass + user_name = 'user' + test_role = generate_test_role( + user_name, ['read:users:activity', 'read:users:servers'] + ) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + app.db.commit() + + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + allowed_keys = {'name', 'kind', 'servers', 'last_activity'} + result_model = set([key for user in r.json() for key in user.keys()]) + assert result_model == allowed_keys async def test_cross_filter(app): - pass + user_name = 'abed' + add_user(app.db, name=user_name) + test_role = generate_test_role( + user_name, ['read:users:activity', 'read:users!user=abed'] + ) + roles.add_role(app.db, test_role) + roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + app.db.commit() + new_users = {'britta', 'jeff', 'annie'} + for new_user_name in new_users: + add_user(app.db, name=new_user_name) + app.db.commit() + r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + assert r.status_code == 200 + restricted_keys = {'name', 'kind', 'last_activity'} + key_in_full_model = 'created' + for user in r.json(): + if user['name'] == user_name: + assert key_in_full_model in user + else: + assert set(user.keys()) == restricted_keys From 970e3a57fa7d4f7ae652fc43b79cf9bb46db2649 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 25 Feb 2021 07:57:07 +0100 Subject: [PATCH 071/270] Cleanup commit --- jupyterhub/apihandlers/base.py | 1 + jupyterhub/scopes.py | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index de89c8f3..01da1b00 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -34,6 +34,7 @@ class APIHandler(BaseHandler): self.raw_scopes = set() self.parsed_scopes = {} self._parse_scopes() + # todo: Check if okay def _parse_scopes(self): """Parse raw scope collection into a dict with filters that can be used to resolve API access""" diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 0d72f1fd..4d2cef92 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -150,14 +150,6 @@ def needs_scope(*scopes): bound_sig = sig.bind(self, *args, **kwargs) bound_sig.apply_defaults() s_kwargs = {} - # current_user = self.current_user() - # if current_user is not None or self.get_current_user_oauth_token(): - # self.raw_scopes = roles.get_subscopes(*current_user.roles) - # if 'all' in self.raw_scopes: - # self.raw_scopes |= get_user_scopes(self.current_user.name) - # self.parsed_scopes = parse_scopes(self.raw_scopes) - # else: - # app_log.warning("No user found in access checking, so no scopes loaded") for resource in {'user', 'server', 'group', 'service'}: resource_name = resource + '_name' if resource_name in bound_sig.arguments: From 9c6c6888107929c3c74b93a8d47ddd62499e08c0 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 26 Feb 2021 15:47:40 +0100 Subject: [PATCH 072/270] Moved scope parsing to scopes module, implemented filter caching and filters now take orm objects --- jupyterhub/apihandlers/base.py | 42 ++++++++---------------------- jupyterhub/apihandlers/services.py | 15 ++++------- jupyterhub/handlers/base.py | 3 +++ jupyterhub/scopes.py | 23 ++++++++++++++++ 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 01da1b00..4ba9755c 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -1,6 +1,7 @@ """Base API handlers""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import functools import json import re from datetime import datetime @@ -10,9 +11,8 @@ from sqlalchemy.exc import SQLAlchemyError from tornado import web from .. import orm -from .. import roles +from .. import scopes from ..handlers import BaseHandler -from ..handlers import scopes from ..utils import isoformat from ..utils import url_path_join @@ -26,28 +26,8 @@ class APIHandler(BaseHandler): - strict referer checking for Cookie-authenticated requests - strict content-security-policy - methods for REST API models - - scope loading """ - async def prepare(self): - await super().prepare() - self.raw_scopes = set() - self.parsed_scopes = {} - self._parse_scopes() - # todo: Check if okay - - def _parse_scopes(self): - """Parse raw scope collection into a dict with filters that can be used to resolve API access""" - self.log.debug("Parsing scopes") - if self.current_user is not None: - self.raw_scopes = roles.get_subscopes(*self.current_user.roles) - oauth_token = self.get_current_user_oauth_token() - if oauth_token: - self.raw_scopes |= scopes.get_user_scopes(oauth_token.name) - if 'all' in self.raw_scopes: - self.raw_scopes |= scopes.get_user_scopes(self.current_user.name) - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) - @property def content_security_policy(self): return '; '.join([super().content_security_policy, "default-src 'none'"]) @@ -85,12 +65,13 @@ class APIHandler(BaseHandler): return False return True + @functools.lru_cache def get_scope_filter(self, req_scope): """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. Filter is a callable that takes a resource name and outputs true or false""" - kind_regex = re.compile(r':?(user|service|group)s:?') + try: - kind = re.search(kind_regex, req_scope).group(1) + kind = re.search(scopes.kind_regex, req_scope).group(1) except AttributeError: self.log.warning( "Regex error while processing scope %s, throwing 500", req_scope @@ -107,17 +88,15 @@ class APIHandler(BaseHandler): % req_scope, ) - def has_access(resource_name): + def has_access(orm_resource): if sub_scope == scopes.Scope.ALL: found_resource = True else: - found_resource = resource_name in sub_scope[kind] + found_resource = orm_resource.name in sub_scope[kind] if not found_resource: # Try group-based access if 'groups' in sub_scope and kind == 'users': - user = self.current_user() - if user: - user_in_group = bool(user.groups & sub_scope['groups']) - found_resource |= user_in_group + user_in_group = bool(orm_resource.groups & sub_scope['groups']) + found_resource |= user_in_group return found_resource return has_access @@ -274,7 +253,7 @@ class APIHandler(BaseHandler): for scope in access_map: if scope in self.parsed_scopes: scope_filter = self.get_scope_filter(scope) - if scope_filter(user.name): + if scope_filter(user): allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} if model: @@ -283,6 +262,7 @@ class APIHandler(BaseHandler): if not (include_servers and 'servers' in allowed_keys): model['servers'] = None else: + # Todo: Replace include_state with scope (read|admin):users:auth_state servers = model['servers'] = {} for name, spawner in user.spawners.items(): # include 'active' servers, not just ready diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 5a48e385..ad6981de 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -32,16 +32,11 @@ class ServiceListAPIHandler(APIHandler): @needs_scope('read:services') def get(self): scope_filter = self.get_scope_filter('read:services') - if scope_filter is None: - data = { - name: service_model(service) for name, service in self.services.items() - } - else: - data = { - name: service_model(service) - for name, service in self.services.items() - if name in scope_filter - } + data = { + name: service_model(service) + for name, service in self.services.items() + if scope_filter(service) + } self.write(json.dumps(data)) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 3263ae5a..fd4585ec 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -81,8 +81,11 @@ class BaseHandler(RequestHandler): The current user (None if not logged in) may be accessed via the `self.current_user` property during the handling of any request. """ + self.raw_scopes = set() + self.parsed_scopes = {} try: await self.get_current_user() + scopes.build_scope_schema(self) except Exception: self.log.exception("Failed to get current user") self._jupyterhub_user = None diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 4d2cef92..7c906d50 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -1,5 +1,6 @@ import functools import inspect +import re from enum import Enum from tornado import web @@ -12,6 +13,23 @@ class Scope(Enum): ALL = True +# Used to identify scope filters +kind_regex = re.compile(r':?(user|service|group)s:?') + + +def build_scope_schema(handler): + """Parse raw scope collection into a dict with filters that can be used to resolve API access""" + app_log.debug("Parsing scopes") + if handler.current_user is not None: + handler.raw_scopes = roles.get_subscopes(*handler.current_user.roles) + oauth_token = handler.get_current_user_oauth_token() + if oauth_token: + handler.raw_scopes |= get_user_scopes(oauth_token.name) + if 'all' in handler.raw_scopes: + handler.raw_scopes |= get_user_scopes(handler.current_user.name) + handler.parsed_scopes = parse_scopes(handler.raw_scopes) + + def get_user_scopes(name, read_only=False): """ Scopes have a metascope 'all' that should be expanded to everything a user can do. @@ -149,6 +167,11 @@ def needs_scope(*scopes): sig = inspect.signature(func) bound_sig = sig.bind(self, *args, **kwargs) bound_sig.apply_defaults() + # Load scopes in case they haven't been loaded yet + if not hasattr(self, 'raw_scopes'): + self.raw_scopes = {} + self.parsed_scopes = {} + s_kwargs = {} for resource in {'user', 'server', 'group', 'service'}: resource_name = resource + '_name' From 0eb275e863ae1daa02534339600701afa69526f3 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 4 Mar 2021 13:20:15 +0100 Subject: [PATCH 073/270] Removed regex. Fixed small bugs, changed status of scope module functions --- jupyterhub/apihandlers/base.py | 34 ++++++++++------------ jupyterhub/apihandlers/groups.py | 2 +- jupyterhub/apihandlers/services.py | 2 +- jupyterhub/handlers/base.py | 18 ++++++++++-- jupyterhub/scopes.py | 46 +++++++++++++++++++----------- 5 files changed, 61 insertions(+), 41 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 4ba9755c..b5e7f31b 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -70,15 +70,6 @@ class APIHandler(BaseHandler): """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. Filter is a callable that takes a resource name and outputs true or false""" - try: - kind = re.search(scopes.kind_regex, req_scope).group(1) - except AttributeError: - self.log.warning( - "Regex error while processing scope %s, throwing 500", req_scope - ) - raise web.HTTPError( - log_message="Unrecognized scope guard on method: %s" % req_scope - ) try: sub_scope = self.parsed_scopes[req_scope] except AttributeError: @@ -88,14 +79,19 @@ class APIHandler(BaseHandler): % req_scope, ) - def has_access(orm_resource): + def has_access(orm_resource, kind): + """ + param orm_resource: User or Service or Group + param kind: 'users' or 'services' or 'groups' + """ if sub_scope == scopes.Scope.ALL: found_resource = True else: found_resource = orm_resource.name in sub_scope[kind] if not found_resource: # Try group-based access - if 'groups' in sub_scope and kind == 'users': - user_in_group = bool(orm_resource.groups & sub_scope['groups']) + if 'group' in sub_scope and kind == 'user': + group_names = {group.name for group in orm_resource.groups} + user_in_group = bool(group_names & set(sub_scope['group'])) found_resource |= user_in_group return found_resource @@ -247,21 +243,21 @@ class APIHandler(BaseHandler): 'read:users:servers': {'kind', 'name', 'servers'}, } self.log.debug( - "Asking for user models with scopes [%s]" % ", ".join(self.raw_scopes) + "Asking for user model of %s with scopes [%s]", + user.name, + ", ".join(self.raw_scopes), ) allowed_keys = set() for scope in access_map: if scope in self.parsed_scopes: scope_filter = self.get_scope_filter(scope) - if scope_filter(user): + if scope_filter(user, kind='user'): allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} if model: if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending - if not (include_servers and 'servers' in allowed_keys): - model['servers'] = None - else: + if include_servers and 'servers' in allowed_keys: # Todo: Replace include_state with scope (read|admin):users:auth_state servers = model['servers'] = {} for name, spawner in user.spawners.items(): @@ -273,7 +269,7 @@ class APIHandler(BaseHandler): ) return model - def group_model(self, group): + def group_model(self, group): # Todo: make consistent to do scope checking here """Get the JSON model for a Group object""" return { 'kind': 'group', @@ -281,7 +277,7 @@ class APIHandler(BaseHandler): 'users': [u.name for u in group.users], } - def service_model(self, service): + def service_model(self, service): # Todo: make consistent to do scope checking here """Get the JSON model for a Service object""" return { 'kind': 'service', diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index c179e9fb..b55dcd94 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -39,7 +39,7 @@ class GroupListAPIHandler(_GroupAPIHandler): """List groups""" groups = self.db.query(orm.Group) scope_filter = self.get_scope_filter('read:groups') - data = [self.group_model(g) for g in groups if scope_filter(g)] + data = [self.group_model(g) for g in groups if scope_filter(g, kind='group')] self.write(json.dumps(data)) @needs_scope('admin:groups') diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index ad6981de..4d7247d0 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -35,7 +35,7 @@ class ServiceListAPIHandler(APIHandler): data = { name: service_model(service) for name, service in self.services.items() - if scope_filter(service) + if scope_filter(service, kind='service') } self.write(json.dumps(data)) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index fd4585ec..4f14d6ca 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -82,14 +82,12 @@ class BaseHandler(RequestHandler): via the `self.current_user` property during the handling of any request. """ self.raw_scopes = set() - self.parsed_scopes = {} try: await self.get_current_user() - scopes.build_scope_schema(self) except Exception: self.log.exception("Failed to get current user") self._jupyterhub_user = None - + self._resolve_scopes() return await maybe_future(super().prepare()) @property @@ -434,6 +432,20 @@ class BaseHandler(RequestHandler): self.log.exception("Error getting current user") return self._jupyterhub_user + def _resolve_scopes(self): + self.raw_scopes = set() + app_log.debug("Loading and parsing scopes") + api_token = self.get_current_user_token() + if api_token: + self.raw_scopes = scopes.get_scopes_for(api_token) + elif self.current_user: + self.raw_scopes = scopes.get_scopes_for(self.current_user) + else: # deprecated oauth tokens + oauth_token = self.get_current_user_oauth_token() + if oauth_token: + self.raw_scopes = scopes.get_scopes_for(oauth_token) + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + @property def current_user(self): """Override .current_user accessor from tornado diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 7c906d50..6a85ec83 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -1,11 +1,11 @@ import functools import inspect -import re from enum import Enum from tornado import web from tornado.log import app_log +from . import orm from . import roles @@ -13,21 +13,32 @@ class Scope(Enum): ALL = True -# Used to identify scope filters -kind_regex = re.compile(r':?(user|service|group)s:?') - - -def build_scope_schema(handler): - """Parse raw scope collection into a dict with filters that can be used to resolve API access""" - app_log.debug("Parsing scopes") - if handler.current_user is not None: - handler.raw_scopes = roles.get_subscopes(*handler.current_user.roles) - oauth_token = handler.get_current_user_oauth_token() - if oauth_token: - handler.raw_scopes |= get_user_scopes(oauth_token.name) - if 'all' in handler.raw_scopes: - handler.raw_scopes |= get_user_scopes(handler.current_user.name) - handler.parsed_scopes = parse_scopes(handler.raw_scopes) +def get_scopes_for(user_or_token): + """Find scopes for a given user or token""" + scopes = set() + if user_or_token is None: + return scopes + elif isinstance(user_or_token, orm.APIToken) or isinstance( + user_or_token, orm.OAuthAccessToken + ): + user = user_or_token.user + user_name = user.name # fixme: Find the right attr + token_scopes = roles.get_subscopes(*user_or_token.roles) + user_scopes = roles.get_subscopes(user.roles) + scopes = token_scopes & user_scopes + discarded_token_scopes = token_scopes - scopes + # Not taking symmetric difference here because owner can easily have more scopes than users + if discarded_token_scopes: + app_log.warn( + "Token-based access, discarding scopes [%s]" + % ", ".join(discarded_token_scopes) + ) + else: + user_name = user_or_token.name + scopes = roles.get_subscopes(*user_or_token.roles) + if 'all' in scopes: + scopes |= get_user_scopes(user_name) + return scopes def get_user_scopes(name, read_only=False): @@ -102,7 +113,8 @@ def _check_scope(api_handler, req_scope, **kwargs): sub_scope = api_handler.parsed_scopes[req_scope] if not kwargs: app_log.debug( - "Client has restricted access to %s. In-method filtering" % api_name + "Client has restricted access to %s. Internal filtering may apply" + % api_name ) return True for (filter_, filter_value) in kwargs.items(): From 9d19ffe457eccff26a2c3bfd4e64eafc4e6fdd34 Mon Sep 17 00:00:00 2001 From: 0mar Date: Sun, 7 Mar 2021 15:29:50 +0100 Subject: [PATCH 074/270] Reimplemented scope logic to account for tokens --- jupyterhub/handlers/base.py | 19 +++++++++------- jupyterhub/scopes.py | 26 ++++++++++------------ jupyterhub/tests/mocking.py | 2 -- jupyterhub/tests/test_api.py | 4 ++-- jupyterhub/tests/utils.py | 43 ++++++------------------------------ 5 files changed, 32 insertions(+), 62 deletions(-) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 4f14d6ca..c1d03fd1 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -353,16 +353,20 @@ class BaseHandler(RequestHandler): auth_info['auth_state'] = await user.get_auth_state() return await self.auth_to_user(auth_info, user) - def get_current_user_token(self): - """get_current_user from Authorization header token""" + def get_token(self): + """get token from authorization header""" token = self.get_auth_token() if token is None: return None orm_token = orm.APIToken.find(self.db, token) + return orm_token + + def get_current_user_token(self): + """get_current_user from Authorization header token""" + # record token activity + orm_token = self.get_token() if orm_token is None: return None - - # record token activity now = datetime.utcnow() recorded = self._record_activity(orm_token, now) if orm_token.user: @@ -435,15 +439,14 @@ class BaseHandler(RequestHandler): def _resolve_scopes(self): self.raw_scopes = set() app_log.debug("Loading and parsing scopes") - api_token = self.get_current_user_token() + api_token = self.get_token() if api_token: self.raw_scopes = scopes.get_scopes_for(api_token) elif self.current_user: self.raw_scopes = scopes.get_scopes_for(self.current_user) else: # deprecated oauth tokens - oauth_token = self.get_current_user_oauth_token() - if oauth_token: - self.raw_scopes = scopes.get_scopes_for(oauth_token) + user_from_oauth = self.get_current_user_oauth_token() + self.raw_scopes = scopes.get_scopes_for(user_from_oauth) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) @property diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 6a85ec83..4bef0241 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -13,31 +13,29 @@ class Scope(Enum): ALL = True -def get_scopes_for(user_or_token): +def get_scopes_for(orm_object): """Find scopes for a given user or token""" scopes = set() - if user_or_token is None: + if orm_object is None: return scopes - elif isinstance(user_or_token, orm.APIToken) or isinstance( - user_or_token, orm.OAuthAccessToken - ): - user = user_or_token.user - user_name = user.name # fixme: Find the right attr - token_scopes = roles.get_subscopes(*user_or_token.roles) - user_scopes = roles.get_subscopes(user.roles) + elif isinstance(orm_object, orm.APIToken): + owner = orm_object.user or orm_object.service + owner_name = owner.name + token_scopes = roles.get_subscopes(*orm_object.roles) + user_scopes = roles.get_subscopes(*owner.roles) scopes = token_scopes & user_scopes discarded_token_scopes = token_scopes - scopes - # Not taking symmetric difference here because owner can easily have more scopes than users + # Not taking symmetric difference here because token owner can naturally have more scopes than token if discarded_token_scopes: - app_log.warn( + app_log.warning( "Token-based access, discarding scopes [%s]" % ", ".join(discarded_token_scopes) ) else: - user_name = user_or_token.name - scopes = roles.get_subscopes(*user_or_token.roles) + owner_name = orm_object.name + scopes = roles.get_subscopes(*orm_object.roles) if 'all' in scopes: - scopes |= get_user_scopes(user_name) + scopes |= get_user_scopes(owner_name) return scopes diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 7e2be899..7f93be9a 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -53,7 +53,6 @@ from ..spawner import SimpleLocalProcessSpawner from ..utils import random_port from ..utils import url_path_join from .utils import async_requests -from .utils import get_scopes from .utils import public_host from .utils import public_url from .utils import ssl_setup @@ -305,7 +304,6 @@ class MockHub(JupyterHub): super().init_tornado_application() # reconnect tornado_settings so that mocks can update the real thing self.tornado_settings = self.users.settings = self.tornado_application.settings - self.tornado_settings['mock_scopes'] = get_scopes() def init_services(self): # explicitly expire services before reinitializing diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index cd97dea5..c5f38389 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1319,7 +1319,7 @@ async def test_token_for_user(app, as_user, for_user, status): if for_user != 'missing': for_user_obj = add_user(app.db, app, name=for_user) data = {'username': for_user} - headers = {'Authorization': 'token %s' % u.new_api_token()} + headers = {'Authorization': 'token %s' % u.new_api_token(roles=[as_user])} r = await api_request( app, 'users', @@ -1414,7 +1414,7 @@ async def test_token_list(app, as_user, for_user, status): u = add_user(app.db, app, name=as_user) if for_user != 'missing': for_user_obj = add_user(app.db, app, name=for_user) - headers = {'Authorization': 'token %s' % u.new_api_token()} + headers = {'Authorization': 'token %s' % u.new_api_token(roles=[as_user])} r = await api_request(app, 'users', for_user, 'tokens', headers=headers) assert r.status_code == status if status != 200: diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index c4a72490..468e432b 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -120,12 +120,17 @@ def add_user(db, app=None, **kwargs): return orm_user -def auth_header(db, name): +def auth_header(db, name, role=None): """Return header with user's API authorization token.""" user = find_user(db, name) if user is None: raise KeyError(f"No such user: {name}") - token = user.new_api_token() + roles = [] + if role: + roles = [role] + elif name == 'admin': + roles = ['admin'] + token = user.new_api_token(roles=roles) return {'Authorization': 'token %s' % token} @@ -206,37 +211,3 @@ def public_url(app, user_or_service=None, path=''): return host + ujoin(prefix, path) else: return host + prefix - - -def get_scopes(role='admin'): - """Get all scopes for a role. Default role is admin, alternatives are user and service""" - all_scopes = { - 'admin': [ - 'all', - 'users', - 'users:name', - 'users:groups', - 'users:activity', - 'users:servers', - 'users:tokens', - 'admin:users', - 'admin:users:servers', - 'groups', - 'admin:groups', - 'services', - 'proxy', - 'shutdown', - 'read:hub', - ], - 'user': [ - 'all', - 'users!user={username}', - 'users:activity!user={username}', - 'users:tokens!user={username}', - ], - 'server': ['users:activity'], - 'service': ['services'], - } - scopes = all_scopes[role] - read_only = ["read:" + el for el in scopes] - return scopes + read_only From 9832a87ac47a26ceb3158fe3c4f9d03c494fa0ec Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 9 Mar 2021 10:29:52 +0100 Subject: [PATCH 075/270] Fixed some tests and unified scope read:user:name --- jupyterhub/apihandlers/base.py | 2 +- jupyterhub/apihandlers/users.py | 2 +- jupyterhub/scopes.py | 10 ++++++++-- jupyterhub/tests/test_api.py | 2 +- jupyterhub/tests/test_scopes.py | 2 +- jupyterhub/tests/utils.py | 15 ++++++++------- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index b5e7f31b..19e15f47 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -237,7 +237,7 @@ class APIHandler(BaseHandler): } access_map = { 'read:users': set(model.keys()), # All available components - 'read:users:names': {'kind', 'name'}, + 'read:users:name': {'kind', 'name'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 59619931..f2f8efc7 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -55,7 +55,7 @@ class UserListAPIHandler(APIHandler): @needs_scope( 'read:users', - 'read:users:names', + 'read:users:name', 'reda:users:servers', 'read:users:groups', 'read:users:activity', diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 4bef0241..0fdcce4b 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -22,7 +22,11 @@ def get_scopes_for(orm_object): owner = orm_object.user or orm_object.service owner_name = owner.name token_scopes = roles.get_subscopes(*orm_object.roles) + if 'all' in token_scopes: + token_scopes |= get_user_scopes(owner_name) user_scopes = roles.get_subscopes(*owner.roles) + if 'all' in user_scopes: + user_scopes |= get_user_scopes(owner_name) scopes = token_scopes & user_scopes discarded_token_scopes = token_scopes - scopes # Not taking symmetric difference here because token owner can naturally have more scopes than token @@ -34,8 +38,10 @@ def get_scopes_for(orm_object): else: owner_name = orm_object.name scopes = roles.get_subscopes(*orm_object.roles) - if 'all' in scopes: - scopes |= get_user_scopes(owner_name) + if 'all' in scopes: + scopes |= get_user_scopes( + owner_name + ) # Todo: Expand scopes in separate method return scopes diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index c5f38389..a7d91abf 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1702,7 +1702,7 @@ async def test_update_activity_403(app, user, admin_user): async def test_update_activity_admin(app, user, admin_user): - token = admin_user.new_api_token() + token = admin_user.new_api_token(roles=['admin']) r = await api_request( app, "users/{}/activity".format(user.name), diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 1a70ee32..d21e8047 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -396,7 +396,7 @@ async def test_group_scope_filter(app): async def test_vertical_filter(app): user_name = 'lindsey' add_user(app.db, name=user_name) - test_role = generate_test_role(user_name, ['read:users:names']) + test_role = generate_test_role(user_name, ['read:users:name']) roles.add_role(app.db, test_role) roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 468e432b..a63c73da 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -120,16 +120,17 @@ def add_user(db, app=None, **kwargs): return orm_user -def auth_header(db, name, role=None): - """Return header with user's API authorization token.""" +def auth_header(db, name, inherit=True): + """Return header with user's API authorization token. + If inherit is True, copies the roles of the invoking user + """ user = find_user(db, name) if user is None: raise KeyError(f"No such user: {name}") - roles = [] - if role: - roles = [role] - elif name == 'admin': - roles = ['admin'] + if inherit: + roles = [role.name for role in user.roles] + else: + roles = None token = user.new_api_token(roles=roles) return {'Authorization': 'token %s' % token} From bf333d8e35420f9d905cffab9ea462986bb00de6 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 9 Mar 2021 15:48:24 +0100 Subject: [PATCH 076/270] Changed metascope all meaning --- jupyterhub/roles.py | 49 +++++++++++++++++++++++++++++++++++++++----- jupyterhub/scopes.py | 48 ++++++------------------------------------- 2 files changed, 50 insertions(+), 47 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index c46f7e19..6062757e 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -12,8 +12,8 @@ def get_default_roles(): default_roles = [ { 'name': 'user', - 'description': 'Everything the user can do', - 'scopes': ['all'], + 'description': 'Standard user privileges', + 'scopes': ['self'], }, { 'name': 'admin', @@ -37,11 +37,41 @@ def get_default_roles(): 'description': 'Post activity only', 'scopes': ['users:activity!user=username'], }, + # {'name': 'token', + # 'description': 'Token with same rights as token owner', + # 'scopes': ['all']} ] return default_roles -def get_scopes(): +def expand_self_scope(name, read_only=False): + """ + Users have a metascope 'self' that should be expanded to standard user privileges. + At the moment that is a user-filtered version (optional read) access to + users + users:name + users:groups + users:activity + users:servers + users:tokens + """ + scope_list = [ + 'users', + 'users:name', + 'users:groups', + 'users:activity', + 'users:servers', + 'users:tokens', + ] + read_scope_list = ['read:' + scope for scope in scope_list] + if read_only: + scope_list = read_scope_list + else: + scope_list.extend(read_scope_list) + return {"{}!user={}".format(scope, name) for scope in scope_list} + + +def get_scope_hierarchy(): """ Returns a dictionary of scopes: scopes.keys() = scopes of highest level and scopes that have their own subscopes @@ -49,7 +79,7 @@ def get_scopes(): """ scopes = { - 'all': ['read:all'], + 'all': ['read:all'], # Todo: optional 'users': ['read:users', 'users:activity', 'users:servers'], 'read:users': [ 'read:users:name', @@ -74,7 +104,7 @@ def get_scopes(): def expand_scope(scopename): """Returns a set of all subscopes""" - scopes = get_scopes() + scopes = get_scope_hierarchy() subscopes = [scopename] def expand_subscopes(index): @@ -99,6 +129,15 @@ def expand_scope(scopename): return expanded_scope +def get_scopes_for(orm_object): + """Get the scopes for User/Service/Group/Token""" + scopes = get_subscopes(*orm_object.roles) + if 'self' in scopes: + scopes.remove('self') + scopes += expand_self_scope(orm_object.name) + return scopes + + def get_subscopes(*args): """Returns a set of all available subscopes for a specified role or list of roles""" diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 0fdcce4b..8624fb9e 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -20,14 +20,11 @@ def get_scopes_for(orm_object): return scopes elif isinstance(orm_object, orm.APIToken): owner = orm_object.user or orm_object.service - owner_name = owner.name - token_scopes = roles.get_subscopes(*orm_object.roles) + token_scopes = roles.get_scopes_for(orm_object) + owner_scopes = roles.get_scopes_for(owner) if 'all' in token_scopes: - token_scopes |= get_user_scopes(owner_name) - user_scopes = roles.get_subscopes(*owner.roles) - if 'all' in user_scopes: - user_scopes |= get_user_scopes(owner_name) - scopes = token_scopes & user_scopes + token_scopes |= owner_scopes + scopes = token_scopes & owner_scopes discarded_token_scopes = token_scopes - scopes # Not taking symmetric difference here because token owner can naturally have more scopes than token if discarded_token_scopes: @@ -36,42 +33,10 @@ def get_scopes_for(orm_object): % ", ".join(discarded_token_scopes) ) else: - owner_name = orm_object.name - scopes = roles.get_subscopes(*orm_object.roles) - if 'all' in scopes: - scopes |= get_user_scopes( - owner_name - ) # Todo: Expand scopes in separate method + scopes = roles.get_scopes_for(orm_object) return scopes -def get_user_scopes(name, read_only=False): - """ - Scopes have a metascope 'all' that should be expanded to everything a user can do. - At the moment that is a user-filtered version (optional read) access to - users - users:name - users:groups - users:activity - users:servers - users:tokens - """ - scope_list = [ - 'users', - 'users:name', - 'users:groups', - 'users:activity', - 'users:servers', - 'users:tokens', - ] - read_scope_list = ['read:' + scope for scope in scope_list] - if read_only: - scope_list = read_scope_list - else: - scope_list.extend(read_scope_list) - return {"{}!user={}".format(scope, name) for scope in scope_list} - - def _needs_scope_expansion(filter_, filter_value, sub_scope): """ Check if there is a requirements to expand the `group` scope to individual `user` scopes. @@ -97,8 +62,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): def _check_scope(api_handler, req_scope, **kwargs): """Check if scopes satisfy requirements - Returns either True for unrestricted access, False for refused access or - an iterable with a filter + Returns True for (restricted) access, False for refused access """ # Parse user name and server name together try: From 39fc501d5018264c64cc1a38bf316d02c0d2fb61 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 9 Mar 2021 16:38:43 +0100 Subject: [PATCH 077/270] Add warnings and errors when creating new roles --- jupyterhub/roles.py | 30 ++++++++++++++++++++----- jupyterhub/tests/test_roles.py | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index c46f7e19..4f024249 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -3,6 +3,8 @@ # Distributed under the terms of the Modified BSD License. from itertools import chain +from tornado.log import app_log + from . import orm @@ -35,7 +37,7 @@ def get_default_roles(): { 'name': 'server', 'description': 'Post activity only', - 'scopes': ['users:activity!user=username'], + 'scopes': ['users:activity'], }, ] return default_roles @@ -114,9 +116,8 @@ def get_subscopes(*args): def add_role(db, role_dict): """Adds a new role to database or modifies an existing one""" - if 'name' not in role_dict.keys(): - raise ValueError('Role must have a name') + raise KeyError('Role definition must have a name') else: name = role_dict['name'] role = orm.Role.find(db, name) @@ -126,15 +127,34 @@ def add_role(db, role_dict): if role is None: role = orm.Role(name=name, description=description, scopes=scopes) + if not scopes: + app_log.warning('Warning: New defined role %s has no scopes', name) db.add(role) else: if description: - role.description = description + if role.name == 'admin' and description != role.description: + raise AttributeError('admin role description cannot be overwritten') + else: + role.description = description if scopes: - role.scopes = scopes + if role.name == 'admin' and scopes != role.scopes: + raise AttributeError('admin role scopes cannot be overwritten') + else: + role.scopes = scopes db.commit() +def remove_role(db, rolename): + """Removes a role from database""" + + role = orm.Role.find(db, rolename) + if role: + db.delete(role) + db.commit() + else: + raise NameError('Cannot remove role %r that does not exist', rolename) + + def existing_only(func): """Decorator for checking if objects and roles exist""" diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index bdc8b98a..854578b1 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -3,7 +3,9 @@ # Distributed under the terms of the Modified BSD License. import json +import pytest from pytest import mark +from tornado.log import app_log from .. import orm from .. import roles @@ -183,6 +185,7 @@ def test_get_subscopes(db, scopes, subscopes): db.delete(role) +@mark.role async def test_load_default_roles(tmpdir, request): """Test loading default roles in app.py""" kwargs = {} @@ -199,6 +202,44 @@ async def test_load_default_roles(tmpdir, request): assert orm.Role.find(db, 'server') is not None +@mark.role +@mark.parametrize( + "role, role_def, response_type, response", + [ + ('no_name', {'scopes': ['users']}, 'error', KeyError), + ( + 'no_scopes', + {'name': 'no-permissions'}, + 'warning', + app_log.warning('Warning: New defined role no-permissions has no scopes'), + ), + ( + 'admin', + {'name': 'admin', 'scopes': ['admin:users']}, + 'error', + AttributeError, + ), + ], +) +async def test_adding_new_roles_raise_errors( + tmpdir, request, role, role_def, response_type, response +): + """Test raising errors and warnings when creating new roles""" + kwargs = {'load_roles': [role_def]} + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + if response_type == 'error': + with pytest.raises(response): + await hub.init_roles() + elif response_type == 'warning': + with pytest.warns(response): + await hub.init_roles() + + @mark.role async def test_load_roles_users(tmpdir, request): """Test loading predefined roles for users in app.py""" From 01f32866204e712bf2117c6d3dc2c3af82e5681e Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 11 Mar 2021 15:30:11 +0100 Subject: [PATCH 078/270] Add check that scopes exists when adding new/modifying existing role --- jupyterhub/roles.py | 59 ++++++++++++++---- jupyterhub/tests/test_roles.py | 106 +++++++++++++++++++++++++++------ 2 files changed, 137 insertions(+), 28 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 4f024249..556c343c 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -114,8 +114,48 @@ def get_subscopes(*args): return scopes +def check_scopes(*args): + """Check if provided scopes exist""" + + allowed_scopes = get_scopes() + allowed_filters = ['!user=', '!group=', '!server='] + subscopes = set( + chain.from_iterable([x for x in allowed_scopes.values() if x is not None]) + ) + + for scope in args: + # check the ! filters + if '!' in scope: + if any(filter in scope for filter in allowed_filters): + scope = scope.split('!', 1)[0] + else: + raise NameError( + 'Scope filter %r in scope %r does not exist', + scope.split('!', 1)[1], + scope, + ) + # check if the actual scope syntax exists + if scope not in allowed_scopes.keys() and scope not in subscopes: + raise NameError('Scope %r does not exist', scope) + + +def overwrite_role(role, role_dict): + """Overwrites role's description and/or scopes with role_dict if role not 'admin'""" + + for attr in role_dict.keys(): + if attr == 'description' or attr == 'scopes': + if role.name == 'admin' and role_dict[attr] != getattr(role, attr): + raise ValueError( + 'admin role description or scopes cannot be overwritten' + ) + else: + setattr(role, attr, role_dict[attr]) + app_log.info('Role %r %r attribute has been changed', role.name, attr) + + def add_role(db, role_dict): """Adds a new role to database or modifies an existing one""" + if 'name' not in role_dict.keys(): raise KeyError('Role definition must have a name') else: @@ -125,22 +165,19 @@ def add_role(db, role_dict): description = role_dict.get('description') scopes = role_dict.get('scopes') + # check if the provided scopes exist + if scopes: + check_scopes(*scopes) + if role is None: - role = orm.Role(name=name, description=description, scopes=scopes) if not scopes: app_log.warning('Warning: New defined role %s has no scopes', name) + + role = orm.Role(name=name, description=description, scopes=scopes) db.add(role) else: - if description: - if role.name == 'admin' and description != role.description: - raise AttributeError('admin role description cannot be overwritten') - else: - role.description = description - if scopes: - if role.name == 'admin' and scopes != role.scopes: - raise AttributeError('admin role scopes cannot be overwritten') - else: - role.scopes = scopes + overwrite_role(role, role_dict) + db.commit() diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 854578b1..1d2f60a1 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -2,6 +2,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import json +from itertools import chain import pytest from pytest import mark @@ -217,14 +218,27 @@ async def test_load_default_roles(tmpdir, request): 'admin', {'name': 'admin', 'scopes': ['admin:users']}, 'error', - AttributeError, + ValueError, + ), + ( + 'admin', + {'name': 'admin', 'description': 'New description'}, + 'error', + ValueError, + ), + ( + 'user', + {'name': 'user', 'scopes': ['read:users:name']}, + 'info', + app_log.info('Role user scopes attribute has been changed'), ), ], ) -async def test_adding_new_roles_raise_errors( +async def test_adding_new_roles( tmpdir, request, role, role_def, response_type, response ): """Test raising errors and warnings when creating new roles""" + kwargs = {'load_roles': [role_def]} ssl_enabled = getattr(request.module, "ssl_enabled", False) if ssl_enabled: @@ -232,14 +246,64 @@ async def test_adding_new_roles_raise_errors( hub = MockHub(**kwargs) hub.init_db() db = hub.db + if response_type == 'error': with pytest.raises(response): await hub.init_roles() - elif response_type == 'warning': + + elif response_type == 'warning' or response_type == 'info': with pytest.warns(response): await hub.init_roles() +@mark.role +@mark.parametrize( + "role, response", + [ + ( + { + 'name': 'test-scopes-1', + 'scopes': [ + 'users', + 'users!user=charlie', + 'admin:groups', + 'read:users:tokens', + ], + }, + 'existing', + ), + ({'name': 'test-scopes-2', 'scopes': ['uses']}, NameError), + ({'name': 'test-scopes-3', 'scopes': ['users:activities']}, NameError), + ({'name': 'test-scopes-4', 'scopes': ['groups!goup=class-A']}, NameError), + ], +) +async def test_scope_existence(tmpdir, request, role, response): + """Test checking of scopes provided in role definitions""" + kwargs = {'load_roles': [role]} + ssl_enabled = getattr(request.module, "ssl_enabled", False) + if ssl_enabled: + kwargs['internal_certs_location'] = str(tmpdir) + hub = MockHub(**kwargs) + hub.init_db() + db = hub.db + + if response == 'existing': + roles.add_role(db, role) + added_role = orm.Role.find(db, role['name']) + assert added_role is not None + assert added_role.scopes == role['scopes'] + + elif response == NameError: + with pytest.raises(response): + roles.add_role(db, role) + added_role = orm.Role.find(db, role['name']) + assert added_role is None + + # delete the tested roles + if added_role: + roles.remove_role(db, added_role.name) + + @mark.role async def test_load_roles_users(tmpdir, request): """Test loading predefined roles for users in app.py""" @@ -296,16 +360,21 @@ async def test_load_roles_users(tmpdir, request): @mark.role async def test_load_roles_services(tmpdir, request): services = [ - {'name': 'cull_idle', 'api_token': 'some-token'}, + {'name': 'idle-culler', 'api_token': 'some-token'}, {'name': 'user_service', 'api_token': 'some-other-token'}, {'name': 'admin_service', 'api_token': 'secret-token', 'admin': True}, ] roles_to_load = [ { - 'name': 'culler', + 'name': 'idle-culler', 'description': 'Cull idle servers', - 'scopes': ['users:servers', 'admin:servers'], - 'services': ['cull_idle'], + 'scopes': [ + 'read:users:name', + 'read:users:activity', + 'read:users:servers', + 'users:servers', + ], + 'services': ['idle-culler'], }, ] kwargs = {'load_roles': roles_to_load} @@ -340,8 +409,8 @@ async def test_load_roles_services(tmpdir, request): assert user_role not in service.roles # test if predefined roles loaded and assigned - culler_role = orm.Role.find(db, name='culler') - cull_idle = orm.Service.find(db, name='cull_idle') + culler_role = orm.Role.find(db, name='idle-culler') + cull_idle = orm.Service.find(db, name='idle-culler') assert culler_role in cull_idle.roles assert user_role not in cull_idle.roles @@ -353,21 +422,24 @@ async def test_load_roles_services(tmpdir, request): @mark.role async def test_load_roles_tokens(tmpdir, request): - services = [ - {'name': 'cull_idle', 'admin': True, 'api_token': 'another-secret-token'} - ] + services = [{'name': 'idle-culler', 'api_token': 'another-secret-token'}] user_tokens = { 'secret-token': 'cyclops', 'super-secret-token': 'admin', } service_tokens = { - 'another-secret-token': 'cull_idle', + 'another-secret-token': 'idle-culler', } roles_to_load = [ { - 'name': 'culler', + 'name': 'idle-culler', 'description': 'Cull idle servers', - 'scopes': ['users:servers', 'admin:servers'], + 'scopes': [ + 'read:users:name', + 'read:users:activity', + 'read:users:servers', + 'users:servers', + ], 'tokens': ['another-secret-token'], }, ] @@ -390,8 +462,8 @@ async def test_load_roles_tokens(tmpdir, request): await hub.init_roles() # test if another-secret-token has culler role - service = orm.Service.find(db, 'cull_idle') - culler_role = orm.Role.find(db, 'culler') + service = orm.Service.find(db, 'idle-culler') + culler_role = orm.Role.find(db, 'idle-culler') token = orm.APIToken.find(db, 'another-secret-token') assert len(token.roles) == 1 assert culler_role in token.roles From 7496fda0890f8121115e103a1dce8f1c96c7b33e Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 11 Mar 2021 19:33:05 +0100 Subject: [PATCH 079/270] Implemented default token roles, self scope for users and tokens for mockservices --- jupyterhub/orm.py | 4 ++-- jupyterhub/roles.py | 33 ++++++++++++++++++--------------- jupyterhub/scopes.py | 1 + jupyterhub/tests/conftest.py | 3 +++ jupyterhub/tests/test_api.py | 4 ++-- jupyterhub/tests/utils.py | 8 ++------ 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 38a51bde..8830a521 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -617,8 +617,8 @@ class APIToken(Hashed, Base): db.add(orm_token) # load default roles if they haven't been initiated # correct to have this here? otherwise some tests fail - user_role = Role.find(db, 'user') - if not user_role: + token_role = Role.find(db, 'token') + if not token_role: default_roles = get_default_roles() for role in default_roles: add_role(db, role) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 6062757e..5223fa9b 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -37,9 +37,11 @@ def get_default_roles(): 'description': 'Post activity only', 'scopes': ['users:activity!user=username'], }, - # {'name': 'token', - # 'description': 'Token with same rights as token owner', - # 'scopes': ['all']} + { + 'name': 'token', + 'description': 'Token with same rights as token owner', + 'scopes': ['all'], + }, ] return default_roles @@ -79,7 +81,7 @@ def get_scope_hierarchy(): """ scopes = { - 'all': ['read:all'], # Todo: optional + 'all': None, # Optional 'read:all' as subscope, not implemented at this stage 'users': ['read:users', 'users:activity', 'users:servers'], 'read:users': [ 'read:users:name', @@ -134,7 +136,7 @@ def get_scopes_for(orm_object): scopes = get_subscopes(*orm_object.roles) if 'self' in scopes: scopes.remove('self') - scopes += expand_self_scope(orm_object.name) + scopes |= expand_self_scope(orm_object.name) return scopes @@ -236,8 +238,8 @@ def update_roles(db, obj, kind, roles=None): assigns default if no roles specified""" Class = orm.get_class(kind) - user_role = orm.Role.find(db, 'user') - + default_token_role = orm.Role.find(db, 'token') + standard_permissions = {'all', 'read:all'} if roles: for rolename in roles: if Class == orm.APIToken: @@ -246,6 +248,7 @@ def update_roles(db, obj, kind, roles=None): if role: # compare the requested role permissions with the owner's permissions (scopes) token_scopes = get_subscopes(role) + extra_scopes = token_scopes - standard_permissions # find the owner and their roles owner = None if obj.user_id: @@ -253,24 +256,24 @@ def update_roles(db, obj, kind, roles=None): elif obj.service_id: owner = db.query(orm.Service).get(obj.service_id) if owner: - owner_scopes = get_subscopes(*owner.roles) - if token_scopes.issubset(owner_scopes): + owner_scopes = get_scopes_for(owner) + if (extra_scopes).issubset(owner_scopes): role.tokens.append(obj) else: raise ValueError( - 'Requested token role %r has higher permissions than the token owner' - % rolename + 'Requested token role %r has more permissions than the token owner: [%s]' + % (rolename, ",".join(extra_scopes - owner_scopes)) ) else: raise NameError('Role %r does not exist' % rolename) else: add_obj(db, objname=obj.name, kind=kind, rolename=rolename) else: - # tokens can have only 'user' role as default - # assign the default only for user tokens + # tokens can have only 'token' role as default + # assign the default only for tokens if Class == orm.APIToken: - if len(obj.roles) < 1 and obj.user is not None: - user_role.tokens.append(obj) + if not obj.roles and obj.user is not None: + default_token_role.tokens.append(obj) db.commit() # users and services can have 'user' or 'admin' roles as default else: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 8624fb9e..26a038d5 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -23,6 +23,7 @@ def get_scopes_for(orm_object): token_scopes = roles.get_scopes_for(orm_object) owner_scopes = roles.get_scopes_for(owner) if 'all' in token_scopes: + token_scopes.remove('all') token_scopes |= owner_scopes scopes = token_scopes & owner_scopes discarded_token_scopes = token_scopes - scopes diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 45bfd203..6831a14b 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -45,6 +45,7 @@ from . import mocking from .. import crypto from .. import orm from ..roles import mock_roles +from ..roles import update_roles from ..utils import random_port from .mocking import MockHub from .test_services import mockservice_cmd @@ -249,6 +250,8 @@ def _mockservice(request, app, url=False): mock_roles(app, name, 'services') assert name in app._service_map service = app._service_map[name] + token = service.orm.api_tokens[0] + update_roles(app.db, token, 'tokens', roles=['token']) async def start(): # wait for proxy to be updated before starting the service diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index a7d91abf..d3e3dadd 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1319,7 +1319,7 @@ async def test_token_for_user(app, as_user, for_user, status): if for_user != 'missing': for_user_obj = add_user(app.db, app, name=for_user) data = {'username': for_user} - headers = {'Authorization': 'token %s' % u.new_api_token(roles=[as_user])} + headers = {'Authorization': 'token %s' % u.new_api_token()} r = await api_request( app, 'users', @@ -1414,7 +1414,7 @@ async def test_token_list(app, as_user, for_user, status): u = add_user(app.db, app, name=as_user) if for_user != 'missing': for_user_obj = add_user(app.db, app, name=for_user) - headers = {'Authorization': 'token %s' % u.new_api_token(roles=[as_user])} + headers = {'Authorization': 'token %s' % u.new_api_token()} r = await api_request(app, 'users', for_user, 'tokens', headers=headers) assert r.status_code == status if status != 200: diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index a63c73da..8ac946ba 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -120,18 +120,14 @@ def add_user(db, app=None, **kwargs): return orm_user -def auth_header(db, name, inherit=True): +def auth_header(db, name): """Return header with user's API authorization token. If inherit is True, copies the roles of the invoking user """ user = find_user(db, name) if user is None: raise KeyError(f"No such user: {name}") - if inherit: - roles = [role.name for role in user.roles] - else: - roles = None - token = user.new_api_token(roles=roles) + token = user.new_api_token() return {'Authorization': 'token %s' % token} From c5ebee0ca0b80ce2b1a7699a5106711db160607f Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 12 Mar 2021 09:40:36 +0100 Subject: [PATCH 080/270] Fixed scope related tests --- jupyterhub/handlers/base.py | 1 + jupyterhub/tests/test_auth_expiry.py | 1 + jupyterhub/tests/test_roles.py | 24 +++++++++++++----------- jupyterhub/tests/test_services.py | 3 +++ jupyterhub/tests/test_singleuser.py | 8 +++----- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index c1d03fd1..b1a40865 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -447,6 +447,7 @@ class BaseHandler(RequestHandler): else: # deprecated oauth tokens user_from_oauth = self.get_current_user_oauth_token() self.raw_scopes = scopes.get_scopes_for(user_from_oauth) + app_log.debug("Found scopes [%s]", ",".join(self.raw_scopes)) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) @property diff --git a/jupyterhub/tests/test_auth_expiry.py b/jupyterhub/tests/test_auth_expiry.py index 48f85eb4..59598219 100644 --- a/jupyterhub/tests/test_auth_expiry.py +++ b/jupyterhub/tests/test_auth_expiry.py @@ -101,6 +101,7 @@ async def test_auth_expired_page(app, user, disable_refresh): assert user._auth_refreshed == before +# Fixme: Why does this text fail? async def test_auth_expired_api(app, user, disable_refresh): cookies = await app.login_user(user.name) assert user._auth_refreshed diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index bdc8b98a..4f2c7475 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -17,11 +17,13 @@ from .utils import api_request def test_orm_roles(db): """Test orm roles setup""" user_role = orm.Role.find(db, name='user') + token_role = orm.Role.find(db, name='token') if not user_role: - user_role = orm.Role(name='user', scopes=['all', 'read:all']) + user_role = orm.Role(name='user', scopes=['self']) db.add(user_role) - db.commit() - + if not token_role: + token_role = orm.Role(name='token', scopes=['all']) + db.add(token_role) service_role = orm.Role(name='service', scopes=['users:servers']) db.add(service_role) db.commit() @@ -53,8 +55,8 @@ def test_orm_roles(db): # assigns it the default 'user' role token = user.new_api_token() user_token = orm.APIToken.find(db, token=token) - assert user_token in user_role.tokens - assert user_role in user_token.roles + assert user_token in token_role.tokens + assert token_role in user_token.roles # check creating token with a specific role token = service.new_api_token(roles=['service']) @@ -66,7 +68,7 @@ def test_orm_roles(db): db.delete(user) db.commit() assert user_role.users == [] - assert user_token not in user_role.tokens + assert user_token not in token_role.tokens # check deleting the service token removes it from 'service' role db.delete(service_token) db.commit() @@ -356,11 +358,11 @@ async def test_load_roles_tokens(tmpdir, request): assert culler_role in token.roles # test if all other tokens have default 'user' role - user_role = orm.Role.find(db, 'user') + token_role = orm.Role.find(db, 'token') sec_token = orm.APIToken.find(db, 'secret-token') - assert user_role in sec_token.roles + assert token_role in sec_token.roles s_sec_token = orm.APIToken.find(db, 'super-secret-token') - assert user_role in s_sec_token.roles + assert token_role in s_sec_token.roles @mark.role @@ -375,7 +377,7 @@ async def test_load_roles_tokens(tmpdir, request): ) async def test_get_new_token_via_api(app, headers, role_list, status): user = add_user(app.db, app, name='user') - roles.add_role(app.db, {'name': 'reader', 'scopes': ['read:all']}) + roles.add_role(app.db, {'name': 'reader', 'scopes': ['all']}) roles.add_role(app.db, {'name': 'user_creator', 'scopes': ['admin:users']}) if role_list: body = json.dumps({'roles': role_list}) @@ -393,7 +395,7 @@ async def test_get_new_token_via_api(app, headers, role_list, status): assert 'token' in reply assert reply['user'] == 'user' if not role_list: - assert reply['roles'] == ['user'] + assert reply['roles'] == ['token'] else: assert reply['roles'] == ['reader'] token_id = reply['id'] diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 379f92aa..55ba907e 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -9,6 +9,7 @@ from subprocess import Popen from async_generator import asynccontextmanager from tornado.ioloop import IOLoop +from ..roles import update_roles from ..utils import maybe_future from ..utils import random_port from ..utils import url_path_join @@ -93,6 +94,8 @@ async def test_external_service(app): await app.proxy.add_all_services(app._service_map) service = app._service_map[name] + api_token = service.orm.api_tokens[0] + update_roles(app.db, api_token, 'tokens', roles=['token']) url = public_url(app, service) + '/api/users' r = await async_requests.get(url, allow_redirects=False) r.raise_for_status() diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index 49b366c9..3d461111 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -50,11 +50,9 @@ async def test_singleuser_auth(app): assert urlparse(r.url).path.endswith('/oauth2/authorize') # submit the oauth form to complete authorization r = await s.post(r.url, data={'scopes': ['identify']}, headers={'Referer': r.url}) - assert ( - urlparse(r.url) - .path.rstrip('/') - .endswith(url_path_join('/user/nandy', user.spawner.default_url or "/tree")) - ) + final_url = urlparse(r.url).path.rstrip('/') + final_path = url_path_join('/user/nandy', user.spawner.default_url or "/tree") + assert final_url.endswith(final_path) # user isn't authorized, should raise 403 assert r.status_code == 403 assert 'burgess' in r.text From bdc7b3ab8d9d9653ce8e8b50b48d51d014297102 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 12 Mar 2021 16:09:23 +0100 Subject: [PATCH 081/270] Account for horizontal filtering in get_subscopes() --- jupyterhub/roles.py | 28 +++++++++++++++++++++++++++- jupyterhub/tests/test_roles.py | 21 +++++++++++++-------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 556c343c..49a30b50 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -73,6 +73,22 @@ def get_scopes(): return scopes +def horizontal_filter(func): + """Decorator to account for horizontal filtering in scope syntax""" + + def ignore(scopename): + # temporarily remove horizontal filtering if present + scopename, mark, hor_filter = scopename.partition('!') + expanded_scope = func(scopename) + # add the filter back + full_expanded_scope = {scope + mark + hor_filter for scope in expanded_scope} + + return full_expanded_scope + + return ignore + + +@horizontal_filter def expand_scope(scopename): """Returns a set of all subscopes""" @@ -264,6 +280,11 @@ def update_roles(db, obj, kind, roles=None): if role: # compare the requested role permissions with the owner's permissions (scopes) token_scopes = get_subscopes(role) + # ignore horizontal filters for comparison + t_scopes = { + scope.split('!', 1)[0] if '!' in scope else scope + for scope in token_scopes + } # find the owner and their roles owner = None if obj.user_id: @@ -272,7 +293,12 @@ def update_roles(db, obj, kind, roles=None): owner = db.query(orm.Service).get(obj.service_id) if owner: owner_scopes = get_subscopes(*owner.roles) - if token_scopes.issubset(owner_scopes): + # ignore horizontal filters for comparison + o_scopes = { + scope.split('!', 1)[0] if '!' in scope else scope + for scope in owner_scopes + } + if t_scopes.issubset(o_scopes): role.tokens.append(obj) else: raise ValueError( diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 1d2f60a1..f00cdb61 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -21,7 +21,7 @@ def test_orm_roles(db): """Test orm roles setup""" user_role = orm.Role.find(db, name='user') if not user_role: - user_role = orm.Role(name='user', scopes=['all', 'read:all']) + user_role = orm.Role(name='user', scopes=['self']) db.add(user_role) db.commit() @@ -175,6 +175,10 @@ def test_orm_roles_delete_cascade(db): ), (['read:users:servers'], {'read:users:servers'}), (['admin:groups'], {'admin:groups'}), + ( + ['users:tokens!group=hobbits'], + {'users:tokens!group=hobbits', 'read:users:tokens!group=hobbits'}, + ), ], ) def test_get_subscopes(db, scopes, subscopes): @@ -316,9 +320,8 @@ async def test_load_roles_users(tmpdir, request): }, { 'name': 'user', - 'description': 'Only read access', - 'scopes': ['read:all'], - 'users': ['bilbo'], + 'description': 'Read access to users names', + 'scopes': ['read:users:name'], }, ] kwargs = {'load_roles': roles_to_load} @@ -333,12 +336,13 @@ async def test_load_roles_users(tmpdir, request): await hub.init_users() await hub.init_roles() - # test if the 'user' role has been overwritten and assigned + # test if the 'user' role has been overwritten user_role = orm.Role.find(db, 'user') - admin_role = orm.Role.find(db, 'admin') assert user_role is not None - assert user_role.scopes == ['read:all'] + assert user_role.description == roles_to_load[1]['description'] + assert user_role.scopes == roles_to_load[1]['scopes'] + admin_role = orm.Role.find(db, 'admin') # test if every user has a role (and no duplicates) # and admins have admin role for user in db.query(orm.User): @@ -504,8 +508,9 @@ async def test_get_new_token_via_api(app, headers, role_list, status): # check the new-token reply for roles reply = r.json() assert 'token' in reply - assert reply['user'] == 'user' + assert reply['user'] == user.name if not role_list: + # token should have a default role assert reply['roles'] == ['user'] else: assert reply['roles'] == ['reader'] From b6221f6cb11699af93cdab7ee373c1416fc12c9c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 12 Mar 2021 17:40:38 +0100 Subject: [PATCH 082/270] Fix tests --- jupyterhub/roles.py | 2 +- jupyterhub/tests/test_roles.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index b30624ea..d008903d 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -135,7 +135,7 @@ def check_scopes(*args): """Check if provided scopes exist""" allowed_scopes = get_scopes() - allowed_filters = ['!user=', '!group=', '!server='] + allowed_filters = ['!user=', '!service=', '!group=', '!server='] subscopes = set( chain.from_iterable([x for x in allowed_scopes.values() if x is not None]) ) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 7d143f24..fed9418e 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -389,7 +389,7 @@ async def test_load_roles_services(tmpdir, request): {'name': 'admin_service', 'api_token': 'secret-token'}, ] service_tokens = { - 'some-token': 'cull_idle', + 'some-token': 'idle-culler', 'some-other-token': 'user_service', 'secret-token': 'admin_service', } @@ -620,9 +620,6 @@ async def test_load_roles_service_tokens(tmpdir, request): hub.init_db() db = hub.db await hub.init_api_tokens() - # make the service admin - service = orm.Service.find(db, 'cull_idle') - service.admin = True await hub.init_roles() # test if another-secret-token has culler role From 5997245cadefb4325fc2a6bc975f12bc39a332fc Mon Sep 17 00:00:00 2001 From: 0mar Date: Sun, 14 Mar 2021 17:50:36 +0100 Subject: [PATCH 083/270] Added tests to verify token scope behavior --- jupyterhub/tests/test_scopes.py | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index d21e8047..8526a831 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -278,6 +278,72 @@ async def test_request_fake_user(app): assert r.json()['message'] == err_message +async def test_refuse_exceeding_token_permissions(app): + user_name = 'abed' + user = add_user(app.db, name=user_name) + add_user(app.db, name='user') + api_token = user.new_api_token() + exceeding_role = generate_test_role(user_name, ['read:users'], 'exceeding_role') + roles.add_role(app.db, exceeding_role) + roles.add_obj(app.db, objname=api_token, kind='tokens', rolename='exceeding_role') + app.db.commit() + headers = {'Authorization': 'token %s' % api_token} + r = await api_request(app, 'users', headers=headers) + assert r.status_code == 200 + result_names = {user['name'] for user in r.json()} + assert result_names == {user_name} + + +async def test_exceeding_user_permissions(app): + user_name = 'abed' + user = add_user(app.db, name=user_name) + add_user(app.db, name='user') + api_token = user.new_api_token() + orm_api_token = orm.APIToken.find(app.db, token=api_token) + reader_role = generate_test_role(user_name, ['read:users'], 'reader_role') + subreader_role = generate_test_role( + user_name, ['read:users:groups'], 'subreader_role' + ) + roles.add_role(app.db, reader_role) + roles.add_role(app.db, subreader_role) + app.db.commit() + roles.update_roles(app.db, user, kind='users', roles=['reader_role']) + roles.update_roles(app.db, orm_api_token, kind='tokens', roles=['subreader_role']) + orm_api_token.roles.remove(orm.Role.find(app.db, name='token')) + app.db.commit() + + headers = {'Authorization': 'token %s' % api_token} + r = await api_request(app, 'users', headers=headers) + assert r.status_code == 200 + keys = {key for user in r.json() for key in user.keys()} + assert 'groups' in keys + assert 'last_activity' not in keys + + +async def test_user_service_separation(app, mockservice_url): + name = mockservice_url.name + user = add_user(app.db, name=name) + + reader_role = generate_test_role(name, ['read:users'], 'reader_role') + subreader_role = generate_test_role(name, ['read:users:groups'], 'subreader_role') + roles.add_role(app.db, reader_role) + roles.add_role(app.db, subreader_role) + app.db.commit() + roles.update_roles(app.db, user, kind='users', roles=['subreader_role']) + roles.update_roles( + app.db, mockservice_url.orm, kind='services', roles=['reader_role'] + ) + user.roles.remove(orm.Role.find(app.db, name='user')) + api_token = user.new_api_token() + app.db.commit() + headers = {'Authorization': 'token %s' % api_token} + r = await api_request(app, 'users', headers=headers) + assert r.status_code == 200 + keys = {key for user in r.json() for key in user.keys()} + assert 'groups' in keys + assert 'last_activity' not in keys + + async def test_request_user_outside_group(app): user_name = 'buster' fake_user = 'hello' From 7d5fc27f7ceafcfb100869045a5372ae08afa7a7 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 16 Mar 2021 11:03:18 +0100 Subject: [PATCH 084/270] Make some funcs in roles.py private --- jupyterhub/roles.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index d008903d..23c2f5ae 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -90,13 +90,13 @@ def horizontal_filter(func): @horizontal_filter -def expand_scope(scopename): +def _expand_scope(scopename): """Returns a set of all subscopes""" scopes = get_scopes() subscopes = [scopename] - def expand_subscopes(index): + def _expand_subscopes(index): more_subscopes = list( filter(lambda scope: scope in scopes.keys(), subscopes[index:]) @@ -109,9 +109,9 @@ def expand_scope(scopename): # record the index from where it should check for "subscopes of sub-subscopes" index_for_sssc = len(subscopes) # check for "subscopes of subscopes" - expand_subscopes(index=1) + _expand_subscopes(index=1) # check for "subscopes of sub-subscopes" - expand_subscopes(index=index_for_sssc) + _expand_subscopes(index=index_for_sssc) expanded_scope = set(subscopes) @@ -126,12 +126,12 @@ def get_subscopes(*args): for role in args: scope_list.extend(role.scopes) - scopes = set(chain.from_iterable(list(map(expand_scope, scope_list)))) + scopes = set(chain.from_iterable(list(map(_expand_scope, scope_list)))) return scopes -def check_scopes(*args): +def _check_scopes(*args): """Check if provided scopes exist""" allowed_scopes = get_scopes() @@ -156,7 +156,7 @@ def check_scopes(*args): raise NameError('Scope %r does not exist', scope) -def overwrite_role(role, role_dict): +def _overwrite_role(role, role_dict): """Overwrites role's description and/or scopes with role_dict if role not 'admin'""" for attr in role_dict.keys(): @@ -186,7 +186,7 @@ def add_role(db, role_dict): # check if the provided scopes exist if scopes: - check_scopes(*scopes) + _check_scopes(*scopes) if role is None: if not scopes: @@ -197,7 +197,7 @@ def add_role(db, role_dict): if role_dict not in default_roles: app_log.info('Adding role %s to database', name) else: - overwrite_role(role, role_dict) + _overwrite_role(role, role_dict) db.commit() @@ -216,7 +216,7 @@ def remove_role(db, rolename): def existing_only(func): """Decorator for checking if objects and roles exist""" - def check_existence(db, objname, kind, rolename): + def _check_existence(db, objname, kind, rolename): Class = orm.get_class(kind) obj = Class.find(db, objname) @@ -229,7 +229,7 @@ def existing_only(func): else: func(db, obj, kind, role) - return check_existence + return _check_existence @existing_only @@ -264,13 +264,13 @@ def remove_obj(db, objname, kind, rolename): ) -def switch_default_role(db, obj, kind, admin): +def _switch_default_role(db, obj, kind, admin): """Switch between default user and admin roles for users/services""" user_role = orm.Role.find(db, 'user') admin_role = orm.Role.find(db, 'admin') - def add_and_remove(db, obj, kind, current_role, new_role): + def _add_and_remove(db, obj, kind, current_role, new_role): if current_role in obj.roles: remove_obj(db, objname=obj.name, kind=kind, rolename=current_role.name) @@ -279,12 +279,12 @@ def switch_default_role(db, obj, kind, admin): add_obj(db, objname=obj.name, kind=kind, rolename=new_role.name) if admin: - add_and_remove(db, obj, kind, user_role, admin_role) + _add_and_remove(db, obj, kind, user_role, admin_role) else: - add_and_remove(db, obj, kind, admin_role, user_role) + _add_and_remove(db, obj, kind, admin_role, user_role) -def token_allowed_role(db, token, role): +def _token_allowed_role(db, token, role): """Returns True if token allowed to have requested role through comparing the requested scopes with the set of token's owner scopes @@ -339,7 +339,7 @@ def update_roles(db, obj, kind, roles=None): 'Checking token permissions against requested role %s', rolename ) - if token_allowed_role(db, obj, role): + if _token_allowed_role(db, obj, role): role.tokens.append(obj) app_log.info( 'Adding role %s for %s: %s', role.name, kind[:-1], obj @@ -369,7 +369,7 @@ def update_roles(db, obj, kind, roles=None): # users and services can have 'user' or 'admin' roles as default else: app_log.debug('Assigning default roles to %s', kind) - switch_default_role(db, obj, kind, obj.admin) + _switch_default_role(db, obj, kind, obj.admin) def add_predef_roles_tokens(db, predef_roles): From f3fc0e96dec795f07a8403beae004265f244f25a Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 16 Mar 2021 19:10:57 +0100 Subject: [PATCH 085/270] Fixed OAuth token behavior, invalid user handling and name clashes --- jupyterhub/apihandlers/base.py | 4 ++-- jupyterhub/handlers/base.py | 23 ++++++++++++++--------- jupyterhub/roles.py | 10 +++++++--- jupyterhub/scopes.py | 11 ++++++----- jupyterhub/tests/test_auth_expiry.py | 1 - jupyterhub/tests/utils.py | 4 +--- 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 19e15f47..be74967f 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -85,14 +85,14 @@ class APIHandler(BaseHandler): param kind: 'users' or 'services' or 'groups' """ if sub_scope == scopes.Scope.ALL: - found_resource = True + return True else: found_resource = orm_resource.name in sub_scope[kind] if not found_resource: # Try group-based access if 'group' in sub_scope and kind == 'user': group_names = {group.name for group in orm_resource.groups} user_in_group = bool(group_names & set(sub_scope['group'])) - found_resource |= user_in_group + found_resource = user_in_group return found_resource return has_access diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index b1a40865..32144813 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -439,16 +439,21 @@ class BaseHandler(RequestHandler): def _resolve_scopes(self): self.raw_scopes = set() app_log.debug("Loading and parsing scopes") - api_token = self.get_token() - if api_token: - self.raw_scopes = scopes.get_scopes_for(api_token) - elif self.current_user: - self.raw_scopes = scopes.get_scopes_for(self.current_user) - else: # deprecated oauth tokens - user_from_oauth = self.get_current_user_oauth_token() - self.raw_scopes = scopes.get_scopes_for(user_from_oauth) - app_log.debug("Found scopes [%s]", ",".join(self.raw_scopes)) + if not self.current_user: + app_log.debug("No user found, no scopes loaded") + try: # check for oauth tokens as long as #3380 not merged + user_from_oauth = self.get_current_user_oauth_token() + self.raw_scopes = {f'read:users!user={user_from_oauth.name}'} + except: + pass + else: + api_token = self.get_token() + if api_token: + self.raw_scopes = scopes.get_scopes_for(api_token) + elif self.current_user: + self.raw_scopes = scopes.get_scopes_for(self.current_user) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + app_log.debug("Found scopes [%s]", ",".join(self.raw_scopes)) @property def current_user(self): diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 5223fa9b..32d5fa1d 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -131,10 +131,14 @@ def expand_scope(scopename): return expanded_scope -def get_scopes_for(orm_object): - """Get the scopes for User/Service/Group/Token""" +def expand_roles_to_scopes(orm_object): + """Get the scopes listed in the roles of the User/Service/Group/Token""" scopes = get_subscopes(*orm_object.roles) if 'self' in scopes: + if not (isinstance(orm_object, orm.User) or hasattr(orm_object, 'orm_user')): + raise ValueError( + "Metascope 'self' only valid for Users, got %s" % orm_object + ) scopes.remove('self') scopes |= expand_self_scope(orm_object.name) return scopes @@ -256,7 +260,7 @@ def update_roles(db, obj, kind, roles=None): elif obj.service_id: owner = db.query(orm.Service).get(obj.service_id) if owner: - owner_scopes = get_scopes_for(owner) + owner_scopes = expand_roles_to_scopes(owner) if (extra_scopes).issubset(owner_scopes): role.tokens.append(obj) else: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 26a038d5..838cd10b 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -14,14 +14,15 @@ class Scope(Enum): def get_scopes_for(orm_object): - """Find scopes for a given user or token""" + """Find scopes for a given user or token and resolve permissions""" scopes = set() if orm_object is None: return scopes elif isinstance(orm_object, orm.APIToken): + app_log.warning(f"Authenticated with token {orm_object}") owner = orm_object.user or orm_object.service - token_scopes = roles.get_scopes_for(orm_object) - owner_scopes = roles.get_scopes_for(owner) + token_scopes = roles.expand_roles_to_scopes(orm_object) + owner_scopes = roles.expand_roles_to_scopes(owner) if 'all' in token_scopes: token_scopes.remove('all') token_scopes |= owner_scopes @@ -30,11 +31,11 @@ def get_scopes_for(orm_object): # Not taking symmetric difference here because token owner can naturally have more scopes than token if discarded_token_scopes: app_log.warning( - "Token-based access, discarding scopes [%s]" + "discarding scopes [%s], not present in owner roles" % ", ".join(discarded_token_scopes) ) else: - scopes = roles.get_scopes_for(orm_object) + scopes = roles.expand_roles_to_scopes(orm_object) return scopes diff --git a/jupyterhub/tests/test_auth_expiry.py b/jupyterhub/tests/test_auth_expiry.py index 59598219..48f85eb4 100644 --- a/jupyterhub/tests/test_auth_expiry.py +++ b/jupyterhub/tests/test_auth_expiry.py @@ -101,7 +101,6 @@ async def test_auth_expired_page(app, user, disable_refresh): assert user._auth_refreshed == before -# Fixme: Why does this text fail? async def test_auth_expired_api(app, user, disable_refresh): cookies = await app.login_user(user.name) assert user._auth_refreshed diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 8ac946ba..718f3cd6 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -121,9 +121,7 @@ def add_user(db, app=None, **kwargs): def auth_header(db, name): - """Return header with user's API authorization token. - If inherit is True, copies the roles of the invoking user - """ + """Return header with user's API authorization token.""" user = find_user(db, name) if user is None: raise KeyError(f"No such user: {name}") From 6f6561122bebb7cc0952e252fe19617ab624cdbe Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 17 Mar 2021 16:01:22 +0100 Subject: [PATCH 086/270] Implemented revision and test suite bug --- jupyterhub/apihandlers/base.py | 2 +- jupyterhub/handlers/base.py | 12 ++++++------ jupyterhub/tests/test_scopes.py | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index be74967f..d23205e9 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -65,7 +65,7 @@ class APIHandler(BaseHandler): return False return True - @functools.lru_cache + @functools.lru_cache() def get_scope_filter(self, req_scope): """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. Filter is a callable that takes a resource name and outputs true or false""" diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 32144813..17f87fae 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -440,17 +440,17 @@ class BaseHandler(RequestHandler): self.raw_scopes = set() app_log.debug("Loading and parsing scopes") if not self.current_user: - app_log.debug("No user found, no scopes loaded") - try: # check for oauth tokens as long as #3380 not merged - user_from_oauth = self.get_current_user_oauth_token() + # check for oauth tokens as long as #3380 not merged + user_from_oauth = self.get_current_user_oauth_token() + if user_from_oauth is not None: self.raw_scopes = {f'read:users!user={user_from_oauth.name}'} - except: - pass + else: + app_log.debug("No user found, no scopes loaded") else: api_token = self.get_token() if api_token: self.raw_scopes = scopes.get_scopes_for(api_token) - elif self.current_user: + else: self.raw_scopes = scopes.get_scopes_for(self.current_user) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) app_log.debug("Found scopes [%s]", ",".join(self.raw_scopes)) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 8526a831..abc1c835 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -318,6 +318,7 @@ async def test_exceeding_user_permissions(app): keys = {key for user in r.json() for key in user.keys()} assert 'groups' in keys assert 'last_activity' not in keys + roles.remove_obj(app.db, user_name, 'users', 'reader_role') async def test_user_service_separation(app, mockservice_url): From 8064cda47a2f8797411f4df4f67eff800727cbc2 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 25 Feb 2021 16:55:12 +0100 Subject: [PATCH 087/270] Update RBAC docs implementing review suggestions --- docs/rest-api.yml | 8 +- docs/source/rbac/index.md | 6 +- docs/source/rbac/roles.md | 45 ++++++----- docs/source/rbac/scopes.md | 52 +++++++++---- docs/source/rbac/tech-implementation.md | 10 ++- docs/source/rbac/use-cases.md | 99 ++++++++++++++----------- 6 files changed, 137 insertions(+), 83 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 0b1ac25d..b60d74d6 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -24,7 +24,7 @@ securityDefinitions: users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers read:users: Read-only access to the above read:users!user=username: Read-only access to a single user's model - read:users:names: Read-only access to users' names + read:users:name: Read-only access to users' names read:users:groups: Read-only access to users' groups read:users:activity: Read-only access to users' activity read:users:activity!group=groupname: Read-only access to specific group's users' activity @@ -41,9 +41,10 @@ securityDefinitions: read:groups: Read-only access to groups admin:groups: Grants access to create/delete groups read:services: Read-only access to services + read:hub: Read-only access to detailed information about JupyterHub proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy shutdown: Grants access to shutdown the Hub -security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope all) or have both (either can be used)? +security: - token: [] - oauth2: - all @@ -75,6 +76,9 @@ paths: Detailed JupyterHub information, including Python version, JupyterHub's version and executable path, and which Authenticator and Spawner are active. + security: + - oauth2: + - read:hub responses: '200': description: Detailed JupyterHub info diff --git a/docs/source/rbac/index.md b/docs/source/rbac/index.md index ec0a1557..5d5e43a4 100644 --- a/docs/source/rbac/index.md +++ b/docs/source/rbac/index.md @@ -1,11 +1,11 @@ # JupyterHub RBAC -Role Based Access Control (RBAC) in JupyterHub serves to provide finer grained access to perform actions by users or services. +Role Based Access Control (RBAC) in JupyterHub serves to provide fine grained control of access to Jupyterhub's API resources. ## Motivation -The JupyterHub API requires authentication before allowing changes to the administration system. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, cannot disrupt the status of the Hub. +The JupyterHub API requires authorization before allowing changes to the backend. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, are not allowed to perform such actions. -This system is functional, but lacks flexibility. If your Hub serves a number of users in different groups, you might want to delegate permissions to other users or automate certain processes. Appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege). +This system is functional, but lacks flexibility. If your Hub serves a number of users in different groups, you might want to delegate permissions to other users or automate certain processes. Appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This poses a risk of the user or service intentionally or unintentionally accessing and modifying any data within the Hub and violates the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege). To remedy situations like this, we implement an RBAC system. By equipping users, groups and services with *roles* that supply them with a collection of permissions (*scopes*), administrators are able to fine-tune which parties are able to access which resources. diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index fbae1196..d34b76f6 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -2,26 +2,26 @@ JupyterHub provides three **default roles** which are automatically loaded to the database at the startup: ```{admonition} **Default roles** -- **_user_** role carries single `all` scope that grants _least user access_ to perform only default user actions. -- **_admin_** role contains all available scopes and grants full rights to all actions similarly to the current admin status. -- **_server_** role allows for posting activity only through the single `users:activity` scope. +- `user` role provides a {ref}`default user scope ` `all` that grants access to only the user's own resources. +- `admin` role contains all available scopes and grants full rights to all actions similarly to the current admin status. +- `server` role allows for posting activity only through the single `users:activity` scope. ``` Roles can also be customly defined and assigned to users, services, groups and tokens. -**_Users_** and **_services_** are assigned a default role ( **_user_** or **_admin_**) if no custom role is requested based on their admin status. +**_Users_** and **_services_** are assigned a default role ( `user` or `admin`) if no custom role is requested based on their admin status. -**_Tokens_**’ roles cannot grant the token higher permissions than their owner’s roles. If no specific role is requested, tokens are assigned the default _user_ role. +**_Tokens_**’ roles cannot grant the token higher permissions than their owner’s roles. If no specific role is requested, tokens are assigned the `user` role. -**_Groups_** do not require any role and are not assigned any roles by default. Once group roles are defined and assigned, the privileges of each group member are extended with the group roles in the background during the API request permission check. This is useful for requesting the same permissions for several users. +**_Groups_** do not require any role and are not assigned any roles by default. Once roles are defined and assigned to groups, the privileges of each group member are extended when needed (see {ref}`resolving-roles-scopes-target` for more details). This is useful for assigning a set of common permissions to several users. (define_role_target)= ## Defining Roles -### In `jupyterhub_config.py` - Roles can be defined or modified in the configuration file as a list of dictionaries. An example: ```python +# in jupyterhub_config.py + c.JupyterHub.load_roles = [  {    'name': 'server-rights', @@ -38,27 +38,36 @@ The role `server-rights` now allows the starting and stopping of servers by any - users `alice` and `bob` - the service `idle-culler` - any member of the `admin-group` -- requests using the tokens `foo-6f6e65` or `bar-74776f` (providing the tokens owner has at least the same permissions). +- requests using the tokens `foo-6f6e65` or `bar-74776f`. +```{note} +The `foo-6f6e65` and `bar-74776f` tokens will be assigned the `server-rights` role only if their owner has the same or higher permissions. For example, if the tokens' owner has only `user` role, JupyterHub will throw an error. See {ref}`Figure 1 ` for more details. +``` Another example: ```python -c.JupyterHub.load_roles.append({ - 'description': 'Read-only user models', - 'name': 'reader', - 'scopes': ['read:users'], - 'services': ['external'], - 'users': ['maria', 'joe'] +# in jupyterhub_config.py + +c.JupyterHub.load_roles = [ + { + 'description': 'Read-only user models', + 'name': 'reader', + 'scopes': ['read:users'], + 'services': ['external'], + 'users': ['maria', 'joe'] } -) +] ``` The role `reader` allows users `maria` and `joe` and service `external` to read (but not modify) any user’s model. ```{admonition} Requirements :class: warning -In a role definition, the `name` field is required, while all other fields are optional. +In a role definition, the `name` field is required, while all other fields are optional. If no scopes are defined for new role, JupyterHub will raise a warning. Moreover, `users`, `services`, `groups` and `tokens` only accept objects that already exist or are defined previously in the file. It is not possible to implicitly add a new user to the database by defining a new role. ``` -In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. Any previously defined role bearers will remain unchanged, but newly defined requesters (in this case `maria` and `joe` and `external`) will be assigned the new role definition. +In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for any role apart from `admin` role that cannot be overwritten; an error will be raised if trying to do so. +Any previously defined role bearers will remain unchanged, but newly defined requesters (in this case `maria` and `joe` and `external`) will be assigned the new role definition. + +Once a role is loaded, it remains in the database until explicitly deleting it through `remove_role` function in `roles.py`. I.e., omitting the `c.JupyterHub.load_roles` or specifying different roles in the `jupyterhub_config.py` file on the next startup will not erase previously defined roles. diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index a0c5b42f..dd35a766 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -1,25 +1,48 @@ # Scopes -A scope has a syntax-based design that reveals which resources it provides access to: -- The base`resource` scopes, such as `users` or `groups`, provides non-elevated 'default' read or write permissions to the resource itself and all sub-resources. For instance, the scope`users:servers` is included within the scope`users`. -- The elevated `admin:resource` scopes extend permissions beyond default. For instance, where the scope `users` provides read and write access to user information, the scope `admin:users` allows creating and deleting users. -- The scope structure `resource:subresource` vertical filtering: it provides access to a subset of the information granted by the `resource` scope. For example, the scope `users:names` provides access to user names only. -- The scope structure `read:resource` (or `read:resource:subresource`) limits permissions to read-only operations on `resource` (or `subresource`). -- The scope structure `resource!user=charlie` allows for horizontal filtering: it limits access to only return resources of user `charlie`. Only one filter per scope is allowed, but filters for the same scope have an additive effect; a larger filter can be used by supplying the scope multiple times with different filters. -- A resource can be filtered based on `user`, `server`, `group` or `service` name. +A scope has a syntax-based design that reveals which resources it provides access to. Resources are objects with a type, associated data, relationships to other resources, and a set of methods that operate on them (see [RESTful API](https://restful-api-design.readthedocs.io/en/latest/resources.html) documentation for more information). + +`` in the scope syntax here refers to the resource name in the [JupyterHub's API](../reference/rest-api.rst) endpoints. For instance, `` equal to `users` corresponds to JupyterHub's API endpoints beginning with _/users_. + +## Scope syntax + +- `` \ +The `` scopes, such as `users` or `groups`, grant read and write permissions to the resource itself and all its sub-resources. E.g., the scope `users:servers` is included within the scope `users`. ++++ + +- `:` \ +The {ref}`vertically filtered ` scopes provide access to a subset of the information granted by the `` scope. E.g., the scope `users:name` allows for accessing user names only. ++++ + +- `!=` \ +{ref}`horizontal-filtering-target` is implemented by adding `!=` to the scope structure. A resource (or subresource) can be filtered based on `user`, `server`, `group` or `service` name. For instance, `!user=charlie` limits access to only return resources of user `charlie`. \ +Only one filter per scope is allowed, but filters for the same scope have an additive effect; a larger filter can be used by supplying the scope multiple times with different filters. ++++ + +- `read:` \ +Limits permissions to **read-only** operations on the resource. ++++ + +- `admin:` \ +Grants **create/delete permissions only** on the corresponding resource. For example, the scope `admin:users` allows creating and deleting users but does not allow for accessing information about existing users or modifying them, which is provided by the scope `users`. + By adding a scope to an existing role, all role bearers will gain the associated permissions. ## Available scopes -[](../reference/rest-api.rst) documentation details all available scopes and which of these are required for what particular API request. +[](../reference/rest-api.rst) documentation lists all available scopes. Each API endpoint has a list of scopes which can be used to access the API. +```{important} +Note that only the {ref}`horizontal filtering ` can be added to scopes to customize them. `` scopes, `:`, `read:` and `admin:` scopes are predefined and cannot be changed otherwise. +``` -## Standard user scope +(default-user-scope-target)= +## Default user scope -The standard user scope `all` provides access to the user's own resources and subresources, including the user's model, activity, servers and tokens. For example, the scope for a user `'gerard'` covers: -- `users!user=gerard` where the `users` scope includes access to the full user model, activity and starting/stopping servers. The filter restricts this access to the user's own resources +The default user scope `all` provides access to the user's own resources and subresources, including the user's model, activity, servers and tokens. For example, the scope for a user `'gerard'` covers: +- `users!user=gerard` where the `users` scope includes access to the full user model, activity and starting/stopping servers. The horizontal filter restricts this access to the user's own resources. - `users:tokens!user=gerard` allows the user to access, request and delete his own tokens only. -(filtering-target)= +(horizontal-filtering-target)= ## Horizontal filtering Horizontal filtering, also called *resource filtering*, is the concept of reducing the payload of an API call to cover only the subset of the *resources* that the scopes of the client provides them access to. @@ -27,11 +50,12 @@ Requested resources are filtered based on the filter of the corresponding scope. In case a user resource is being accessed, any scopes with *group* filters will be expanded to filters for each *user* in those groups. +(vertical-filtering-target)= ## Vertical filtering Vertical filtering, also called *attribute filtering*, is the concept of reducing the payload of an API call to cover only the *attributes* of the resources that the scopes of the client provides them access to. This occurs when the client scopes are subscopes of the API endpoint that is called. -For instance, if a client requests a user list with the only scope being `read:user:groups`, the returned list of user models will contain only a list of groups per user. +For instance, if a client requests a user list with the only scope being `read:users:groups`, the returned list of user models will contain only a list of groups per user. In case the client has multiple subscopes, the call returns the union of the data the client has access to. -The payload of an API call can be filtered both horizontally and vertically simultaneously. For instance, performing an API call to the endpoint `/users/` with the scope `users:names!user=juliette` returns a payload of `[{name: 'juliette'}]` (provided that this name is present in the database). +The payload of an API call can be filtered both horizontally and vertically simultaneously. For instance, performing an API call to the endpoint `/users/` with the scope `users:name!user=juliette` returns a payload of `[{name: 'juliette'}]` (provided that this name is present in the database). diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index a92e614b..d710fe94 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -2,12 +2,18 @@ Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `update_roles` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. +(resolving-roles-scopes-target)= ## Resolving roles and scopes + +**Resolving roles** refers to determining which roles a user, service, token or group has, extracting the list of scopes from each role and combining them into a single set of scopes. + +**Resolving scopes** involves comparing two sets of scopes taking into account the scope hierarchy. This includes {ref}`vertical ` and {ref}`horizontal filtering ` and limiting or elevated permissions (`read:` or `admin:`, respectively). + Roles and scopes are resolved on several occasions, for example when requesting an API token with specific roles or making an API request. The following sections provide more details. ### Requesting API token with specific roles API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific existing roles. To date, it is only possible to add roles to a token in two ways: -1. through the `config.py` file as described in the {ref}`define_role_target` section +1. through the `jupyterhub_config.py` file as described in the {ref}`define_role_target` section 2. through the POST /users/{name}/tokens API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). The RBAC framework adds several steps into the token issue flow. @@ -35,7 +41,7 @@ With the RBAC framework each authenticated JupyterHub API request is guarded by When an API request is performed, the passed API token's roles are again resolved into a set of scopes and compared to the scopes required to access the API as follows: - if the API scopes are present within the set of token's scopes, the access is granted and the API returns its "full" response - if that is not the case, another check is utilized to determine if sub-scopes of the required API scopes can be found in the token's scope set: - - if the subscopes are present, the RBAC framework employs the {ref}`filtering ` procedures to refine the API response to provide access to only resource attributes specified by the token provided scopes + - if the subscopes are present, the RBAC framework employs the {ref}`filtering ` procedures to refine the API response to provide access to only resource attributes specified by the token provided scopes - for example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model - if the subscopes are not present, the access to API is denied diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md index da812d79..8d0925fb 100644 --- a/docs/source/rbac/use-cases.md +++ b/docs/source/rbac/use-cases.md @@ -9,9 +9,9 @@ To determine which scopes a role should have it is best to follow these steps: Below, different use cases are presented on how to use the RBAC framework. -## User scripting their own access +## User access -A regular user should be able to view and manage all of their own resources. This can be achieved using the scope `all` (or assigning the default _user_ role). If the user's access is to be restricted from modifying any of their resources (e.g., during marking), their role should be changed to read-only access, in this case scope `read:all`. +A regular user should be able to view and manage all of their own resources. This can be achieved using the scope `all` (or assigning the `user` role). If the user's access is to be restricted from modifying any of their resources (e.g., when a teacher wants to check their notebooks), their role should be changed to read-only access, in this case scope `read:all`. ## Service to cull idle servers @@ -21,29 +21,36 @@ Below follows a short tutorial on how to add a cull-idle service in the RBAC sys 1. Install the cull-idle server script with `pip install jupyterhub-idle-culler`. 2. Define a new service `idle-culler` and a new role for this service: -```python -c.JupyterHub.roles.append( - { - "name": "idle-culler", - "description": "Culls idle servers", - "scopes": ["read:users:servers", "admin:users:servers"], - "services": ["idle-culler"], - } -) + ```python + # in jupyterhub_config.py + c.JupyterHub.services = [ + { + "name": "idle-culler", + "command": [ + sys.executable, "-m", + "jupyterhub_idle_culler", + "--timeout=3600" + ], + } + ] -c.JupyterHub.services.append( - { - "name": "idle-culler", - "command": [ - sys.executable, "-m", - "jupyterhub_idle_culler", - "--timeout=3600" - ], - } -) + c.JupyterHub.load_roles = [ + { + "name": "idle-culler", + "description": "Culls idle servers", + "scopes": ["read:users:name", "read:users:activity", "read:users:servers", "users:servers"], + "services": ["idle-culler"], + } + ] + ``` + ```{important} + Note that in the RBAC system the `admin` field in the `idle-culler` service definition is omitted. Instead, the `idle-culler` role provides the service with only the permissions it needs. -``` + If the optional actions of deleting the idle servers and/or removing inactive users are desired, **add the following scopes** to the `idle-culler` role definition: + - `admin:users:servers` for deleting servers + - `admin:users` for deleting users. + ``` 3. Restart JupyterHub to complete the process. @@ -58,7 +65,7 @@ From the above, the scopes required for the role are 2. `users:servers` 3. `admin:users:servers` -If needed, the scopes can be modified to limit the associated permissions to e.g. a particular group members with `!group=groupname` filter. +If needed, the scopes can be modified to limit the permissions to e.g. a particular group with `!group=groupname` filter. ## Users as group admins/Group admin roles @@ -68,31 +75,35 @@ For example, a group of students `class-A` may have a role allowing all group me The roles can then be defined as follows: ```python +# in jupyterhub_config.py + c.JupyterHub.load_groups = { 'class-A': ['johan', 'student1', 'student2'], 'class-B': ['student3', 'student4'] } + c.JupyterHub.load_roles = [ - { -   'name': 'class-A-student', -   'description': 'Grants access to information about the group', -   'scopes': ['read:groups!group=class-A'], -   'groups': ['class-A'] - }, - { -   'name': 'class-B-student', -   'description': 'Grants access to information about the group', -   'scopes': ['read:groups!group=class-B'], -   'groups': ['class-B'] - }, - { -   'name': 'teacher', -   'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', -   'scopes': [ 'read:users!group=class-B', 'users:servers!group=class-B'], -   'users': ['johan'] - } + { +   'name': 'class-A-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-A'], +   'groups': ['class-A'] + }, + { +   'name': 'class-B-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-B'], +   'groups': ['class-B'] + }, + { +   'name': 'teacher', +   'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', +   'scopes': [ 'read:users!group=class-B', 'users:servers!group=class-B'], +   'users': ['johan'] + } ] ``` -In the above example, `johan` has privileges inherited from `class-A role` and the `teacher` role on top of those. - -Note the filters (`!group=`) limiting the privileges only to the particular groups. `johan` can access the servers and information of `class-B` members only. +In the above example, `johan` has privileges inherited from `class-A-student` role and the `teacher` role on top of those. +```{note} +The scope filters (`!group=`) limit the privileges only to the particular groups. `johan` can access the servers and information of `class-B` group members only. +``` From 43a67672761e5e93a1813646485d4f4d86771f11 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 22 Mar 2021 15:57:52 +0100 Subject: [PATCH 088/270] run pre-commit after merge --- docs/rest-api.yml | 100 +++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 16890c59..859c6332 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -15,8 +15,8 @@ securityDefinitions: oauth2: type: oauth2 flow: accessCode - authorizationUrl: '/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? - tokenUrl: '/hub/api/oauth2/token' + authorizationUrl: "/hub/api/oauth2/authorize" # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? + tokenUrl: "/hub/api/oauth2/token" scopes: all: Everything a user can do read:all: Read-only access to everything a user can read (also whoami handler) @@ -45,7 +45,7 @@ securityDefinitions: security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope all) or have both (either can be used)? - token: [] - oauth2: - - all + - all basePath: /hub/api produces: - application/json @@ -112,8 +112,8 @@ paths: summary: List users security: - oauth2: - - users - - read:users + - users + - read:users parameters: - name: state in: query @@ -140,7 +140,7 @@ paths: summary: Create multiple users security: - oauth2: - - admin:users + - admin:users parameters: - name: body in: body @@ -169,9 +169,9 @@ paths: summary: Get a user by name security: - oauth2: - - users - - read:users - - read:users!user=username + - users + - read:users + - read:users!user=username parameters: - name: name description: username @@ -187,7 +187,7 @@ paths: summary: Create a single user security: - oauth2: - - admin:users + - admin:users parameters: - name: name description: username @@ -204,7 +204,7 @@ paths: description: Change a user's name or admin status security: - oauth2: - - users + - users parameters: - name: name description: username @@ -233,7 +233,7 @@ paths: summary: Delete a user security: - oauth2: - - admin:users + - admin:users parameters: - name: name description: username @@ -251,8 +251,8 @@ paths: actively using a server. security: - oauth2: - - users - - users:activity!user=username + - users + - users:activity!user=username parameters: - name: name description: username @@ -307,8 +307,8 @@ paths: summary: Start a user's single-user notebook server security: - oauth2: - - users - - users:servers + - users + - users:servers parameters: - name: name description: username @@ -337,8 +337,8 @@ paths: summary: Stop a user's server security: - oauth2: - - users - - users:servers + - users + - users:servers parameters: - name: name description: username @@ -355,9 +355,9 @@ paths: summary: Start a user's single-user named-server notebook server security: - oauth2: - - users - - users:servers - - users:servers!server=servername + - users + - users:servers + - users:servers!server=servername parameters: - name: name description: username @@ -391,9 +391,9 @@ paths: summary: Stop a user's named-server security: - oauth2: - - users - - users:servers - - users:servers!server=servername + - users + - users:servers + - users:servers!server=servername parameters: - name: name description: username @@ -433,7 +433,7 @@ paths: summary: List tokens for the user security: - oauth2: - - users:tokens + - users:tokens responses: "200": description: The list of tokens @@ -449,7 +449,7 @@ paths: summary: Create a new token for the user security: - oauth2: - - users:tokens + - users:tokens parameters: - name: token_params in: body @@ -473,7 +473,7 @@ paths: $ref: "#/definitions/Token" "400": description: Body must be a JSON dict or empty - '403': + "403": description: Requested role does not exist /users/{name}/tokens/{token_id}: parameters: @@ -490,7 +490,7 @@ paths: summary: Get the model for a token by id security: - oauth2: - - users:tokens + - users:tokens responses: "200": description: The info for the new token @@ -500,7 +500,7 @@ paths: summary: Delete (revoke) a token by id security: - oauth2: - - users:tokens + - users:tokens responses: "204": description: The token has been deleted @@ -509,8 +509,8 @@ paths: summary: Return authenticated user's model security: - oauth2: - - all - - read:all + - all + - read:all responses: "200": description: The authenticated user's model is returned. @@ -521,8 +521,8 @@ paths: summary: List groups security: - oauth2: - - groups - - read:groups + - groups + - read:groups responses: "200": description: The list of groups @@ -535,9 +535,9 @@ paths: summary: Get a group by name security: - oauth2: - - groups - - groups!group=groupname - - read:groups + - groups + - groups!group=groupname + - read:groups parameters: - name: name description: group name @@ -553,7 +553,7 @@ paths: summary: Create a group security: - oauth2: - - admin:groups + - admin:groups parameters: - name: name description: group name @@ -569,7 +569,7 @@ paths: summary: Delete a group security: - oauth2: - - admin:groups + - admin:groups parameters: - name: name description: group name @@ -584,8 +584,8 @@ paths: summary: Add users to a group security: - oauth2: - - groups - - groups!group=groupname + - groups + - groups!group=groupname parameters: - name: name description: group name @@ -613,8 +613,8 @@ paths: summary: Remove users from a group security: - oauth2: - - groups - - groups!group=groupname + - groups + - groups!group=groupname parameters: - name: name description: group name @@ -641,7 +641,7 @@ paths: summary: List services security: - oauth2: - - read:services + - read:services responses: "200": description: The service list @@ -654,7 +654,7 @@ paths: summary: Get a service by name security: - oauth2: - - read:services + - read:services parameters: - name: name description: service name @@ -672,7 +672,7 @@ paths: description: A convenience alias for getting the routing table directly from the proxy security: - oauth2: - - proxy + - proxy responses: "200": description: Routing table @@ -683,7 +683,7 @@ paths: summary: Force the Hub to sync with the proxy security: - oauth2: - - proxy + - proxy responses: "200": description: Success @@ -692,7 +692,7 @@ paths: description: Notifies the Hub of a new proxy to use. security: - oauth2: - - proxy + - proxy parameters: - name: body in: body @@ -727,7 +727,7 @@ paths: accepts passwords (e.g. not OAuth). security: - oauth2: - - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope + - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope parameters: - name: credentials in: body @@ -754,7 +754,7 @@ paths: summary: Identify a user or service from an API token security: - oauth2: - - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? + - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path @@ -869,7 +869,7 @@ paths: summary: Shutdown the Hub security: - oauth2: - - shutdown + - shutdown parameters: - name: body in: body From 665e5c7427f57d307da63ed896493f89c7185d02 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 22 Mar 2021 13:10:03 +0100 Subject: [PATCH 089/270] ensure /authorizations/token can read the owner model of the token itself --- jupyterhub/apihandlers/auth.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index 76fcd8b8..7e28fd2d 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -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,6 +23,11 @@ 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) @@ -32,9 +37,15 @@ class TokenAPIHandler(APIHandler): # record activity whenever we see a token now = orm_token.last_activity = datetime.utcnow() if orm_token.user: + # 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.add(f'read:users!user={orm_token.user.name}') + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) orm_token.user.last_activity = now model = self.user_model(self.users[orm_token.user]) elif orm_token.service: + self.raw_scopes.add(f'read:services!service={orm_token.service.name}') + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) model = self.service_model(orm_token.service) else: self.log.warning("%s has no user or service. Deleting..." % orm_token) From 64089b40bc34a551a15a586132b187596373844d Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Mon, 22 Mar 2021 17:14:05 +0100 Subject: [PATCH 090/270] Add temporary default service role (no scopes) --- jupyterhub/roles.py | 11 ++++++++++- jupyterhub/tests/test_roles.py | 33 ++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 32d5fa1d..ec656e55 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -42,6 +42,11 @@ def get_default_roles(): 'description': 'Token with same rights as token owner', 'scopes': ['all'], }, + { + 'name': 'service', + 'description': 'Temporary no scope role for services', + 'scopes': [], + }, ] return default_roles @@ -218,9 +223,13 @@ def remove_obj(db, objname, kind, rolename): def switch_default_role(db, obj, kind, admin): - """Switch between default user and admin roles for users/services""" + """Switch between default user/service and admin roles for users/services""" user_role = orm.Role.find(db, 'user') + # temporary fix of default service role + if kind == 'services': + user_role = orm.Role.find(db, 'service') + admin_role = orm.Role.find(db, 'admin') def add_and_remove(db, obj, kind, current_role, new_role): diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 4f2c7475..c300f43d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -18,14 +18,16 @@ def test_orm_roles(db): """Test orm roles setup""" user_role = orm.Role.find(db, name='user') token_role = orm.Role.find(db, name='token') + service_role = orm.Role.find(db, name='service') if not user_role: user_role = orm.Role(name='user', scopes=['self']) db.add(user_role) if not token_role: token_role = orm.Role(name='token', scopes=['all']) db.add(token_role) - service_role = orm.Role(name='service', scopes=['users:servers']) - db.add(service_role) + if not service_role: + service_role = orm.Role(name='service', scopes=[]) + db.add(service_role) db.commit() user = orm.User(name='falafel') @@ -199,6 +201,8 @@ async def test_load_default_roles(tmpdir, request): assert orm.Role.find(db, 'user') is not None assert orm.Role.find(db, 'admin') is not None assert orm.Role.find(db, 'server') is not None + assert orm.Role.find(db, 'token') is not None + assert orm.Role.find(db, 'service') is not None @mark.role @@ -293,18 +297,29 @@ async def test_load_roles_services(tmpdir, request): # test if every service has a role (and no duplicates) admin_role = orm.Role.find(db, name='admin') user_role = orm.Role.find(db, name='user') - for service in db.query(orm.Service): - assert len(service.roles) > 0 - assert len(service.roles) == len(set(service.roles)) - if service.admin: - assert admin_role in service.roles - assert user_role not in service.roles + service_role = orm.Role.find(db, name='service') # test if predefined roles loaded and assigned culler_role = orm.Role.find(db, name='culler') cull_idle = orm.Service.find(db, name='cull_idle') assert culler_role in cull_idle.roles - assert user_role not in cull_idle.roles + assert service_role not in cull_idle.roles + + # test if every service has a role (and no duplicates) + for service in db.query(orm.Service): + assert len(service.roles) > 0 + assert len(service.roles) == len(set(service.roles)) + + # test default role assignment + if service.admin: + assert admin_role in service.roles + assert service_role not in service.roles + elif culler_role not in service.roles: + assert service_role in service.roles + assert service_role.scopes == [] + assert admin_role not in service.roles + # make sure 'user' role not assigned to service + assert user_role not in service.roles # delete the test services for service in db.query(orm.Service): From e26e8f9c36657921c2f782aedca6ae303e0c8bd2 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 23 Mar 2021 11:47:50 +0100 Subject: [PATCH 091/270] Prevent deleting default roles --- jupyterhub/roles.py | 6 ++++++ jupyterhub/tests/test_roles.py | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 23c2f5ae..1782afdd 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -205,10 +205,16 @@ def add_role(db, role_dict): def remove_role(db, rolename): """Removes a role from database""" + # default roles are not removable + default_roles = get_default_roles() + if any(role['name'] == rolename for role in default_roles): + raise ValueError('Default role %r cannot be removed', rolename) + role = orm.Role.find(db, rolename) if role: db.delete(role) db.commit() + app_log.info('Role %s has been deleted', rolename) else: raise NameError('Cannot remove role %r that does not exist', rolename) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index fed9418e..1423fd88 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -280,6 +280,41 @@ async def test_adding_new_roles( await hub.init_roles() +@mark.role +@mark.parametrize( + "role_type, rolename, response_type, response", + [ + ( + 'existing', + 'test-role1', + 'info', + app_log.info('Role user scopes attribute has been changed'), + ), + ('non-existing', 'test-role2', 'error', NameError), + ('default', 'user', 'error', ValueError), + ], +) +async def test_delete_roles(db, role_type, rolename, response_type, response): + """Test raising errors and info when deleting roles""" + + if response_type == 'info': + # add the role to db + test_role = orm.Role(name=rolename) + db.add(test_role) + db.commit() + check_role = orm.Role.find(db, rolename) + assert check_role is not None + # check the role is deleted and info raised + with pytest.warns(response): + roles.remove_role(db, rolename) + check_role = orm.Role.find(db, rolename) + assert check_role is None + + elif response_type == 'error': + with pytest.raises(response): + roles.remove_role(db, rolename) + + @mark.role @mark.parametrize( "role, response", From 58a80e50505478d4b08174e02e26bf2205d45dde Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 23 Mar 2021 13:27:00 +0100 Subject: [PATCH 092/270] ensure MockAPIHandler has request.path defined --- jupyterhub/tests/test_scopes.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index abc1c835..ecc2af22 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -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): From 97e1a5cb2690d3bf8e11625aaf8bce87c415329f Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 23 Mar 2021 13:56:46 +0100 Subject: [PATCH 093/270] add scopes.identify_scopes helper --- jupyterhub/apihandlers/auth.py | 13 +++++++------ jupyterhub/scopes.py | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index 7e28fd2d..938d88ec 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -34,18 +34,19 @@ class TokenAPIHandler(APIHandler): 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: - # 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.add(f'read:users!user={orm_token.user.name}') - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) orm_token.user.last_activity = now model = self.user_model(self.users[orm_token.user]) elif orm_token.service: - self.raw_scopes.add(f'read:services!service={orm_token.service.name}') - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) model = self.service_model(orm_token.service) else: self.log.warning("%s has no user or service. Deleting..." % orm_token) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 838cd10b..0819cc08 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -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}") From c9ca06606084dbbf030f27e8e95119d47e6d0a00 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 24 Mar 2021 19:22:33 +0100 Subject: [PATCH 094/270] prepull commit --- jupyterhub/apihandlers/base.py | 29 ++++++++++++++++------------- jupyterhub/roles.py | 1 + 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index be74967f..9f719511 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -269,22 +269,25 @@ class APIHandler(BaseHandler): ) return model - def group_model(self, group): # Todo: make consistent to do scope checking here + def group_model(self, group): """Get the JSON model for a Group object""" - return { - 'kind': 'group', - 'name': group.name, - 'users': [u.name for u in group.users], - } + model = {'kind': 'group', 'name': group.name} + req_scope = 'read:groups' + if req_scope in self.parsed_scopes: + scope_filter = self.get_scope_filter(req_scope) + if scope_filter(group, kind='group'): + model['users'] = [u.name for u in group.users] + return model - def service_model(self, service): # Todo: make consistent to do scope checking here + def service_model(self, service): """Get the JSON model for a Service object""" - return { - 'kind': 'service', - 'name': service.name, - 'admin': service.admin, - 'roles': [r.name for r in service.roles], - } + model = {'kind': 'servce', 'name': service.name} + req_scope = 'read:services' + if req_scope in self.parsed_scopes: + scope_filter = self.get_scope_filter(req_scope) + if scope_filter(service, kind='service'): + model['roles'] = [r.name for r in service.roles] + return model _user_model_types = {'name': str, 'admin': bool, 'groups': list, 'auth_state': dict} diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 32d5fa1d..0a779906 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -88,6 +88,7 @@ def get_scope_hierarchy(): 'read:users:groups', 'read:users:activity', 'read:users:servers', + 'read:users:auth_state', ], 'users:tokens': ['read:users:tokens'], 'admin:users': None, From b74075d94578a4e53fbaa236c4fb7ea74d13f584 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 26 Mar 2021 10:51:17 +0100 Subject: [PATCH 095/270] Fixed self scope for services with tests --- jupyterhub/apihandlers/base.py | 2 +- jupyterhub/roles.py | 7 ++---- jupyterhub/tests/test_roles.py | 29 ++++++++++++++++++++++ jupyterhub/tests/test_scopes.py | 44 +++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index a749ff5f..a8e94ecb 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -281,7 +281,7 @@ class APIHandler(BaseHandler): def service_model(self, service): """Get the JSON model for a Service object""" - model = {'kind': 'servce', 'name': service.name} + model = {'kind': 'service', 'name': service.name} req_scope = 'read:services' if req_scope in self.parsed_scopes: scope_filter = self.get_scope_filter(req_scope) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 573e4eae..e16f1a94 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -141,12 +141,9 @@ def expand_roles_to_scopes(orm_object): """Get the scopes listed in the roles of the User/Service/Group/Token""" scopes = get_subscopes(*orm_object.roles) if 'self' in scopes: - if not (isinstance(orm_object, orm.User) or hasattr(orm_object, 'orm_user')): - raise ValueError( - "Metascope 'self' only valid for Users, got %s" % orm_object - ) scopes.remove('self') - scopes |= expand_self_scope(orm_object.name) + if isinstance(orm_object, orm.User) or hasattr(orm_object, 'orm_user'): + scopes |= expand_self_scope(orm_object.name) return scopes diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index c300f43d..8ac16c99 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -421,3 +421,32 @@ async def test_get_new_token_via_api(app, headers, role_list, status): # verify deletion r = await api_request(app, 'users/user/tokens', token_id) assert r.status_code == 404 + + +@mark.role +@mark.parametrize( + "kind, has_user_scopes", + [ + ('users', True), + ('services', False), + ], +) +async def test_self_expansion(app, kind, has_user_scopes): + Class = orm.get_class(kind) + orm_obj = Class(name=f'test_{kind}') + app.db.add(orm_obj) + app.db.commit() + test_role = orm.Role(name='test_role', scopes=['self']) + orm_obj.roles.append(test_role) + # test expansion of user/service scopes + scopes = roles.expand_roles_to_scopes(orm_obj) + assert bool(scopes) == has_user_scopes + + # test expansion of token scopes + orm_obj.new_api_token() + print(orm_obj.api_tokens[0]) + token_scopes = scopes.get_scopes_for(orm_obj.api_tokens[0]) + print(token_scopes) + assert bool(token_scopes) == has_user_scopes + app.db.delete(orm_obj) + app.db.delete(test_role) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index ecc2af22..89b57cb1 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -11,6 +11,7 @@ from .. import orm from .. import roles from ..handlers import BaseHandler from ..scopes import _check_scope +from ..scopes import get_scopes_for from ..scopes import needs_scope from ..scopes import parse_scopes from ..scopes import Scope @@ -514,3 +515,46 @@ async def test_cross_filter(app): assert key_in_full_model in user else: assert set(user.keys()) == restricted_keys + + +@mark.parametrize( + "kind, has_user_scopes", + [ + ('users', True), + ('services', False), + ], +) +async def test_metascope_self_expansion(app, kind, has_user_scopes): + Class = orm.get_class(kind) + orm_obj = Class(name=f'test_{kind}') + app.db.add(orm_obj) + app.db.commit() + test_role = orm.Role(name='test_role', scopes=['self']) + orm_obj.roles.append(test_role) + # test expansion of user/service scopes + scopes = roles.expand_roles_to_scopes(orm_obj) + assert bool(scopes) == has_user_scopes + + # test expansion of token scopes + orm_obj.new_api_token() + token_scopes = get_scopes_for(orm_obj.api_tokens[0]) + assert bool(token_scopes) == has_user_scopes + app.db.delete(orm_obj) + app.db.delete(test_role) + + +async def test_metascope_all_expansion(app): + user = add_user(app.db, name='user') + scope_set = {scope for role in user.roles for scope in role.scopes} + user.new_api_token() + token = user.api_tokens[0] + # Check 'all' expansion + token_scope_set = get_scopes_for(token) + user_scope_set = get_scopes_for(user) + assert user_scope_set == token_scope_set + + # Check no roles means no permissions + token.roles.clear() + app.db.commit() + token_scope_set = get_scopes_for(token) + assert not token_scope_set From c5c44f6dbedbed3f29e9e7d0ee1627743825a9de Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 26 Mar 2021 13:47:01 +0100 Subject: [PATCH 096/270] Replaced auth_state and server_state with scopes --- jupyterhub/apihandlers/base.py | 34 +++++++++++++++++++++++++++++---- jupyterhub/apihandlers/users.py | 14 +++++++++----- jupyterhub/roles.py | 3 +-- jupyterhub/tests/test_roles.py | 29 ---------------------------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index a8e94ecb..ddf1d1b8 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -220,7 +220,13 @@ class APIHandler(BaseHandler): model.update(extra) return model - def user_model(self, user, include_servers=False, include_state=False): + def user_model( + self, + user, + include_servers=False, + include_server_state=False, + include_auth_state=False, + ): """Get the JSON model for a User object""" if isinstance(user, orm.User): user = self.users[user.id] @@ -234,13 +240,26 @@ class APIHandler(BaseHandler): 'pending': None, 'created': isoformat(user.created), 'last_activity': isoformat(user.last_activity), + 'auth_state': '', # placeholder, filled in later } access_map = { - 'read:users': set(model.keys()), # All available components + 'read:users': { + 'kind', + 'name', + 'admin', + 'roles', + 'groups', + 'server', + 'pending', + 'created', + 'last_activity', + }, 'read:users:name': {'kind', 'name'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, + 'read:users:auth_state': {'kind', 'name', 'auth_state'}, + 'read:users:server_state': {'kind', 'name', 'server_state'}, } self.log.debug( "Asking for user model of %s with scopes [%s]", @@ -254,18 +273,20 @@ class APIHandler(BaseHandler): if scope_filter(user, kind='user'): allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} + if not include_auth_state: + model.pop("auth_state", None) if model: + include_server_state &= 'server_state' in allowed_keys if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending if include_servers and 'servers' in allowed_keys: - # Todo: Replace include_state with scope (read|admin):users:auth_state servers = model['servers'] = {} for name, spawner in user.spawners.items(): # include 'active' servers, not just ready # (this includes pending events) if spawner.active: servers[name] = self.server_model( - spawner, include_state=include_state + spawner, include_state=include_server_state ) return model @@ -287,6 +308,11 @@ class APIHandler(BaseHandler): scope_filter = self.get_scope_filter(req_scope) if scope_filter(service, kind='service'): model['roles'] = [r.name for r in service.roles] + model[ + 'admin' + ] = ( + service.admin + ) # todo: Remove once we replace admin flag with role check return model _user_model_types = {'name': str, 'admin': bool, 'groups': list, 'auth_state': dict} diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index f2f8efc7..dea4bd6d 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -105,7 +105,7 @@ class UserListAPIHandler(APIHandler): for u in query: if post_filter is None or post_filter(u): user_model = self.user_model( - u, include_servers=True, include_state=True + u, include_servers=True, include_server_state=True ) if user_model: data.append(user_model) @@ -187,18 +187,22 @@ def admin_or_self(method): class UserAPIHandler(APIHandler): - @needs_scope('read:users') + @needs_scope( + 'read:users' + ) # Todo: Add the same list of scopes as at UserListAPIHandler async def get(self, user_name): user = self.find_user(user_name) model = self.user_model( - user, include_servers=True, include_state=self.current_user.admin + user, + include_servers=True, + include_server_state=True, + include_auth_state=True, ) # auth state will only be shown if the requester is an admin # this means users can't see their own auth state unless they # are admins, Hub admins often are also marked as admins so they # will see their auth state but normal users won't - requester = self.current_user - if requester.admin: + if 'auth_state' in model: model['auth_state'] = await user.get_auth_state() self.write(json.dumps(model)) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index e16f1a94..93221eb5 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -93,10 +93,9 @@ def get_scope_hierarchy(): 'read:users:groups', 'read:users:activity', 'read:users:servers', - 'read:users:auth_state', ], 'users:tokens': ['read:users:tokens'], - 'admin:users': None, + 'admin:users': ['read:users:auth_state', 'read:users:server_state'], 'admin:users:servers': None, 'groups': ['read:groups'], 'admin:groups': None, diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 8ac16c99..c300f43d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -421,32 +421,3 @@ async def test_get_new_token_via_api(app, headers, role_list, status): # verify deletion r = await api_request(app, 'users/user/tokens', token_id) assert r.status_code == 404 - - -@mark.role -@mark.parametrize( - "kind, has_user_scopes", - [ - ('users', True), - ('services', False), - ], -) -async def test_self_expansion(app, kind, has_user_scopes): - Class = orm.get_class(kind) - orm_obj = Class(name=f'test_{kind}') - app.db.add(orm_obj) - app.db.commit() - test_role = orm.Role(name='test_role', scopes=['self']) - orm_obj.roles.append(test_role) - # test expansion of user/service scopes - scopes = roles.expand_roles_to_scopes(orm_obj) - assert bool(scopes) == has_user_scopes - - # test expansion of token scopes - orm_obj.new_api_token() - print(orm_obj.api_tokens[0]) - token_scopes = scopes.get_scopes_for(orm_obj.api_tokens[0]) - print(token_scopes) - assert bool(token_scopes) == has_user_scopes - app.db.delete(orm_obj) - app.db.delete(test_role) From 036a4eb9347f6c98390c31bb965fb385072eabf1 Mon Sep 17 00:00:00 2001 From: 0mar Date: Sun, 28 Mar 2021 18:54:31 +0200 Subject: [PATCH 097/270] Revert to using user roles for services --- jupyterhub/roles.py | 9 --------- jupyterhub/tests/test_roles.py | 12 +++--------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 93221eb5..afc46e85 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -42,11 +42,6 @@ def get_default_roles(): 'description': 'Token with same rights as token owner', 'scopes': ['all'], }, - { - 'name': 'service', - 'description': 'Temporary no scope role for services', - 'scopes': [], - }, ] return default_roles @@ -223,10 +218,6 @@ def switch_default_role(db, obj, kind, admin): """Switch between default user/service and admin roles for users/services""" user_role = orm.Role.find(db, 'user') - # temporary fix of default service role - if kind == 'services': - user_role = orm.Role.find(db, 'service') - admin_role = orm.Role.find(db, 'admin') def add_and_remove(db, obj, kind, current_role, new_role): diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index c300f43d..b676aed7 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -202,7 +202,6 @@ async def test_load_default_roles(tmpdir, request): assert orm.Role.find(db, 'admin') is not None assert orm.Role.find(db, 'server') is not None assert orm.Role.find(db, 'token') is not None - assert orm.Role.find(db, 'service') is not None @mark.role @@ -297,13 +296,11 @@ async def test_load_roles_services(tmpdir, request): # test if every service has a role (and no duplicates) admin_role = orm.Role.find(db, name='admin') user_role = orm.Role.find(db, name='user') - service_role = orm.Role.find(db, name='service') # test if predefined roles loaded and assigned culler_role = orm.Role.find(db, name='culler') cull_idle = orm.Service.find(db, name='cull_idle') assert culler_role in cull_idle.roles - assert service_role not in cull_idle.roles # test if every service has a role (and no duplicates) for service in db.query(orm.Service): @@ -313,13 +310,10 @@ async def test_load_roles_services(tmpdir, request): # test default role assignment if service.admin: assert admin_role in service.roles - assert service_role not in service.roles - elif culler_role not in service.roles: - assert service_role in service.roles - assert service_role.scopes == [] - assert admin_role not in service.roles - # make sure 'user' role not assigned to service assert user_role not in service.roles + elif culler_role not in service.roles: + assert user_role in service.roles + assert admin_role not in service.roles # delete the test services for service in db.query(orm.Service): From 1515747b1e87aa78828e26b732d0234efa9910ca Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 29 Mar 2021 21:26:34 +0200 Subject: [PATCH 098/270] Refactored role methods --- jupyterhub/apihandlers/users.py | 7 +- jupyterhub/app.py | 13 +-- jupyterhub/handlers/base.py | 4 +- jupyterhub/orm.py | 11 ++- jupyterhub/roles.py | 140 +++++++++++++++--------------- jupyterhub/tests/conftest.py | 2 +- jupyterhub/tests/mocking.py | 2 +- jupyterhub/tests/test_app.py | 2 +- jupyterhub/tests/test_roles.py | 8 +- jupyterhub/tests/test_scopes.py | 89 ++++++++++--------- jupyterhub/tests/test_services.py | 2 +- jupyterhub/tests/utils.py | 6 +- 12 files changed, 148 insertions(+), 138 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index dea4bd6d..5263db86 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -14,6 +14,7 @@ from tornado import web from tornado.iostream import StreamClosedError from .. import orm +from ..roles import assign_default_roles from ..roles import update_roles from ..scopes import needs_scope from ..user import User @@ -151,7 +152,7 @@ class UserListAPIHandler(APIHandler): user = self.user_from_username(name) if admin: user.admin = True - update_roles(self.db, obj=user, kind='users') + assign_default_roles(self.db, entity=user) self.db.commit() try: await maybe_future(self.authenticator.add_user(user)) @@ -218,7 +219,7 @@ class UserAPIHandler(APIHandler): self._check_user_model(data) if 'admin' in data: user.admin = data['admin'] - update_roles(self.db, obj=user, kind='users') + assign_default_roles(self.db, entity=user) self.db.commit() try: @@ -286,7 +287,7 @@ class UserAPIHandler(APIHandler): else: setattr(user, key, value) if key == 'admin': - update_roles(self.db, obj=user, kind='users') + assign_default_roles(self.db, entity=user) self.db.commit() user_ = self.user_model(user) user_['auth_state'] = await user.get_auth_state() diff --git a/jupyterhub/app.py b/jupyterhub/app.py index d4429ade..1b90976f 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1857,15 +1857,16 @@ class JupyterHub(Application): # load default roles default_roles = roles.get_default_roles() for role in default_roles: - roles.add_role(db, role) + roles.create_role(db, role) # load predefined roles from config file for predef_role in self.load_roles: - roles.add_role(db, predef_role) + roles.create_role(db, predef_role) # add users, services and/or tokens for bearer in role_bearers: if bearer in predef_role.keys(): for bname in predef_role[bearer]: + if bearer == 'users': bname = self.authenticator.normalize_username(bname) if not ( @@ -1877,8 +1878,10 @@ class JupyterHub(Application): "Username %r is not in Authenticator.allowed_users" % bname ) - roles.add_obj( - db, objname=bname, kind=bearer, rolename=predef_role['name'] + Class = orm.get_class(bearer) + orm_obj = Class.find(db, bname) + roles.grant_role( + db, entity=orm_obj, rolename=predef_role['name'] ) # make sure all users, services and tokens have at least one role (update with default) @@ -1886,7 +1889,7 @@ class JupyterHub(Application): Class = orm.get_class(bearer) for obj in db.query(Class): if len(obj.roles) < 1: - roles.update_roles(db, obj=obj, kind=bearer) + roles.assign_default_roles(db, entity=obj) db.commit() async def _add_tokens(self, token_dict, kind): diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 2cf17acf..4841b2a8 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -480,7 +480,7 @@ class BaseHandler(RequestHandler): # not found, create and register user u = orm.User(name=username) self.db.add(u) - roles.update_roles(self.db, obj=u, kind='users') + roles.assign_default_roles(self.db, entity=u) TOTAL_USERS.inc() self.db.commit() user = self._user_from_orm(u) @@ -765,7 +765,7 @@ class BaseHandler(RequestHandler): # Only set `admin` if the authenticator returned an explicit value. if admin is not None and admin != user.admin: user.admin = admin - roles.update_roles(self.db, obj=user, kind='users') + roles.assign_default_roles(self.db, entity=user) self.db.commit() # always set auth_state and commit, # because there could be key-rotation or clearing of previous values diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 8830a521..8aee2be9 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -39,7 +39,8 @@ from sqlalchemy.types import Text from sqlalchemy.types import TypeDecorator from tornado.log import app_log -from .roles import add_role +from .roles import assign_default_roles +from .roles import create_role from .roles import get_default_roles from .roles import update_roles from .utils import compare_token @@ -621,8 +622,12 @@ class APIToken(Hashed, Base): if not token_role: default_roles = get_default_roles() for role in default_roles: - add_role(db, role) - update_roles(db, obj=orm_token, kind='tokens', roles=roles) + create_role(db, role) + if roles: + update_roles(db, entity=orm_token, roles=roles) + else: + assign_default_roles(db, entity=orm_token) + db.commit() return token diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index afc46e85..53b1d084 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -73,7 +73,7 @@ def expand_self_scope(name, read_only=False): return {"{}!user={}".format(scope, name) for scope in scope_list} -def get_scope_hierarchy(): +def _get_scope_hierarchy(): """ Returns a dictionary of scopes: scopes.keys() = scopes of highest level and scopes that have their own subscopes @@ -106,7 +106,7 @@ def get_scope_hierarchy(): def expand_scope(scopename): """Returns a set of all subscopes""" - scopes = get_scope_hierarchy() + scopes = _get_scope_hierarchy() subscopes = [scopename] def expand_subscopes(index): @@ -133,7 +133,7 @@ def expand_scope(scopename): def expand_roles_to_scopes(orm_object): """Get the scopes listed in the roles of the User/Service/Group/Token""" - scopes = get_subscopes(*orm_object.roles) + scopes = _get_subscopes(*orm_object.roles) if 'self' in scopes: scopes.remove('self') if isinstance(orm_object, orm.User) or hasattr(orm_object, 'orm_user'): @@ -141,7 +141,7 @@ def expand_roles_to_scopes(orm_object): return scopes -def get_subscopes(*args): +def _get_subscopes(*args): """Returns a set of all available subscopes for a specified role or list of roles""" scope_list = [] @@ -154,7 +154,7 @@ def get_subscopes(*args): return scopes -def add_role(db, role_dict): +def create_role(db, role_dict): """Adds a new role to database or modifies an existing one""" if 'name' not in role_dict.keys(): @@ -180,105 +180,103 @@ def add_role(db, role_dict): def existing_only(func): """Decorator for checking if objects and roles exist""" - def check_existence(db, objname, kind, rolename): - - Class = orm.get_class(kind) - obj = Class.find(db, objname) + def check_existence(db, entity, rolename): role = orm.Role.find(db, rolename) - - if obj is None: - raise ValueError("%r of kind %r does not exist" % (objname, kind)) + if entity is None: + raise ValueError( + "%r of kind %r does not exist" % (entity, type(entity).__name__) + ) elif role is None: raise ValueError("Role %r does not exist" % rolename) else: - func(db, obj, kind, role) + func(db, entity, role) return check_existence @existing_only -def add_obj(db, objname, kind, rolename): +def grant_role(db, entity, rolename): """Adds a role for users, services or tokens""" - - if rolename not in objname.roles: - objname.roles.append(rolename) + if rolename not in entity.roles: + entity.roles.append(rolename) db.commit() @existing_only -def remove_obj(db, objname, kind, rolename): +def strip_role(db, entity, rolename): """Removes a role for users, services or tokens""" - - if rolename in objname.roles: - objname.roles.remove(rolename) + if rolename in entity.roles: + entity.roles.remove(rolename) db.commit() -def switch_default_role(db, obj, kind, admin): +def _switch_default_role(db, obj, admin): """Switch between default user/service and admin roles for users/services""" - user_role = orm.Role.find(db, 'user') admin_role = orm.Role.find(db, 'admin') - def add_and_remove(db, obj, kind, current_role, new_role): - + def add_and_remove(db, obj, current_role, new_role): if current_role in obj.roles: - remove_obj(db, objname=obj.name, kind=kind, rolename=current_role.name) + strip_role(db, entity=obj, rolename=current_role.name) # only add new default role if the user has no other roles if len(obj.roles) < 1: - add_obj(db, objname=obj.name, kind=kind, rolename=new_role.name) + grant_role(db, entity=obj, rolename=new_role.name) if admin: - add_and_remove(db, obj, kind, user_role, admin_role) + add_and_remove(db, obj, user_role, admin_role) else: - add_and_remove(db, obj, kind, admin_role, user_role) + add_and_remove(db, obj, admin_role, user_role) -def update_roles(db, obj, kind, roles=None): +def assign_default_roles(db, entity): + """Assigns the default roles to an entity: + users and services get 'user' role, unless they have admin flag + Tokens get 'token' role""" + default_token_role = orm.Role.find(db, 'token') + # tokens can have only 'token' role as default + # assign the default only for tokens + if isinstance(entity, orm.APIToken): + if not entity.roles and entity.user is not None: + default_token_role.tokens.append(entity) + db.commit() + # users and services can have 'user' or 'admin' roles as default + else: + # todo: when we deprecate admin flag: replace with role check + _switch_default_role(db, entity, entity.admin) + + +def update_roles(db, entity, roles): """Updates object's roles if specified, assigns default if no roles specified""" - - Class = orm.get_class(kind) - default_token_role = orm.Role.find(db, 'token') + Class = type(entity) standard_permissions = {'all', 'read:all'} - if roles: - for rolename in roles: - if Class == orm.APIToken: - - role = orm.Role.find(db, rolename) - if role: - # compare the requested role permissions with the owner's permissions (scopes) - token_scopes = get_subscopes(role) - extra_scopes = token_scopes - standard_permissions - # find the owner and their roles - owner = None - if obj.user_id: - owner = db.query(orm.User).get(obj.user_id) - elif obj.service_id: - owner = db.query(orm.Service).get(obj.service_id) - if owner: - owner_scopes = expand_roles_to_scopes(owner) - if (extra_scopes).issubset(owner_scopes): - role.tokens.append(obj) - else: - raise ValueError( - 'Requested token role %r has more permissions than the token owner: [%s]' - % (rolename, ",".join(extra_scopes - owner_scopes)) - ) - else: - raise NameError('Role %r does not exist' % rolename) - else: - add_obj(db, objname=obj.name, kind=kind, rolename=rolename) - else: - # tokens can have only 'token' role as default - # assign the default only for tokens + for rolename in roles: if Class == orm.APIToken: - if not obj.roles and obj.user is not None: - default_token_role.tokens.append(obj) - db.commit() - # users and services can have 'user' or 'admin' roles as default + + role = orm.Role.find(db, rolename) + if role: + # compare the requested role permissions with the owner's permissions (scopes) + token_scopes = _get_subscopes(role) + extra_scopes = token_scopes - standard_permissions + # find the owner and their roles + owner = None + if entity.user_id: + owner = db.query(orm.User).get(entity.user_id) + elif entity.service_id: + owner = db.query(orm.Service).get(entity.service_id) + if owner: + owner_scopes = expand_roles_to_scopes(owner) + if (extra_scopes).issubset(owner_scopes): + role.tokens.append(entity) + else: + raise ValueError( + 'Requested token role %r has more permissions than the token owner: [%s]' + % (rolename, ",".join(extra_scopes - owner_scopes)) + ) + else: + raise NameError('Role %r does not exist' % rolename) else: - switch_default_role(db, obj, kind, obj.admin) + grant_role(db, entity=entity, rolename=rolename) def mock_roles(app, name, kind): @@ -287,5 +285,5 @@ def mock_roles(app, name, kind): obj = Class.find(app.db, name=name) default_roles = get_default_roles() for role in default_roles: - add_role(app.db, role) - update_roles(db=app.db, obj=obj, kind=kind) + create_role(app.db, role) + assign_default_roles(db=app.db, entity=obj) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 6831a14b..eb203029 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -251,7 +251,7 @@ def _mockservice(request, app, url=False): assert name in app._service_map service = app._service_map[name] token = service.orm.api_tokens[0] - update_roles(app.db, token, 'tokens', roles=['token']) + update_roles(app.db, token, roles=['token']) async def start(): # wait for proxy to be updated before starting the service diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 532e8482..5ea51b61 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -342,7 +342,7 @@ class MockHub(JupyterHub): self.db.add(user) self.db.commit() metrics.TOTAL_USERS.inc() - roles.update_roles(self.db, obj=user, kind='users') + roles.assign_default_roles(self.db, entity=user) self.db.commit() def stop(self): diff --git a/jupyterhub/tests/test_app.py b/jupyterhub/tests/test_app.py index a918e9b7..06c18ba7 100644 --- a/jupyterhub/tests/test_app.py +++ b/jupyterhub/tests/test_app.py @@ -50,7 +50,7 @@ def test_raise_error_on_missing_specified_config(): process = Popen( [sys.executable, '-m', 'jupyterhub', '--config', 'not-available.py'] ) - # wait inpatiently for the process to exit like we want it to + # wait impatiently for the process to exit like we want it to for i in range(100): time.sleep(0.1) returncode = process.poll() diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index b676aed7..e929f078 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -180,9 +180,9 @@ def test_orm_roles_delete_cascade(db): ) def test_get_subscopes(db, scopes, subscopes): """Test role scopes expansion into their subscopes""" - roles.add_role(db, {'name': 'testing_scopes', 'scopes': scopes}) + roles.create_role(db, {'name': 'testing_scopes', 'scopes': scopes}) role = orm.Role.find(db, name='testing_scopes') - response = roles.get_subscopes(role) + response = roles._get_subscopes(role) assert response == subscopes db.delete(role) @@ -386,8 +386,8 @@ async def test_load_roles_tokens(tmpdir, request): ) async def test_get_new_token_via_api(app, headers, role_list, status): user = add_user(app.db, app, name='user') - roles.add_role(app.db, {'name': 'reader', 'scopes': ['all']}) - roles.add_role(app.db, {'name': 'user_creator', 'scopes': ['admin:users']}) + roles.create_role(app.db, {'name': 'reader', 'scopes': ['all']}) + roles.create_role(app.db, {'name': 'user_creator', 'scopes': ['admin:users']}) if role_list: body = json.dumps({'roles': role_list}) else: diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 89b57cb1..9b431f65 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -230,7 +230,7 @@ async def test_expand_groups(app, user_name, in_group, status_code): 'read:groups', ], } - roles.add_role(app.db, test_role) + roles.create_role(app.db, test_role) user = add_user(app.db, name=user_name) group_name = 'bluth' group = orm.Group.find(app.db, name=group_name) @@ -240,8 +240,8 @@ async def test_expand_groups(app, user_name, in_group, status_code): if in_group and user not in group.users: group.users.append(user) kind = 'users' - roles.update_roles(app.db, user, kind, roles=['test']) - roles.remove_obj(app.db, user_name, kind, 'user') + roles.update_roles(app.db, user, roles=['test']) + roles.strip_role(app.db, user, 'user') app.db.commit() r = await api_request( app, 'users', user_name, headers=auth_header(app.db, user_name) @@ -265,10 +265,10 @@ err_message = "No access to resources or resources not found" async def test_request_fake_user(app): user_name = 'buster' fake_user = 'annyong' - add_user(app.db, name=user_name) + user = add_user(app.db, name=user_name) test_role = generate_test_role(user_name, ['read:users!group=stuff']) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') app.db.commit() r = await api_request( app, 'users', fake_user, headers=auth_header(app.db, user_name) @@ -284,8 +284,8 @@ async def test_refuse_exceeding_token_permissions(app): add_user(app.db, name='user') api_token = user.new_api_token() exceeding_role = generate_test_role(user_name, ['read:users'], 'exceeding_role') - roles.add_role(app.db, exceeding_role) - roles.add_obj(app.db, objname=api_token, kind='tokens', rolename='exceeding_role') + roles.create_role(app.db, exceeding_role) + roles.grant_role(app.db, entity=user.api_tokens[0], rolename='exceeding_role') app.db.commit() headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', headers=headers) @@ -304,11 +304,11 @@ async def test_exceeding_user_permissions(app): subreader_role = generate_test_role( user_name, ['read:users:groups'], 'subreader_role' ) - roles.add_role(app.db, reader_role) - roles.add_role(app.db, subreader_role) + roles.create_role(app.db, reader_role) + roles.create_role(app.db, subreader_role) app.db.commit() - roles.update_roles(app.db, user, kind='users', roles=['reader_role']) - roles.update_roles(app.db, orm_api_token, kind='tokens', roles=['subreader_role']) + roles.update_roles(app.db, user, roles=['reader_role']) + roles.update_roles(app.db, orm_api_token, roles=['subreader_role']) orm_api_token.roles.remove(orm.Role.find(app.db, name='token')) app.db.commit() @@ -318,7 +318,7 @@ async def test_exceeding_user_permissions(app): keys = {key for user in r.json() for key in user.keys()} assert 'groups' in keys assert 'last_activity' not in keys - roles.remove_obj(app.db, user_name, 'users', 'reader_role') + roles.strip_role(app.db, user, 'reader_role') async def test_user_service_separation(app, mockservice_url): @@ -327,13 +327,11 @@ async def test_user_service_separation(app, mockservice_url): reader_role = generate_test_role(name, ['read:users'], 'reader_role') subreader_role = generate_test_role(name, ['read:users:groups'], 'subreader_role') - roles.add_role(app.db, reader_role) - roles.add_role(app.db, subreader_role) + roles.create_role(app.db, reader_role) + roles.create_role(app.db, subreader_role) app.db.commit() - roles.update_roles(app.db, user, kind='users', roles=['subreader_role']) - roles.update_roles( - app.db, mockservice_url.orm, kind='services', roles=['reader_role'] - ) + roles.update_roles(app.db, user, roles=['subreader_role']) + roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role']) user.roles.remove(orm.Role.find(app.db, name='user')) api_token = user.new_api_token() app.db.commit() @@ -348,12 +346,12 @@ async def test_user_service_separation(app, mockservice_url): async def test_request_user_outside_group(app): user_name = 'buster' fake_user = 'hello' - add_user(app.db, name=user_name) + user = add_user(app.db, name=user_name) add_user(app.db, name=fake_user) test_role = generate_test_role(user_name, ['read:users!group=stuff']) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') - roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') + roles.strip_role(app.db, entity=user, rolename='user') app.db.commit() r = await api_request( app, 'users', fake_user, headers=auth_header(app.db, user_name) @@ -369,9 +367,9 @@ async def test_user_filter(app): app.db.commit() scopes = ['read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar'] test_role = generate_test_role(user, scopes) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') - roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') + roles.strip_role(app.db, entity=user, rolename='user') name_in_scope = {'lindsay', 'oscar', 'gob'} outside_scope = {'maeby', 'marta'} group_name = 'bluth' @@ -402,8 +400,8 @@ async def test_service_filter(app): user = add_user(app.db, name=user_name) app.db.commit() test_role = generate_test_role(user, ['read:services!service=cull_idle']) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') r = await api_request(app, 'services', headers=auth_header(app.db, user_name)) assert r.status_code == 200 service_names = set(r.json().keys()) @@ -413,12 +411,12 @@ async def test_service_filter(app): async def test_user_filter_with_group(app): # Move role setup to setup method? user_name = 'sally' - add_user(app.db, name=user_name) + user = add_user(app.db, name=user_name) external_user_name = 'britta' add_user(app.db, name=external_user_name) test_role = generate_test_role(user_name, ['read:users!group=sitwell']) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') name_set = {'sally', 'stan'} group_name = 'sitwell' @@ -441,11 +439,11 @@ async def test_user_filter_with_group(app): async def test_group_scope_filter(app): user_name = 'rollerblade' - add_user(app.db, name=user_name) + user = add_user(app.db, name=user_name) scopes = ['read:groups!group=sitwell', 'read:groups!group=bluth'] test_role = generate_test_role(user_name, scopes) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') group_set = {'sitwell', 'bluth', 'austero'} for group_name in group_set: @@ -462,11 +460,11 @@ async def test_group_scope_filter(app): async def test_vertical_filter(app): user_name = 'lindsey' - add_user(app.db, name=user_name) + user = add_user(app.db, name=user_name) test_role = generate_test_role(user_name, ['read:users:name']) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') - roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') + roles.strip_role(app.db, entity=user, rolename='user') app.db.commit() r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) @@ -477,12 +475,13 @@ async def test_vertical_filter(app): async def test_stacked_vertical_filter(app): user_name = 'user' + user = add_user(app.db, name=user_name) test_role = generate_test_role( user_name, ['read:users:activity', 'read:users:servers'] ) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') - roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') + roles.strip_role(app.db, entity=user, rolename='user') app.db.commit() r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) @@ -494,13 +493,13 @@ async def test_stacked_vertical_filter(app): async def test_cross_filter(app): user_name = 'abed' - add_user(app.db, name=user_name) + user = add_user(app.db, name=user_name) test_role = generate_test_role( user_name, ['read:users:activity', 'read:users!user=abed'] ) - roles.add_role(app.db, test_role) - roles.add_obj(app.db, objname=user_name, kind='users', rolename='test') - roles.remove_obj(app.db, objname=user_name, kind='users', rolename='user') + roles.create_role(app.db, test_role) + roles.grant_role(app.db, entity=user, rolename='test') + roles.strip_role(app.db, entity=user, rolename='user') app.db.commit() new_users = {'britta', 'jeff', 'annie'} for new_user_name in new_users: diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 55ba907e..c14a714b 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -95,7 +95,7 @@ async def test_external_service(app): service = app._service_map[name] api_token = service.orm.api_tokens[0] - update_roles(app.db, api_token, 'tokens', roles=['token']) + update_roles(app.db, api_token, roles=['token']) url = public_url(app, service) + '/api/users' r = await async_requests.get(url, allow_redirects=False) r.raise_for_status() diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 718f3cd6..dd47f93f 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -9,6 +9,7 @@ from certipy import Certipy from jupyterhub import metrics from jupyterhub import orm from jupyterhub.objects import Server +from jupyterhub.roles import assign_default_roles from jupyterhub.roles import update_roles from jupyterhub.utils import url_path_join as ujoin @@ -113,7 +114,10 @@ def add_user(db, app=None, **kwargs): setattr(orm_user, attr, value) db.commit() requested_roles = kwargs.get('roles') - update_roles(db, obj=orm_user, kind='users', roles=requested_roles) + if requested_roles: + update_roles(db, entity=orm_user, roles=requested_roles) + else: + assign_default_roles(db, entity=orm_user) if app: return app.users[orm_user.id] else: From db66443793f8bb63119cd6451ca9f6d63507d13c Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 30 Mar 2021 08:50:20 +0200 Subject: [PATCH 099/270] No more reinitialization of roles on each startup --- jupyterhub/apihandlers/users.py | 3 +-- jupyterhub/app.py | 17 ++++++++++++----- jupyterhub/roles.py | 11 ++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 5263db86..9fbe63f9 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -15,7 +15,6 @@ from tornado.iostream import StreamClosedError from .. import orm from ..roles import assign_default_roles -from ..roles import update_roles from ..scopes import needs_scope from ..user import User from ..utils import isoformat @@ -57,7 +56,7 @@ class UserListAPIHandler(APIHandler): @needs_scope( 'read:users', 'read:users:name', - 'reda:users:servers', + 'read:users:servers', 'read:users:groups', 'read:users:activity', ) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 1b90976f..8131cad7 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1884,11 +1884,16 @@ class JupyterHub(Application): db, entity=orm_obj, rolename=predef_role['name'] ) - # make sure all users, services and tokens have at least one role (update with default) - for bearer in role_bearers: - Class = orm.get_class(bearer) - for obj in db.query(Class): - if len(obj.roles) < 1: + # make sure that on no admin situation, all roles are reset + admin_role = orm.Role.find(db, name='admin') + if not admin_role.users: + app_log.info( + "No admin users found; assuming hub upgrade. Initializing default roles for all entities" + ) + for bearer in role_bearers: + Class = orm.get_class(bearer) + for obj in db.query(Class): + # if len(obj.roles) < 1: # todo: Should I check if some roles are already assigned? roles.assign_default_roles(db, entity=obj) db.commit() @@ -1994,6 +1999,8 @@ class JupyterHub(Application): if orm_service is None: # not found, create a new one orm_service = orm.Service(name=name) + if spec.get('admin', False): + roles.update_roles(self.db, entity=orm_service, roles=['admin']) self.db.add(orm_service) orm_service.admin = spec.get('admin', False) self.db.commit() diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 53b1d084..1712f9ad 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -230,7 +230,7 @@ def _switch_default_role(db, obj, admin): def assign_default_roles(db, entity): """Assigns the default roles to an entity: - users and services get 'user' role, unless they have admin flag + users and services get 'user' role, or admin role if they have admin flag Tokens get 'token' role""" default_token_role = orm.Role.find(db, 'token') # tokens can have only 'token' role as default @@ -246,13 +246,10 @@ def assign_default_roles(db, entity): def update_roles(db, entity, roles): - """Updates object's roles if specified, - assigns default if no roles specified""" - Class = type(entity) + """Updates object's roles""" standard_permissions = {'all', 'read:all'} for rolename in roles: - if Class == orm.APIToken: - + if isinstance(entity, orm.APIToken): role = orm.Role.find(db, rolename) if role: # compare the requested role permissions with the owner's permissions (scopes) @@ -266,7 +263,7 @@ def update_roles(db, entity, roles): owner = db.query(orm.Service).get(entity.service_id) if owner: owner_scopes = expand_roles_to_scopes(owner) - if (extra_scopes).issubset(owner_scopes): + if extra_scopes.issubset(owner_scopes): role.tokens.append(entity) else: raise ValueError( From 71a5842ad212b2bf17538ccefc44f1cf2120b362 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 1 Apr 2021 17:26:34 +0200 Subject: [PATCH 100/270] Removed user model flags, scope-guarded server model with new scopes --- jupyterhub/apihandlers/base.py | 58 +++++++++++++++++---------------- jupyterhub/apihandlers/users.py | 19 +++++------ jupyterhub/roles.py | 2 +- jupyterhub/tests/test_api.py | 1 + 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index ddf1d1b8..600931d5 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -79,23 +79,32 @@ class APIHandler(BaseHandler): % req_scope, ) - def has_access(orm_resource, kind): + def has_access_to(orm_resource, kind): """ - param orm_resource: User or Service or Group - param kind: 'users' or 'services' or 'groups' + param orm_resource: User or Service or Group or spawner + param kind: 'user' or 'service' or 'group' or 'server'. + `kind` could probably be derived from `orm_resource`, problem is Jupyterhub.users.User """ if sub_scope == scopes.Scope.ALL: return True else: found_resource = orm_resource.name in sub_scope[kind] if not found_resource: # Try group-based access - if 'group' in sub_scope and kind == 'user': + if kind == 'server': + # First check if we have access to user info + user_name = orm_resource.user.name + found_resource = user_name in sub_scope['user'] + if not found_resource: + # Now check for specific servers: + server_format = f"{orm_resource.user / orm_resource.name}" + found_resource = server_format in sub_scope[kind] + elif 'group' in sub_scope and kind == 'user': group_names = {group.name for group in orm_resource.groups} user_in_group = bool(group_names & set(sub_scope['group'])) found_resource = user_in_group return found_resource - return has_access + return has_access_to def get_current_user_cookie(self): """Override get_user_cookie to check Referer header""" @@ -168,17 +177,24 @@ class APIHandler(BaseHandler): def server_model(self, spawner, include_state=False): """Get the JSON model for a Spawner""" - return { + server_scope = 'read:users:servers' + server_state_scope = 'admin:users:server_state' + model = { 'name': spawner.name, 'last_activity': isoformat(spawner.orm_spawner.last_activity), 'started': isoformat(spawner.orm_spawner.started), 'pending': spawner.pending, 'ready': spawner.ready, - 'state': spawner.get_state() if include_state else None, 'url': url_path_join(spawner.user.url, spawner.name, '/'), 'user_options': spawner.user_options, 'progress_url': spawner._progress_url, } + # First check users, then servers + if server_state_scope in self.parsed_scopes: + scope_filter = self.get_scope_filter(server_state_scope) + if scope_filter(spawner, kind='server'): + model['state'] = spawner.get_state() + return model def token_model(self, token): """Get the JSON model for an APIToken""" @@ -220,13 +236,7 @@ class APIHandler(BaseHandler): model.update(extra) return model - def user_model( - self, - user, - include_servers=False, - include_server_state=False, - include_auth_state=False, - ): + def user_model(self, user): """Get the JSON model for a User object""" if isinstance(user, orm.User): user = self.users[user.id] @@ -258,8 +268,8 @@ class APIHandler(BaseHandler): 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, - 'read:users:auth_state': {'kind', 'name', 'auth_state'}, - 'read:users:server_state': {'kind', 'name', 'server_state'}, + 'admin:users:auth_state': {'kind', 'name', 'auth_state'}, + 'admin:users:server_state': {'kind', 'name', 'servers', 'server_state'}, } self.log.debug( "Asking for user model of %s with scopes [%s]", @@ -273,21 +283,16 @@ class APIHandler(BaseHandler): if scope_filter(user, kind='user'): allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} - if not include_auth_state: - model.pop("auth_state", None) if model: - include_server_state &= 'server_state' in allowed_keys if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending - if include_servers and 'servers' in allowed_keys: + if 'servers' in allowed_keys: servers = model['servers'] = {} for name, spawner in user.spawners.items(): # include 'active' servers, not just ready # (this includes pending events) if spawner.active: - servers[name] = self.server_model( - spawner, include_state=include_server_state - ) + servers[name] = self.server_model(spawner) return model def group_model(self, group): @@ -308,11 +313,8 @@ class APIHandler(BaseHandler): scope_filter = self.get_scope_filter(req_scope) if scope_filter(service, kind='service'): model['roles'] = [r.name for r in service.roles] - model[ - 'admin' - ] = ( - service.admin - ) # todo: Remove once we replace admin flag with role check + model['admin'] = service.admin + # todo: Remove once we replace admin flag with role check return model _user_model_types = {'name': str, 'admin': bool, 'groups': list, 'auth_state': dict} diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index dea4bd6d..2fb0dcd6 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -104,9 +104,7 @@ class UserListAPIHandler(APIHandler): data = [] for u in query: if post_filter is None or post_filter(u): - user_model = self.user_model( - u, include_servers=True, include_server_state=True - ) + user_model = self.user_model(u) if user_model: data.append(user_model) self.write(json.dumps(data)) @@ -188,16 +186,15 @@ def admin_or_self(method): class UserAPIHandler(APIHandler): @needs_scope( - 'read:users' - ) # Todo: Add the same list of scopes as at UserListAPIHandler + 'read:users', + 'read:users:name', + 'reda:users:servers', + 'read:users:groups', + 'read:users:activity', + ) async def get(self, user_name): user = self.find_user(user_name) - model = self.user_model( - user, - include_servers=True, - include_server_state=True, - include_auth_state=True, - ) + model = self.user_model(user) # auth state will only be shown if the requester is an admin # this means users can't see their own auth state unless they # are admins, Hub admins often are also marked as admins so they diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index afc46e85..4b6f4246 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -90,7 +90,7 @@ def get_scope_hierarchy(): 'read:users:servers', ], 'users:tokens': ['read:users:tokens'], - 'admin:users': ['read:users:auth_state', 'read:users:server_state'], + 'admin:users': ['admin:users:auth_state', 'admin:users:server_state'], 'admin:users:servers': None, 'groups': ['read:groups'], 'admin:groups': None, diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index d3e3dadd..41c563d5 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -159,6 +159,7 @@ def fill_user(model): model.setdefault('created', TIMESTAMP) model.setdefault('last_activity', TIMESTAMP) model.setdefault('servers', {}) + model.setdefault('auth_state', '') return model From 933e4d555b5bcd8938a5d804df45a0add3b8b97d Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 6 Apr 2021 10:39:50 +0200 Subject: [PATCH 101/270] Add TO DO flag for users:activity scope in server role --- jupyterhub/roles.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 4b5c2f2f..ec92d769 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -38,7 +38,9 @@ def get_default_roles(): { 'name': 'server', 'description': 'Post activity only', - 'scopes': ['users:activity'], + 'scopes': [ + 'users:activity' + ], # TO DO - fix scope to refer to only self once implemented }, { 'name': 'token', From 2f34557689e63bfd5e4da54e66f620ebc2caff97 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 7 Apr 2021 10:37:49 +0200 Subject: [PATCH 102/270] Resolve comments --- jupyterhub/apihandlers/base.py | 22 +++++++++++++++------- jupyterhub/tests/test_api.py | 6 ++++-- jupyterhub/tests/test_named_servers.py | 1 - 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 600931d5..ab7dff71 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -175,7 +175,7 @@ class APIHandler(BaseHandler): json.dumps({'status': status_code, 'message': message or status_message}) ) - def server_model(self, spawner, include_state=False): + def server_model(self, spawner): """Get the JSON model for a Spawner""" server_scope = 'read:users:servers' server_state_scope = 'admin:users:server_state' @@ -250,7 +250,7 @@ class APIHandler(BaseHandler): 'pending': None, 'created': isoformat(user.created), 'last_activity': isoformat(user.last_activity), - 'auth_state': '', # placeholder, filled in later + 'auth_state': None, # placeholder, filled in later } access_map = { 'read:users': { @@ -297,23 +297,31 @@ class APIHandler(BaseHandler): def group_model(self, group): """Get the JSON model for a Group object""" - model = {'kind': 'group', 'name': group.name} + model = {} req_scope = 'read:groups' if req_scope in self.parsed_scopes: scope_filter = self.get_scope_filter(req_scope) if scope_filter(group, kind='group'): - model['users'] = [u.name for u in group.users] + model = { + 'kind': 'group', + 'name': group.name, + 'users': [u.name for u in group.users], + } return model def service_model(self, service): """Get the JSON model for a Service object""" - model = {'kind': 'service', 'name': service.name} + model = {} req_scope = 'read:services' if req_scope in self.parsed_scopes: scope_filter = self.get_scope_filter(req_scope) if scope_filter(service, kind='service'): - model['roles'] = [r.name for r in service.roles] - model['admin'] = service.admin + model = { + 'kind': 'service', + 'name': service.name, + 'roles': [r.name for r in service.roles], + 'admin': service.admin, + } # todo: Remove once we replace admin flag with role check return model diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 41c563d5..1044ade9 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -159,7 +159,6 @@ def fill_user(model): model.setdefault('created', TIMESTAMP) model.setdefault('last_activity', TIMESTAMP) model.setdefault('servers', {}) - model.setdefault('auth_state', '') return model @@ -180,9 +179,12 @@ async def test_get_users(app): 'admin': False, 'roles': ['user'], 'last_activity': None, + 'auth_state': None, } assert users == [ - fill_user({'name': 'admin', 'admin': True, 'roles': ['admin']}), + fill_user( + {'name': 'admin', 'admin': True, 'roles': ['admin'], 'auth_state': None} + ), fill_user(user_model), ] r = await api_request(app, 'users', headers=auth_header(db, 'user')) diff --git a/jupyterhub/tests/test_named_servers.py b/jupyterhub/tests/test_named_servers.py index 884921c0..88a48d6d 100644 --- a/jupyterhub/tests/test_named_servers.py +++ b/jupyterhub/tests/test_named_servers.py @@ -52,7 +52,6 @@ async def test_default_server(app, named_servers): r.raise_for_status() user_model = normalize_user(r.json()) - print(user_model) assert user_model == fill_user( { 'name': username, From a512867a1e079fa6987dc82d6bb1f473d4600367 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 7 Apr 2021 14:10:38 +0200 Subject: [PATCH 103/270] Update scopes in docs/rest-api.yml --- docs/rest-api.yml | 310 ++++++++++++++++++++++++---------------------- 1 file changed, 159 insertions(+), 151 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index b60d74d6..a53fa689 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -1,13 +1,12 @@ # see me at: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#/default -swagger: '2.0' +swagger: "2.0" info: title: JupyterHub description: The REST API for JupyterHub version: 1.2.0dev license: name: BSD-3-Clause -schemes: - [http, https] +schemes: [http, https] securityDefinitions: token: type: apiKey @@ -16,38 +15,41 @@ securityDefinitions: oauth2: type: oauth2 flow: accessCode - authorizationUrl: '/hub/api/oauth2/authorize' # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? - tokenUrl: '/hub/api/oauth2/token' + authorizationUrl: "/hub/api/oauth2/authorize" # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? + tokenUrl: "/hub/api/oauth2/token" scopes: - all: Everything a user can do - read:all: Read-only access to everything a user can read (also whoami handler) + self: Everything a standard user can do + all: Everything a token owner can do users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers read:users: Read-only access to the above - read:users!user=username: Read-only access to a single user's model + read:users!user=username: Read-only access to a single user's model (example horizontal filter) read:users:name: Read-only access to users' names read:users:groups: Read-only access to users' groups read:users:activity: Read-only access to users' activity - read:users:activity!group=groupname: Read-only access to specific group's users' activity - read:users:servers: Read-only access to users' servers - users:activity!user=username: Update a user's activity + read:users:activity!group=groupname: Read-only access to specific group's users' activity (example horizontal filter) + users:activity: Update users' activity + users:activity!user=username: Update a single user's activity (example horizontal filter) users:servers: Grants access to start/stop any server - users:servers!server=servername: Limits the above to a specific server + users:servers!server=servername: Limits the above to a specific server (example horizontal filter) + read:users:servers: Read-only access to users' servers users:tokens: Grants access to users' token (includes create/revoke a token) - read:users:tokens: Identify a user from a token - admin:users: Grants access to creating/removing users - admin:users:servers: Grants access to create/remove users' servers + read:users:tokens: Read-only access to users' tokens + admin:users: Grants access to creating/removing users on top of managing access + admin:users:auth_state: Access users' auth state + admin:users:servers: Grants access to create/remove users' servers on top of managing access + admin:users:server_state: Access servers' state groups: Add/remove users from any group - groups!group=groupname: Add/remove users from a specific group only + groups!group=groupname: Add/remove users from a specific group only (example horizontal filter) read:groups: Read-only access to groups admin:groups: Grants access to create/delete groups read:services: Read-only access to services read:hub: Read-only access to detailed information about JupyterHub proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy shutdown: Grants access to shutdown the Hub -security: +security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope self) or have both (either can be used)? - token: [] - oauth2: - - all + - self basePath: /hub/api produces: - application/json @@ -61,7 +63,7 @@ paths: This endpoint is not authenticated for the purpose of clients and user to identify the JupyterHub version before setting up authentication. responses: - '200': + "200": description: The JupyterHub version schema: type: object @@ -72,15 +74,15 @@ paths: /info: get: summary: Get detailed info about JupyterHub + security: + - oauth2: + - read:hub description: | Detailed JupyterHub information, including Python version, JupyterHub's version and executable path, and which Authenticator and Spawner are active. - security: - - oauth2: - - read:hub responses: - '200': + "200": description: Detailed JupyterHub info schema: type: object @@ -117,8 +119,12 @@ paths: summary: List users security: - oauth2: - - users - - read:users + - read:users + - read:users:name + - read:users:groups + - read:users:activity + - read:users:servers + #TODO: add admin:users:auth_state/server_state? parameters: - name: state in: query @@ -135,17 +141,17 @@ paths: Added in JupyterHub 1.3 responses: - '200': + "200": description: The Hub's user list schema: type: array items: - $ref: '#/definitions/User' + $ref: "#/definitions/User" post: summary: Create multiple users security: - oauth2: - - admin:users + - admin:users parameters: - name: body in: body @@ -162,21 +168,24 @@ paths: description: whether the created users should be admins type: boolean responses: - '201': + "201": description: The users have been created schema: type: array description: The created users items: - $ref: '#/definitions/User' + $ref: "#/definitions/User" /users/{name}: get: summary: Get a user by name security: - oauth2: - - users - - read:users - - read:users!user=username + - read:users + - read:users:name + - read:users:groups + - read:users:activity + - read:users:servers + #TODO: add admin:users:auth_state/server_state? parameters: - name: name description: username @@ -184,15 +193,15 @@ paths: required: true type: string responses: - '200': + "200": description: The User model schema: - $ref: '#/definitions/User' + $ref: "#/definitions/User" post: summary: Create a single user security: - oauth2: - - admin:users + - admin:users parameters: - name: name description: username @@ -200,16 +209,16 @@ paths: required: true type: string responses: - '201': + "201": description: The user has been created schema: - $ref: '#/definitions/User' + $ref: "#/definitions/User" patch: summary: Modify a user description: Change a user's name or admin status security: - oauth2: - - users + - users parameters: - name: name description: username @@ -230,15 +239,15 @@ paths: type: boolean description: update admin (optional, if another key is updated i.e. name) responses: - '200': + "200": description: The updated user info schema: - $ref: '#/definitions/User' + $ref: "#/definitions/User" delete: summary: Delete a user security: - oauth2: - - admin:users + - admin:users parameters: - name: name description: username @@ -246,20 +255,17 @@ paths: required: true type: string responses: - '204': + "204": description: The user has been deleted /users/{name}/activity: post: - summary: - Notify Hub of activity for a given user. - description: - Notify the Hub of activity by the user, + summary: Notify Hub of activity for a given user. + description: Notify the Hub of activity by the user, e.g. accessing a service or (more likely) actively using a server. security: - oauth2: - - users - - users:activity!user=username + - users:activity parameters: - name: name description: username @@ -285,7 +291,7 @@ paths: The default server has an empty name (''). type: object properties: - '': + "": description: | Activity for a single server. type: object @@ -298,24 +304,23 @@ paths: description: | Timestamp of last-seen activity on this server. example: - last_activity: '2019-02-06T12:54:14Z' + last_activity: "2019-02-06T12:54:14Z" servers: - '': - last_activity: '2019-02-06T12:54:14Z' + "": + last_activity: "2019-02-06T12:54:14Z" gpu: - last_activity: '2019-02-06T12:54:14Z' + last_activity: "2019-02-06T12:54:14Z" responses: - '401': - $ref: '#/responses/Unauthorized' - '404': + "401": + $ref: "#/responses/Unauthorized" + "404": description: No such user /users/{name}/server: post: summary: Start a user's single-user notebook server security: - oauth2: - - users - - users:servers + - users:servers parameters: - name: name description: username @@ -336,16 +341,15 @@ paths: type: object responses: - '201': + "201": description: The user's notebook server has started - '202': + "202": description: The user's notebook server has not yet started, but has been requested delete: summary: Stop a user's server security: - oauth2: - - users - - users:servers + - users:servers parameters: - name: name description: username @@ -353,18 +357,16 @@ paths: required: true type: string responses: - '204': + "204": description: The user's notebook server has stopped - '202': + "202": description: The user's notebook server has not yet stopped as it is taking a while to stop /users/{name}/servers/{server_name}: post: summary: Start a user's single-user named-server notebook server security: - oauth2: - - users - - users:servers - - users:servers!server=servername + - users:servers parameters: - name: name description: username @@ -374,7 +376,7 @@ paths: - name: server_name description: | name given to a named-server. - + Note that depending on your JupyterHub infrastructure there are chracterter size limitation to `server_name`. Default spawner with K8s pod will not allow Jupyter Notebooks to be spawned with a name that contains more than 253 characters (keep in mind that the pod will be spawned with extra characters to identify the user and hub). in: path required: true @@ -390,17 +392,15 @@ paths: schema: type: object responses: - '201': + "201": description: The user's notebook named-server has started - '202': + "202": description: The user's notebook named-server has not yet started, but has been requested delete: summary: Stop a user's named-server security: - oauth2: - - users - - users:servers - - users:servers!server=servername + - users:servers parameters: - name: name description: username @@ -425,9 +425,9 @@ paths: Removing a server deletes things like the state of the stopped server. Default: false. responses: - '204': + "204": description: The user's notebook named-server has stopped - '202': + "202": description: The user's notebook named-server has not yet stopped as it is taking a while to stop /users/{name}/tokens: parameters: @@ -440,23 +440,23 @@ paths: summary: List tokens for the user security: - oauth2: - - users:tokens + - read:users:tokens responses: - '200': + "200": description: The list of tokens schema: type: array items: - $ref: '#/definitions/Token' - '401': - $ref: '#/responses/Unauthorized' - '404': + $ref: "#/definitions/Token" + "401": + $ref: "#/responses/Unauthorized" + "404": description: No such user post: summary: Create a new token for the user security: - oauth2: - - users:tokens + - users:tokens parameters: - name: token_params in: body @@ -471,19 +471,19 @@ paths: type: string description: A note attached to the token for future bookkeeping roles: - type: list + type: array + items: + type: string description: A list of role names that the token should have responses: - '201': + "201": description: The newly created token schema: - $ref: '#/definitions/Token' - '400': + $ref: "#/definitions/Token" + "400": description: Body must be a JSON dict or empty - '403': - description: Requested roles cannot have higher permissions than the token owner - '404': - description: Requested roles not found + "403": + description: Requested role does not exist /users/{name}/tokens/{token_id}: parameters: - name: name @@ -499,54 +499,55 @@ paths: summary: Get the model for a token by id security: - oauth2: - - users:tokens + - read:users:tokens responses: - '200': + "200": description: The info for the new token schema: - $ref: '#/definitions/Token' + $ref: "#/definitions/Token" delete: summary: Delete (revoke) a token by id security: - oauth2: - - users:tokens + - users:tokens responses: - '204': + "204": description: The token has been deleted /user: get: summary: Return authenticated user's model security: - oauth2: - - all - - read:all + - read:users + - read:users:name + - read:users:groups + - read:users:activity + - read:users:servers + #TODO: add admin:users:auth_state/server_state? responses: - '200': + "200": description: The authenticated user's model is returned. schema: - $ref: '#/definitions/User' + $ref: "#/definitions/User" /groups: get: summary: List groups security: - oauth2: - - groups - - read:groups + - read:groups responses: - '200': + "200": description: The list of groups schema: type: array items: - $ref: '#/definitions/Group' + $ref: "#/definitions/Group" /groups/{name}: get: summary: Get a group by name security: - oauth2: - - groups - - groups!group=groupname - - read:groups + - read:groups parameters: - name: name description: group name @@ -554,15 +555,15 @@ paths: required: true type: string responses: - '200': + "200": description: The group model schema: - $ref: '#/definitions/Group' + $ref: "#/definitions/Group" post: summary: Create a group security: - oauth2: - - admin:groups + - admin:groups parameters: - name: name description: group name @@ -570,15 +571,15 @@ paths: required: true type: string responses: - '201': + "201": description: The group has been created schema: - $ref: '#/definitions/Group' + $ref: "#/definitions/Group" delete: summary: Delete a group security: - oauth2: - - admin:groups + - admin:groups parameters: - name: name description: group name @@ -586,15 +587,14 @@ paths: required: true type: string responses: - '204': + "204": description: The group has been deleted /groups/{name}/users: post: summary: Add users to a group security: - oauth2: - - groups - - groups!group=groupname + - groups parameters: - name: name description: group name @@ -614,16 +614,15 @@ paths: items: type: string responses: - '200': + "200": description: The users have been added to the group schema: - $ref: '#/definitions/Group' + $ref: "#/definitions/Group" delete: summary: Remove users from a group security: - oauth2: - - groups - - groups!group=groupname + - groups parameters: - name: name description: group name @@ -643,27 +642,27 @@ paths: items: type: string responses: - '200': + "200": description: The users have been removed from the group /services: get: summary: List services security: - oauth2: - - read:services + - read:services responses: - '200': + "200": description: The service list schema: type: array items: - $ref: '#/definitions/Service' + $ref: "#/definitions/Service" /services/{name}: get: summary: Get a service by name security: - oauth2: - - read:services + - read:services parameters: - name: name description: service name @@ -671,19 +670,19 @@ paths: required: true type: string responses: - '200': + "200": description: The Service model schema: - $ref: '#/definitions/Service' + $ref: "#/definitions/Service" /proxy: get: summary: Get the proxy's routing table description: A convenience alias for getting the routing table directly from the proxy security: - oauth2: - - proxy + - proxy responses: - '200': + "200": description: Routing table schema: type: object @@ -692,16 +691,16 @@ paths: summary: Force the Hub to sync with the proxy security: - oauth2: - - proxy + - proxy responses: - '200': + "200": description: Success patch: summary: Notify the Hub about a new proxy description: Notifies the Hub of a new proxy to use. security: - oauth2: - - proxy + - proxy parameters: - name: body in: body @@ -723,7 +722,7 @@ paths: type: string description: CONFIGPROXY_AUTH_TOKEN for the new proxy responses: - '200': + "200": description: Success /authorizations/token: post: @@ -736,7 +735,7 @@ paths: accepts passwords (e.g. not OAuth). security: - oauth2: - - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope + - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope parameters: - name: credentials in: body @@ -748,7 +747,7 @@ paths: password: type: string responses: - '200': + "200": description: The new API token schema: type: object @@ -756,23 +755,23 @@ paths: token: type: string description: The new API token. - '403': + "403": description: The user can not be authenticated. /authorizations/token/{token}: get: summary: Identify a user or service from an API token security: - oauth2: - - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? + - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? parameters: - name: token in: path required: true type: string responses: - '200': + "200": description: The user or service identified by the API token - '404': + "404": description: A user or service is not found. /authorizations/cookie/{cookie_name}/{cookie_value}: get: @@ -788,16 +787,16 @@ paths: required: true type: string responses: - '200': + "200": description: The user identified by the cookie schema: - $ref: '#/definitions/User' - '404': + $ref: "#/definitions/User" + "404": description: A user is not found. deprecated: true # minrk: let’s not add a scope for this, let’s remove it /oauth2/authorize: get: - summary: 'OAuth 2.0 authorize endpoint' + summary: "OAuth 2.0 authorize endpoint" description: | Redirect users to this URL to begin the OAuth process. It is not an API endpoint. @@ -823,9 +822,9 @@ paths: required: true type: string responses: - '200': + "200": description: Success - '400': + "400": description: OAuth2Error /oauth2/token: post: @@ -862,7 +861,7 @@ paths: required: true type: string responses: - '200': + "200": description: JSON response including the token schema: type: object @@ -878,7 +877,7 @@ paths: summary: Shutdown the Hub security: - oauth2: - - shutdown + - shutdown parameters: - name: body in: body @@ -892,9 +891,9 @@ paths: type: boolean description: Whether users' notebook servers should be shutdown as well (default from Hub config) responses: - '202': + "202": description: Shutdown successful - '400': + "400": description: Unexpeced value for proxy or servers # Descriptions of common responses responses: @@ -937,7 +936,11 @@ definitions: type: array description: The active servers for this user. items: - $ref: '#/definitions/Server' + $ref: "#/definitions/Server" + auth_state: + type: string + #TODO: will there be predefined states? Should it rather be object instead of string? + description: Authentication state of the user. Only available with admin:users:auth_state scope. None otherwise. Server: type: object properties: @@ -974,7 +977,7 @@ definitions: description: UTC timestamp last-seen activity on this server. state: type: object - description: Arbitrary internal state from this server's spawner. Only available on the hub's users list or get-user-by-name method, and only if a hub admin. None otherwise. + description: Arbitrary internal state from this server's spawner. Only available on the hub's users list or get-user-by-name method, and only with admin:users:server_state scope. None otherwise. user_options: type: object description: User specified options for the user's spawned instance of a single-user server. @@ -989,6 +992,11 @@ definitions: description: The names of users who are members of this group items: type: string + roles: + type: array + description: The names of roles this group has + items: + type: string Service: type: object properties: From 949ec5cc755f08a8a0b1f58ed3b79e07dc0f62f1 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 7 Apr 2021 14:34:41 +0200 Subject: [PATCH 104/270] Add and update scopes, roles, charts and text in docs/source/rbac docs --- docs/source/images/rbac-api-request-chart.png | Bin 237823 -> 461416 bytes .../images/rbac-api-token-request-chart.png | Bin 214426 -> 0 bytes .../images/rbac-token-request-chart.png | Bin 0 -> 494274 bytes docs/source/rbac/index.md | 5 +- docs/source/rbac/roles.md | 48 ++++++++----- docs/source/rbac/scopes.md | 68 ++++++++++++------ docs/source/rbac/tech-implementation.md | 38 ++++++---- docs/source/rbac/upgrade.md | 1 + docs/source/rbac/use-cases.md | 43 ++++++----- 9 files changed, 133 insertions(+), 70 deletions(-) delete mode 100644 docs/source/images/rbac-api-token-request-chart.png create mode 100644 docs/source/images/rbac-token-request-chart.png create mode 100644 docs/source/rbac/upgrade.md diff --git a/docs/source/images/rbac-api-request-chart.png b/docs/source/images/rbac-api-request-chart.png index a0476399bee51e7b9c34fdb3c4a5c2003b9c32ec..02d0ff335074a56fe0c3a1eabad3ab23cb290b17 100644 GIT binary patch literal 461416 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�Oj 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 K@EZ$q6BN9guqB*Bt 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�G>NId1E8Z!G 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%0A_!U3B$Sxm%&&K6MyWdOf57%85g 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 literal 237823 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

+c!cEhrjK+)A#du&mzfDLTA{a02_q;J- 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

yz?>LEqB1GNg2QCX0+rvHO_NL*PMYuoE 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 `all` that grants access to only the user's own resources. -- `admin` role contains all available scopes and grants full rights to all actions similarly to the current admin status. -- `server` role allows for posting activity only through the single `users:activity` scope. +- `user` role provides a {ref}`default user scope ` `self` that grants access to only the user's own resources. +- `admin` role contains all available scopes and grants full rights to all actions similarly to the current admin status. This role **cannot be edited**. +- `token` role provides a {ref}`default token scope ` `all` that resolves to the same permissions as the token's owner has. +- `server` role allows for posting activity of "itself" only. The scope is currently under development. + +**These roles cannot be deleted.** ``` -Roles can also be customly defined and assigned to users, services, groups and tokens. +New roles can also be customly defined (see {ref}`define_role_target`). Roles can be assigned to the following entities: +- Users +- Services +- Groups +- Tokens -**_Users_** and **_services_** are assigned a default role ( `user` or `admin`) if no custom role is requested based on their admin status. +An entity can have zero, one, or multiple roles, and there are no restrictions on which roles can be assigned to which entity. Roles can be added to or removed from entities at any time. -**_Tokens_**’ roles cannot grant the token higher permissions than their owner’s roles. If no specific role is requested, tokens are assigned the `user` role. +**Users and services** \ +When a new user or service gets created, they are assigned their default role ( `user` or `admin`) if no custom role is requested, currently based on their admin status. -**_Groups_** do not require any role and are not assigned any roles by default. Once roles are defined and assigned to groups, the privileges of each group member are extended when needed (see {ref}`resolving-roles-scopes-target` for more details). This is useful for assigning a set of common permissions to several users. +**Groups** \ +A group does not require any role, and has no roles by default. If a user is a member of a group, they autimatically inherit any of the group's permissions (see {ref}`resolving-roles-scopes-target` for more details). This is useful for assigning a set of common permissions to several users. + +**Tokens** \ +A token’s permissions are evaluated based on their owning entity. Since a token is always issued for a user or service, it can never have more permissions than its owner. If no specific role is requested for a new token, the token is assigned the `token` role. (define_role_target)= ## Defining Roles @@ -26,7 +38,7 @@ c.JupyterHub.load_roles = [  {    'name': 'server-rights',    'description': 'Allows parties to start and stop user servers', -   'scopes': ['users:servers', 'read:users:servers'], +   'scopes': ['users:servers'],    'users': ['alice', 'bob'],    'services': ['idle-culler'],    'groups': ['admin-group'], @@ -39,8 +51,8 @@ The role `server-rights` now allows the starting and stopping of servers by any - the service `idle-culler` - any member of the `admin-group` - requests using the tokens `foo-6f6e65` or `bar-74776f`. -```{note} -The `foo-6f6e65` and `bar-74776f` tokens will be assigned the `server-rights` role only if their owner has the same or higher permissions. For example, if the tokens' owner has only `user` role, JupyterHub will throw an error. See {ref}`Figure 1 ` for more details. +```{attention} +The `foo-6f6e65` and `bar-74776f` tokens will be assigned the `server-rights` role only if their owner has the corresponding permissions, otherwise JupyterHub throws an error. See {ref}`resolving-roles-scopes-target` for more details on how this is assessed. ``` Another example: @@ -62,12 +74,14 @@ The role `reader` allows users `maria` and `joe` and service `external` to read ```{admonition} Requirements :class: warning -In a role definition, the `name` field is required, while all other fields are optional. If no scopes are defined for new role, JupyterHub will raise a warning. -Moreover, `users`, `services`, `groups` and `tokens` only accept objects that already exist or are defined previously in the file. +In a role definition, the `name` field is required, while all other fields are optional.\ +If no scopes are defined for new role, JupyterHub will raise a warning. Providing non-existing scopes will result in an error.\ +Moreover, `users`, `services`, `groups` and `tokens` only accept objects that already exist or are defined previously in the file.\ It is not possible to implicitly add a new user to the database by defining a new role. ``` +\ +In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the `admin` role, which cannot be overwritten; an error will be raised if trying to do so. \ +Any previously defined role bearers for this role will remain the role bearers but their permissions will change if the role's permissions are overwritten. The newly defined bearers (in this case `maria` and `joe` and `external`) will be added to the existing ones. -In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for any role apart from `admin` role that cannot be overwritten; an error will be raised if trying to do so. -Any previously defined role bearers will remain unchanged, but newly defined requesters (in this case `maria` and `joe` and `external`) will be assigned the new role definition. - -Once a role is loaded, it remains in the database until explicitly deleting it through `remove_role` function in `roles.py`. I.e., omitting the `c.JupyterHub.load_roles` or specifying different roles in the `jupyterhub_config.py` file on the next startup will not erase previously defined roles. +Once a role is loaded, it remains in the database until explicitly deleting it through `delete_role()` function in `roles.py`. Default roles cannot be deleted. \ +Omitting the `c.JupyterHub.load_roles` or specifying different roles in the `jupyterhub_config.py` file on the next startup will not erase previously defined roles, nor their bearers. diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index dd35a766..8b2b1bd8 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -2,7 +2,7 @@ A scope has a syntax-based design that reveals which resources it provides access to. Resources are objects with a type, associated data, relationships to other resources, and a set of methods that operate on them (see [RESTful API](https://restful-api-design.readthedocs.io/en/latest/resources.html) documentation for more information). -`` in the scope syntax here refers to the resource name in the [JupyterHub's API](../reference/rest-api.rst) endpoints. For instance, `` equal to `users` corresponds to JupyterHub's API endpoints beginning with _/users_. +`` in the RBAC scope design refers to the resource name in the [JupyterHub's API](../reference/rest-api.rst) endpoints in most cases. For instance, `` equal to `users` corresponds to JupyterHub's API endpoints beginning with _/users_. ## Scope syntax @@ -10,37 +10,47 @@ A scope has a syntax-based design that reveals which resources it provides acces The `` scopes, such as `users` or `groups`, grant read and write permissions to the resource itself and all its sub-resources. E.g., the scope `users:servers` is included within the scope `users`. +++ -- `:` \ -The {ref}`vertically filtered ` scopes provide access to a subset of the information granted by the `` scope. E.g., the scope `users:name` allows for accessing user names only. -+++ - -- `!=` \ -{ref}`horizontal-filtering-target` is implemented by adding `!=` to the scope structure. A resource (or subresource) can be filtered based on `user`, `server`, `group` or `service` name. For instance, `!user=charlie` limits access to only return resources of user `charlie`. \ -Only one filter per scope is allowed, but filters for the same scope have an additive effect; a larger filter can be used by supplying the scope multiple times with different filters. -+++ - - `read:` \ -Limits permissions to **read-only** operations on the resource. +Limits permissions to read-only operations on the resource. +++ - `admin:` \ -Grants **create/delete permissions only** on the corresponding resource. For example, the scope `admin:users` allows creating and deleting users but does not allow for accessing information about existing users or modifying them, which is provided by the scope `users`. +Grants create/delete permissions on the corresponding resource in addition to read and write permissions. ++++ + +- `:` \ +The {ref}`vertically filtered ` scopes provide access to a subset of the information granted by the `` scope. E.g., the scope `users:servers` allows for accessing user servers only. ++++ + +- `!=` \ +{ref}`horizontal-filtering-target` is implemented by the `!=`scope structure. A resource (or sub-resource) can be filtered based on `user`, `server`, `group` or `service` name. For instance, `!user=charlie` limits access to only return resources of user `charlie`. \ +Only one filter per scope is allowed, but filters for the same scope have an additive effect; a larger filter can be used by supplying the scope multiple times with different filters. By adding a scope to an existing role, all role bearers will gain the associated permissions. -## Available scopes -[](../reference/rest-api.rst) documentation lists all available scopes. Each API endpoint has a list of scopes which can be used to access the API. -```{important} -Note that only the {ref}`horizontal filtering ` can be added to scopes to customize them. `` scopes, `:`, `read:` and `admin:` scopes are predefined and cannot be changed otherwise. -``` +## Metascopes + +Metascopes do not follow the general scope syntax. Instead, a metascope resolves to a set of scopes, which can refer to different resources, based on their owning entity. In JupyterHub, there are currently two metascopes: +1. default user scope `self`, and +2. default token scope `all`. (default-user-scope-target)= -## Default user scope +### Default user scope +Access to the user's own resources and subresources is covered by metascope `self`. This metascope includes the user's model, activity, servers and tokens. For example, `self` for a user named "gerard" includes: +- `users!user=gerard` where the `users` scope provides access to the full user model and activity. The filter restricts this access to the user's own resources. +- `users:servers!user=gerard` which grants the user access to their own servers without being able to create/delete any. +- `users:tokens!user=gerard` which allows the user to access, request and delete their own tokens. -The default user scope `all` provides access to the user's own resources and subresources, including the user's model, activity, servers and tokens. For example, the scope for a user `'gerard'` covers: -- `users!user=gerard` where the `users` scope includes access to the full user model, activity and starting/stopping servers. The horizontal filter restricts this access to the user's own resources. -- `users:tokens!user=gerard` allows the user to access, request and delete his own tokens only. +The `self` scope is only valid for user entities. In other cases (e.g., for services) it resolves to an empty set of scopes. + +(default-token-scope-target)= +### Default token scope +The token metascope `all` covers the same scopes as the token owner's scopes during requests. For example, if a token owner has roles containing the scopes `read:groups` and `read:users`, the `all` scope resolves to the set of scopes `{read:groups, read:users}`. + +If the token owner has default `user` role, the `all` scope resolves to `self`, which will subsequently be expanded to include all the user-specific scopes (or empty set in the case of services). + +If the token owner is a member of any group with roles, the group scopes will also be included in resolving the `all` scope. (horizontal-filtering-target)= ## Horizontal filtering @@ -59,3 +69,19 @@ In case the client has multiple subscopes, the call returns the union of the dat The payload of an API call can be filtered both horizontally and vertically simultaneously. For instance, performing an API call to the endpoint `/users/` with the scope `users:name!user=juliette` returns a payload of `[{name: 'juliette'}]` (provided that this name is present in the database). + + +## Available scopes + +Table below lists all available scopes and illustrates their hierarchy. + +_Table of scopes here_ + +```{Caution} +Note that only the {ref}`horizontal filtering ` can be added to scopes to customize them. \ +Metascopes `self` and `all`, ``, `:`, `read:` and `admin:` scopes are predefined and cannot be changed otherwise. +``` +### Scopes and APIs +The scopes are also listed in the [](../reference/rest-api.rst) documentation. Each API endpoint has a list of scopes which can be used to access the API; if no scopes are listed, the API is not authenticated and can be accessed without any permissions (i.e., no scopes). + +Listed scopes by each API endpoint reflect the "lowest" permissions required to gain any access to the corresponding API. For example, posting user's activity (_POST /users/:name/activity_) needs `users:activity` scope. If scope `users` is passed during the request, the access will be granted as the required scope is a subscope of the `users` scope. If, on the other hand, `read:users:activity` scope is passed, the access will be denied. diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index d710fe94..f62e7fd7 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -1,49 +1,59 @@ # Technical Implementation -Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target`. Objects can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `update_roles` and `remove_obj` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. +Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target` section. Users, services, groups and tokens can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `update_roles()` and `strip_role()` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. (resolving-roles-scopes-target)= ## Resolving roles and scopes **Resolving roles** refers to determining which roles a user, service, token or group has, extracting the list of scopes from each role and combining them into a single set of scopes. -**Resolving scopes** involves comparing two sets of scopes taking into account the scope hierarchy. This includes {ref}`vertical ` and {ref}`horizontal filtering ` and limiting or elevated permissions (`read:` or `admin:`, respectively). +**Resolving scopes** involves expanding scopes into all their possible subscopes and, if applicable, comparing two sets of scopes. Both procedures take into account the scope hierarchy, {ref}`vertical ` and {ref}`horizontal filtering ` limiting or elevated permissions (`read:` or `admin:`, respectively), and metascopes. Roles and scopes are resolved on several occasions, for example when requesting an API token with specific roles or making an API request. The following sections provide more details. ### Requesting API token with specific roles API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific existing roles. To date, it is only possible to add roles to a token in two ways: 1. through the `jupyterhub_config.py` file as described in the {ref}`define_role_target` section -2. through the POST /users/{name}/tokens API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). +2. through the _POST /users/:name/tokens_ API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). The RBAC framework adds several steps into the token issue flow. If no roles are requested, the token is issued with a default role (providing the requester is allowed to create the token). -If the token is requested with a specific role or multiple roles, the permissions of the would-be token's owner are checked against the requested permissions to ensure the token will not grant its owner additional privileges. In practice, this corresponds to resolving all the token owner's roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared and if the token's scopes are a subset of the token owner's scopes, the token is issued with the requested roles. +If the token is requested with any roles, the permissions of requesting entity are checked against the requested permissions to ensure the token will not grant its owner additional privileges. -{ref}`Figure 1 ` below illustrates this process. The orange rectangles highlight where in the process the roles and scopes are resolved. +If, due to modifications of roles or entities, at API request time a token has any scopes that its owner does not, those scopes are not taken into account. The API request is resolved without additional errors, but the Hub logs a warning (see {ref}`Figure 2 `). -```{figure} ../images/rbac-api-token-request-chart.png +Resolving token's roles (yellow box in {ref}`Figure 1 `) corresponds to resolving all the token's owner roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared (Resolve the scopes box in orange in {ref}`Figure 1 `), taking into account the scope hierarchy but, solely for role assignment, omitting any {ref}`horizontal filter ` comparison. If the token's scopes are a subset of the token owner's scopes, the token is issued with the requested roles; if not, JupyterHub will raise an error. + +{ref}`Figure 1 ` below illustrates the steps involved. The orange rectangles highlight where in the process the roles and scopes are resolved. + +```{figure} ../images/rbac-token-request-chart.png :align: center -:name: api-token-request-chart +:name: token-request-chart Figure 1. Resolving roles and scopes during API token request ``` ```{note} -The above check is also performed when roles are requested for existing tokens, e.g., when adding tokens to {ref}`role definitions through the config.py `. +The above check is also performed when roles are requested for existing tokens, e.g., when adding tokens to {ref}`role definitions ` through the `jupyterhub_config.py`. ``` ### Making API request With the RBAC framework each authenticated JupyterHub API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API. -When an API request is performed, the passed API token's roles are again resolved into a set of scopes and compared to the scopes required to access the API as follows: -- if the API scopes are present within the set of token's scopes, the access is granted and the API returns its "full" response -- if that is not the case, another check is utilized to determine if sub-scopes of the required API scopes can be found in the token's scope set: - - if the subscopes are present, the RBAC framework employs the {ref}`filtering ` procedures to refine the API response to provide access to only resource attributes specified by the token provided scopes - - for example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model - - if the subscopes are not present, the access to API is denied +When an API request is performed, the passed API token's roles are again resolved (yellow box in {ref}`Figure 2 `) to ensure the token does not grant more permissions than its owner has at the request time (e.g., due to changing/losing roles). +If the owner's roles do not include some scopes of the token's scopes, only the intersection of the token's and owner's scopes will be passed further. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will results in only the `read:users:name` scope being passed on. In the case of no intersection, en empty set of scopes will be passed on. + +The passed scopes are compared to the scopes required to access the API as follows: + +- if the API scopes are present within the set of passed scopes, the access is granted and the API returns its "full" response + +- if that is not the case, another check is utilized to determine if subscopes of the required API scopes can be found in the passed scope set: + + - if found, the RBAC framework employs the {ref}`filtering ` procedures to refine the API response to access only resource attributes corresponding to the passed scopes. For example, providing a scope `read:users:activity!group=class-C` for the _GET /users_ API will return a list of user models from group `class-C` containing only the `last_activity` attribute for each user model + + - if not found, the access to API is denied {ref}`Figure 2 ` illustrates this process highlighting the steps where the role and scope resolutions as well as filtering occur in orange. diff --git a/docs/source/rbac/upgrade.md b/docs/source/rbac/upgrade.md new file mode 100644 index 00000000..64e488d8 --- /dev/null +++ b/docs/source/rbac/upgrade.md @@ -0,0 +1 @@ +# Upgrading JupyterHub with RBAC framework diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md index 8d0925fb..55ea8484 100644 --- a/docs/source/rbac/use-cases.md +++ b/docs/source/rbac/use-cases.md @@ -1,17 +1,14 @@ # Use Cases -To determine which scopes a role should have it is best to follow these steps: +To determine which scopes a role should have, one can follow these steps: 1. Determine what actions the role holder should have/have not access to -2. Match the actions against the JupyterHub's REST APIs +2. Match the actions against the [JupyterHub's APIs](../reference/rest-api.rst) 3. Check which scopes are required to access the APIs -4. Customize the scopes with filters if needed -5. Define the role with required scopes and assign to users/services/groups/tokens +4. Combine scopes and subscopes if applicable +5. Customize the scopes with filters if needed +6. Define the role with required scopes and assign to users/services/groups/tokens Below, different use cases are presented on how to use the RBAC framework. - -## User access - -A regular user should be able to view and manage all of their own resources. This can be achieved using the scope `all` (or assigning the `user` role). If the user's access is to be restricted from modifying any of their resources (e.g., when a teacher wants to check their notebooks), their role should be changed to read-only access, in this case scope `read:all`. ## Service to cull idle servers @@ -39,7 +36,7 @@ Below follows a short tutorial on how to add a cull-idle service in the RBAC sys { "name": "idle-culler", "description": "Culls idle servers", - "scopes": ["read:users:name", "read:users:activity", "read:users:servers", "users:servers"], + "scopes": ["read:users:name", "read:users:activity", "users:servers"], "services": ["idle-culler"], } ] @@ -47,27 +44,41 @@ Below follows a short tutorial on how to add a cull-idle service in the RBAC sys ```{important} Note that in the RBAC system the `admin` field in the `idle-culler` service definition is omitted. Instead, the `idle-culler` role provides the service with only the permissions it needs. - If the optional actions of deleting the idle servers and/or removing inactive users are desired, **add the following scopes** to the `idle-culler` role definition: - - `admin:users:servers` for deleting servers - - `admin:users` for deleting users. + If the optional actions of deleting the idle servers and/or removing inactive users are desired, **change the following scopes** in the `idle-culler` role definition: + - `users:servers` to `admin:users:servers` for deleting servers + - `read:users:name`, `read:users:activity` to `admin:users` for deleting users. ``` 3. Restart JupyterHub to complete the process. ## API launcher A service capable of creating/removing users and launching multiple servers should have access to: -1. POST and DELETE /users -2. POST and DELETE /users/{name}/server +1. _POST_ and _DELETE /users_ +2. _POST_ and _DELETE /users/:name/server_ or _/users/:name/servers/:server_name_ 3. Creating/deleting servers -From the above, the scopes required for the role are +The scopes required to access the API enpoints: 1. `admin:users` 2. `users:servers` 3. `admin:users:servers` +From the above, the role definition is: +```python +# in jupyterhub_config.py + +c.JupyterHub.load_roles = [ + { + "name": "api-launcher", + "description": "Manages servers", + "scopes": ["admin:users", "admin:users:servers"], + "services": [] + } +] +``` + If needed, the scopes can be modified to limit the permissions to e.g. a particular group with `!group=groupname` filter. -## Users as group admins/Group admin roles +## Group admin roles Roles can be used to specify different group member privileges. From d38460bfa97e547e3f00e33520f2054d633c40be Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 8 Apr 2021 14:52:01 +0200 Subject: [PATCH 105/270] Added tests and removed model flags --- jupyterhub/apihandlers/base.py | 7 ++- jupyterhub/apihandlers/users.py | 11 +++-- jupyterhub/app.py | 2 +- jupyterhub/roles.py | 6 +-- jupyterhub/scopes.py | 52 +++++++++++------------ jupyterhub/tests/test_roles.py | 6 +++ jupyterhub/tests/test_scopes.py | 75 +++++++++++++++++++++++++++++++++ 7 files changed, 122 insertions(+), 37 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 600931d5..2b4a447a 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -88,9 +88,12 @@ class APIHandler(BaseHandler): if sub_scope == scopes.Scope.ALL: return True else: - found_resource = orm_resource.name in sub_scope[kind] + try: + found_resource = orm_resource.name in sub_scope[kind] + except KeyError: + found_resource = False if not found_resource: # Try group-based access - if kind == 'server': + if kind == 'server' and 'user' in sub_scope: # First check if we have access to user info user_name = orm_resource.user.name found_resource = user_name in sub_scope['user'] diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index ceb53801..56775e34 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -188,11 +188,13 @@ class UserAPIHandler(APIHandler): @needs_scope( 'read:users', 'read:users:name', - 'reda:users:servers', + 'read:users:servers', 'read:users:groups', 'read:users:activity', ) - async def get(self, user_name): + async def get( + self, user_name + ): # Fixme: Does not work when only server filter is selected user = self.find_user(user_name) model = self.user_model(user) # auth state will only be shown if the requester is an admin @@ -263,7 +265,7 @@ class UserAPIHandler(APIHandler): self.set_status(204) - @needs_scope('admin:users') + @needs_scope('admin:users') # Todo: Change to `users`? async def patch(self, user_name): user = self.find_user(user_name) if user is None: @@ -326,6 +328,7 @@ class UserTokenListAPIHandler(APIHandler): oauth_tokens.append(self.token_model(token)) self.write(json.dumps({'api_tokens': api_tokens, 'oauth_tokens': oauth_tokens})) + # Todo: Set to @needs_scope('users:tokens') async def post(self, user_name): body = self.get_json_body() or {} if not isinstance(body, dict): @@ -765,7 +768,7 @@ class ActivityAPIHandler(APIHandler): ) return servers - @needs_scope('users') + @needs_scope('users:activity') def post(self, user_name): user = self.find_user(user_name) if user is None: diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 8131cad7..3f733dd8 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1377,7 +1377,7 @@ class JupyterHub(Application): Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler object: :: - + def default_url_fn(handler): user = handler.current_user if user and user.admin: diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 886354e6..53df7857 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -90,8 +90,8 @@ def _get_scope_hierarchy(): 'read:users:servers', ], 'users:tokens': ['read:users:tokens'], - 'admin:users': ['admin:users:auth_state', 'admin:users:server_state'], - 'admin:users:servers': None, + 'admin:users': ['admin:users:auth_state'], + 'admin:users:servers': ['admin:users:server_state'], 'groups': ['read:groups'], 'admin:groups': None, 'read:services': None, @@ -236,7 +236,7 @@ def assign_default_roles(db, entity): # tokens can have only 'token' role as default # assign the default only for tokens if isinstance(entity, orm.APIToken): - if not entity.roles and entity.user is not None: + if not entity.roles and (entity.user or entity.service) is not None: default_token_role.tokens.append(entity) db.commit() # users and services can have 'user' or 'admin' roles as default diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 0819cc08..58c0e334 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -64,7 +64,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): def _check_scope(api_handler, req_scope, **kwargs): """Check if scopes satisfy requirements - Returns True for (restricted) access, False for refused access + Returns True for (potentially restricted) access, False for refused access """ # Parse user name and server name together try: @@ -74,24 +74,23 @@ def _check_scope(api_handler, req_scope, **kwargs): if 'user' in kwargs and 'server' in kwargs: kwargs['server'] = "{}/{}".format(kwargs['user'], kwargs['server']) if req_scope not in api_handler.parsed_scopes: - app_log.debug("No scopes present to access %s" % api_name) + app_log.debug("No access to %s via %s", api_name, req_scope) return False if api_handler.parsed_scopes[req_scope] == Scope.ALL: - app_log.debug("Unrestricted access to %s call", api_name) + app_log.debug("Unrestricted access to %s via %s", api_name, req_scope) return True # Apply filters sub_scope = api_handler.parsed_scopes[req_scope] if not kwargs: app_log.debug( - "Client has restricted access to %s. Internal filtering may apply" - % api_name + "Client has restricted access to %s via %s. Internal filtering may apply", + api_name, + req_scope, ) return True for (filter_, filter_value) in kwargs.items(): if filter_ in sub_scope and filter_value in sub_scope[filter_]: - app_log.debug( - "Restricted client access supported by endpoint %s" % api_name - ) + app_log.debug("Argument-based access to %s via %s", api_name, req_scope) return True if _needs_scope_expansion(filter_, filter_value, sub_scope): group_names = sub_scope['group'] @@ -160,27 +159,26 @@ def needs_scope(*scopes): if resource_name in bound_sig.arguments: resource_value = bound_sig.arguments[resource_name] s_kwargs[resource] = resource_value - has_access = False for scope in scopes: - has_access |= _check_scope(self, scope, **s_kwargs) - if has_access: - return func(self, *args, **kwargs) - else: - try: - end_point = self.request.path - except AttributeError: - end_point = self.__name__ - app_log.warning( - "Not authorizing access to {}. Requires any of [{}], not derived from scopes [{}]".format( - end_point, ", ".join(scopes), ", ".join(self.raw_scopes) - ) - ) - raise web.HTTPError( - 403, - "Action is not authorized with current scopes; requires any of [{}]".format( - ", ".join(scopes) - ), + app_log.debug("Checking access via scope %s", scope) + has_access = _check_scope(self, scope, **s_kwargs) + if has_access: + return func(self, *args, **kwargs) + try: + end_point = self.request.path + except AttributeError: + end_point = self.__name__ + app_log.warning( + "Not authorizing access to {}. Requires any of [{}], not derived from scopes [{}]".format( + end_point, ", ".join(scopes), ", ".join(self.raw_scopes) ) + ) + raise web.HTTPError( + 403, + "Action is not authorized with current scopes; requires any of [{}]".format( + ", ".join(scopes) + ), + ) return _auth_func diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index e929f078..3dc49052 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -340,6 +340,12 @@ async def test_load_roles_tokens(tmpdir, request): 'scopes': ['users:servers', 'admin:servers'], 'tokens': ['another-secret-token'], }, + { + 'name': 'admin', + 'description': 'Admin access', + 'scopes': ['a lot'], + 'users': ['admin'], + }, ] kwargs = { 'load_roles': roles_to_load, diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 9b431f65..0706e8f4 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -540,6 +540,7 @@ async def test_metascope_self_expansion(app, kind, has_user_scopes): assert bool(token_scopes) == has_user_scopes app.db.delete(orm_obj) app.db.delete(test_role) + app.db.commit() async def test_metascope_all_expansion(app): @@ -557,3 +558,77 @@ async def test_metascope_all_expansion(app): app.db.commit() token_scope_set = get_scopes_for(token) assert not token_scope_set + + +@mark.parametrize( + "scopes, can_stop ,num_servers, keys_in, keys_out", + [ + (['read:users:servers!user=almond'], False, 2, {'name'}, {'state'}), + ( + ['admin:users:server_state', 'read:users:servers'], + True, + 2, + {'name', 'state'}, + set(), + ), + (['users:servers', 'read:users:name'], True, 0, set(), set()), + ( + [ + 'read:users:name!user=almond', + 'read:users:servers!server=almond/bianca', # fixme: server-scope not working yet + 'admin:users:server_state!server=almond/bianca', + ], + False, + 1, + {'name', 'state'}, + set(), + ), + ], +) +async def test_server_state_access( + app, scopes, can_stop, num_servers, keys_in, keys_out +): + with mock.patch.dict( + app.tornado_settings, + {'allow_named_servers': True, 'named_server_limit_per_user': 2}, + ): + ## 1. Test a user can access all servers without auth_state + ## 2. Test a service with admin:user but no admin:users:servers gets no access to any server data + ## 3. Test a service with admin:user:server_state gets access to auth_state + ## 4. Test a service with user:servers:server gives access to one server, and the correct server. + username = 'almond' + user = add_user(app.db, app, name=username) + + server_names = ['bianca', 'terry'] + try: + for server_name in server_names: + await api_request( + app, 'users', username, 'servers', server_name, method='post' + ) + role = orm.Role(name=f"{username}-role", scopes=scopes) + app.db.add(role) + app.db.commit() + service_name = 'server_accessor' + service = orm.Service(name=service_name) + app.db.add(service) + service.roles.append(role) + app.db.commit() + api_token = service.new_api_token() + app.init_roles() + headers = {'Authorization': 'token %s' % api_token} + r = await api_request(app, 'users', username, headers=headers) + r.raise_for_status() + user_model = r.json() + if num_servers: + assert 'servers' in user_model + server_models = user_model['servers'] + assert len(server_models) == num_servers + for server, server_model in server_models.items(): + assert keys_in.issubset(server_model) + assert keys_out.isdisjoint(server_model) + else: + assert 'servers' not in user_model + finally: + app.db.delete(role) + app.db.delete(service) + app.db.commit() From 649524d357a0580227d6a941f0243dd87d74a3f8 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 8 Apr 2021 16:03:17 +0200 Subject: [PATCH 106/270] Add available scopes table in docs/source/rbac/scopes.md --- docs/source/rbac/scopes.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index 4c27abdd..cdc07a89 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -78,9 +78,35 @@ The payload of an API call can be filtered both horizontally and vertically simu ## Available scopes -Table below lists all available scopes and illustrates their hierarchy. +Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them. -_Table of scopes here_ +Table 1. Available scopes and their hierarchy +| Scope name | Description | +| :--------- | :---------- | +| (no scope) | Allows for only identifying the owning entity. | +| `self` | Metascope, grants access to user's own resources; resolves to (no scope) for services. | +| `all` | Metascope, valid for tokens only. Grants access to everything that the token's owning entity can do. | +| `admin:users` | Grants read, write, create and delete access to users and their authentication state _but not their servers or tokens._ | +|    `admin:users:auth_state` | Grants access to users' authentication state only. | +|    `users` | Grants read and write permissions to users' models _apart from servers, tokens and authentication state_. | +|       `users:activity` | Grants access to read and post users' activity only. | +|       `read:users` | Read-only access to users' models _apart from servers, tokens and authentication state_. | +|          `read:users:name` | Read-only access to users' names. | +|          `read:users:groups` | Read-only access to users' groups. | +|          `read:users:activity` | Read-only access to users' activity. | +| `admin:users:servers` | Grants read, start/stop, create and delete permissions to users' servers and their state. | +|    `admin:users:server_state` | Grants access to servers' state only. | +|    `users:servers` | Allows for starting/stopping users' servers in addition to read access. _Does not include the server state_. | +|       `read:users:servers` | Read-only access to users' servers. _Does not include the server state_. | +| `users:tokens` | Grants read, write, create and delete permissions to users' tokens. | +|    `read:users:tokens` | Read-only access to users' tokens. | +| `admin:groups` | Grants read, write, create and delete access to groups. | +|    `groups` | Grants read and write permissions to groups, including adding/removing users to/from groups. | +|       `read:groups` | Read-only access to groups. | +| `read:services` | Read-only access to services. | +| `read:hub` | Read-only access to detailed information about the Hub. | +| `proxy` | Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. | +| `shutdown` | Grants access to shutdown the hub. | ```{Caution} Note that only the {ref}`horizontal filtering ` can be added to scopes to customize them. \ From d38a7b9aa7d93a6bc4587f319535220687b0b7c5 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 8 Apr 2021 16:08:43 +0200 Subject: [PATCH 107/270] Change scope for PATCH /users API in rest-api.yml --- docs/rest-api.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 179cc876..6263bfec 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -218,7 +218,8 @@ paths: description: Change a user's name or admin status security: - oauth2: - - users + - admin:users + #TODO: confirm, this scope allows to also create/delete users but users scope would allow any user to change their own name and admin status parameters: - name: name description: username From c9f8141cb415b371adb4cf5dab69a794153c86bb Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 8 Apr 2021 16:48:20 +0200 Subject: [PATCH 108/270] Fix rbac-api-request-chart in docs/source/images --- docs/source/images/rbac-api-request-chart.png | Bin 461416 -> 456589 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/source/images/rbac-api-request-chart.png b/docs/source/images/rbac-api-request-chart.png index 02d0ff335074a56fe0c3a1eabad3ab23cb290b17..b70e3a0cddca48dbe4aef039110de1f6a3dd385d 100644 GIT binary patch literal 456589 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

hUwf*xbAol(K~a6!?CTa3vs-iJ2S3xC5h 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
Pf;T+lba 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

    @#K<^7u+3!XEj+k{+!XyLQR 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 DauEs0 literal 461416 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�Oj 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 K@EZ$q6BN9guqB*Bt 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�G>NId1E8Z!G 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%0A_!U3B$Sxm%&&K6MyWdOf57%85g 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 From 12dc231b1c3e5468d674a63e9f2f9c70749e90dd Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 8 Apr 2021 17:36:18 +0200 Subject: [PATCH 109/270] Fixed code base and tests after merge --- jupyterhub/apihandlers/base.py | 1 + jupyterhub/roles.py | 41 ++++++++++++++++++++++++++++++++- jupyterhub/tests/test_roles.py | 37 ++++++++++++++--------------- jupyterhub/tests/test_scopes.py | 4 ++-- 4 files changed, 60 insertions(+), 23 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 6e96bea8..e8ebc82a 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -305,6 +305,7 @@ class APIHandler(BaseHandler): if req_scope in self.parsed_scopes: scope_filter = self.get_scope_filter(req_scope) if scope_filter(group, kind='group'): + model['roles'] = [r.name for r in group.roles] model['users'] = [u.name for u in group.users] return model diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 1b814987..81ba6425 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -86,6 +86,7 @@ def _get_scope_hierarchy(): """ scopes = { + 'self': None, 'all': None, # Optional 'read:all' as subscope, not implemented at this stage 'users': ['read:users', 'users:activity', 'users:servers'], 'read:users': [ @@ -256,7 +257,7 @@ def create_role(db, role_dict): db.commit() -def remove_role(db, rolename): +def delete_role(db, rolename): """Removes a role from database""" # default roles are not removable @@ -424,6 +425,44 @@ def update_roles(db, entity, roles): grant_role(db, entity=entity, rolename=rolename) +def add_predef_roles_tokens(db, predef_roles): + + """Adds tokens to predefined roles in config file + if their permissions allow""" + + for predef_role in predef_roles: + if 'tokens' in predef_role.keys(): + token_role = orm.Role.find(db, name=predef_role['name']) + for token_name in predef_role['tokens']: + token = orm.APIToken.find(db, token_name) + if token is None: + raise ValueError( + "Token %r does not exist and cannot assign it to role %r" + % (token_name, token_role.name) + ) + else: + update_roles(db, token, roles=[token_role.name]) + + +def check_for_default_roles(db, bearer): + + """Checks that role bearers have at least one role (default if none). + Groups can be without a role""" + + Class = orm.get_class(bearer) + if Class == orm.Group: + pass + else: + for obj in ( + db.query(Class) + .outerjoin(orm.Role, Class.roles) + .group_by(Class.id) + .having(func.count(orm.Role.id) == 0) + ): + assign_default_roles(db, obj) + db.commit() + + def mock_roles(app, name, kind): """Loads and assigns default roles for mocked objects""" Class = orm.get_class(kind) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 2635834d..5192ccf9 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -10,6 +10,7 @@ from tornado.log import app_log from .. import orm from .. import roles +from ..scopes import get_scopes_for from ..utils import maybe_future from .mocking import MockHub from .utils import add_user @@ -326,13 +327,13 @@ async def test_delete_roles(db, role_type, rolename, response_type, response): assert check_role is not None # check the role is deleted and info raised with pytest.warns(response): - roles.remove_role(db, rolename) + roles.delete_role(db, rolename) check_role = orm.Role.find(db, rolename) assert check_role is None elif response_type == 'error': with pytest.raises(response): - roles.remove_role(db, rolename) + roles.delete_role(db, rolename) @mark.role @@ -367,20 +368,20 @@ async def test_scope_existence(tmpdir, request, role, response): db = hub.db if response == 'existing': - roles.add_role(db, role) + roles.create_role(db, role) added_role = orm.Role.find(db, role['name']) assert added_role is not None assert added_role.scopes == role['scopes'] elif response == NameError: with pytest.raises(response): - roles.add_role(db, role) + roles.create_role(db, role) added_role = orm.Role.find(db, role['name']) assert added_role is None # delete the tested roles if added_role: - roles.remove_role(db, added_role.name) + roles.delete_role(db, added_role.name) @mark.role @@ -427,7 +428,7 @@ async def test_load_roles_users(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role @@ -507,7 +508,7 @@ async def test_load_roles_services(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role @@ -556,7 +557,7 @@ async def test_load_roles_groups(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role @@ -609,7 +610,7 @@ async def test_load_roles_user_tokens(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role @@ -652,12 +653,14 @@ async def test_load_roles_user_tokens_not_allowed(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role async def test_load_roles_service_tokens(tmpdir, request): - services = [{'name': 'idle-culler', 'api_token': 'another-secret-token'}] + services = [ + {'name': 'idle-culler', 'api_token': 'another-secret-token'}, + ] service_tokens = { 'another-secret-token': 'idle-culler', } @@ -674,12 +677,6 @@ async def test_load_roles_service_tokens(tmpdir, request): 'services': ['idle-culler'], 'tokens': ['another-secret-token'], }, - { - 'name': 'admin', - 'description': 'Admin access', - 'scopes': ['a lot'], - 'users': ['admin'], - }, ] kwargs = { 'load_roles': roles_to_load, @@ -714,7 +711,7 @@ async def test_load_roles_service_tokens(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role @@ -770,7 +767,7 @@ async def test_load_roles_service_tokens_not_allowed(tmpdir, request): # delete the test roles for role in roles_to_load: - roles.remove_role(db, role['name']) + roles.delete_role(db, role['name']) @mark.role @@ -858,7 +855,7 @@ async def test_self_expansion(app, kind, has_user_scopes): # test expansion of token scopes orm_obj.new_api_token() print(orm_obj.api_tokens[0]) - token_scopes = scopes.get_scopes_for(orm_obj.api_tokens[0]) + token_scopes = get_scopes_for(orm_obj.api_tokens[0]) print(token_scopes) assert bool(token_scopes) == has_user_scopes app.db.delete(orm_obj) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 0706e8f4..aed175e9 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -575,11 +575,11 @@ async def test_metascope_all_expansion(app): ( [ 'read:users:name!user=almond', - 'read:users:servers!server=almond/bianca', # fixme: server-scope not working yet + 'read:users:servers!server=almond/bianca', 'admin:users:server_state!server=almond/bianca', ], False, - 1, + 0, # fixme: server-scope not working yet {'name', 'state'}, set(), ), From 95759b25f2c2157203c5674f75541bd416e5fc5f Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 9 Apr 2021 12:06:21 +0200 Subject: [PATCH 110/270] Fixed config role token assignment --- jupyterhub/app.py | 7 +++++++ jupyterhub/orm.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index b8d25d66..5f7a59d5 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1942,6 +1942,12 @@ class JupyterHub(Application): db.add(obj) db.commit() self.log.info("Adding API token for %s: %s", kind, name) + # If we have roles in the configuration file, they will be added later + config_roles = None + for config_role in self.load_roles: + if 'tokens' in config_role and token in config_role['tokens']: + config_roles = [] + break try: # set generated=False to ensure that user-provided tokens # get extra hashing (don't trust entropy of user-provided tokens) @@ -1949,6 +1955,7 @@ class JupyterHub(Application): token, note="from config", generated=self.trust_user_provided_tokens, + roles=config_roles, ) except Exception: if created: diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 10f7e404..7b344e66 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -632,7 +632,7 @@ class APIToken(Hashed, Base): default_roles = get_default_roles() for role in default_roles: create_role(db, role) - if roles: + if roles is not None: update_roles(db, entity=orm_token, roles=roles) else: assign_default_roles(db, entity=orm_token) From e67647c4c20de9794409d45dbce53944fef1441f Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 9 Apr 2021 13:17:56 +0200 Subject: [PATCH 111/270] Added todo --- jupyterhub/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 5f7a59d5..f4f7440d 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1943,6 +1943,7 @@ class JupyterHub(Application): db.commit() self.log.info("Adding API token for %s: %s", kind, name) # If we have roles in the configuration file, they will be added later + # Todo: works but ugly config_roles = None for config_role in self.load_roles: if 'tokens' in config_role and token in config_role['tokens']: From 07436a0ff02e6068544b859dda45ee3ea8eb7b93 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 9 Apr 2021 15:31:08 +0200 Subject: [PATCH 112/270] Added test for access through groups --- jupyterhub/apihandlers/base.py | 8 ++++++-- jupyterhub/tests/test_scopes.py | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 86c73034..bbbda5d8 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -101,8 +101,12 @@ class APIHandler(BaseHandler): # Now check for specific servers: server_format = f"{orm_resource.user / orm_resource.name}" found_resource = server_format in sub_scope[kind] - elif 'group' in sub_scope and kind == 'user': - group_names = {group.name for group in orm_resource.groups} + elif 'group' in sub_scope: + group_names = set() + if kind == 'user': + group_names = {group.name for group in orm_resource.groups} + elif kind == 'server': + group_names = {group.name for group in orm_resource.user.groups} user_in_group = bool(group_names & set(sub_scope['group'])) found_resource = user_in_group return found_resource diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index aed175e9..b97b4728 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -564,9 +564,10 @@ async def test_metascope_all_expansion(app): "scopes, can_stop ,num_servers, keys_in, keys_out", [ (['read:users:servers!user=almond'], False, 2, {'name'}, {'state'}), + (['read:users:servers!group=nuts'], False, 2, {'name'}, {'state'}), ( ['admin:users:server_state', 'read:users:servers'], - True, + True, # Todo: test for server stop 2, {'name', 'state'}, set(), @@ -595,10 +596,17 @@ async def test_server_state_access( ## 1. Test a user can access all servers without auth_state ## 2. Test a service with admin:user but no admin:users:servers gets no access to any server data ## 3. Test a service with admin:user:server_state gets access to auth_state - ## 4. Test a service with user:servers:server gives access to one server, and the correct server. + ## 4. Test a service with user:servers!server=x gives access to one server, and the correct server. + ## 5. Test a service with users:servers!group=x gives access to both servers username = 'almond' user = add_user(app.db, app, name=username) - + group_name = 'nuts' + group = orm.Group.find(app.db, name=group_name) + if not group: + group = orm.Group(name=group_name) + app.db.add(group) + group.users.append(user) + app.db.commit() server_names = ['bianca', 'terry'] try: for server_name in server_names: @@ -631,4 +639,5 @@ async def test_server_state_access( finally: app.db.delete(role) app.db.delete(service) + app.db.delete(group) app.db.commit() From be17ae68ee70c4be7db6a1c1a9c9849f08cf667d Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 7 Apr 2021 08:38:05 +0200 Subject: [PATCH 113/270] Upgraded to log warning, resolved comment --- jupyterhub/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index f4f7440d..5cdb5aa6 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1890,7 +1890,7 @@ class JupyterHub(Application): # make sure that on no admin situation, all roles are reset admin_role = orm.Role.find(db, name='admin') if not admin_role.users: - app_log.info( + app_log.warning( "No admin users found; assuming hub upgrade. Initializing default roles for all entities" ) # make sure all users, services and tokens have at least one role (update with default) From 4577266d95bc492c7e29e4a5638c3a367b88b349 Mon Sep 17 00:00:00 2001 From: 0mar Date: Sat, 10 Apr 2021 16:24:20 +0200 Subject: [PATCH 114/270] Refactored scope test suite with proper fixtures and teardowns --- jupyterhub/tests/test_scopes.py | 359 ++++++++++++++++---------------- 1 file changed, 175 insertions(+), 184 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index b97b4728..496d053a 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -89,6 +89,10 @@ class MockAPIHandler: self.request = mock.Mock(spec=HTTPServerRequest) self.request.path = '/path' + def set_scopes(self, *scopes): + self.raw_scopes = set(scopes) + self.parsed_scopes = parse_scopes(self.raw_scopes) + @needs_scope('users') def user_thing(self, user_name): return True @@ -116,6 +120,12 @@ class MockAPIHandler: return True +@pytest.fixture +def mock_handler(): + obj = MockAPIHandler() + return obj + + @mark.parametrize( "scopes, method, arguments, is_allowed", [ @@ -169,12 +179,11 @@ class MockAPIHandler: (['users!user=gob'], 'other_thing', ('maeby',), True), ], ) -def test_scope_method_access(scopes, method, arguments, is_allowed): - obj = MockAPIHandler() - obj.current_user = mock.Mock(name=arguments[0]) - obj.raw_scopes = set(scopes) - obj.parsed_scopes = parse_scopes(obj.raw_scopes) - api_call = getattr(obj, method) +def test_scope_method_access(mock_handler, scopes, method, arguments, is_allowed): + mock_handler = MockAPIHandler() + mock_handler.current_user = mock.Mock(name=arguments[0]) + mock_handler.set_scopes(*scopes) + api_call = getattr(mock_handler, method) if is_allowed: assert api_call(*arguments) else: @@ -182,31 +191,18 @@ def test_scope_method_access(scopes, method, arguments, is_allowed): api_call(*arguments) -def test_double_scoped_method_succeeds(): - obj = MockAPIHandler() - obj.current_user = mock.Mock(name='lucille') - obj.raw_scopes = {'users', 'read:services'} - obj.parsed_scopes = parse_scopes(obj.raw_scopes) - assert obj.secret_thing() +def test_double_scoped_method_succeeds(mock_handler): + mock_handler.current_user = mock.Mock(name='lucille') + mock_handler.set_scopes('users', 'read:services') + mock_handler.parsed_scopes = parse_scopes(mock_handler.raw_scopes) + assert mock_handler.secret_thing() -def test_double_scoped_method_denials(): - obj = MockAPIHandler() - obj.current_user = mock.Mock(name='lucille2') - obj.raw_scopes = {'users', 'read:groups'} - obj.parsed_scopes = parse_scopes(obj.raw_scopes) +def test_double_scoped_method_denials(mock_handler): + mock_handler.current_user = mock.Mock(name='lucille2') + mock_handler.set_scopes('users', 'read:groups') with pytest.raises(web.HTTPError): - obj.secret_thing() - - -def generate_test_role(user_name, scopes, role_name='test'): - role = { - 'name': role_name, - 'description': '', - 'users': [user_name], - 'scopes': scopes, - } - return role + mock_handler.secret_thing() @mark.parametrize( @@ -247,6 +243,8 @@ async def test_expand_groups(app, user_name, in_group, status_code): app, 'users', user_name, headers=auth_header(app.db, user_name) ) assert r.status_code == status_code + app.db.delete(group) + app.db.commit() async def test_by_fake_user(app): @@ -262,79 +260,121 @@ async def test_by_fake_user(app): err_message = "No access to resources or resources not found" -async def test_request_fake_user(app): - user_name = 'buster' - fake_user = 'annyong' - user = add_user(app.db, name=user_name) - test_role = generate_test_role(user_name, ['read:users!group=stuff']) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') +@pytest.fixture +def temp_role(app): + """Generate a temporary role with certain scopes. + Convenience function that takes care of db stuff and teardown""" + temp_roles = [] + index = [1] + + def temp_role_creator(scopes, role_name=None): + if not role_name: + role_name = f'test_role_{index[0]}' + index[0] += 1 + role = orm.Role(name=role_name, scopes=list(scopes)) + temp_roles.append(role) + app.db.add(role) + app.db.commit() + return role + + yield temp_role_creator + for role in temp_roles: + app.db.delete(role) app.db.commit() + + +@pytest.fixture +def user_with_scopes(app, temp_role): + """Generate a temporary user with specific scopes. + Takes care of db stuff and teardown""" + temp_users = [] + index = [1] + role_function = temp_role + + def temp_user_creator(*scopes): + name = f"temporary_user_{index[0]}" + index[0] += 1 + role = role_function(scopes) + orm_user = orm.User(name=name) + app.db.add(orm_user) + app.db.commit() + temp_users.append(orm_user) + roles.update_roles(app.db, orm_user, roles=[role.name]) + return app.users[orm_user.id] + + yield temp_user_creator + for user in temp_users: + app.users.delete(user) + + +@pytest.fixture +def service_with_scopes(app, temp_role): + """Generate a temporary service with specific scopes. + Takes care of db stuff and teardown""" + temp_service = [] + index = [1] + role_function = temp_role + + def temp_service_creator(*scopes): + name = f"temporary_service_{index[0]}" + index[0] += 1 + role = role_function(scopes) + app.services.append({'name': name}) + app.init_services() + orm_service = orm.Service.find(app.db, name) + app.db.commit() + roles.update_roles(app.db, orm_service, roles=[role.name]) + return orm_service + + yield temp_service_creator + for service in temp_service: + app.db.delete(service) + app.db.commit() + + +async def test_request_fake_user(app, user_with_scopes): + fake_user = 'annyong' + user = user_with_scopes('read:users!group=stuff') r = await api_request( - app, 'users', fake_user, headers=auth_header(app.db, user_name) + app, 'users', fake_user, headers=auth_header(app.db, user.name) ) assert r.status_code == 404 # Consistency between no user and user not accessible assert r.json()['message'] == err_message -async def test_refuse_exceeding_token_permissions(app): - user_name = 'abed' - user = add_user(app.db, name=user_name) - add_user(app.db, name='user') - api_token = user.new_api_token() - exceeding_role = generate_test_role(user_name, ['read:users'], 'exceeding_role') - roles.create_role(app.db, exceeding_role) - roles.grant_role(app.db, entity=user.api_tokens[0], rolename='exceeding_role') - app.db.commit() - headers = {'Authorization': 'token %s' % api_token} - r = await api_request(app, 'users', headers=headers) - assert r.status_code == 200 - result_names = {user['name'] for user in r.json()} - assert result_names == {user_name} +async def test_refuse_exceeding_token_permissions(app, user_with_scopes, temp_role): + user = user_with_scopes('self') + user.new_api_token() + temp_role(['admin:users'], 'exceeding_role') + with pytest.raises(ValueError): + roles.update_roles(app.db, entity=user.api_tokens[0], roles=['exceeding_role']) -async def test_exceeding_user_permissions(app): - user_name = 'abed' - user = add_user(app.db, name=user_name) - add_user(app.db, name='user') +async def test_exceeding_user_permissions(app, user_with_scopes, temp_role): + user = user_with_scopes('read:users:groups') api_token = user.new_api_token() orm_api_token = orm.APIToken.find(app.db, token=api_token) - reader_role = generate_test_role(user_name, ['read:users'], 'reader_role') - subreader_role = generate_test_role( - user_name, ['read:users:groups'], 'subreader_role' - ) - roles.create_role(app.db, reader_role) - roles.create_role(app.db, subreader_role) - app.db.commit() - roles.update_roles(app.db, user, roles=['reader_role']) - roles.update_roles(app.db, orm_api_token, roles=['subreader_role']) - orm_api_token.roles.remove(orm.Role.find(app.db, name='token')) - app.db.commit() - + temp_role(['read:users'], 'reader_role') + roles.grant_role(app.db, orm_api_token, rolename='reader_role') headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', headers=headers) assert r.status_code == 200 keys = {key for user in r.json() for key in user.keys()} assert 'groups' in keys assert 'last_activity' not in keys - roles.strip_role(app.db, user, 'reader_role') -async def test_user_service_separation(app, mockservice_url): +async def test_user_service_separation(app, mockservice_url, temp_role): name = mockservice_url.name user = add_user(app.db, name=name) - reader_role = generate_test_role(name, ['read:users'], 'reader_role') - subreader_role = generate_test_role(name, ['read:users:groups'], 'subreader_role') - roles.create_role(app.db, reader_role) - roles.create_role(app.db, subreader_role) - app.db.commit() + temp_role(['read:users'], 'reader_role') + temp_role(['read:users:groups'], 'subreader_role') roles.update_roles(app.db, user, roles=['subreader_role']) roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role']) user.roles.remove(orm.Role.find(app.db, name='user')) api_token = user.new_api_token() - app.db.commit() headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', headers=headers) assert r.status_code == 200 @@ -343,33 +383,22 @@ async def test_user_service_separation(app, mockservice_url): assert 'last_activity' not in keys -async def test_request_user_outside_group(app): - user_name = 'buster' - fake_user = 'hello' - user = add_user(app.db, name=user_name) - add_user(app.db, name=fake_user) - test_role = generate_test_role(user_name, ['read:users!group=stuff']) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - roles.strip_role(app.db, entity=user, rolename='user') - app.db.commit() +async def test_request_user_outside_group(app, user_with_scopes): + outside_user = 'hello' + user = user_with_scopes('read:users!group=stuff') + add_user(app.db, name=outside_user) r = await api_request( - app, 'users', fake_user, headers=auth_header(app.db, user_name) + app, 'users', outside_user, headers=auth_header(app.db, user.name) ) assert r.status_code == 404 # Consistency between no user and user not accessible assert r.json()['message'] == err_message -async def test_user_filter(app): - user_name = 'rita' - user = add_user(app.db, name=user_name) - app.db.commit() - scopes = ['read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar'] - test_role = generate_test_role(user, scopes) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - roles.strip_role(app.db, entity=user, rolename='user') +async def test_user_filter(app, user_with_scopes): + user = user_with_scopes( + 'read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar' + ) name_in_scope = {'lindsay', 'oscar', 'gob'} outside_scope = {'maeby', 'marta'} group_name = 'bluth' @@ -378,17 +407,19 @@ async def test_user_filter(app): group = orm.Group(name=group_name) app.db.add(group) for name in name_in_scope | outside_scope: - user = add_user(app.db, name=name) + group_user = add_user(app.db, name=name) if name not in group.users: - group.users.append(user) + group.users.append(group_user) app.db.commit() - r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 result_names = {user['name'] for user in r.json()} assert result_names == name_in_scope + app.db.delete(group) + app.db.commit() -async def test_service_filter(app): +async def test_service_filter(app, user_with_scopes): services = [ {'name': 'cull_idle', 'api_token': 'some-token'}, {'name': 'user_service', 'api_token': 'some-other-token'}, @@ -396,124 +427,88 @@ async def test_service_filter(app): for service in services: app.services.append(service) app.init_services() - user_name = 'buster' - user = add_user(app.db, name=user_name) - app.db.commit() - test_role = generate_test_role(user, ['read:services!service=cull_idle']) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - r = await api_request(app, 'services', headers=auth_header(app.db, user_name)) + user = user_with_scopes('read:services!service=cull_idle') + r = await api_request(app, 'services', headers=auth_header(app.db, user.name)) assert r.status_code == 200 service_names = set(r.json().keys()) assert service_names == {'cull_idle'} -async def test_user_filter_with_group(app): - # Move role setup to setup method? - user_name = 'sally' - user = add_user(app.db, name=user_name) - external_user_name = 'britta' - add_user(app.db, name=external_user_name) - test_role = generate_test_role(user_name, ['read:users!group=sitwell']) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - - name_set = {'sally', 'stan'} +async def test_user_filter_with_group(app, user_with_scopes): group_name = 'sitwell' + user1 = user_with_scopes(f'read:users!group={group_name}') + user2 = user_with_scopes('self') + external_user = user_with_scopes('self') + name_set = {user1.name, user2.name} group = orm.Group.find(app.db, name=group_name) if not group: group = orm.Group(name=group_name) app.db.add(group) - for name in name_set: - user = add_user(app.db, name=name) - if name not in group.users: - group.users.append(user) + for user in {user1, user2}: + group.users.append(user) app.db.commit() - r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + r = await api_request(app, 'users', headers=auth_header(app.db, user1.name)) assert r.status_code == 200 result_names = {user['name'] for user in r.json()} assert result_names == name_set - assert external_user_name not in result_names + assert external_user.name not in result_names + app.db.delete(group) + app.db.commit() -async def test_group_scope_filter(app): - user_name = 'rollerblade' - user = add_user(app.db, name=user_name) - scopes = ['read:groups!group=sitwell', 'read:groups!group=bluth'] - test_role = generate_test_role(user_name, scopes) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - - group_set = {'sitwell', 'bluth', 'austero'} - for group_name in group_set: +async def test_group_scope_filter(app, user_with_scopes): + in_groups = {'sitwell', 'bluth'} + out_groups = {'austero'} + user = user_with_scopes(*(f'read:groups!group={group}' for group in in_groups)) + for group_name in in_groups | out_groups: group = orm.Group.find(app.db, name=group_name) if not group: group = orm.Group(name=group_name) app.db.add(group) app.db.commit() - r = await api_request(app, 'groups', headers=auth_header(app.db, user_name)) + r = await api_request(app, 'groups', headers=auth_header(app.db, user.name)) assert r.status_code == 200 result_names = {user['name'] for user in r.json()} - assert result_names == {'sitwell', 'bluth'} - - -async def test_vertical_filter(app): - user_name = 'lindsey' - user = add_user(app.db, name=user_name) - test_role = generate_test_role(user_name, ['read:users:name']) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - roles.strip_role(app.db, entity=user, rolename='user') + assert result_names == in_groups + for group_name in in_groups | out_groups: + group = orm.Group.find(app.db, name=group_name) + app.db.delete(group) app.db.commit() - r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + +async def test_vertical_filter(app, user_with_scopes): + user = user_with_scopes('read:users:name') + r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 allowed_keys = {'name', 'kind'} assert set([key for user in r.json() for key in user.keys()]) == allowed_keys -async def test_stacked_vertical_filter(app): - user_name = 'user' - user = add_user(app.db, name=user_name) - test_role = generate_test_role( - user_name, ['read:users:activity', 'read:users:servers'] - ) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - roles.strip_role(app.db, entity=user, rolename='user') - app.db.commit() - - r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) +async def test_stacked_vertical_filter(app, user_with_scopes): + user = user_with_scopes('read:users:activity', 'read:users:servers') + r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 allowed_keys = {'name', 'kind', 'servers', 'last_activity'} result_model = set([key for user in r.json() for key in user.keys()]) assert result_model == allowed_keys -async def test_cross_filter(app): - user_name = 'abed' - user = add_user(app.db, name=user_name) - test_role = generate_test_role( - user_name, ['read:users:activity', 'read:users!user=abed'] - ) - roles.create_role(app.db, test_role) - roles.grant_role(app.db, entity=user, rolename='test') - roles.strip_role(app.db, entity=user, rolename='user') - app.db.commit() +async def test_cross_filter(app, user_with_scopes): + user = user_with_scopes('read:users:activity', 'self') new_users = {'britta', 'jeff', 'annie'} for new_user_name in new_users: add_user(app.db, name=new_user_name) app.db.commit() - r = await api_request(app, 'users', headers=auth_header(app.db, user_name)) + r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 restricted_keys = {'name', 'kind', 'last_activity'} key_in_full_model = 'created' - for user in r.json(): - if user['name'] == user_name: - assert key_in_full_model in user + for model_user in r.json(): + if model_user['name'] == user.name: + assert key_in_full_model in model_user else: - assert set(user.keys()) == restricted_keys + assert set(model_user.keys()) == restricted_keys @mark.parametrize( @@ -523,13 +518,13 @@ async def test_cross_filter(app): ('services', False), ], ) -async def test_metascope_self_expansion(app, kind, has_user_scopes): - Class = orm.get_class(kind) - orm_obj = Class(name=f'test_{kind}') - app.db.add(orm_obj) - app.db.commit() - test_role = orm.Role(name='test_role', scopes=['self']) - orm_obj.roles.append(test_role) +async def test_metascope_self_expansion( + app, kind, has_user_scopes, user_with_scopes, service_with_scopes +): + if kind == 'users': + orm_obj = user_with_scopes('self') + else: + orm_obj = service_with_scopes('self') # test expansion of user/service scopes scopes = roles.expand_roles_to_scopes(orm_obj) assert bool(scopes) == has_user_scopes @@ -538,14 +533,10 @@ async def test_metascope_self_expansion(app, kind, has_user_scopes): orm_obj.new_api_token() token_scopes = get_scopes_for(orm_obj.api_tokens[0]) assert bool(token_scopes) == has_user_scopes - app.db.delete(orm_obj) - app.db.delete(test_role) - app.db.commit() -async def test_metascope_all_expansion(app): - user = add_user(app.db, name='user') - scope_set = {scope for role in user.roles for scope in role.scopes} +async def test_metascope_all_expansion(app, user_with_scopes): + user = user_with_scopes('self') user.new_api_token() token = user.api_tokens[0] # Check 'all' expansion From a7f2247331809ca14543c893d7e49a7955d35ec0 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 12 Apr 2021 16:49:29 +0200 Subject: [PATCH 115/270] Minor fixes --- jupyterhub/roles.py | 2 +- jupyterhub/tests/test_scopes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 81ba6425..e4bc2e1e 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -371,7 +371,7 @@ def _token_allowed_role(db, token, role): raw_owner_scopes = { scope.split('!', 1)[0] if '!' in scope else scope for scope in owner_scopes } - if (raw_extra_scopes).issubset(raw_owner_scopes): + if raw_extra_scopes.issubset(raw_owner_scopes): return True else: return False diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 496d053a..2799af44 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -613,7 +613,7 @@ async def test_server_state_access( service.roles.append(role) app.db.commit() api_token = service.new_api_token() - app.init_roles() + await app.init_roles() headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', username, headers=headers) r.raise_for_status() From 2fdf820fe5839f1d6e60602795a54e0180c9acfe Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 10 Mar 2021 14:59:39 +0100 Subject: [PATCH 116/270] bump dev version to 2.0 --- jupyterhub/_version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jupyterhub/_version.py b/jupyterhub/_version.py index 591bafc5..ed389f1e 100644 --- a/jupyterhub/_version.py +++ b/jupyterhub/_version.py @@ -3,8 +3,8 @@ # Distributed under the terms of the Modified BSD License. version_info = ( - 1, - 4, + 2, + 0, 0, "", # release (b1, rc1, or "" for final or dev) "dev", # dev or nothing for beta/rc/stable releases From 0b56fd9e62e92198407db96c24bf06725a9ea02a Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 10 Mar 2021 16:41:37 +0100 Subject: [PATCH 117/270] remove separate oauth tokens - merge oauth token fields into APITokens - create oauth client 'jupyterhub' which owns current API tokens - db upgrade is currently to drop both token tables, and force recreation on next start --- .../alembic/versions/833da8570507_rbac.py | 119 +++++++++++++++++ jupyterhub/apihandlers/auth.py | 2 - jupyterhub/apihandlers/base.py | 26 +--- jupyterhub/apihandlers/users.py | 31 +---- jupyterhub/app.py | 22 +++- jupyterhub/handlers/base.py | 28 +--- jupyterhub/handlers/pages.py | 28 ++-- jupyterhub/oauth/provider.py | 21 ++- jupyterhub/orm.py | 124 +++++++----------- jupyterhub/services/service.py | 10 ++ jupyterhub/tests/populate_db.py | 6 +- jupyterhub/tests/test_api.py | 7 +- jupyterhub/tests/test_orm.py | 34 ++--- jupyterhub/tests/test_pages.py | 2 +- jupyterhub/tests/test_services_auth.py | 6 +- 15 files changed, 264 insertions(+), 202 deletions(-) create mode 100644 jupyterhub/alembic/versions/833da8570507_rbac.py diff --git a/jupyterhub/alembic/versions/833da8570507_rbac.py b/jupyterhub/alembic/versions/833da8570507_rbac.py new file mode 100644 index 00000000..a060f10c --- /dev/null +++ b/jupyterhub/alembic/versions/833da8570507_rbac.py @@ -0,0 +1,119 @@ +"""rbac + +Revision ID: 833da8570507 +Revises: 4dc2d5a8c53c +Create Date: 2021-02-17 15:03:04.360368 + +""" +# revision identifiers, used by Alembic. +revision = '833da8570507' +down_revision = '4dc2d5a8c53c' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + # FIXME: currently drops all api tokens and forces recreation! + # this ensures a consistent database, but requires: + # 1. all servers to be stopped for upgrade (maybe unavoidable anyway) + # 2. any manually issued/stored tokens to be re-issued + + # tokens loaded via configuration will be recreated on launch and unaffected + op.drop_table('api_tokens') + op.drop_table('oauth_access_tokens') + return + # TODO: explore in-place migration. This seems hard! + # 1. add new columns in api tokens + # 2. fill default fields (client_id='jupyterhub') for all api tokens + # 3. copy oauth tokens into api tokens + # 4. give oauth tokens 'identify' scopes + + c = op.get_bind() + naming_convention = { + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + } + with op.batch_alter_table( + "api_tokens", + naming_convention=naming_convention, + ) as batch_op: + batch_op.add_column( + sa.Column( + 'client_id', + sa.Unicode(255), + # sa.ForeignKey('oauth_clients.identifier', ondelete='CASCADE'), + nullable=True, + ), + ) + # batch_cursor = op.get_bind() + # batch_cursor.execute( + # """ + # UPDATE api_tokens + # SET client_id='jupyterhub' + # WHERE client_id IS NULL + # """ + # ) + batch_op.create_foreign_key( + "fk_api_token_client_id", + # 'api_tokens', + 'oauth_clients', + ['client_id'], + ['identifier'], + ondelete='CASCADE', + ) + + c.execute( + """ + UPDATE api_tokens + SET client_id='jupyterhub' + WHERE client_id IS NULL + """ + ) + + op.add_column( + 'api_tokens', + sa.Column( + 'grant_type', + sa.Enum( + 'authorization_code', + 'implicit', + 'password', + 'client_credentials', + 'refresh_token', + name='granttype', + ), + server_default='authorization_code', + nullable=False, + ), + ) + op.add_column( + 'api_tokens', sa.Column('refresh_token', sa.Unicode(length=255), nullable=True) + ) + op.add_column( + 'api_tokens', sa.Column('session_id', sa.Unicode(length=255), nullable=True) + ) + + # TODO: migrate OAuth tokens into APIToken table + + op.drop_index('ix_oauth_access_tokens_prefix', table_name='oauth_access_tokens') + op.drop_table('oauth_access_tokens') + + +def downgrade(): + # delete OAuth tokens for non-jupyterhub clients + # drop new columns from api tokens + op.drop_constraint(None, 'api_tokens', type_='foreignkey') + op.drop_column('api_tokens', 'session_id') + op.drop_column('api_tokens', 'refresh_token') + op.drop_column('api_tokens', 'grant_type') + op.drop_column('api_tokens', 'client_id') + # FIXME: only drop tokens whose client id is not 'jupyterhub' + # until then, drop all tokens + op.drop_table("api_tokens") + + op.drop_table('api_token_role_map') + op.drop_table('service_role_map') + op.drop_table('user_role_map') + op.drop_table('roles') diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index 938d88ec..e7f72880 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -29,8 +29,6 @@ class TokenAPIHandler(APIHandler): "/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) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index bbbda5d8..9832afc5 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -205,23 +205,6 @@ class APIHandler(BaseHandler): def token_model(self, token): """Get the JSON model for an APIToken""" - expires_at = None - if isinstance(token, orm.APIToken): - kind = 'api_token' - roles = [r.name for r in token.roles] - extra = {'note': token.note} - expires_at = token.expires_at - elif isinstance(token, orm.OAuthAccessToken): - kind = 'oauth' - # oauth tokens do not bear roles - roles = [] - extra = {'oauth_client': token.client.description or token.client.client_id} - if token.expires_at: - expires_at = datetime.fromtimestamp(token.expires_at) - else: - raise TypeError( - "token must be an APIToken or OAuthAccessToken, not %s" % type(token) - ) if token.user: owner_key = 'user' @@ -234,13 +217,14 @@ class APIHandler(BaseHandler): model = { owner_key: owner, 'id': token.api_id, - 'kind': kind, - 'roles': [role for role in roles], + 'kind': 'api_token', + 'roles': [r.name for r in token.roles], 'created': isoformat(token.created), 'last_activity': isoformat(token.last_activity), - 'expires_at': isoformat(expires_at), + 'expires_at': isoformat(token.expires_at), + 'note': token.note, + 'oauth_client': token.client.description or token.client.client_id, } - model.update(extra) return model def user_model(self, user): diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 56775e34..c70d35ad 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -32,9 +32,6 @@ class SelfAPIHandler(APIHandler): async def get(self): user = self.current_user - if user is None: - # whoami can be accessed via oauth token - user = self.get_current_user_oauth_token() if user is None: raise web.HTTPError(403) if isinstance(user, orm.Service): @@ -316,17 +313,7 @@ class UserTokenListAPIHandler(APIHandler): continue api_tokens.append(self.token_model(token)) - oauth_tokens = [] - # OAuth tokens use integer timestamps - now_timestamp = now.timestamp() - for token in sorted(user.oauth_tokens, key=sort_key): - if token.expires_at and token.expires_at < now_timestamp: - # exclude expired tokens - self.db.delete(token) - self.db.commit() - continue - oauth_tokens.append(self.token_model(token)) - self.write(json.dumps({'api_tokens': api_tokens, 'oauth_tokens': oauth_tokens})) + self.write(json.dumps({'api_tokens': api_tokens})) # Todo: Set to @needs_scope('users:tokens') async def post(self, user_name): @@ -410,19 +397,15 @@ class UserTokenAPIHandler(APIHandler): (e.g. wrong owner, invalid key format, etc.) """ not_found = "No such token %s for user %s" % (token_id, user.name) - prefix, id_ = token_id[0], token_id[1:] - if prefix == 'a': - Token = orm.APIToken - elif prefix == 'o': - Token = orm.OAuthAccessToken - else: + prefix, id_ = token_id[:1], token_id[1:] + if prefix != 'a': raise web.HTTPError(404, not_found) try: id_ = int(id_) except ValueError: raise web.HTTPError(404, not_found) - orm_token = self.db.query(Token).filter(Token.id == id_).first() + orm_token = self.db.query(orm.APIToken).filter_by(id=id_).first() if orm_token is None or orm_token.user is not user.orm_user: raise web.HTTPError(404, "Token not found %s", orm_token) return orm_token @@ -444,10 +427,10 @@ class UserTokenAPIHandler(APIHandler): raise web.HTTPError(404, "No such user: %s" % user_name) token = self.find_token_by_id(user, token_id) # deleting an oauth token deletes *all* oauth tokens for that client - if isinstance(token, orm.OAuthAccessToken): - client_id = token.client_id + client_id = token.client_id + if token.client_id != "jupyterhub": tokens = [ - token for token in user.oauth_tokens if token.client_id == client_id + token for token in user.api_tokens if token.client_id == client_id ] else: tokens = [token] diff --git a/jupyterhub/app.py b/jupyterhub/app.py index a0c5fde0..6f3cf45d 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2014,12 +2014,13 @@ class JupyterHub(Application): run periodically """ # this should be all the subclasses of Expiring - for cls in (orm.APIToken, orm.OAuthAccessToken, orm.OAuthCode): + for cls in (orm.APIToken, orm.OAuthCode): self.log.debug("Purging expired {name}s".format(name=cls.__name__)) cls.purge_expired(self.db) async def init_api_tokens(self): """Load predefined API tokens (for services) into database""" + await self._add_tokens(self.service_tokens, kind='service') await self._add_tokens(self.api_tokens, kind='user') @@ -2292,13 +2293,30 @@ class JupyterHub(Application): login_url=url_path_join(base_url, 'login'), token_expires_in=self.oauth_token_expires_in, ) + # ensure the default oauth client exists + if ( + not self.db.query(orm.OAuthClient) + .filter_by(identifier="jupyterhub") + .first() + ): + # create the oauth client for jupyterhub itself + # this allows us to distinguish between orphaned tokens + # (failed cascade deletion) and tokens issued by the hub + # it has no client_secret, which means it cannot be used + # to make requests + self.oauth_provider.add_client( + client_id="jupyterhub", + client_secret="", + redirect_uri="", + description="JupyterHub", + ) def cleanup_oauth_clients(self): """Cleanup any OAuth clients that shouldn't be in the database. This should mainly be services that have been removed from configuration or renamed. """ - oauth_client_ids = set() + oauth_client_ids = {"jupyterhub"} for service in self._service_map.values(): if service.oauth_available: oauth_client_ids.add(service.oauth_client_id) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 4841b2a8..adf0c363 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -247,26 +247,6 @@ class BaseHandler(RequestHandler): return None return match.group(1) - def get_current_user_oauth_token(self): - """Get the current user identified by OAuth access token - - Separate from API token because OAuth access tokens - can only be used for identifying users, - not using the API. - """ - token = self.get_auth_token() - if token is None: - return None - orm_token = orm.OAuthAccessToken.find(self.db, token) - if orm_token is None: - return None - - now = datetime.utcnow() - recorded = self._record_activity(orm_token, now) - if self._record_activity(orm_token.user, now) or recorded: - self.db.commit() - return self._user_from_orm(orm_token.user) - def _record_activity(self, obj, timestamp=None): """record activity on an ORM object @@ -373,7 +353,7 @@ class BaseHandler(RequestHandler): # FIXME: scopes should give us better control than this # don't consider API requests originating from a server # to be activity from the user - if not orm_token.note.startswith("Server at "): + if not orm_token.note or not orm_token.note.startswith("Server at "): recorded = self._record_activity(orm_token.user, now) or recorded if recorded: self.db.commit() @@ -501,10 +481,8 @@ class BaseHandler(RequestHandler): # don't clear session tokens if not logged in, # because that could be a malicious logout request! count = 0 - for access_token in ( - self.db.query(orm.OAuthAccessToken) - .filter(orm.OAuthAccessToken.user_id == user.id) - .filter(orm.OAuthAccessToken.session_id == session_id) + for access_token in self.db.query(orm.APIToken).filter_by( + user_id=user.id, session_id=session_id ): self.db.delete(access_token) count += 1 diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index a9422699..356aae71 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -552,36 +552,32 @@ class TokenPageHandler(BaseHandler): return (token.last_activity or never, token.created or never) now = datetime.utcnow() - api_tokens = [] - for token in sorted(user.api_tokens, key=sort_key, reverse=True): - if token.expires_at and token.expires_at < now: - self.db.delete(token) - self.db.commit() - continue - api_tokens.append(token) # group oauth client tokens by client id - # AccessTokens have expires_at as an integer timestamp - now_timestamp = now.timestamp() - oauth_tokens = defaultdict(list) - for token in user.oauth_tokens: - if token.expires_at and token.expires_at < now_timestamp: - self.log.warning("Deleting expired token") + all_tokens = defaultdict(list) + for token in sorted(user.api_tokens, key=sort_key, reverse=True): + if token.expires_at and token.expires_at < now: + self.log.warning(f"Deleting expired token {token}") self.db.delete(token) self.db.commit() continue if not token.client_id: # token should have been deleted when client was deleted - self.log.warning("Deleting stale oauth token for %s", user.name) + self.log.warning("Deleting stale oauth token {token}") self.db.delete(token) self.db.commit() continue - oauth_tokens[token.client_id].append(token) + all_tokens[token.client_id].append(token) + # individually list tokens issued by jupyterhub itself + api_tokens = all_tokens.pop("jupyterhub", []) + + # group all other tokens issued under their owners # get the earliest created and latest last_activity # timestamp for a given oauth client oauth_clients = [] - for client_id, tokens in oauth_tokens.items(): + + for client_id, tokens in all_tokens.items(): created = tokens[0].created last_activity = tokens[0].last_activity for token in tokens[1:]: diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 7dd7b160..ee96dfbe 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -2,18 +2,18 @@ implements https://oauthlib.readthedocs.io/en/latest/oauth2/server.html """ +from datetime import timedelta + from oauthlib import uri_validate from oauthlib.oauth2 import RequestValidator from oauthlib.oauth2 import WebApplicationServer from oauthlib.oauth2.rfc6749.grant_types import authorization_code from oauthlib.oauth2.rfc6749.grant_types import base -from tornado.escape import url_escape from tornado.log import app_log from .. import orm from ..utils import compare_token from ..utils import hash_token -from ..utils import url_path_join # patch absolute-uri check # because we want to allow relative uri oauth @@ -60,6 +60,9 @@ class JupyterHubRequestValidator(RequestValidator): ) if oauth_client is None: return False + if not client_secret or not oauth_client.secret: + # disallow authentication with no secret + return False if not compare_token(oauth_client.secret, client_secret): app_log.warning("Client secret mismatch for %s", client_id) return False @@ -339,10 +342,10 @@ class JupyterHubRequestValidator(RequestValidator): .filter_by(identifier=request.client.client_id) .first() ) - orm_access_token = orm.OAuthAccessToken( - client=client, + orm_access_token = orm.APIToken.new( + client_id=client.identifier, grant_type=orm.GrantType.authorization_code, - expires_at=orm.OAuthAccessToken.now() + token['expires_in'], + expires_at=orm.APIToken.now() + timedelta(seconds=token['expires_in']), refresh_token=token['refresh_token'], # TODO: save scopes, # scopes=scopes, @@ -412,6 +415,8 @@ class JupyterHubRequestValidator(RequestValidator): ) if orm_client is None: return False + if not orm_client.secret: + return False request.client = orm_client return True @@ -574,14 +579,16 @@ class JupyterHubOAuthServer(WebApplicationServer): app_log.info(f'Creating oauth client {client_id}') else: app_log.info(f'Updating oauth client {client_id}') - orm_client.secret = hash_token(client_secret) + orm_client.secret = hash_token(client_secret) if client_secret else "" orm_client.redirect_uri = redirect_uri orm_client.description = description self.db.commit() def fetch_by_client_id(self, client_id): """Find a client by its id""" - return self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first() + client = self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first() + if client and client.secret: + return client def make_provider(session_factory, url_prefix, login_url, **oauth_server_kwargs): diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 6e6e8693..a00e265a 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -277,9 +277,6 @@ class User(Base): last_activity = Column(DateTime, nullable=True) api_tokens = relationship("APIToken", backref="user", cascade="all, delete-orphan") - oauth_tokens = relationship( - "OAuthAccessToken", backref="user", cascade="all, delete-orphan" - ) oauth_codes = relationship( "OAuthCode", backref="user", cascade="all, delete-orphan" ) @@ -485,7 +482,9 @@ class Hashed(Expiring): @classmethod def check_token(cls, db, token): """Check if a token is acceptable""" + print("checking", cls, token, len(token), cls.min_length) if len(token) < cls.min_length: + print("raising") raise ValueError( "Tokens must be at least %i characters, got %r" % (cls.min_length, token) @@ -530,6 +529,20 @@ class Hashed(Expiring): return orm_token +# ------------------------------------ +# OAuth tables +# ------------------------------------ + + +class GrantType(enum.Enum): + # we only use authorization_code for now + authorization_code = 'authorization_code' + implicit = 'implicit' + password = 'password' + client_credentials = 'client_credentials' + refresh_token = 'refresh_token' + + class APIToken(Hashed, Base): """An API token""" @@ -548,6 +561,15 @@ class APIToken(Hashed, Base): def api_id(self): return 'a%i' % self.id + # added in 2.0 + client_id = Column( + Unicode(255), ForeignKey('oauth_clients.identifier', ondelete='CASCADE') + ) + grant_type = Column(Enum(GrantType), nullable=False) + refresh_token = Column(Unicode(255)) + # the browser session id associated with a given token + session_id = Column(Unicode(255)) + # token metadata for bookkeeping now = datetime.utcnow # for expiry created = Column(DateTime, default=datetime.utcnow) @@ -566,8 +588,12 @@ class APIToken(Hashed, Base): # this shouldn't happen kind = 'owner' name = 'unknown' - return "<{cls}('{pre}...', {kind}='{name}')>".format( - cls=self.__class__.__name__, pre=self.prefix, kind=kind, name=name + return "<{cls}('{pre}...', {kind}='{name}', client_id={client_id!r})>".format( + cls=self.__class__.__name__, + pre=self.prefix, + kind=kind, + name=name, + client_id=self.client_id, ) @classmethod @@ -588,6 +614,14 @@ class APIToken(Hashed, Base): raise ValueError("kind must be 'user', 'service', or None, not %r" % kind) for orm_token in prefix_match: if orm_token.match(token): + if not orm_token.client_id: + app_log.warning( + "Deleting stale oauth token for %s with no client", + orm_token.user and orm_token.user.name, + ) + db.delete(orm_token) + db.commit() + return return orm_token @classmethod @@ -600,6 +634,7 @@ class APIToken(Hashed, Base): note='', generated=True, expires_in=None, + client_id='jupyterhub', ): """Generate a new API token for a user or service""" assert user or service @@ -614,7 +649,12 @@ class APIToken(Hashed, Base): cls.check_token(db, token) # two stages to ensure orm_token.generated has been set # before token setter is called - orm_token = cls(generated=generated, note=note or '') + orm_token = cls( + generated=generated, + note=note or '', + grant_type=GrantType.authorization_code, + client_id=client_id, + ) orm_token.token = token if user: assert user.id is not None @@ -641,76 +681,6 @@ class APIToken(Hashed, Base): return token -# ------------------------------------ -# OAuth tables -# ------------------------------------ - - -class GrantType(enum.Enum): - # we only use authorization_code for now - authorization_code = 'authorization_code' - implicit = 'implicit' - password = 'password' - client_credentials = 'client_credentials' - refresh_token = 'refresh_token' - - -class OAuthAccessToken(Hashed, Base): - __tablename__ = 'oauth_access_tokens' - id = Column(Integer, primary_key=True, autoincrement=True) - - @staticmethod - def now(): - return datetime.utcnow().timestamp() - - @property - def api_id(self): - return 'o%i' % self.id - - client_id = Column( - Unicode(255), ForeignKey('oauth_clients.identifier', ondelete='CASCADE') - ) - grant_type = Column(Enum(GrantType), nullable=False) - expires_at = Column(Integer) - refresh_token = Column(Unicode(255)) - # TODO: drop refresh_expires_at. Refresh tokens shouldn't expire - refresh_expires_at = Column(Integer) - user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE')) - service = None # for API-equivalence with APIToken - - # the browser session id associated with a given token - session_id = Column(Unicode(255)) - - # from Hashed - hashed = Column(Unicode(255), unique=True) - prefix = Column(Unicode(16), index=True) - - created = Column(DateTime, default=datetime.utcnow) - last_activity = Column(DateTime, nullable=True) - - def __repr__(self): - return "<{cls}('{prefix}...', client_id={client_id!r}, user={user!r}, expires_in={expires_in}>".format( - cls=self.__class__.__name__, - client_id=self.client_id, - user=self.user and self.user.name, - prefix=self.prefix, - expires_in=self.expires_in, - ) - - @classmethod - def find(cls, db, token): - orm_token = super().find(db, token) - if orm_token and not orm_token.client_id: - app_log.warning( - "Deleting stale oauth token for %s with no client", - orm_token.user and orm_token.user.name, - ) - db.delete(orm_token) - db.commit() - return - return orm_token - - class OAuthCode(Expiring, Base): __tablename__ = 'oauth_codes' @@ -752,7 +722,7 @@ class OAuthClient(Base): return self.identifier access_tokens = relationship( - OAuthAccessToken, backref='client', cascade='all, delete-orphan' + APIToken, backref='client', cascade='all, delete-orphan' ) codes = relationship(OAuthCode, backref='client', cascade='all, delete-orphan') diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index 44fd763c..c72ae382 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -51,6 +51,7 @@ from traitlets import Dict from traitlets import HasTraits from traitlets import Instance from traitlets import Unicode +from traitlets import validate from traitlets.config import LoggingConfigurable from .. import orm @@ -284,6 +285,15 @@ class Service(LoggingConfigurable): def _default_client_id(self): return 'service-%s' % self.name + @validate("oauth_client_id") + def _validate_client_id(self, proposal): + if not proposal.value.startswith("service-"): + raise ValueError( + f"service {self.name} has oauth_client_id='{proposal.value}'." + " Service oauth client ids must start with 'service-'" + ) + return proposal.value + oauth_redirect_uri = Unicode( help="""OAuth redirect URI for this service. diff --git a/jupyterhub/tests/populate_db.py b/jupyterhub/tests/populate_db.py index 2b5c6007..4db35cf9 100644 --- a/jupyterhub/tests/populate_db.py +++ b/jupyterhub/tests/populate_db.py @@ -70,7 +70,11 @@ def populate_db(url): code = orm.OAuthCode(client_id=client.identifier) db.add(code) db.commit() - access_token = orm.OAuthAccessToken( + if jupyterhub.version_info < (2, 0): + Token = orm.OAuthAccessToken + else: + Token = orm.APIToken + access_token = Token( client_id=client.identifier, user_id=user.id, grant_type=orm.GrantType.authorization_code, diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index e22ee51c..a8074b81 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -273,7 +273,7 @@ async def test_get_self(app): oauth_client = orm.OAuthClient(identifier='eurydice') db.add(oauth_client) db.commit() - oauth_token = orm.OAuthAccessToken( + oauth_token = orm.APIToken( user=u.orm_user, client=oauth_client, token=token, @@ -1423,12 +1423,11 @@ async def test_token_list(app, as_user, for_user, status): if status != 200: return reply = r.json() - assert sorted(reply) == ['api_tokens', 'oauth_tokens'] + assert sorted(reply) == ['api_tokens'] assert len(reply['api_tokens']) == len(for_user_obj.api_tokens) assert all(token['user'] == for_user for token in reply['api_tokens']) - assert all(token['user'] == for_user for token in reply['oauth_tokens']) # validate individual token ids - for token in reply['api_tokens'] + reply['oauth_tokens']: + for token in reply['api_tokens']: r = await api_request( app, 'users', for_user, 'tokens', token['id'], headers=headers ) diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index c761a040..8187c481 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -355,7 +355,7 @@ def test_user_delete_cascade(db): spawner.server = server = orm.Server() oauth_code = orm.OAuthCode(client=oauth_client, user=user) db.add(oauth_code) - oauth_token = orm.OAuthAccessToken( + oauth_token = orm.APIToken( client=oauth_client, user=user, grant_type=orm.GrantType.authorization_code ) db.add(oauth_token) @@ -377,7 +377,7 @@ def test_user_delete_cascade(db): assert_not_found(db, orm.Spawner, spawner_id) assert_not_found(db, orm.Server, server_id) assert_not_found(db, orm.OAuthCode, oauth_code_id) - assert_not_found(db, orm.OAuthAccessToken, oauth_token_id) + assert_not_found(db, orm.APIToken, oauth_token_id) def test_oauth_client_delete_cascade(db): @@ -391,12 +391,12 @@ def test_oauth_client_delete_cascade(db): # these should all be deleted automatically when the user goes away oauth_code = orm.OAuthCode(client=oauth_client, user=user) db.add(oauth_code) - oauth_token = orm.OAuthAccessToken( + oauth_token = orm.APIToken( client=oauth_client, user=user, grant_type=orm.GrantType.authorization_code ) db.add(oauth_token) db.commit() - assert user.oauth_tokens == [oauth_token] + assert user.tokens == [oauth_token] # record all of the ids oauth_code_id = oauth_code.id @@ -408,8 +408,8 @@ def test_oauth_client_delete_cascade(db): # verify that everything gets deleted assert_not_found(db, orm.OAuthCode, oauth_code_id) - assert_not_found(db, orm.OAuthAccessToken, oauth_token_id) - assert user.oauth_tokens == [] + assert_not_found(db, orm.APIToken, oauth_token_id) + assert user.tokens == [] assert user.oauth_codes == [] @@ -510,32 +510,32 @@ def test_expiring_api_token(app, user): def test_expiring_oauth_token(app, user): db = app.db token = "abc123" - now = orm.OAuthAccessToken.now + now = orm.APIToken.now client = orm.OAuthClient(identifier="xxx", secret="yyy") db.add(client) - orm_token = orm.OAuthAccessToken( + orm_token = orm.APIToken( token=token, grant_type=orm.GrantType.authorization_code, client=client, user=user, - expires_at=now() + 30, + expires_at=now() + datetime.timedelta(seconds=30), ) db.add(orm_token) db.commit() - found = orm.OAuthAccessToken.find(db, token) + found = orm.APIToken.find(db, token) assert found is orm_token # purge_expired doesn't delete non-expired - orm.OAuthAccessToken.purge_expired(db) - found = orm.OAuthAccessToken.find(db, token) + orm.APIToken.purge_expired(db) + found = orm.APIToken.find(db, token) assert found is orm_token - with mock.patch.object(orm.OAuthAccessToken, 'now', lambda: now() + 60): - found = orm.OAuthAccessToken.find(db, token) + with mock.patch.object(orm.APIToken, 'now', lambda: now() + 60): + found = orm.APIToken.find(db, token) assert found is None - assert orm_token in db.query(orm.OAuthAccessToken) - orm.OAuthAccessToken.purge_expired(db) - assert orm_token not in db.query(orm.OAuthAccessToken) + assert orm_token in db.query(orm.APIToken) + orm.APIToken.purge_expired(db) + assert orm_token not in db.query(orm.APIToken) def test_expiring_oauth_code(app, user): diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index 7140b823..3b4b6a39 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -869,7 +869,7 @@ async def test_oauth_token_page(app): user = app.users[orm.User.find(app.db, name)] client = orm.OAuthClient(identifier='token') app.db.add(client) - oauth_token = orm.OAuthAccessToken( + oauth_token = orm.APIToken( client=client, user=user, grant_type=orm.GrantType.authorization_code ) app.db.add(oauth_token) diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index b41d50db..540150bb 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -444,11 +444,7 @@ async def test_oauth_logout(app, mockservice_url): def auth_tokens(): """Return list of OAuth access tokens for the user""" - return list( - app.db.query(orm.OAuthAccessToken).filter( - orm.OAuthAccessToken.user_id == app_user.id - ) - ) + return list(app.db.query(orm.APIToken).filter_by(user_id=app_user.id)) # ensure we start empty assert auth_tokens() == [] From 900c2f1ed3eb97f40fd91c6b22db679d569b9a89 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 11 Mar 2021 11:30:21 +0100 Subject: [PATCH 118/270] Drop support for db upgrade from before 1.0 - define jupyterhub oauth client during token app --- jupyterhub/app.py | 2 ++ jupyterhub/tests/populate_db.py | 53 ++++++++++++++++----------------- jupyterhub/tests/test_db.py | 2 +- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 6f3cf45d..f9d1b9a9 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -214,6 +214,8 @@ class NewToken(Application): hub = JupyterHub(parent=self) hub.load_config_file(hub.config_file) hub.init_db() + hub.init_hub() + hub.init_oauth() def init_users(): loop = asyncio.new_event_loop() diff --git a/jupyterhub/tests/populate_db.py b/jupyterhub/tests/populate_db.py index 4db35cf9..ba95104a 100644 --- a/jupyterhub/tests/populate_db.py +++ b/jupyterhub/tests/populate_db.py @@ -62,36 +62,33 @@ def populate_db(url): db.commit() # create some oauth objects - if jupyterhub.version_info >= (0, 8): - # create oauth client - client = orm.OAuthClient(identifier='oauth-client') - db.add(client) - db.commit() - code = orm.OAuthCode(client_id=client.identifier) - db.add(code) - db.commit() - if jupyterhub.version_info < (2, 0): - Token = orm.OAuthAccessToken - else: - Token = orm.APIToken - access_token = Token( - client_id=client.identifier, - user_id=user.id, - grant_type=orm.GrantType.authorization_code, - ) - db.add(access_token) - db.commit() + client = orm.OAuthClient(identifier='oauth-client') + db.add(client) + db.commit() + code = orm.OAuthCode(client_id=client.identifier) + db.add(code) + db.commit() + if jupyterhub.version_info < (2, 0): + Token = orm.OAuthAccessToken + else: + Token = orm.APIToken + access_token = Token( + client_id=client.identifier, + user_id=user.id, + grant_type=orm.GrantType.authorization_code, + ) + db.add(access_token) + db.commit() # set some timestamps added in 0.9 - if jupyterhub.version_info >= (0, 9): - assert user.created - assert admin.created - # set last_activity - user.last_activity = datetime.utcnow() - spawner = user.orm_spawners[''] - spawner.started = datetime.utcnow() - spawner.last_activity = datetime.utcnow() - db.commit() + assert user.created + assert admin.created + # set last_activity + user.last_activity = datetime.utcnow() + spawner = user.orm_spawners[''] + spawner.started = datetime.utcnow() + spawner.last_activity = datetime.utcnow() + db.commit() if __name__ == '__main__': diff --git a/jupyterhub/tests/test_db.py b/jupyterhub/tests/test_db.py index beb63099..77231f97 100644 --- a/jupyterhub/tests/test_db.py +++ b/jupyterhub/tests/test_db.py @@ -36,7 +36,7 @@ def generate_old_db(env_dir, hub_version, db_url): check_call([env_py, populate_db, db_url]) -@pytest.mark.parametrize('hub_version', ['0.7.2', '0.8.1', '0.9.4']) +@pytest.mark.parametrize('hub_version', ['1.0.0', "1.2.2", "1.3.0"]) async def test_upgrade(tmpdir, hub_version): db_url = os.getenv('JUPYTERHUB_TEST_DB_URL') if db_url: From e504fa4bf57fad86c2399f3fce94cacbb4ee2b05 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 22 Mar 2021 17:07:02 +0100 Subject: [PATCH 119/270] resolve special scopes for self in 'self' handler instead of `_resolve_scopes` on all requests --- jupyterhub/apihandlers/users.py | 6 ++++++ jupyterhub/handlers/base.py | 15 ++++----------- jupyterhub/oauth/provider.py | 6 ++++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index c70d35ad..492a3a29 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -14,6 +14,7 @@ from tornado import web from tornado.iostream import StreamClosedError from .. import orm +from .. import scopes from ..roles import assign_default_roles from ..scopes import needs_scope from ..user import User @@ -35,8 +36,13 @@ class SelfAPIHandler(APIHandler): if user is None: raise web.HTTPError(403) if isinstance(user, orm.Service): + # ensure we have the minimal 'identify' scopes for the token owner + self.raw_scopes.update(scopes.identify_scopes(user)) + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) model = self.service_model(user) else: + self.raw_scopes.update(scopes.identify_scopes(user.orm_user)) + self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) model = self.user_model(user) self.write(json.dumps(model)) diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index adf0c363..3c49577c 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -419,17 +419,10 @@ class BaseHandler(RequestHandler): def _resolve_scopes(self): self.raw_scopes = set() app_log.debug("Loading and parsing scopes") - if not self.current_user: - # check for oauth tokens as long as #3380 not merged - user_from_oauth = self.get_current_user_oauth_token() - if user_from_oauth is not None: - self.raw_scopes = {f'read:users!user={user_from_oauth.name}'} - else: - app_log.debug("No user found, no scopes loaded") - else: - api_token = self.get_token() - if api_token: - self.raw_scopes = scopes.get_scopes_for(api_token) + if self.current_user: + orm_token = self.get_token() + if orm_token: + self.raw_scopes = scopes.get_scopes_for(orm_token) else: self.raw_scopes = scopes.get_scopes_for(self.current_user) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index ee96dfbe..bb395752 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -342,13 +342,15 @@ class JupyterHubRequestValidator(RequestValidator): .filter_by(identifier=request.client.client_id) .first() ) + # FIXME: pick a role + # this will be empty for now + roles = list(self.db.query(orm.Role).filter_by(name='identify')) orm_access_token = orm.APIToken.new( client_id=client.identifier, grant_type=orm.GrantType.authorization_code, expires_at=orm.APIToken.now() + timedelta(seconds=token['expires_in']), refresh_token=token['refresh_token'], - # TODO: save scopes, - # scopes=scopes, + roles=roles, token=token['access_token'], session_id=request.session_id, user=request.user, From ad9ebdd60fa1645b363dd4630bbb7cb63dfb4ff5 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Apr 2021 13:01:15 +0200 Subject: [PATCH 120/270] add missing session_id to newly merged API tokens and remove grant_type which is not a property of the tokens themselves --- jupyterhub/oauth/provider.py | 13 ++++++------ jupyterhub/orm.py | 35 +++++++++++++++++++++++++-------- jupyterhub/tests/populate_db.py | 7 +++++-- jupyterhub/tests/test_api.py | 1 - jupyterhub/tests/test_orm.py | 15 +++++++------- jupyterhub/tests/test_pages.py | 3 ++- 6 files changed, 49 insertions(+), 25 deletions(-) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index bb395752..c1369863 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -345,18 +345,19 @@ class JupyterHubRequestValidator(RequestValidator): # FIXME: pick a role # this will be empty for now roles = list(self.db.query(orm.Role).filter_by(name='identify')) - orm_access_token = orm.APIToken.new( + # FIXME: support refresh tokens + # These should be in a new table + token.pop("refresh_token", None) + + # APIToken.new commits the token to the db + orm.APIToken.new( client_id=client.identifier, - grant_type=orm.GrantType.authorization_code, - expires_at=orm.APIToken.now() + timedelta(seconds=token['expires_in']), - refresh_token=token['refresh_token'], + expires_in=token['expires_in'], roles=roles, token=token['access_token'], session_id=request.session_id, user=request.user, ) - self.db.add(orm_access_token) - self.db.commit() return client.redirect_uri def validate_bearer_token(self, token, scopes, request): diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index a00e265a..c35a7255 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -548,9 +548,15 @@ class APIToken(Hashed, Base): __tablename__ = 'api_tokens' - user_id = Column(Integer, ForeignKey('users.id', ondelete="CASCADE"), nullable=True) + user_id = Column( + Integer, + ForeignKey('users.id', ondelete="CASCADE"), + nullable=True, + ) service_id = Column( - Integer, ForeignKey('services.id', ondelete="CASCADE"), nullable=True + Integer, + ForeignKey('services.id', ondelete="CASCADE"), + nullable=True, ) id = Column(Integer, primary_key=True) @@ -563,12 +569,23 @@ class APIToken(Hashed, Base): # added in 2.0 client_id = Column( - Unicode(255), ForeignKey('oauth_clients.identifier', ondelete='CASCADE') + Unicode(255), + ForeignKey( + 'oauth_clients.identifier', + ondelete='CASCADE', + ), ) - grant_type = Column(Enum(GrantType), nullable=False) - refresh_token = Column(Unicode(255)) - # the browser session id associated with a given token - session_id = Column(Unicode(255)) + # FIXME: refresh_tokens not implemented + # should be a relation to another token table + # refresh_token = Column( + # Integer, + # ForeignKey('refresh_tokens.id', ondelete="CASCADE"), + # nullable=True, + # ) + + # the browser session id associated with a given token, + # if issued during oauth to be stored in a cookie + session_id = Column(Unicode(255), nullable=True) # token metadata for bookkeeping now = datetime.utcnow # for expiry @@ -633,8 +650,10 @@ class APIToken(Hashed, Base): roles=None, note='', generated=True, + session_id=None, expires_in=None, client_id='jupyterhub', + return_orm=False, ): """Generate a new API token for a user or service""" assert user or service @@ -652,8 +671,8 @@ class APIToken(Hashed, Base): orm_token = cls( generated=generated, note=note or '', - grant_type=GrantType.authorization_code, client_id=client_id, + session_id=session_id, ) orm_token.token = token if user: diff --git a/jupyterhub/tests/populate_db.py b/jupyterhub/tests/populate_db.py index ba95104a..4504a13c 100644 --- a/jupyterhub/tests/populate_db.py +++ b/jupyterhub/tests/populate_db.py @@ -6,6 +6,7 @@ used in test_db.py """ import os from datetime import datetime +from functools import partial import jupyterhub from jupyterhub import orm @@ -69,13 +70,15 @@ def populate_db(url): db.add(code) db.commit() if jupyterhub.version_info < (2, 0): - Token = orm.OAuthAccessToken + Token = partial( + orm.OAuthAccessToken, + grant_type=orm.GrantType.authorization_code, + ) else: Token = orm.APIToken access_token = Token( client_id=client.identifier, user_id=user.id, - grant_type=orm.GrantType.authorization_code, ) db.add(access_token) db.commit() diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index a8074b81..2881a69c 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -277,7 +277,6 @@ async def test_get_self(app): user=u.orm_user, client=oauth_client, token=token, - grant_type=orm.GrantType.authorization_code, ) db.add(oauth_token) db.commit() diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index 8187c481..093c29be 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -356,7 +356,8 @@ def test_user_delete_cascade(db): oauth_code = orm.OAuthCode(client=oauth_client, user=user) db.add(oauth_code) oauth_token = orm.APIToken( - client=oauth_client, user=user, grant_type=orm.GrantType.authorization_code + client=oauth_client, + user=user, ) db.add(oauth_token) db.commit() @@ -392,11 +393,12 @@ def test_oauth_client_delete_cascade(db): oauth_code = orm.OAuthCode(client=oauth_client, user=user) db.add(oauth_code) oauth_token = orm.APIToken( - client=oauth_client, user=user, grant_type=orm.GrantType.authorization_code + client=oauth_client, + user=user, ) db.add(oauth_token) db.commit() - assert user.tokens == [oauth_token] + assert user.api_tokens == [oauth_token] # record all of the ids oauth_code_id = oauth_code.id @@ -409,7 +411,7 @@ def test_oauth_client_delete_cascade(db): # verify that everything gets deleted assert_not_found(db, orm.OAuthCode, oauth_code_id) assert_not_found(db, orm.APIToken, oauth_token_id) - assert user.tokens == [] + assert user.api_tokens == [] assert user.oauth_codes == [] @@ -515,10 +517,9 @@ def test_expiring_oauth_token(app, user): db.add(client) orm_token = orm.APIToken( token=token, - grant_type=orm.GrantType.authorization_code, client=client, user=user, - expires_at=now() + datetime.timedelta(seconds=30), + expires_at=now() + timedelta(seconds=30), ) db.add(orm_token) db.commit() @@ -530,7 +531,7 @@ def test_expiring_oauth_token(app, user): found = orm.APIToken.find(db, token) assert found is orm_token - with mock.patch.object(orm.APIToken, 'now', lambda: now() + 60): + with mock.patch.object(orm.APIToken, 'now', lambda: now() + timedelta(seconds=60)): found = orm.APIToken.find(db, token) assert found is None assert orm_token in db.query(orm.APIToken) diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index 3b4b6a39..1bba9926 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -870,7 +870,8 @@ async def test_oauth_token_page(app): client = orm.OAuthClient(identifier='token') app.db.add(client) oauth_token = orm.APIToken( - client=client, user=user, grant_type=orm.GrantType.authorization_code + client=client, + user=user, ) app.db.add(oauth_token) app.db.commit() From 8f36e26b2dc42bee69011278e4f634b21105b2d8 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Apr 2021 13:01:35 +0200 Subject: [PATCH 121/270] create initial oauth client in db fixture --- jupyterhub/tests/conftest.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index eb203029..7efee9c1 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -129,6 +129,12 @@ def db(): user = orm.User(name=getuser()) _db.add(user) _db.commit() + # make sure some initial db contents are filled out + # specifically, the 'default' jupyterhub oauth client + app = MockHub() + app.db = _db + app.init_hub() + app.init_oauth() return _db @@ -164,9 +170,14 @@ def cleanup_after(request, io_loop): allows cleanup of servers between tests without having to launch a whole new app """ + try: yield finally: + if _db is not None: + # cleanup after failed transactions + _db.rollback() + if not MockHub.initialized(): return app = MockHub.instance() From d85c316928618affbf1d24aab42a9b1db2b28e10 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Apr 2021 13:08:16 +0200 Subject: [PATCH 122/270] update db names in init-db.sh for generating upgrade databases for new upgrade-from versions --- ci/init-db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/init-db.sh b/ci/init-db.sh index b510f549..32a73d29 100755 --- a/ci/init-db.sh +++ b/ci/init-db.sh @@ -20,7 +20,7 @@ fi # Configure a set of databases in the database server for upgrade tests set -x -for SUFFIX in '' _upgrade_072 _upgrade_081 _upgrade_094; do +for SUFFIX in '' _upgrade_100 _upgrade_122 _upgrade_130; do $SQL_CLIENT "DROP DATABASE jupyterhub${SUFFIX};" 2>/dev/null || true $SQL_CLIENT "CREATE DATABASE jupyterhub${SUFFIX} ${EXTRA_CREATE_DATABASE_ARGS:-};" done From 834694ca7e3413cf71404b3642bbd255aec455db Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 13 Apr 2021 18:08:51 +0200 Subject: [PATCH 123/270] Refactored names and suggested fixes --- jupyterhub/tests/test_scopes.py | 118 +++++++++++++++++--------------- 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 2799af44..c0f4269d 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -180,7 +180,6 @@ def mock_handler(): ], ) def test_scope_method_access(mock_handler, scopes, method, arguments, is_allowed): - mock_handler = MockAPIHandler() mock_handler.current_user = mock.Mock(name=arguments[0]) mock_handler.set_scopes(*scopes) api_call = getattr(mock_handler, method) @@ -235,7 +234,6 @@ async def test_expand_groups(app, user_name, in_group, status_code): app.db.add(group) if in_group and user not in group.users: group.users.append(user) - kind = 'users' roles.update_roles(app.db, user, roles=['test']) roles.strip_role(app.db, user, 'user') app.db.commit() @@ -261,21 +259,21 @@ err_message = "No access to resources or resources not found" @pytest.fixture -def temp_role(app): +def create_temp_role(app): """Generate a temporary role with certain scopes. - Convenience function that takes care of db stuff and teardown""" + Convenience function that provides setup, database handling and teardown""" temp_roles = [] index = [1] def temp_role_creator(scopes, role_name=None): if not role_name: - role_name = f'test_role_{index[0]}' + role_name = f'temp_role_{index[0]}' index[0] += 1 - role = orm.Role(name=role_name, scopes=list(scopes)) - temp_roles.append(role) - app.db.add(role) + temp_role = orm.Role(name=role_name, scopes=list(scopes)) + temp_roles.append(temp_role) + app.db.add(temp_role) app.db.commit() - return role + return temp_role yield temp_role_creator for role in temp_roles: @@ -284,17 +282,18 @@ def temp_role(app): @pytest.fixture -def user_with_scopes(app, temp_role): +def create_user_with_scopes(app, create_temp_role): """Generate a temporary user with specific scopes. - Takes care of db stuff and teardown""" + Convenience function that provides setup, database handling and teardown""" temp_users = [] - index = [1] - role_function = temp_role + counter = 0 + get_role = create_temp_role def temp_user_creator(*scopes): - name = f"temporary_user_{index[0]}" - index[0] += 1 - role = role_function(scopes) + nonlocal counter + counter += 1 + name = f"temp_user_{counter}" + role = get_role(scopes) orm_user = orm.User(name=name) app.db.add(orm_user) app.db.commit() @@ -308,16 +307,17 @@ def user_with_scopes(app, temp_role): @pytest.fixture -def service_with_scopes(app, temp_role): +def create_service_with_scopes(app, create_temp_role): """Generate a temporary service with specific scopes. - Takes care of db stuff and teardown""" + Convenience function that provides setup, database handling and teardown""" temp_service = [] - index = [1] - role_function = temp_role + counter = 0 + role_function = create_temp_role def temp_service_creator(*scopes): - name = f"temporary_service_{index[0]}" - index[0] += 1 + nonlocal counter + counter += 1 + name = f"temp_service_{counter}" role = role_function(scopes) app.services.append({'name': name}) app.init_services() @@ -332,9 +332,9 @@ def service_with_scopes(app, temp_role): app.db.commit() -async def test_request_fake_user(app, user_with_scopes): +async def test_request_fake_user(app, create_user_with_scopes): fake_user = 'annyong' - user = user_with_scopes('read:users!group=stuff') + user = create_user_with_scopes('read:users!group=stuff') r = await api_request( app, 'users', fake_user, headers=auth_header(app.db, user.name) ) @@ -343,19 +343,23 @@ async def test_request_fake_user(app, user_with_scopes): assert r.json()['message'] == err_message -async def test_refuse_exceeding_token_permissions(app, user_with_scopes, temp_role): - user = user_with_scopes('self') +async def test_refuse_exceeding_token_permissions( + app, create_user_with_scopes, create_temp_role +): + user = create_user_with_scopes('self') user.new_api_token() - temp_role(['admin:users'], 'exceeding_role') + create_temp_role(['admin:users'], 'exceeding_role') with pytest.raises(ValueError): roles.update_roles(app.db, entity=user.api_tokens[0], roles=['exceeding_role']) -async def test_exceeding_user_permissions(app, user_with_scopes, temp_role): - user = user_with_scopes('read:users:groups') +async def test_exceeding_user_permissions( + app, create_user_with_scopes, create_temp_role +): + user = create_user_with_scopes('read:users:groups') api_token = user.new_api_token() orm_api_token = orm.APIToken.find(app.db, token=api_token) - temp_role(['read:users'], 'reader_role') + create_temp_role(['read:users'], 'reader_role') roles.grant_role(app.db, orm_api_token, rolename='reader_role') headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', headers=headers) @@ -365,12 +369,12 @@ async def test_exceeding_user_permissions(app, user_with_scopes, temp_role): assert 'last_activity' not in keys -async def test_user_service_separation(app, mockservice_url, temp_role): +async def test_user_service_separation(app, mockservice_url, create_temp_role): name = mockservice_url.name user = add_user(app.db, name=name) - temp_role(['read:users'], 'reader_role') - temp_role(['read:users:groups'], 'subreader_role') + create_temp_role(['read:users'], 'reader_role') + create_temp_role(['read:users:groups'], 'subreader_role') roles.update_roles(app.db, user, roles=['subreader_role']) roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role']) user.roles.remove(orm.Role.find(app.db, name='user')) @@ -383,9 +387,9 @@ async def test_user_service_separation(app, mockservice_url, temp_role): assert 'last_activity' not in keys -async def test_request_user_outside_group(app, user_with_scopes): +async def test_request_user_outside_group(app, create_user_with_scopes): outside_user = 'hello' - user = user_with_scopes('read:users!group=stuff') + user = create_user_with_scopes('read:users!group=stuff') add_user(app.db, name=outside_user) r = await api_request( app, 'users', outside_user, headers=auth_header(app.db, user.name) @@ -395,8 +399,8 @@ async def test_request_user_outside_group(app, user_with_scopes): assert r.json()['message'] == err_message -async def test_user_filter(app, user_with_scopes): - user = user_with_scopes( +async def test_user_filter(app, create_user_with_scopes): + user = create_user_with_scopes( 'read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar' ) name_in_scope = {'lindsay', 'oscar', 'gob'} @@ -419,7 +423,7 @@ async def test_user_filter(app, user_with_scopes): app.db.commit() -async def test_service_filter(app, user_with_scopes): +async def test_service_filter(app, create_user_with_scopes): services = [ {'name': 'cull_idle', 'api_token': 'some-token'}, {'name': 'user_service', 'api_token': 'some-other-token'}, @@ -427,18 +431,18 @@ async def test_service_filter(app, user_with_scopes): for service in services: app.services.append(service) app.init_services() - user = user_with_scopes('read:services!service=cull_idle') + user = create_user_with_scopes('read:services!service=cull_idle') r = await api_request(app, 'services', headers=auth_header(app.db, user.name)) assert r.status_code == 200 service_names = set(r.json().keys()) assert service_names == {'cull_idle'} -async def test_user_filter_with_group(app, user_with_scopes): +async def test_user_filter_with_group(app, create_user_with_scopes): group_name = 'sitwell' - user1 = user_with_scopes(f'read:users!group={group_name}') - user2 = user_with_scopes('self') - external_user = user_with_scopes('self') + user1 = create_user_with_scopes(f'read:users!group={group_name}') + user2 = create_user_with_scopes('self') + external_user = create_user_with_scopes('self') name_set = {user1.name, user2.name} group = orm.Group.find(app.db, name=group_name) if not group: @@ -457,10 +461,12 @@ async def test_user_filter_with_group(app, user_with_scopes): app.db.commit() -async def test_group_scope_filter(app, user_with_scopes): +async def test_group_scope_filter(app, create_user_with_scopes): in_groups = {'sitwell', 'bluth'} out_groups = {'austero'} - user = user_with_scopes(*(f'read:groups!group={group}' for group in in_groups)) + user = create_user_with_scopes( + *(f'read:groups!group={group}' for group in in_groups) + ) for group_name in in_groups | out_groups: group = orm.Group.find(app.db, name=group_name) if not group: @@ -477,16 +483,16 @@ async def test_group_scope_filter(app, user_with_scopes): app.db.commit() -async def test_vertical_filter(app, user_with_scopes): - user = user_with_scopes('read:users:name') +async def test_vertical_filter(app, create_user_with_scopes): + user = create_user_with_scopes('read:users:name') r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 allowed_keys = {'name', 'kind'} assert set([key for user in r.json() for key in user.keys()]) == allowed_keys -async def test_stacked_vertical_filter(app, user_with_scopes): - user = user_with_scopes('read:users:activity', 'read:users:servers') +async def test_stacked_vertical_filter(app, create_user_with_scopes): + user = create_user_with_scopes('read:users:activity', 'read:users:servers') r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 allowed_keys = {'name', 'kind', 'servers', 'last_activity'} @@ -494,8 +500,8 @@ async def test_stacked_vertical_filter(app, user_with_scopes): assert result_model == allowed_keys -async def test_cross_filter(app, user_with_scopes): - user = user_with_scopes('read:users:activity', 'self') +async def test_cross_filter(app, create_user_with_scopes): + user = create_user_with_scopes('read:users:activity', 'self') new_users = {'britta', 'jeff', 'annie'} for new_user_name in new_users: add_user(app.db, name=new_user_name) @@ -519,12 +525,12 @@ async def test_cross_filter(app, user_with_scopes): ], ) async def test_metascope_self_expansion( - app, kind, has_user_scopes, user_with_scopes, service_with_scopes + app, kind, has_user_scopes, create_user_with_scopes, create_service_with_scopes ): if kind == 'users': - orm_obj = user_with_scopes('self') + orm_obj = create_user_with_scopes('self') else: - orm_obj = service_with_scopes('self') + orm_obj = create_service_with_scopes('self') # test expansion of user/service scopes scopes = roles.expand_roles_to_scopes(orm_obj) assert bool(scopes) == has_user_scopes @@ -535,8 +541,8 @@ async def test_metascope_self_expansion( assert bool(token_scopes) == has_user_scopes -async def test_metascope_all_expansion(app, user_with_scopes): - user = user_with_scopes('self') +async def test_metascope_all_expansion(app, create_user_with_scopes): + user = create_user_with_scopes('self') user.new_api_token() token = user.api_tokens[0] # Check 'all' expansion From c8821b7700758a467d88fd83075e079a74f15b82 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 13 Apr 2021 13:32:16 +0200 Subject: [PATCH 124/270] init default oauth client in init_db ensures jupyterhub client is present, which is required for creation of tokens, etc. --- jupyterhub/app.py | 39 ++++++++++++++++++------------------ jupyterhub/tests/conftest.py | 12 +++++------ 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index f9d1b9a9..cdd130b6 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -214,8 +214,6 @@ class NewToken(Application): hub = JupyterHub(parent=self) hub.load_config_file(hub.config_file) hub.init_db() - hub.init_hub() - hub.init_oauth() def init_users(): loop = asyncio.new_event_loop() @@ -1694,6 +1692,26 @@ class JupyterHub(Application): except orm.DatabaseSchemaMismatch as e: self.exit(e) + # ensure the default oauth client exists + if ( + not self.db.query(orm.OAuthClient) + .filter_by(identifier="jupyterhub") + .one_or_none() + ): + # create the oauth client for jupyterhub itself + # this allows us to distinguish between orphaned tokens + # (failed cascade deletion) and tokens issued by the hub + # it has no client_secret, which means it cannot be used + # to make requests + client = orm.OAuthClient( + identifier="jupyterhub", + secret="", + redirect_uri="", + description="JupyterHub", + ) + self.db.add(client) + self.db.commit() + def init_hub(self): """Load the Hub URL config""" hub_args = dict( @@ -2295,23 +2313,6 @@ class JupyterHub(Application): login_url=url_path_join(base_url, 'login'), token_expires_in=self.oauth_token_expires_in, ) - # ensure the default oauth client exists - if ( - not self.db.query(orm.OAuthClient) - .filter_by(identifier="jupyterhub") - .first() - ): - # create the oauth client for jupyterhub itself - # this allows us to distinguish between orphaned tokens - # (failed cascade deletion) and tokens issued by the hub - # it has no client_secret, which means it cannot be used - # to make requests - self.oauth_provider.add_client( - client_id="jupyterhub", - client_secret="", - redirect_uri="", - description="JupyterHub", - ) def cleanup_oauth_clients(self): """Cleanup any OAuth clients that shouldn't be in the database. diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 7efee9c1..f439bfb0 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -125,16 +125,14 @@ def db(): """Get a db session""" global _db if _db is None: - _db = orm.new_session_factory('sqlite:///:memory:')() + # make sure some initial db contents are filled out + # specifically, the 'default' jupyterhub oauth client + app = MockHub(db_url='sqlite:///:memory:') + app.init_db() + _db = app.db user = orm.User(name=getuser()) _db.add(user) _db.commit() - # make sure some initial db contents are filled out - # specifically, the 'default' jupyterhub oauth client - app = MockHub() - app.db = _db - app.init_hub() - app.init_oauth() return _db From 75fc1544bc69975d6756175a3d1c89e74c759894 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 14 Apr 2021 13:27:30 +0200 Subject: [PATCH 125/270] cleanup rbac db upgrade --- .../alembic/versions/833da8570507_rbac.py | 74 +------------------ 1 file changed, 2 insertions(+), 72 deletions(-) diff --git a/jupyterhub/alembic/versions/833da8570507_rbac.py b/jupyterhub/alembic/versions/833da8570507_rbac.py index a060f10c..b76fc707 100644 --- a/jupyterhub/alembic/versions/833da8570507_rbac.py +++ b/jupyterhub/alembic/versions/833da8570507_rbac.py @@ -16,7 +16,7 @@ import sqlalchemy as sa def upgrade(): - # FIXME: currently drops all api tokens and forces recreation! + # FIXME, maybe: currently drops all api tokens and forces recreation! # this ensures a consistent database, but requires: # 1. all servers to be stopped for upgrade (maybe unavoidable anyway) # 2. any manually issued/stored tokens to be re-issued @@ -31,84 +31,14 @@ def upgrade(): # 3. copy oauth tokens into api tokens # 4. give oauth tokens 'identify' scopes - c = op.get_bind() - naming_convention = { - "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", - } - with op.batch_alter_table( - "api_tokens", - naming_convention=naming_convention, - ) as batch_op: - batch_op.add_column( - sa.Column( - 'client_id', - sa.Unicode(255), - # sa.ForeignKey('oauth_clients.identifier', ondelete='CASCADE'), - nullable=True, - ), - ) - # batch_cursor = op.get_bind() - # batch_cursor.execute( - # """ - # UPDATE api_tokens - # SET client_id='jupyterhub' - # WHERE client_id IS NULL - # """ - # ) - batch_op.create_foreign_key( - "fk_api_token_client_id", - # 'api_tokens', - 'oauth_clients', - ['client_id'], - ['identifier'], - ondelete='CASCADE', - ) - - c.execute( - """ - UPDATE api_tokens - SET client_id='jupyterhub' - WHERE client_id IS NULL - """ - ) - - op.add_column( - 'api_tokens', - sa.Column( - 'grant_type', - sa.Enum( - 'authorization_code', - 'implicit', - 'password', - 'client_credentials', - 'refresh_token', - name='granttype', - ), - server_default='authorization_code', - nullable=False, - ), - ) - op.add_column( - 'api_tokens', sa.Column('refresh_token', sa.Unicode(length=255), nullable=True) - ) - op.add_column( - 'api_tokens', sa.Column('session_id', sa.Unicode(length=255), nullable=True) - ) - - # TODO: migrate OAuth tokens into APIToken table - - op.drop_index('ix_oauth_access_tokens_prefix', table_name='oauth_access_tokens') - op.drop_table('oauth_access_tokens') - def downgrade(): # delete OAuth tokens for non-jupyterhub clients # drop new columns from api tokens op.drop_constraint(None, 'api_tokens', type_='foreignkey') op.drop_column('api_tokens', 'session_id') - op.drop_column('api_tokens', 'refresh_token') - op.drop_column('api_tokens', 'grant_type') op.drop_column('api_tokens', 'client_id') + # FIXME: only drop tokens whose client id is not 'jupyterhub' # until then, drop all tokens op.drop_table("api_tokens") From 6093f9d4447af884c73eaea0f45c8878d98ae824 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 15 Apr 2021 10:45:39 +0200 Subject: [PATCH 126/270] Fix log message about modifying roles --- jupyterhub/roles.py | 7 ++++-- jupyterhub/tests/test_roles.py | 44 ++++++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index e4bc2e1e..e67c3a19 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -221,8 +221,11 @@ def _overwrite_role(role, role_dict): 'admin role description or scopes cannot be overwritten' ) else: - setattr(role, attr, role_dict[attr]) - app_log.info('Role %r %r attribute has been changed', role.name, attr) + if role_dict[attr] != getattr(role, attr): + setattr(role, attr, role_dict[attr]) + app_log.info( + 'Role %r %r attribute has been changed', role.name, attr + ) def create_role(db, role_dict): diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 5192ccf9..94e1aba8 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -246,6 +246,16 @@ async def test_load_default_roles(tmpdir, request): 'info', app_log.info('Role new-role added to database'), ), + ( + 'the-same-role', + { + 'name': 'new-role', + 'description': 'Some description', + 'scopes': ['groups'], + }, + 'no-log', + None, + ), ('no_name', {'scopes': ['users']}, 'error', KeyError), ( 'no_scopes', @@ -271,28 +281,28 @@ async def test_load_default_roles(tmpdir, request): 'info', app_log.info('Role user scopes attribute has been changed'), ), + # rewrite the user role back to 'default' + ( + 'user', + {'name': 'user', 'scopes': ['self']}, + 'info', + app_log.info('Role user scopes attribute has been changed'), + ), ], ) -async def test_adding_new_roles( - tmpdir, request, role, role_def, response_type, response -): - """Test raising errors and warnings when creating new roles""" +async def test_creating_roles(app, role, role_def, response_type, response): + """Test raising errors and warnings when creating/modifying roles""" - kwargs = {'load_roles': [role_def]} - ssl_enabled = getattr(request.module, "ssl_enabled", False) - if ssl_enabled: - kwargs['internal_certs_location'] = str(tmpdir) - hub = MockHub(**kwargs) - hub.init_db() - db = hub.db + db = app.db if response_type == 'error': with pytest.raises(response): - await hub.init_roles() + roles.create_role(db, role_def) elif response_type == 'warning' or response_type == 'info': with pytest.warns(response): - await hub.init_roles() + roles.create_role(db, role_def) + # check the role has been created/modified role = orm.Role.find(db, role_def['name']) assert role is not None if 'description' in role_def.keys(): @@ -300,6 +310,14 @@ async def test_adding_new_roles( if 'scopes' in role_def.keys(): assert role.scopes == role_def['scopes'] + # make sure no warnings/info logged when the role exists and its definition hasn't been changed + elif response_type == 'no-log': + with pytest.warns(response) as record: + roles.create_role(db, role_def) + assert not record.list + role = orm.Role.find(db, role_def['name']) + assert role is not None + @mark.role @mark.parametrize( From 0e55064056a3ef5422b26a7924d3a1b3144333a8 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 15 Apr 2021 10:48:04 +0200 Subject: [PATCH 127/270] Remove duplicate scopes assignment for expand_roles_to_scopes() --- jupyterhub/roles.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index e67c3a19..1c520873 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -154,8 +154,6 @@ def _expand_scope(scopename): def expand_roles_to_scopes(orm_object): - """Get the scopes listed in the roles of the User/Service/Group/Token""" - scopes = _get_subscopes(*orm_object.roles) """Get the scopes listed in the roles of the User/Service/Group/Token If User, take into account the user's groups roles as well""" From 7544965145b8c15f793151a66d860453a41bf4ef Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 15 Apr 2021 16:34:46 +0200 Subject: [PATCH 128/270] Fixed server model, removed some auth decorators --- jupyterhub/apihandlers/base.py | 57 ++++++++++++++---------------- jupyterhub/apihandlers/services.py | 22 ------------ jupyterhub/apihandlers/users.py | 24 ++----------- jupyterhub/roles.py | 24 ++++++++----- jupyterhub/tests/test_scopes.py | 10 ++---- jupyterhub/utils.py | 13 ------- 6 files changed, 46 insertions(+), 104 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 9832afc5..1659a001 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -87,29 +87,23 @@ class APIHandler(BaseHandler): """ if sub_scope == scopes.Scope.ALL: return True - else: - try: - found_resource = orm_resource.name in sub_scope[kind] - except KeyError: - found_resource = False - if not found_resource: # Try group-based access - if kind == 'server' and 'user' in sub_scope: - # First check if we have access to user info - user_name = orm_resource.user.name - found_resource = user_name in sub_scope['user'] - if not found_resource: - # Now check for specific servers: - server_format = f"{orm_resource.user / orm_resource.name}" - found_resource = server_format in sub_scope[kind] - elif 'group' in sub_scope: - group_names = set() - if kind == 'user': - group_names = {group.name for group in orm_resource.groups} - elif kind == 'server': - group_names = {group.name for group in orm_resource.user.groups} - user_in_group = bool(group_names & set(sub_scope['group'])) - found_resource = user_in_group - return found_resource + elif orm_resource.name in sub_scope.get(kind, []): + return True + if kind == 'server': + server_format = f"{orm_resource.user.name}/{orm_resource.name}" + if server_format in sub_scope.get(kind, []): + return True + # Fall back on checking if we have user access + if orm_resource.user.name in sub_scope.get('user', []): + return True + # Fall back on checking if we have group access for this user + orm_resource = orm_resource.user + if 'group' in sub_scope: + group_names = {group.name for group in orm_resource.groups} + user_in_group = bool(group_names & set(sub_scope['group'])) + if user_in_group: + return True + return False return has_access_to @@ -183,8 +177,8 @@ class APIHandler(BaseHandler): ) def server_model(self, spawner): - """Get the JSON model for a Spawner""" - server_scope = 'read:users:servers' + """Get the JSON model for a Spawner + Assume server permission already granted""" server_state_scope = 'admin:users:server_state' model = { 'name': spawner.name, @@ -196,7 +190,6 @@ class APIHandler(BaseHandler): 'user_options': spawner.user_options, 'progress_url': spawner._progress_url, } - # First check users, then servers if server_state_scope in self.parsed_scopes: scope_filter = self.get_scope_filter(server_state_scope) if scope_filter(spawner, kind='server'): @@ -260,7 +253,6 @@ class APIHandler(BaseHandler): 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, 'admin:users:auth_state': {'kind', 'name', 'auth_state'}, - 'admin:users:server_state': {'kind', 'name', 'servers', 'server_state'}, } self.log.debug( "Asking for user model of %s with scopes [%s]", @@ -277,13 +269,18 @@ class APIHandler(BaseHandler): if model: if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending - if 'servers' in allowed_keys: - servers = model['servers'] = {} + + servers = model['servers'] = {} + scope = 'read:users:servers' + if scope in self.parsed_scopes: + scope_filter = self.get_scope_filter('read:users:servers') for name, spawner in user.spawners.items(): # include 'active' servers, not just ready # (this includes pending events) - if spawner.active: + if spawner.active and scope_filter(spawner, kind='server'): servers[name] = self.server_model(spawner) + if not servers: + model.pop('servers') return model def group_model(self, group): diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 4d7247d0..f0b87c30 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -40,28 +40,6 @@ class ServiceListAPIHandler(APIHandler): self.write(json.dumps(data)) -def admin_or_self(method): - """Decorator for restricting access to either the target service or admin""" - """***Deprecated in favor of RBAC. Use scope-based decorator***""" - - def decorated_method(self, name): - current = self.current_user - if current is None: - raise web.HTTPError(403) - if not current.admin: - # not admin, maybe self - if not isinstance(current, orm.Service): - raise web.HTTPError(403) - if current.name != name: - raise web.HTTPError(403) - # raise 404 if not found - if name not in self.services: - raise web.HTTPError(404) - return method(self, name) - - return decorated_method - - class ServiceAPIHandler(APIHandler): @needs_scope('read:services') def get(self, service_name): diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 492a3a29..5010d1c7 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -169,24 +169,6 @@ class UserListAPIHandler(APIHandler): self.set_status(201) -def admin_or_self(method): - """Decorator for restricting access to either the target user or admin""" - - def m(self, name, *args, **kwargs): - current = self.current_user - if current is None: - raise web.HTTPError(403) - if not (current.name == name or current.admin): - raise web.HTTPError(403) - - # raise 404 if not found - if not self.find_user(name): - raise web.HTTPError(404) - return method(self, name, *args, **kwargs) - - return m - - class UserAPIHandler(APIHandler): @needs_scope( 'read:users', @@ -195,9 +177,7 @@ class UserAPIHandler(APIHandler): 'read:users:groups', 'read:users:activity', ) - async def get( - self, user_name - ): # Fixme: Does not work when only server filter is selected + async def get(self, user_name): user = self.find_user(user_name) model = self.user_model(user) # auth state will only be shown if the requester is an admin @@ -268,7 +248,7 @@ class UserAPIHandler(APIHandler): self.set_status(204) - @needs_scope('admin:users') # Todo: Change to `users`? + @needs_scope('admin:users') async def patch(self, user_name): user = self.find_user(user_name) if user is None: diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index e4bc2e1e..051b3c07 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -24,6 +24,7 @@ def get_default_roles(): 'scopes': [ 'all', 'users', + 'users:servers', 'users:tokens', 'admin:users', 'admin:users:servers', @@ -51,7 +52,7 @@ def get_default_roles(): return default_roles -def expand_self_scope(name, read_only=False): +def expand_self_scope(name): """ Users have a metascope 'self' that should be expanded to standard user privileges. At the moment that is a user-filtered version (optional read) access to @@ -71,10 +72,7 @@ def expand_self_scope(name, read_only=False): 'users:tokens', ] read_scope_list = ['read:' + scope for scope in scope_list] - if read_only: - scope_list = read_scope_list - else: - scope_list.extend(read_scope_list) + scope_list.extend(read_scope_list) return {"{}!user={}".format(scope, name) for scope in scope_list} @@ -87,18 +85,18 @@ def _get_scope_hierarchy(): scopes = { 'self': None, - 'all': None, # Optional 'read:all' as subscope, not implemented at this stage - 'users': ['read:users', 'users:activity', 'users:servers'], + 'all': None, + 'users': ['read:users', 'users:groups', 'users:activity'], 'read:users': [ 'read:users:name', 'read:users:groups', 'read:users:activity', - 'read:users:servers', ], 'users:tokens': ['read:users:tokens'], 'admin:users': ['admin:users:auth_state'], 'admin:users:servers': ['admin:users:server_state'], 'groups': ['read:groups'], + 'users:servers': ['read:users:servers'], 'admin:groups': None, 'read:services': None, 'read:hub': None, @@ -112,13 +110,21 @@ def _get_scope_hierarchy(): def horizontal_filter(func): """Decorator to account for horizontal filtering in scope syntax""" + def expand_server_filter(hor_filter): + resource, mark, value = hor_filter.partition('=') + if resource == 'server': + user, mark, server = value.partition('/') + return f'read:users:name!user={user}' + def ignore(scopename): # temporarily remove horizontal filtering if present scopename, mark, hor_filter = scopename.partition('!') expanded_scope = func(scopename) # add the filter back full_expanded_scope = {scope + mark + hor_filter for scope in expanded_scope} - + server_filter = expand_server_filter(hor_filter) + if server_filter: + full_expanded_scope.add(server_filter) return full_expanded_scope return ignore diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index c0f4269d..e16e6f5f 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -561,6 +561,7 @@ async def test_metascope_all_expansion(app, create_user_with_scopes): "scopes, can_stop ,num_servers, keys_in, keys_out", [ (['read:users:servers!user=almond'], False, 2, {'name'}, {'state'}), + (['admin:users', 'read:users'], False, 0, set(), set()), (['read:users:servers!group=nuts'], False, 2, {'name'}, {'state'}), ( ['admin:users:server_state', 'read:users:servers'], @@ -569,15 +570,13 @@ async def test_metascope_all_expansion(app, create_user_with_scopes): {'name', 'state'}, set(), ), - (['users:servers', 'read:users:name'], True, 0, set(), set()), ( [ - 'read:users:name!user=almond', 'read:users:servers!server=almond/bianca', 'admin:users:server_state!server=almond/bianca', ], False, - 0, # fixme: server-scope not working yet + 1, {'name', 'state'}, set(), ), @@ -590,11 +589,6 @@ async def test_server_state_access( app.tornado_settings, {'allow_named_servers': True, 'named_server_limit_per_user': 2}, ): - ## 1. Test a user can access all servers without auth_state - ## 2. Test a service with admin:user but no admin:users:servers gets no access to any server data - ## 3. Test a service with admin:user:server_state gets access to auth_state - ## 4. Test a service with user:servers!server=x gives access to one server, and the correct server. - ## 5. Test a service with users:servers!group=x gives access to both servers username = 'almond' user = add_user(app.db, app, name=username) group_name = 'nuts' diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index d420c13c..73905ea2 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -287,19 +287,6 @@ def authenticated_403(self): raise web.HTTPError(403) -@auth_decorator -def admin_only(self): - """Decorator for restricting access to admin users - Deprecated in favor of scopes.need_scope() - """ - user = self.current_user - app_log.warning( - "Admin decorator is deprecated and will be removed soon. Use scope-based decorator instead" - ) - if user is None or not user.admin: - raise web.HTTPError(403) - - @auth_decorator def metrics_authentication(self): """Decorator for restricting access to metrics""" From cb104ffe42e8ba28537e065d7c99140c4ec05864 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 15 Apr 2021 17:30:13 +0200 Subject: [PATCH 129/270] Fixed tests --- jupyterhub/apihandlers/base.py | 17 ++++++++--------- jupyterhub/tests/test_api.py | 2 +- jupyterhub/tests/test_named_servers.py | 4 ++-- jupyterhub/tests/test_roles.py | 4 +--- jupyterhub/tests/test_scopes.py | 4 ++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 1659a001..2522ee3b 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -70,14 +70,12 @@ class APIHandler(BaseHandler): """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. Filter is a callable that takes a resource name and outputs true or false""" - try: - sub_scope = self.parsed_scopes[req_scope] - except AttributeError: - raise web.HTTPError( - 403, - "Resource scope %s (that was just accessed) not found in parsed scope model" - % req_scope, - ) + def has_no_access(orm_resource, kind): + return False + + if req_scope not in self.parsed_scopes: + return has_no_access + sub_scope = self.parsed_scopes[req_scope] def has_access_to(orm_resource, kind): """ @@ -98,7 +96,8 @@ class APIHandler(BaseHandler): return True # Fall back on checking if we have group access for this user orm_resource = orm_resource.user - if 'group' in sub_scope: + kind = 'user' + if kind == 'user' and 'group' in sub_scope: group_names = {group.name for group in orm_resource.groups} user_in_group = bool(group_names & set(sub_scope['group'])) if user_in_group: diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 2881a69c..6597e587 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -158,7 +158,7 @@ def fill_user(model): model.setdefault('pending', None) model.setdefault('created', TIMESTAMP) model.setdefault('last_activity', TIMESTAMP) - model.setdefault('servers', {}) + # model.setdefault('servers', {}) return model diff --git a/jupyterhub/tests/test_named_servers.py b/jupyterhub/tests/test_named_servers.py index 88a48d6d..e07f405f 100644 --- a/jupyterhub/tests/test_named_servers.py +++ b/jupyterhub/tests/test_named_servers.py @@ -86,7 +86,7 @@ async def test_default_server(app, named_servers): user_model = normalize_user(r.json()) assert user_model == fill_user( - {'name': username, 'roles': ['user'], 'servers': {}, 'auth_state': None} + {'name': username, 'roles': ['user'], 'auth_state': None} ) @@ -160,7 +160,7 @@ async def test_delete_named_server(app, named_servers): user_model = normalize_user(r.json()) assert user_model == fill_user( - {'name': username, 'roles': ['user'], 'auth_state': None, 'servers': {}} + {'name': username, 'roles': ['user'], 'auth_state': None} ) # wrapper Spawner is gone assert servername not in user.spawners diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 5192ccf9..279324cf 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -181,11 +181,10 @@ def test_orm_roles_delete_cascade(db): 'users', 'read:users', 'users:activity', - 'users:servers', + 'users:groups', 'read:users:name', 'read:users:groups', 'read:users:activity', - 'read:users:servers', }, ), ( @@ -195,7 +194,6 @@ def test_orm_roles_delete_cascade(db): 'read:users:name', 'read:users:groups', 'read:users:activity', - 'read:users:servers', }, ), (['read:users:servers'], {'read:users:servers'}), diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index e16e6f5f..e9190bcc 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -492,10 +492,10 @@ async def test_vertical_filter(app, create_user_with_scopes): async def test_stacked_vertical_filter(app, create_user_with_scopes): - user = create_user_with_scopes('read:users:activity', 'read:users:servers') + user = create_user_with_scopes('read:users:activity', 'read:users:groups') r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 - allowed_keys = {'name', 'kind', 'servers', 'last_activity'} + allowed_keys = {'name', 'kind', 'groups', 'last_activity'} result_model = set([key for user in r.json() for key in user.keys()]) assert result_model == allowed_keys From b23385902803861c3b7206464030a0d43846eacd Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 16 Apr 2021 14:03:31 +0200 Subject: [PATCH 130/270] Refactored scope_filter --- jupyterhub/apihandlers/base.py | 73 +++++++++++++++------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 2522ee3b..f630e350 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -13,6 +13,7 @@ from tornado import web from .. import orm from .. import scopes from ..handlers import BaseHandler +from ..user import User from ..utils import isoformat from ..utils import url_path_join @@ -70,18 +71,17 @@ class APIHandler(BaseHandler): """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. Filter is a callable that takes a resource name and outputs true or false""" - def has_no_access(orm_resource, kind): + def no_access(orm_resource, kind): return False if req_scope not in self.parsed_scopes: - return has_no_access + return no_access sub_scope = self.parsed_scopes[req_scope] def has_access_to(orm_resource, kind): """ param orm_resource: User or Service or Group or spawner param kind: 'user' or 'service' or 'group' or 'server'. - `kind` could probably be derived from `orm_resource`, problem is Jupyterhub.users.User """ if sub_scope == scopes.Scope.ALL: return True @@ -178,7 +178,6 @@ class APIHandler(BaseHandler): def server_model(self, spawner): """Get the JSON model for a Spawner Assume server permission already granted""" - server_state_scope = 'admin:users:server_state' model = { 'name': spawner.name, 'last_activity': isoformat(spawner.orm_spawner.last_activity), @@ -189,10 +188,9 @@ class APIHandler(BaseHandler): 'user_options': spawner.user_options, 'progress_url': spawner._progress_url, } - if server_state_scope in self.parsed_scopes: - scope_filter = self.get_scope_filter(server_state_scope) - if scope_filter(spawner, kind='server'): - model['state'] = spawner.get_state() + scope_filter = self.get_scope_filter('admin:users:server_state') + if scope_filter(spawner, kind='server'): + model['state'] = spawner.get_state() return model def token_model(self, token): @@ -260,24 +258,21 @@ class APIHandler(BaseHandler): ) allowed_keys = set() for scope in access_map: - if scope in self.parsed_scopes: - scope_filter = self.get_scope_filter(scope) - if scope_filter(user, kind='user'): - allowed_keys |= access_map[scope] + scope_filter = self.get_scope_filter(scope) + if scope_filter(user, kind='user'): + allowed_keys |= access_map[scope] model = {key: model[key] for key in allowed_keys if key in model} if model: if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending servers = model['servers'] = {} - scope = 'read:users:servers' - if scope in self.parsed_scopes: - scope_filter = self.get_scope_filter('read:users:servers') - for name, spawner in user.spawners.items(): - # include 'active' servers, not just ready - # (this includes pending events) - if spawner.active and scope_filter(spawner, kind='server'): - servers[name] = self.server_model(spawner) + scope_filter = self.get_scope_filter('read:users:servers') + for name, spawner in user.spawners.items(): + # include 'active' servers, not just ready + # (this includes pending events) + if spawner.active and scope_filter(spawner, kind='server'): + servers[name] = self.server_model(spawner) if not servers: model.pop('servers') return model @@ -285,32 +280,28 @@ class APIHandler(BaseHandler): def group_model(self, group): """Get the JSON model for a Group object""" model = {} - req_scope = 'read:groups' - if req_scope in self.parsed_scopes: - scope_filter = self.get_scope_filter(req_scope) - if scope_filter(group, kind='group'): - model = { - 'kind': 'group', - 'name': group.name, - 'roles': [r.name for r in group.roles], - 'users': [u.name for u in group.users], - } + scope_filter = self.get_scope_filter('read:groups') + if scope_filter(group, kind='group'): + model = { + 'kind': 'group', + 'name': group.name, + 'roles': [r.name for r in group.roles], + 'users': [u.name for u in group.users], + } return model def service_model(self, service): """Get the JSON model for a Service object""" model = {} - req_scope = 'read:services' - if req_scope in self.parsed_scopes: - scope_filter = self.get_scope_filter(req_scope) - if scope_filter(service, kind='service'): - model = { - 'kind': 'service', - 'name': service.name, - 'roles': [r.name for r in service.roles], - 'admin': service.admin, - } - # todo: Remove once we replace admin flag with role check + scope_filter = self.get_scope_filter('read:services') + if scope_filter(service, kind='service'): + model = { + 'kind': 'service', + 'name': service.name, + 'roles': [r.name for r in service.roles], + 'admin': service.admin, + } + # todo: Remove once we replace admin flag with role check return model _user_model_types = { From 46e2f72fa65372a072a175047642837b70155a08 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 16 Apr 2021 14:54:04 +0200 Subject: [PATCH 131/270] Test server start/stop --- jupyterhub/apihandlers/users.py | 2 +- jupyterhub/tests/test_scopes.py | 104 ++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 5010d1c7..23ac0027 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -301,7 +301,7 @@ class UserTokenListAPIHandler(APIHandler): self.write(json.dumps({'api_tokens': api_tokens})) - # Todo: Set to @needs_scope('users:tokens') + @needs_scope('users:tokens') async def post(self, user_name): body = self.get_json_body() or {} if not isinstance(body, dict): diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index e9190bcc..98a5dc93 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -289,10 +289,11 @@ def create_user_with_scopes(app, create_temp_role): counter = 0 get_role = create_temp_role - def temp_user_creator(*scopes): + def temp_user_creator(*scopes, name=None): nonlocal counter - counter += 1 - name = f"temp_user_{counter}" + if name is None: + counter += 1 + name = f"temp_user_{counter}" role = get_role(scopes) orm_user = orm.User(name=name) app.db.add(orm_user) @@ -314,10 +315,11 @@ def create_service_with_scopes(app, create_temp_role): counter = 0 role_function = create_temp_role - def temp_service_creator(*scopes): + def temp_service_creator(*scopes, name=None): nonlocal counter - counter += 1 - name = f"temp_service_{counter}" + if name is None: + counter += 1 + name = f"temp_service_{counter}" role = role_function(scopes) app.services.append({'name': name}) app.init_services() @@ -562,10 +564,16 @@ async def test_metascope_all_expansion(app, create_user_with_scopes): [ (['read:users:servers!user=almond'], False, 2, {'name'}, {'state'}), (['admin:users', 'read:users'], False, 0, set(), set()), - (['read:users:servers!group=nuts'], False, 2, {'name'}, {'state'}), + ( + ['read:users:servers!group=nuts', 'users:servers'], + True, + 2, + {'name'}, + {'state'}, + ), ( ['admin:users:server_state', 'read:users:servers'], - True, # Todo: test for server stop + False, 2, {'name', 'state'}, set(), @@ -583,14 +591,20 @@ async def test_metascope_all_expansion(app, create_user_with_scopes): ], ) async def test_server_state_access( - app, scopes, can_stop, num_servers, keys_in, keys_out + app, + create_user_with_scopes, + create_service_with_scopes, + scopes, + can_stop, + num_servers, + keys_in, + keys_out, ): with mock.patch.dict( app.tornado_settings, {'allow_named_servers': True, 'named_server_limit_per_user': 2}, ): - username = 'almond' - user = add_user(app.db, app, name=username) + user = create_user_with_scopes('self', name='almond') group_name = 'nuts' group = orm.Group.find(app.db, name=group_name) if not group: @@ -599,36 +613,38 @@ async def test_server_state_access( group.users.append(user) app.db.commit() server_names = ['bianca', 'terry'] - try: - for server_name in server_names: - await api_request( - app, 'users', username, 'servers', server_name, method='post' - ) - role = orm.Role(name=f"{username}-role", scopes=scopes) - app.db.add(role) - app.db.commit() - service_name = 'server_accessor' - service = orm.Service(name=service_name) - app.db.add(service) - service.roles.append(role) - app.db.commit() - api_token = service.new_api_token() - await app.init_roles() - headers = {'Authorization': 'token %s' % api_token} - r = await api_request(app, 'users', username, headers=headers) - r.raise_for_status() - user_model = r.json() - if num_servers: - assert 'servers' in user_model - server_models = user_model['servers'] - assert len(server_models) == num_servers - for server, server_model in server_models.items(): - assert keys_in.issubset(server_model) - assert keys_out.isdisjoint(server_model) - else: - assert 'servers' not in user_model - finally: - app.db.delete(role) - app.db.delete(service) - app.db.delete(group) - app.db.commit() + for server_name in server_names: + await api_request( + app, 'users', user.name, 'servers', server_name, method='post' + ) + service = create_service_with_scopes(*scopes) + api_token = service.new_api_token() + await app.init_roles() + headers = {'Authorization': 'token %s' % api_token} + r = await api_request(app, 'users', user.name, headers=headers) + r.raise_for_status() + user_model = r.json() + if num_servers: + assert 'servers' in user_model + server_models = user_model['servers'] + assert len(server_models) == num_servers + for server, server_model in server_models.items(): + assert keys_in.issubset(server_model) + assert keys_out.isdisjoint(server_model) + else: + assert 'servers' not in user_model + r = await api_request( + app, + 'users', + user.name, + 'servers', + server_names[0], + method='delete', + headers=headers, + ) + if can_stop: + assert r.status_code == 204 + else: + assert r.status_code == 403 + app.db.delete(group) + app.db.commit() From c6e3e06af901db3e70ebcc7f55553b45b86caf62 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 16 Apr 2021 16:31:01 +0200 Subject: [PATCH 132/270] Add Upgrade section to docs/source/rbac/upgrade.md --- docs/source/rbac/scopes.md | 2 ++ docs/source/rbac/upgrade.md | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index cdc07a89..957ea212 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -76,6 +76,8 @@ In case the client has multiple subscopes, the call returns the union of the dat The payload of an API call can be filtered both horizontally and vertically simultaneously. For instance, performing an API call to the endpoint `/users/` with the scope `users:name!user=juliette` returns a payload of `[{name: 'juliette'}]` (provided that this name is present in the database). +(available-scopes-target)= + ## Available scopes Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them. diff --git a/docs/source/rbac/upgrade.md b/docs/source/rbac/upgrade.md index 64e488d8..8fb7b708 100644 --- a/docs/source/rbac/upgrade.md +++ b/docs/source/rbac/upgrade.md @@ -1 +1,54 @@ # Upgrading JupyterHub with RBAC framework + +RBAC framework requires different database setup than any previous JupyterHub versions due to eliminating the distinction between OAuth and API tokens (see {ref}`oauth-vs-api-tokens-target` for more details). This requires merging the previously two different database tables into one. By doing so, all existing tokens created before the upgrade no longer comply with the new database version and must be replaced. + +This is achieved by the Hub deleting all existing tokens during the database upgrade and recreating the tokens loaded via the `jupyterhub_config.py` file with updated structure. However, any manually issued or stored tokens are not recreated automatically and must be manually re-issued after the upgrade. + +No other database records are affected. + +(rbac-upgrade-steps-target)= + +## Upgrade steps + +1. All running **servers must be stopped** before proceeding with the upgrade. +2. To upgrade the Hub, follow the [Upgrading JupyterHub](../admin/upgrading.rst) instructions. + ```{attention} + We advise against defining any new roles in the `jupyterhub.config.py` file right after the upgrade is completed and JupyterHub restarted for the first time. This preserves the 'current' state of the Hub. You can define and assign new roles on any other following startup. + ``` +3. After restarting the Hub **re-issue all tokens that were previously issued manually** (i.e., not through the `jupyterhub_config.py` file). + +When the JupyterHub is restarted for the first time after the upgrade, all users, services and tokens stored in the database or re-loaded through the configuration file will be assigned their default role. Any newly added entities after that will be assigned their default role only if no other specific role is requested for them. + +## Changing the permissions after the upgrade + +Once all the {ref}`upgrade steps ` above are completed, the RBAC framework will be available for utilization. You can define new roles, modify default roles (apart from `admin`) and assign them to entities as described in the {ref}`define_role_target` section. + +We recommended the following procedure to start with RBAC: + +1. Identify which admin users and services you would like to grant only the permissions they need through the new roles +2. Strip these users and services of their admin status via API or UI. This will change their roles from `admin` to `user`. + ```{note} + Stripping entities of their roles is currently under development and will be available only via API/UI. + ``` +3. Define new roles that you would like to start using with appropriate scopes and assign them to these entities in `jupyterhub_config.py`. +4. Restart the JupyterHub for the new roles to take effect. + +(oauth-vs-api-tokens-target)= + +## OAuth vs API tokens + +### Before RBAC + +Previous JupyterHub versions utilize two types of tokens, OAuth token and API token. + +OAuth token is issued by the Hub to a single-user server when the user logs in. The token is stored in the browser cookie and is used to identify the user who owns the server during the OAuth flow. This token by default expires when the cookie reaches its expiry time of 2 weeks (or after 1 hour in JupyterHub versions < 1.3.0). + +API token is issued by the Hub to a single-user server when launched and is used to communicate with the Hub's APIs such as posting activity or completing the OAuth flow. This token has no expiry by default. + +API tokens can also be issued to users via API ([_/hub/token_](../reference/urls.md) or [_POST /users/:username/tokens_](../reference/rest-api.rst)) and services via `jupyterhub_config.py` to perform API requests. + +### With RBAC + +The RBAC framework allows for granting tokens different levels of permissions via scopes attached to roles. The 'only identify' purpose of the separate OAuth tokens is no longer required. API tokens can be used used for every action, including the login and authentication, for which an API token with no role (i.e., no scope in {ref}`available-scopes-target`) is used. + +OAuth tokens are therefore dropped from the Hub upgraded with the RBAC framework. From b0f45487539c30a28904fcca494e986ebfd8ba70 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 16 Apr 2021 16:49:15 +0200 Subject: [PATCH 133/270] Add read:users(services):roles scopes to docs/source/rbac/scopes.md --- docs/source/rbac/scopes.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index 957ea212..bba8c517 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -94,18 +94,21 @@ Table 1. Available scopes and their hierarchy |       `users:activity` | Grants access to read and post users' activity only. | |       `read:users` | Read-only access to users' models _apart from servers, tokens and authentication state_. | |          `read:users:name` | Read-only access to users' names. | +|          `read:users:roles` | Read-only access to a list of users' roles names. | |          `read:users:groups` | Read-only access to users' groups. | |          `read:users:activity` | Read-only access to users' activity. | | `admin:users:servers` | Grants read, start/stop, create and delete permissions to users' servers and their state. | |    `admin:users:server_state` | Grants access to servers' state only. | -|    `users:servers` | Allows for starting/stopping users' servers in addition to read access. _Does not include the server state_. | -|       `read:users:servers` | Read-only access to users' servers. _Does not include the server state_. | +|    `users:servers` | Allows for starting/stopping users' servers in addition to read access to their models. _Does not include the server state_. | +|       `read:users:servers` | Read-only access to users' server models. _Does not include the server state_. | | `users:tokens` | Grants read, write, create and delete permissions to users' tokens. | |    `read:users:tokens` | Read-only access to users' tokens. | | `admin:groups` | Grants read, write, create and delete access to groups. | |    `groups` | Grants read and write permissions to groups, including adding/removing users to/from groups. | |       `read:groups` | Read-only access to groups. | -| `read:services` | Read-only access to services. | +| `read:services` | Read-only access to service models. | +|    `read:services:name` | Read-only access to service names. | +|    `read:services:roles` | Read-only access to a list of service roles names. | | `read:hub` | Read-only access to detailed information about the Hub. | | `proxy` | Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. | | `shutdown` | Grants access to shutdown the hub. | From 0638783939736c86c42af2fb74c5817c94071dd1 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 16 Apr 2021 17:11:46 +0200 Subject: [PATCH 134/270] Synchronize docs/rest-api.yml with Available scopes table in docs/source/rbac/scopes.md --- docs/rest-api.yml | 59 ++++++++++++++++++++------------------ docs/source/rbac/scopes.md | 2 +- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 6263bfec..cbd82736 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -18,34 +18,37 @@ securityDefinitions: authorizationUrl: "/hub/api/oauth2/authorize" # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? tokenUrl: "/hub/api/oauth2/token" scopes: - self: Everything a standard user can do - all: Everything a token owner can do - users: Grants access to managing users including reading users’ model, posting activity and starting/stoping users servers - read:users: Read-only access to the above - read:users!user=username: Read-only access to a single user's model (example horizontal filter) - read:users:name: Read-only access to users' names - read:users:groups: Read-only access to users' groups - read:users:activity: Read-only access to users' activity - read:users:activity!group=groupname: Read-only access to specific group's users' activity (example horizontal filter) - users:activity: Update users' activity - users:activity!user=username: Update a single user's activity (example horizontal filter) - users:servers: Grants access to start/stop any server - users:servers!server=servername: Limits the above to a specific server (example horizontal filter) - read:users:servers: Read-only access to users' servers - users:tokens: Grants access to users' token (includes create/revoke a token) - read:users:tokens: Read-only access to users' tokens - admin:users: Grants access to creating/removing users on top of managing access - admin:users:auth_state: Access users' auth state - admin:users:servers: Grants access to create/remove users' servers on top of managing access - admin:users:server_state: Access servers' state - groups: Add/remove users from any group - groups!group=groupname: Add/remove users from a specific group only (example horizontal filter) - read:groups: Read-only access to groups - admin:groups: Grants access to create/delete groups - read:services: Read-only access to services - read:hub: Read-only access to detailed information about JupyterHub - proxy: Grants access to proxy's routing table, syncing and notifying about a new proxy - shutdown: Grants access to shutdown the Hub + self: Metascope, grants access to user's own resources; resolves to (no scope) for services. + all: Metascope, valid for tokens only. Grants access to everything that the token's owning entity can do. + admin:users: Grants read, write, create and delete access to users and their authentication state but not their servers or tokens. + admin:users:auth_state: Grants access to users' authentication state only. + users: Grants read and write permissions to users' models apart from servers, tokens and authentication state. + users:activity: Grants access to read and post users' activity only. + users:activity!user=username: Update a single user's activity (example horizontal filter). + read:users: Read-only access to users' models apart from servers, tokens and authentication state. + read:users!user=username: As above limited to a specific user (example horizontal filter). + read:users:name: Read-only access to users' names. + read:users:roles: Read-only access to a list of users' roles names. + read:users:groups: Read-only access to a list of users' group names. + read:users:activity: Read-only access to users' activity. + read:users:activity!group=groupname: Read-only access to specific group's users' activity (example horizontal filter). + admin:users:servers: Grants read, start/stop, create and delete permissions to users' servers and their state. + admin:users:server_state: Grants access to servers' state only. + users:servers: Allows for starting/stopping users' servers in addition to read access to their models. Does not include the server state. + users:servers!server=servername: Limits the above to a specific server (example horizontal filter). + read:users:servers: Read-only access to users' server models. Does not include the server state. + users:tokens: Grants read, write, create and delete permissions to users' tokens. + read:users:tokens: Read-only access to users' tokens. + admin:groups: Grants read, write, create and delete access to groups. + groups: Grants read and write permissions to groups, including adding/removing users to/from groups. + groups!group=groupname: As above limited to a specific group only (example horizontal filter) + read:groups: Read-only access to groups. + read:services: Read-only access to service models. + read:services:name: Read-only access to service names. + read:services:roles: Read-only access to a list of service roles names. + read:hub: Read-only access to detailed information about JupyterHub. + proxy: Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. + shutdown: Grants access to shutdown the Hub. security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope self) or have both (either can be used)? - token: [] - oauth2: diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index bba8c517..a8f64bf0 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -95,7 +95,7 @@ Table 1. Available scopes and their hierarchy |       `read:users` | Read-only access to users' models _apart from servers, tokens and authentication state_. | |          `read:users:name` | Read-only access to users' names. | |          `read:users:roles` | Read-only access to a list of users' roles names. | -|          `read:users:groups` | Read-only access to users' groups. | +|          `read:users:groups` | Read-only access to a list of users' group names. | |          `read:users:activity` | Read-only access to users' activity. | | `admin:users:servers` | Grants read, start/stop, create and delete permissions to users' servers and their state. | |    `admin:users:server_state` | Grants access to servers' state only. | From 5a956818536a79e73f223a0f14cb6886baba8200 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 16 Apr 2021 17:26:19 +0200 Subject: [PATCH 135/270] Add %TODO: flag for generating the table in docs/source/rbac/scopes.md --- docs/source/rbac/scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index a8f64bf0..a368776d 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -81,7 +81,7 @@ The payload of an API call can be filtered both horizontally and vertically simu ## Available scopes Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them. - +% TODO: Automatically generate this table from code when creating docs Table 1. Available scopes and their hierarchy | Scope name | Description | | :--------- | :---------- | From 24245a029f1b5041c1f1ea6bb3ad1aa9cf4b074c Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 19 Apr 2021 13:10:21 +0200 Subject: [PATCH 136/270] be strict about role names - 3-255 characters - ascii lowercase, numbers, - - must start with letter - must not end with - this lets us avoid url escaping issues in e.g. oauth params --- jupyterhub/roles.py | 22 ++++++++++++++++++++++ jupyterhub/tests/test_roles.py | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 1c520873..a10c6175 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -1,6 +1,7 @@ """Roles utils""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import re from itertools import chain from sqlalchemy import func @@ -226,6 +227,26 @@ def _overwrite_role(role, role_dict): ) +_role_name_pattern = re.compile(r'^[a-z][a-z0-9\-]{1,253}[a-z0-9]$') + + +def _validate_role_name(name): + """Ensure a role has a valid name + + Raises ValueError if role name is invalid + """ + if not _role_name_pattern.match(name): + raise ValueError( + f"Invalid role name: {name!r}." + " Role names must:\n" + " - be 3-255 characters\n" + " - contain only lowercase ascii letters, numbers, and '-'\n" + " - start with a letter\n" + " - not end with '-'\n" + ) + return True + + def create_role(db, role_dict): """Adds a new role to database or modifies an existing one""" @@ -235,6 +256,7 @@ def create_role(db, role_dict): raise KeyError('Role definition must have a name') else: name = role_dict['name'] + _validate_role_name(name) role = orm.Role.find(db, name) description = role_dict.get('description') diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 94e1aba8..5cebee56 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -878,3 +878,25 @@ async def test_self_expansion(app, kind, has_user_scopes): assert bool(token_scopes) == has_user_scopes app.db.delete(orm_obj) app.db.delete(test_role) + + +@mark.role +@mark.parametrize( + "name, valid", + [ + ('abc', True), + ('group', True), + ("a-pretty-long-name-with-123", True), + ("0-abc", False), # starts with number + ("role-", False), # ends with - + ("has-Uppercase", False), # Uppercase + ("a" * 256, False), # too long + ("has space", False), # space is illegal + ], +) +async def test_valid_names(name, valid): + if valid: + assert roles._validate_role_name(name) + else: + with pytest.raises(ValueError): + roles._validate_role_name(name) From 863ab1eb124bc69ef028f08415068b24fcec5c29 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 19 Apr 2021 13:37:21 +0200 Subject: [PATCH 137/270] allow unreserved RFC3986 characters in role names: _-~. --- jupyterhub/roles.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index a10c6175..3f74a8ad 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -227,7 +227,7 @@ def _overwrite_role(role, role_dict): ) -_role_name_pattern = re.compile(r'^[a-z][a-z0-9\-]{1,253}[a-z0-9]$') +_role_name_pattern = re.compile(r'^[a-z][a-z0-9\-_~\.]{1,253}[a-z0-9]$') def _validate_role_name(name): @@ -240,9 +240,9 @@ def _validate_role_name(name): f"Invalid role name: {name!r}." " Role names must:\n" " - be 3-255 characters\n" - " - contain only lowercase ascii letters, numbers, and '-'\n" + " - contain only lowercase ascii letters, numbers, and URL unreserved special characters '-.~_'\n" " - start with a letter\n" - " - not end with '-'\n" + " - end with letter or number\n" ) return True From ef1351b441ad0374f3d5929b86e671a449cf3adc Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 20 Apr 2021 11:04:04 +0200 Subject: [PATCH 138/270] Added todo for future PR --- jupyterhub/apihandlers/users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 23ac0027..b245fbc4 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -301,7 +301,7 @@ class UserTokenListAPIHandler(APIHandler): self.write(json.dumps({'api_tokens': api_tokens})) - @needs_scope('users:tokens') + # @needs_scope('users:tokens') #Todo: needs internal scope checking async def post(self, user_name): body = self.get_json_body() or {} if not isinstance(body, dict): From 53f0d885054fb5de6fd7ae7ec094db4fca73ff47 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 19 Apr 2021 12:39:48 +0200 Subject: [PATCH 139/270] hook up oauthlib's logger to ours for better debugging --- jupyterhub/app.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index dd191206..76dd0df3 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1377,14 +1377,16 @@ class JupyterHub(Application): max(self.log_level, logging.INFO) ) - # hook up tornado 3's loggers to our app handlers for log in (app_log, access_log, gen_log): # ensure all log statements identify the application they come from log.name = self.log.name - logger = logging.getLogger('tornado') - logger.propagate = True - logger.parent = self.log - logger.setLevel(self.log.level) + + # hook up tornado's and oauthlib's loggers to our own + for name in ("tornado", "oauthlib"): + logger = logging.getLogger(name) + logger.propagate = True + logger.parent = self.log + logger.setLevel(self.log.level) @staticmethod def add_url_prefix(prefix, handlers): From 4728325bf764bfc08d5f27fe6838dadef33cccf3 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 19 Apr 2021 12:45:35 +0200 Subject: [PATCH 140/270] persist roles through oauth process - Attach role limit to OAuthClient - Attach authorized roles to OAuthCode - pass roles from code to API token on completion standard 'scopes' in oauth process are matched against our 'roles' instead of our low-level scopes --- jupyterhub/oauth/provider.py | 53 ++++++++++++++++++++-------- jupyterhub/orm.py | 67 +++++++++++++++++------------------- 2 files changed, 71 insertions(+), 49 deletions(-) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index c1369863..55aa55bb 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -149,7 +149,12 @@ class JupyterHubRequestValidator(RequestValidator): - Resource Owner Password Credentials Grant - Client Credentials grant """ - return ['identify'] + orm_client = ( + self.db.query(orm.OAuthClient).filter_by(identifier=client_id).first() + ) + if orm_client is None: + raise ValueError("No such client: %s" % client_id) + return [role.name for role in orm_client.allowed_roles] def get_original_scopes(self, refresh_token, request, *args, **kwargs): """Get the list of scopes associated with the refresh token. @@ -249,8 +254,7 @@ class JupyterHubRequestValidator(RequestValidator): code=code['code'], # oauth has 5 minutes to complete expires_at=int(orm.OAuthCode.now() + 300), - # TODO: persist oauth scopes - # scopes=request.scopes, + roles=request._jupyterhub_roles, user=request.user.orm_user, redirect_uri=orm_client.redirect_uri, session_id=request.session_id, @@ -324,10 +328,6 @@ class JupyterHubRequestValidator(RequestValidator): """ log_token = {} log_token.update(token) - scopes = token['scope'].split(' ') - # TODO: - if scopes != ['identify']: - raise ValueError("Only 'identify' scope is supported") # redact sensitive keys in log for key in ('access_token', 'refresh_token', 'state'): if key in token: @@ -335,6 +335,7 @@ class JupyterHubRequestValidator(RequestValidator): if isinstance(value, str): log_token[key] = 'REDACTED' app_log.debug("Saving bearer token %s", log_token) + if request.user is None: raise ValueError("No user for access token: %s" % request.user) client = ( @@ -342,9 +343,6 @@ class JupyterHubRequestValidator(RequestValidator): .filter_by(identifier=request.client.client_id) .first() ) - # FIXME: pick a role - # this will be empty for now - roles = list(self.db.query(orm.Role).filter_by(name='identify')) # FIXME: support refresh tokens # These should be in a new table token.pop("refresh_token", None) @@ -353,7 +351,7 @@ class JupyterHubRequestValidator(RequestValidator): orm.APIToken.new( client_id=client.identifier, expires_in=token['expires_in'], - roles=roles, + roles=request._jupyterhub_roles, token=token['access_token'], session_id=request.session_id, user=request.user, @@ -455,9 +453,8 @@ class JupyterHubRequestValidator(RequestValidator): return False request.user = orm_code.user request.session_id = orm_code.session_id - # TODO: record state on oauth codes - # TODO: specify scopes - request.scopes = ['identify'] + request.scopes = [role.name for role in orm_code.roles] + request._jupyterhub_roles = orm_code.roles return True def validate_grant_type( @@ -553,6 +550,34 @@ class JupyterHubRequestValidator(RequestValidator): - Resource Owner Password Credentials Grant - Client Credentials Grant """ + orm_client = ( + self.db.query(orm.OAuthClient).filter_by(identifier=client_id).one_or_none() + ) + if orm_client is None: + app_log.warning("No such oauth client %s", client_id) + return False + client_allowed_roles = {role.name: role for role in orm_client.allowed_roles} + # explicitly allow 'identify', which was the only allowed scope previously + # requesting 'identify' gets no actual permissions other than self-identification + client_allowed_roles.setdefault('identify', None) + roles = [] + requested_roles = set(scopes) + disallowed_roles = requested_roles.difference(client_allowed_roles) + if disallowed_roles: + app_log.error( + f"Role(s) not allowed for {client_id}: {','.join(disallowed_roles)}" + ) + return False + + # store resolved roles on request + app_log.debug( + f"Allowing request for role(s) for {client_id}: {','.join(requested_roles) or '[]'}" + ) + request._jupyterhub_roles = [ + client_allowed_roles[name] + for name in requested_roles + if client_allowed_roles[name] is not None + ] return True diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index c35a7255..e78fcc02 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -137,43 +137,34 @@ class Server(Base): return "" % (self.ip, self.port) -# user:role many:many mapping table -user_role_map = Table( - 'user_role_map', - Base.metadata, - Column('user_id', ForeignKey('users.id', ondelete='CASCADE'), primary_key=True), - Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), -) +# lots of things have roles +# mapping tables are the same for all of them -# service:role many:many mapping table -service_role_map = Table( - 'service_role_map', - Base.metadata, - Column( - 'service_id', ForeignKey('services.id', ondelete='CASCADE'), primary_key=True - ), - Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), -) +_role_map_tables = [] -# token:role many:many mapping table -api_token_role_map = Table( - 'api_token_role_map', - Base.metadata, - Column( - 'api_token_id', - ForeignKey('api_tokens.id', ondelete='CASCADE'), - primary_key=True, - ), - Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), -) - -# group:role many:many mapping table -group_role_map = Table( - 'group_role_map', - Base.metadata, - Column('group_id', ForeignKey('groups.id', ondelete='CASCADE'), primary_key=True), - Column('role_id', ForeignKey('roles.id', ondelete='CASCADE'), primary_key=True), -) +for has_role in ( + 'user', + 'group', + 'service', + 'api_token', + 'oauth_client', + 'oauth_code', +): + role_map = Table( + f'{has_role}_role_map', + Base.metadata, + Column( + f'{has_role}_id', + ForeignKey(f'{has_role}s.id', ondelete='CASCADE'), + primary_key=True, + ), + Column( + 'role_id', + ForeignKey('roles.id', ondelete='CASCADE'), + primary_key=True, + ), + ) + _role_map_tables.append(role_map) class Role(Base): @@ -714,6 +705,8 @@ class OAuthCode(Expiring, Base): # state = Column(Unicode(1023)) user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE')) + roles = relationship('Role', secondary='oauth_code_role_map') + @staticmethod def now(): return datetime.utcnow().timestamp() @@ -745,6 +738,10 @@ class OAuthClient(Base): ) codes = relationship(OAuthCode, backref='client', cascade='all, delete-orphan') + # these are the roles an oauth client is allowed to request + # *not* the roles of the client itself + allowed_roles = relationship('Role', secondary='oauth_client_role_map') + # General database utilities From be76b5ebbadc3586363f27bd30a88c9c0dbc2620 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 20 Apr 2021 14:29:09 +0200 Subject: [PATCH 141/270] tests for oauth roles --- jupyterhub/oauth/provider.py | 4 +- jupyterhub/tests/test_services_auth.py | 57 +++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 55aa55bb..17b3eead 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -351,7 +351,7 @@ class JupyterHubRequestValidator(RequestValidator): orm.APIToken.new( client_id=client.identifier, expires_in=token['expires_in'], - roles=request._jupyterhub_roles, + roles=[rolename for rolename in request.scopes], token=token['access_token'], session_id=request.session_id, user=request.user, @@ -454,7 +454,6 @@ class JupyterHubRequestValidator(RequestValidator): request.user = orm_code.user request.session_id = orm_code.session_id request.scopes = [role.name for role in orm_code.roles] - request._jupyterhub_roles = orm_code.roles return True def validate_grant_type( @@ -573,6 +572,7 @@ class JupyterHubRequestValidator(RequestValidator): app_log.debug( f"Allowing request for role(s) for {client_id}: {','.join(requested_roles) or '[]'}" ) + # these will be stored on the OAuthCode object request._jupyterhub_roles = [ client_allowed_roles[name] for name in requested_roles diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 540150bb..ac10661e 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -9,8 +9,10 @@ from functools import partial from queue import Queue from threading import Thread from unittest import mock +from urllib.parse import parse_qs from urllib.parse import urlparse +import pytest import requests import requests_mock from pytest import raises @@ -318,8 +320,48 @@ async def test_hubauth_service_token(app, mockservice_url): assert path.endswith('/hub/login') -async def test_oauth_service(app, mockservice_url): +@pytest.mark.parametrize( + "client_allowed_roles, request_roles, expected_roles", + [ + # allow empty roles + ([], [], []), + # allow original 'identify' scope to map to no role + ([], ["identify"], []), + # requesting roles outside client list doesn't work + ([], ["admin"], None), + ([], ["token"], None), + # requesting nonexistent roles fails in the same way (no server error) + ([], ["nosuchrole"], None), + # requesting exactly client allow list works + (["user"], ["user"], ["user"]), + # no explicit request, defaults to all + (["token", "user"], [], ["token", "user"]), + # explicit 'identify' maps to none + (["token", "user"], ["identify"], []), + # any item outside the list isn't allowed + (["token", "user"], ["token", "server"], None), + # reuesting subset + (["admin", "user"], ["user"], ["user"]), + (["user", "token", "server"], ["token", "user"], ["token", "user"]), + ], +) +async def test_oauth_service( + app, + mockservice_url, + client_allowed_roles, + request_roles, + expected_roles, +): service = mockservice_url + oauth_client = ( + app.db.query(orm.OAuthClient) + .filter_by(identifier=service.oauth_client_id) + .one() + ) + oauth_client.allowed_roles = [ + orm.Role.find(app.db, role_name) for role_name in client_allowed_roles + ] + app.db.commit() url = url_path_join(public_url(app, mockservice_url) + 'owhoami/?arg=x') # first request is only going to login and get us to the oauth form page s = AsyncSession() @@ -334,7 +376,18 @@ async def test_oauth_service(app, mockservice_url): assert set(r.history[0].cookies.keys()) == {'service-%s-oauth-state' % service.name} # submit the oauth form to complete authorization - r = await s.post(r.url, data={'scopes': ['identify']}, headers={'Referer': r.url}) + data = {} + if request_roles: + data["scopes"] = request_roles + r = await s.post(r.url, data=data, headers={'Referer': r.url}) + if expected_roles is None: + # expected failed auth, stop here + # verify expected 'invalid scope' error, not server error + dest_url, _, query = r.url.partition("?") + assert dest_url == public_url(app, mockservice_url) + "oauth_callback" + assert parse_qs(query).get("error") == ["invalid_scope"] + assert r.status_code == 400 + return r.raise_for_status() assert r.url == url # verify oauth cookie is set From 399203e5d3cd8a66ca438a60fcb12790dd59e4d1 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 20 Apr 2021 14:55:36 +0200 Subject: [PATCH 142/270] Fixed scope checking in UserTokenListAPIHandler --- jupyterhub/apihandlers/users.py | 16 +++++++++------- jupyterhub/tests/test_api.py | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index b245fbc4..75a60986 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -301,7 +301,6 @@ class UserTokenListAPIHandler(APIHandler): self.write(json.dumps({'api_tokens': api_tokens})) - # @needs_scope('users:tokens') #Todo: needs internal scope checking async def post(self, user_name): body = self.get_json_body() or {} if not isinstance(body, dict): @@ -330,13 +329,16 @@ class UserTokenListAPIHandler(APIHandler): if requester is None: # couldn't identify requester raise web.HTTPError(403) + self._jupyterhub_user = requester + self._resolve_scopes() user = self.find_user(user_name) - if requester is not user and not requester.admin: - raise web.HTTPError(403, "Only admins can request tokens for other users") - if not user: - raise web.HTTPError(404, "No such user: %s" % user_name) - if requester is not user: - kind = 'user' if isinstance(requester, User) else 'service' + kind = 'user' if isinstance(requester, User) else 'service' + scope_filter = self.get_scope_filter('users:tokens') + if user is None or not scope_filter(user, kind): + raise web.HTTPError( + 404, + f"{kind.title()} {user_name} not found or no permissions to generate tokens", + ) note = body.get('note') if not note: diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 6597e587..1029b728 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1311,7 +1311,7 @@ async def test_get_new_token(app, headers, status, note, expires_in): [ ('admin', 'other', 200), ('admin', 'missing', 404), - ('user', 'other', 403), + ('user', 'other', 404), ('user', 'user', 200), ], ) From d8ded9aed80e4ff39cb01fff3ee8406a3935874b Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 20 Apr 2021 14:58:34 +0200 Subject: [PATCH 143/270] resolve self in _get_subscopes avoids inconsistent behavior in different uses of _get_subscopes where 'self' is left unmodified, leading to errors --- jupyterhub/roles.py | 73 +++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 0a829853..d7aa6f4a 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -163,22 +163,24 @@ def _expand_scope(scopename): def expand_roles_to_scopes(orm_object): """Get the scopes listed in the roles of the User/Service/Group/Token If User, take into account the user's groups roles as well""" + from .user import User + + if isinstance(orm_object, User): + orm_object = User.orm_user pass_roles = orm_object.roles + if isinstance(orm_object, orm.User): groups_roles = [] for group in orm_object.groups: groups_roles.extend(group.roles) pass_roles.extend(groups_roles) - scopes = _get_subscopes(*pass_roles) - if 'self' in scopes: - scopes.remove('self') - if isinstance(orm_object, orm.User) or hasattr(orm_object, 'orm_user'): - scopes |= expand_self_scope(orm_object.name) + + scopes = _get_subscopes(*pass_roles, owner=orm_object) return scopes -def _get_subscopes(*args): +def _get_subscopes(*args, owner=None): """Returns a set of all available subscopes for a specified role or list of roles""" scope_list = [] @@ -188,6 +190,11 @@ def _get_subscopes(*args): scopes = set(chain.from_iterable(list(map(_expand_scope, scope_list)))) + if 'self' in scopes: + scopes.remove('self') + if owner and isinstance(owner, orm.User): + scopes |= expand_self_scope(owner.name) + return scopes @@ -380,32 +387,36 @@ def _token_allowed_role(db, token, role): """Returns True if token allowed to have requested role through comparing the requested scopes with the set of token's owner scopes""" - standard_permissions = {'all', 'read:all'} + owner = token.user + if owner is None: + owner = token.service - token_scopes = _get_subscopes(role) - extra_scopes = token_scopes - standard_permissions + if owner is None: + raise ValueError(f"Owner not found for {token}") + + token_scopes = _get_subscopes(role, owner=owner) + + implicit_permissions = {'all', 'read:all'} + explicit_scopes = token_scopes - implicit_permissions # ignore horizontal filters - raw_extra_scopes = { - scope.split('!', 1)[0] if '!' in scope else scope for scope in extra_scopes + raw_scopes = { + scope.split('!', 1)[0] if '!' in scope else scope for scope in explicit_scopes } - # find the owner and their roles - owner = None - if token.user_id: - owner = db.query(orm.User).get(token.user_id) - elif token.service_id: - owner = db.query(orm.Service).get(token.service_id) - if owner: - owner_scopes = expand_roles_to_scopes(owner) - # ignore horizontal filters - raw_owner_scopes = { - scope.split('!', 1)[0] if '!' in scope else scope for scope in owner_scopes - } - if raw_extra_scopes.issubset(raw_owner_scopes): - return True - else: - return False + # find the owner's scopes + owner_scopes = expand_roles_to_scopes(owner) + # ignore horizontal filters + raw_owner_scopes = { + scope.split('!', 1)[0] if '!' in scope else scope for scope in owner_scopes + } + disallowed_scopes = raw_scopes.difference(raw_owner_scopes) + if not disallowed_scopes: + # no scopes requested outside owner's own scopes + return True else: - raise ValueError('Owner the token %r not found', token) + app_log.warning( + f"Token requesting scopes exceeding owner {owner.name}: {disallowed_scopes}" + ) + return False def assign_default_roles(db, entity): @@ -440,12 +451,10 @@ def update_roles(db, entity, roles): ) if _token_allowed_role(db, entity, role): role.tokens.append(entity) - app_log.info('Adding role %s for token: %s', role.name, entity) + app_log.info('Adding role %s to token: %s', role.name, entity) else: raise ValueError( - 'Requested token role %r of %r has more permissions than the token owner', - rolename, - entity, + f'Requested token role {rolename} of {entity} has more permissions than the token owner' ) else: raise NameError('Role %r does not exist' % rolename) From 0c7c1ed6b435afa7687beb335afc0e005b537ab4 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 20 Apr 2021 15:13:17 +0200 Subject: [PATCH 144/270] scopes.get_scopes_for is the only roles/scopes API to allow User wrapper all else requires orm objects --- jupyterhub/roles.py | 6 ++---- jupyterhub/scopes.py | 13 ++++++++++++- jupyterhub/tests/test_scopes.py | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index d7aa6f4a..6ea75a89 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -163,10 +163,8 @@ def _expand_scope(scopename): def expand_roles_to_scopes(orm_object): """Get the scopes listed in the roles of the User/Service/Group/Token If User, take into account the user's groups roles as well""" - from .user import User - - if isinstance(orm_object, User): - orm_object = User.orm_user + if not isinstance(orm_object, orm.Base): + raise TypeError(f"Only orm objects allowed, got {orm_object}") pass_roles = orm_object.roles diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 58c0e334..c5e6365c 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -18,7 +18,18 @@ def get_scopes_for(orm_object): scopes = set() if orm_object is None: return scopes - elif isinstance(orm_object, orm.APIToken): + + if not isinstance(orm_object, orm.Base): + from .user import User + + if isinstance(orm_object, User): + orm_object = orm_object.orm_user + else: + raise TypeError( + f"Only allow orm objects or User wrappers, got {orm_object}" + ) + + if isinstance(orm_object, orm.APIToken): app_log.warning(f"Authenticated with token {orm_object}") owner = orm_object.user or orm_object.service token_scopes = roles.expand_roles_to_scopes(orm_object) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 98a5dc93..7fc2e62e 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -530,7 +530,7 @@ async def test_metascope_self_expansion( app, kind, has_user_scopes, create_user_with_scopes, create_service_with_scopes ): if kind == 'users': - orm_obj = create_user_with_scopes('self') + orm_obj = create_user_with_scopes('self').orm_user else: orm_obj = create_service_with_scopes('self') # test expansion of user/service scopes From cab84500c5c1f8c991879b1d145ad48dc96c78eb Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 20 Apr 2021 16:39:22 +0200 Subject: [PATCH 145/270] Add !user filter to users:activity scope and its expansion --- jupyterhub/roles.py | 22 ++++++++++++++++++++-- jupyterhub/tests/test_roles.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 1c520873..9c663952 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -1,6 +1,7 @@ """Roles utils""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import re from itertools import chain from sqlalchemy import func @@ -39,7 +40,7 @@ def get_default_roles(): 'name': 'server', 'description': 'Post activity only', 'scopes': [ - 'users:activity' + 'users:activity!user' ], # TO DO - fix scope to refer to only self once implemented }, { @@ -164,10 +165,27 @@ def expand_roles_to_scopes(orm_object): groups_roles.extend(group.roles) pass_roles.extend(groups_roles) scopes = _get_subscopes(*pass_roles) + + # transform !user filter to !user=ownername + for scope in scopes: + base_scope, _, filter = scope.partition('!') + if filter == 'user': + scopes.remove(scope) + if isinstance(orm_object, orm.APIToken): + owner = orm_object.user + if owner is None: + owner = orm_object.service + name = owner.name + else: + name = orm_object.name + trans_scope = f'{base_scope}!user={name}' + scopes.add(trans_scope) + if 'self' in scopes: scopes.remove('self') if isinstance(orm_object, orm.User) or hasattr(orm_object, 'orm_user'): scopes |= expand_self_scope(orm_object.name) + return scopes @@ -188,7 +206,7 @@ def _check_scopes(*args): """Check if provided scopes exist""" allowed_scopes = _get_scope_hierarchy() - allowed_filters = ['!user=', '!service=', '!group=', '!server='] + allowed_filters = ['!user=', '!service=', '!group=', '!server=', '!user'] subscopes = set( chain.from_iterable([x for x in allowed_scopes.values() if x is not None]) ) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 94e1aba8..247feb5a 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -878,3 +878,37 @@ async def test_self_expansion(app, kind, has_user_scopes): assert bool(token_scopes) == has_user_scopes app.db.delete(orm_obj) app.db.delete(test_role) + + +@mark.role +@mark.parametrize( + "scope_list, kind, test_token", + [ + (['users:activity!user'], 'users', False), + (['users:activity!user', 'read:users'], 'users', False), + (['users:activity!user'], 'users', True), + ], +) +async def test_user_filter_expansion(app, scope_list, kind, test_token): + Class = orm.get_class(kind) + orm_obj = Class(name=f'test_{kind}') + app.db.add(orm_obj) + app.db.commit() + + test_role = orm.Role(name='test_role', scopes=scope_list) + orm_obj.roles.append(test_role) + + if test_token: + token = orm_obj.new_api_token(roles=['test_role']) + orm_token = orm.APIToken.find(app.db, token) + scope_set = roles.expand_roles_to_scopes(orm_token) + else: + scope_set = roles.expand_roles_to_scopes(orm_obj) + + for scope in scope_set: + if '!user' in scope: + assert not scope.endswith('!user') + assert scope.endswith(orm_obj.name) + + app.db.delete(orm_obj) + app.db.delete(test_role) From 79b57b7f3bea5524b09480777839cd9b7aefc22d Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 20 Apr 2021 16:48:56 +0200 Subject: [PATCH 146/270] Add admin:users:auth_state/server_state to docs/rest-api.yml --- docs/rest-api.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index cbd82736..9f40f6da 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -188,7 +188,8 @@ paths: - read:users:groups - read:users:activity - read:users:servers - #TODO: add admin:users:auth_state/server_state? + - admin:users:auth_state + - admin:users:server_state parameters: - name: name description: username @@ -222,7 +223,6 @@ paths: security: - oauth2: - admin:users - #TODO: confirm, this scope allows to also create/delete users but users scope would allow any user to change their own name and admin status parameters: - name: name description: username @@ -527,7 +527,8 @@ paths: - read:users:groups - read:users:activity - read:users:servers - #TODO: add admin:users:auth_state/server_state? + - admin:users:auth_state + - admin:users:server_state responses: "200": description: The authenticated user's model is returned. From 4687a76a6fdad0dc7ac53049ffabba41a190f432 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 20 Apr 2021 17:28:41 +0200 Subject: [PATCH 147/270] Add role name conventions to docs/source/rbac/roles.md --- docs/source/rbac/roles.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 3fe84560..60df2062 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -83,6 +83,12 @@ The role `reader` allows users `maria` and `joe` and service `external` to read ```{admonition} Requirements :class: warning In a role definition, the `name` field is required, while all other fields are optional.\ +**Role names must:** +- be 3 - 255 characters +- use ascii lowercase, numbers, 'unreserved' URL punctuation `-_.~` +- start with a letter +- end with letter or number. + If no scopes are defined for new role, JupyterHub will raise a warning. Providing non-existing scopes will result in an error.\ Moreover, `users`, `services`, `groups` and `tokens` only accept objects that already exist or are defined previously in the file.\ It is not possible to implicitly add a new user to the database by defining a new role. From 103c6a406ad6ac95f5412137cbe754b991295fdd Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 21 Apr 2021 09:43:24 +0200 Subject: [PATCH 148/270] Changed error code of UserTokenListAPIHandler back to 403 --- jupyterhub/apihandlers/users.py | 2 +- jupyterhub/tests/test_api.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 75a60986..2d5ccfab 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -336,7 +336,7 @@ class UserTokenListAPIHandler(APIHandler): scope_filter = self.get_scope_filter('users:tokens') if user is None or not scope_filter(user, kind): raise web.HTTPError( - 404, + 403, f"{kind.title()} {user_name} not found or no permissions to generate tokens", ) diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 1029b728..9bd66be9 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1310,8 +1310,8 @@ async def test_get_new_token(app, headers, status, note, expires_in): "as_user, for_user, status", [ ('admin', 'other', 200), - ('admin', 'missing', 404), - ('user', 'other', 404), + ('admin', 'missing', 403), + ('user', 'other', 403), ('user', 'user', 200), ], ) From a2b76bceb9de40cad9cdd4704591ca6adee1f65a Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 22 Apr 2021 13:39:36 +0200 Subject: [PATCH 149/270] minor copy-editing, TODOs in rbac docs --- docs/source/rbac/index.md | 9 +++++++-- docs/source/rbac/roles.md | 25 +++++++++++++++++-------- docs/source/rbac/scopes.md | 4 ++-- docs/source/rbac/tech-implementation.md | 22 ++++++++++++---------- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/docs/source/rbac/index.md b/docs/source/rbac/index.md index 5963af63..3f9ed98f 100644 --- a/docs/source/rbac/index.md +++ b/docs/source/rbac/index.md @@ -2,11 +2,16 @@ Role Based Access Control (RBAC) in JupyterHub serves to provide fine grained control of access to Jupyterhub's API resources. +RBAC is new in JupyterHub 2.0. + ## Motivation -The JupyterHub API requires authorization before allowing changes to the backend. For instance, currently the default behaviour is that creating or deleting users requires _admin rights_. This ensures that an arbitrary user, or even an unauthenticated third party, are not allowed to perform such actions. +The JupyterHub API requires authorization to access its APIs. +This ensures that an arbitrary user, or even an unauthenticated third party, are not allowed to perform such actions. +For instance, the behaviour prior to adoption of RBAC is that creating or deleting users requires _admin rights_. -This system is functional, but lacks flexibility. If your Hub serves a number of users in different groups, you might want to delegate permissions to other users or automate certain processes. With the current framework, appointing a 'group-only admin' or a bot that culls idle servers, requires granting full rights to all actions. This poses a risk of the user or service intentionally or unintentionally accessing and modifying any data within the Hub and violates the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege). +The prior system is functional, but lacks flexibility. If your Hub serves a number of users in different groups, you might want to delegate permissions to other users or automate certain processes. +Prior to RBAC, appointing a 'group-only admin' or a bot that culls idle servers, requires granting full admin rights to all actions. This poses a risk of the user or service intentionally or unintentionally accessing and modifying any data within the Hub and violates the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege). To remedy situations like this, JupyterHub is transitioning to an RBAC system. By equipping users, groups and services with _roles_ that supply them with a collection of permissions (_scopes_), administrators are able to fine-tune which parties are granted access to which resources. diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 60df2062..49aeaeda 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -3,7 +3,7 @@ JupyterHub provides four roles that are available by default: ```{admonition} **Default roles** -- `user` role provides a {ref}`default user scope ` `self` that grants access to only the user's own resources. +- `user` role provides a {ref}`default user scope ` `self` that grants access to the user's own resources. - `admin` role contains all available scopes and grants full rights to all actions similarly to the current admin status. This role **cannot be edited**. - `token` role provides a {ref}`default token scope ` `all` that resolves to the same permissions as the token's owner has. - `server` role allows for posting activity of "itself" only. The scope is currently under development. @@ -11,7 +11,12 @@ JupyterHub provides four roles that are available by default: **These roles cannot be deleted.** ``` -New roles can also be customly defined (see {ref}`define_role_target`). Roles can be assigned to the following entities: +The `user`, `admin`, and `token` roles by default all preserve the permissions prior to RBAC. +Only the `server` role is changed from pre-2.0, to reduce its permissions to activity-only +instead of the default of a full access token. + +Additional custom roles can also be defined (see {ref}`define_role_target`). +Roles can be assigned to the following entities: - Users - Services @@ -24,7 +29,7 @@ An entity can have zero, one, or multiple roles, and there are no restrictions o When a new user or service gets created, they are assigned their default role ( `user` or `admin`) if no custom role is requested, currently based on their admin status. **Groups** \ -A group does not require any role, and has no roles by default. If a user is a member of a group, they autimatically inherit any of the group's permissions (see {ref}`resolving-roles-scopes-target` for more details). This is useful for assigning a set of common permissions to several users. +A group does not require any role, and has no roles by default. If a user is a member of a group, they automatically inherit any of the group's permissions (see {ref}`resolving-roles-scopes-target` for more details). This is useful for assigning a set of common permissions to several users. **Tokens** \ A token’s permissions are evaluated based on their owning entity. Since a token is always issued for a user or service, it can never have more permissions than its owner. If no specific role is requested for a new token, the token is assigned the `token` role. @@ -35,6 +40,11 @@ A token’s permissions are evaluated based on their owning entity. Since a toke Roles can be defined or modified in the configuration file as a list of dictionaries. An example: +% TODO: think about loading users/tokens into roles if membership has been changed via API. +% What should be the result? +% What happens if a user is _removed_ from this list? +% Do they lose their role assignment or keep it? + ```python # in jupyterhub_config.py @@ -89,14 +99,13 @@ In a role definition, the `name` field is required, while all other fields are o - start with a letter - end with letter or number. -If no scopes are defined for new role, JupyterHub will raise a warning. Providing non-existing scopes will result in an error.\ -Moreover, `users`, `services`, `groups` and `tokens` only accept objects that already exist or are defined previously in the file.\ +If no scopes are defined for new role, JupyterHub will raise a warning. Providing non-existing scopes will result in an error. +Moreover, `users`, `services`, `groups`, and `tokens` only accept objects that already exist or are defined previously in the file. It is not possible to implicitly add a new user to the database by defining a new role. ``` -\ -In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the `admin` role, which cannot be overwritten; an error will be raised if trying to do so. \ +In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the `admin` role, which cannot be overwritten; an error will be raised if trying to do so. Any previously defined role bearers for this role will remain the role bearers but their permissions will change if the role's permissions are overwritten. The newly defined bearers (in this case `maria` and `joe` and `external`) will be added to the existing ones. -Once a role is loaded, it remains in the database until explicitly deleting it through `delete_role()` function in `roles.py`. Default roles cannot be deleted. \ +Once a role is loaded, it remains in the database until explicitly deleting it through `delete_role()` function in `roles.py`. Default roles cannot be deleted. Omitting the `c.JupyterHub.load_roles` or specifying different roles in the `jupyterhub_config.py` file on the next startup will not erase previously defined roles, nor their bearers. diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index a368776d..9478525d 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -4,7 +4,7 @@ A scope has a syntax-based design that reveals which resources it provides acces `` in the RBAC scope design refers to the resource name in the [JupyterHub's API](../reference/rest-api.rst) endpoints in most cases. For instance, `` equal to `users` corresponds to JupyterHub's API endpoints beginning with _/users_. -## Scope syntax +## Scope conventions - `` \ The `` scopes, such as `users` or `groups`, grant read and write permissions to the resource itself and all its sub-resources. E.g., the scope `users:servers` is included within the scope `users`. @@ -15,7 +15,7 @@ A scope has a syntax-based design that reveals which resources it provides acces +++ - `admin:` \ - Grants create/delete permissions on the corresponding resource in addition to read and write permissions. + Grants additional permissions such as create/delete on the corresponding resource in addition to read and write permissions. +++ - `:` \ diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index c1e353e8..7df666a2 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -1,12 +1,14 @@ # Technical Implementation -Roles are stored in the database similarly as users, services, etc., and can be added or modified as explained in {ref}`define_role_target` section. Users, services, groups and tokens can gain, change and lose roles. For example, one can change a token's role, and as such its permissions, without the need to initiate new token (currently through `update_roles()` and `strip_role()` functions in `roles.py`, this will be eventually available through APIs). Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. +Roles are stored in the database, where they are associated with users, services, etc., and can be added or modified as explained in {ref}`define_role_target` section. Users, services, groups, and tokens can gain, change, and lose roles. +For example, one can change a token's role, and thereby its permissions, without the need to issue a new token (currently through `update_roles()` and `strip_role()` functions in `roles.py`, this will be eventually available through APIs). +Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. (resolving-roles-scopes-target)= ## Resolving roles and scopes -**Resolving roles** refers to determining which roles a user, service, token or group has, extracting the list of scopes from each role and combining them into a single set of scopes. +**Resolving roles** refers to determining which roles a user, service, token, or group has, extracting the list of scopes from each role and combining them into a single set of scopes. **Resolving scopes** involves expanding scopes into all their possible subscopes and, if applicable, comparing two sets of scopes. Both procedures take into account the scope hierarchy, {ref}`vertical ` and {ref}`horizontal filtering ` limiting or elevated permissions (`read:` or `admin:`, respectively), and metascopes. @@ -19,15 +21,15 @@ API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requ 1. through the `jupyterhub_config.py` file as described in the {ref}`define_role_target` section 2. through the _POST /users/:name/tokens_ API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). -The RBAC framework adds several steps into the token issue flow. +RBAC adds several steps into the token issue flow. -If no roles are requested, the token is issued with a default role (providing the requester is allowed to create the token). +If no roles are requested, the token is issued with the default `token` role (providing the requester is allowed to create the token). -If the token is requested with any roles, the permissions of requesting entity are checked against the requested permissions to ensure the token will not grant its owner additional privileges. +If the token is requested with any roles, the permissions of requesting entity are checked against the requested permissions to ensure the token would not grant its owner additional privileges. -If, due to modifications of roles or entities, at API request time a token has any scopes that its owner does not, those scopes are not taken into account. The API request is resolved without additional errors, but the Hub logs a warning (see {ref}`Figure 2 `). +If, due to modifications of roles or entities, at API request time a token has any scopes that its owner does not, those scopes are removed. The API request is resolved without additional errors, but the Hub logs a warning (see {ref}`Figure 2 `). -Resolving token's roles (yellow box in {ref}`Figure 1 `) corresponds to resolving all the token's owner roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared (Resolve the scopes box in orange in {ref}`Figure 1 `), taking into account the scope hierarchy but, solely for role assignment, omitting any {ref}`horizontal filter ` comparison. If the token's scopes are a subset of the token owner's scopes, the token is issued with the requested roles; if not, JupyterHub will raise an error. +Resolving a token's roles (yellow box in {ref}`Figure 1 `) corresponds to resolving all the token's owner roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared (Resolve the scopes box in orange in {ref}`Figure 1 `), taking into account the scope hierarchy but, solely for role assignment, omitting any {ref}`horizontal filter ` comparison. If the token's scopes are a subset of the token owner's scopes, the token is issued with the requested roles; if not, JupyterHub will raise an error. {ref}`Figure 1 ` below illustrates the steps involved. The orange rectangles highlight where in the process the roles and scopes are resolved. @@ -42,12 +44,12 @@ Figure 1. Resolving roles and scopes during API token request The above check is also performed when roles are requested for existing tokens, e.g., when adding tokens to {ref}`role definitions ` through the `jupyterhub_config.py`. ``` -### Making API request +### Making an API request With the RBAC framework each authenticated JupyterHub API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API. -When an API request is performed, the passed API token's roles are again resolved (yellow box in {ref}`Figure 2 `) to ensure the token does not grant more permissions than its owner has at the request time (e.g., due to changing/losing roles). -If the owner's roles do not include some scopes of the token's scopes, only the intersection of the token's and owner's scopes will be passed further. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will results in only the `read:users:name` scope being passed on. In the case of no intersection, en empty set of scopes will be passed on. +When an API request is performed, the requesting API token's roles are again resolved (yellow box in {ref}`Figure 2 `) to ensure the token does not grant more permissions than its owner has at the request time (e.g., due to changing/losing roles). +If the owner's roles do not include some scopes of the token's scopes, only the intersection of the token's and owner's scopes will be used. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will results in only the `read:users:name` scope being passed on. In the case of no intersection, an empty set of scopes will be used. The passed scopes are compared to the scopes required to access the API as follows: From 3a183c1b555f5f011d70b4a6df0e26bd0706e5fa Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 22 Apr 2021 16:58:34 +0200 Subject: [PATCH 150/270] Assign server token server role on creation --- jupyterhub/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/user.py b/jupyterhub/user.py index ce1dc300..3c0938f1 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -531,7 +531,7 @@ class User: orm_server = orm.Server(base_url=base_url) db.add(orm_server) note = "Server at %s" % base_url - api_token = self.new_api_token(note=note) + api_token = self.new_api_token(note=note, roles=['server']) db.commit() spawner = self.spawners[server_name] From 97a9ad76a8d455e9a9dddb3d5ce5cce16396bbc9 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 22 Apr 2021 17:11:26 +0200 Subject: [PATCH 151/270] Ignore horizontal scope filters in get_scopes_for() func Avoids discarding token scopes such as users:activity!user=george for user george who has scope users:activity (e.g. if george is admin) --- jupyterhub/scopes.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index c5e6365c..e93244c2 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -37,8 +37,25 @@ def get_scopes_for(orm_object): if 'all' in token_scopes: token_scopes.remove('all') token_scopes |= owner_scopes - scopes = token_scopes & owner_scopes - discarded_token_scopes = token_scopes - scopes + + # Ignore horizontal filters for comparison + token_base_scopes = {scope.partition('!')[0] for scope in token_scopes} + owner_base_scopes = {scope.partition('!')[0] for scope in owner_scopes} + + base_scopes = token_base_scopes & owner_base_scopes + discarded_token_scopes = token_base_scopes - base_scopes + + # Pass the token intersection scopes with original horizontal filters + scopes = set() + for scope in token_scopes: + base, _, filter = scope.partition('!') + for base_scope in base_scopes: + if base_scope == base: + scopes.add(scope) + + # scopes = token_scopes & owner_scopes + # discarded_token_scopes = token_scopes - scopes + # Not taking symmetric difference here because token owner can naturally have more scopes than token if discarded_token_scopes: app_log.warning( From 411ff954f1e90f5a8fca415274bb09c8cbf1e3eb Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 22 Apr 2021 17:14:28 +0200 Subject: [PATCH 152/270] Temporarily fix test_spawn_fails() test Checking server token permissions against its owner was failing as the user is just manually added to db without role --- jupyterhub/tests/test_orm.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index 093c29be..389137b5 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -13,6 +13,7 @@ from tornado import gen from .. import crypto from .. import objects from .. import orm +from .. import roles from ..emptyclass import EmptyClass from ..user import User from .mocking import MockSpawner @@ -221,6 +222,13 @@ async def test_spawn_fails(db): db.add(orm_user) db.commit() + # TODO: default roles should be assigned to users anytime a user is added to database (in orm?) + # the user added here has no role while the server token gets the default server role + def_roles = roles.get_default_roles() + for role in def_roles: + roles.create_role(db, role) + roles.assign_default_roles(db, orm_user) + class BadSpawner(MockSpawner): async def start(self): raise RuntimeError("Split the party") From b0479ea5e575c0f3e95b2e84a8e13faa278636a0 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 22 Apr 2021 17:37:30 +0200 Subject: [PATCH 153/270] Test server token gets server role upon creation --- jupyterhub/tests/test_roles.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 62dd6cf9..1fc22439 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -932,3 +932,21 @@ async def test_valid_names(name, valid): else: with pytest.raises(ValueError): roles._validate_role_name(name) + + +@mark.role +async def test_server_token_role(app): + orm_user = app.db.query(orm.User).first() + user = app.users[orm_user] + print(user.api_tokens) + assert user.api_tokens == [] + spawner = user.spawner + spawner.cmd = ['jupyterhub-singleuser'] + await user.spawn() + assert len(user.api_tokens) == 1 + server_token = user.api_tokens[0] + + server_role = orm.Role.find(app.db, 'server') + token_role = orm.Role.find(app.db, 'token') + assert server_role in server_token.roles + assert token_role not in server_token.roles From b2ecbfd491dee7d00a3eb657e67f806f3d082559 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 22 Apr 2021 18:32:19 +0200 Subject: [PATCH 154/270] Stop server in test_server_token_role() --- jupyterhub/tests/test_roles.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 1fc22439..83cf2163 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -936,17 +936,22 @@ async def test_valid_names(name, valid): @mark.role async def test_server_token_role(app): - orm_user = app.db.query(orm.User).first() - user = app.users[orm_user] - print(user.api_tokens) + user = add_user(app.db, app, name='test_user') assert user.api_tokens == [] spawner = user.spawner spawner.cmd = ['jupyterhub-singleuser'] await user.spawn() - assert len(user.api_tokens) == 1 - server_token = user.api_tokens[0] + + server_token = spawner.api_token + orm_server_token = orm.APIToken.find(app.db, server_token) + assert orm_server_token server_role = orm.Role.find(app.db, 'server') token_role = orm.Role.find(app.db, 'token') - assert server_role in server_token.roles - assert token_role not in server_token.roles + assert server_role in orm_server_token.roles + assert token_role not in orm_server_token.roles + + assert orm_server_token.user.name == user.name + assert user.api_tokens == [orm_server_token] + + await user.stop() From a5af48ef242bffbd1fac3900b9a56ef60cb8f9fd Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 23 Apr 2021 09:30:02 +0200 Subject: [PATCH 155/270] Added list of allowed roles to service --- jupyterhub/app.py | 4 ++-- jupyterhub/oauth/provider.py | 5 ++++- jupyterhub/services/service.py | 8 ++++++++ jupyterhub/tests/test_roles.py | 17 +++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 86d904ef..6da806ad 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -111,7 +111,6 @@ from .objects import Hub, Server # For faking stats from .emptyclass import EmptyClass - common_aliases = { 'log-level': 'Application.log_level', 'f': 'JupyterHub.config_file', @@ -119,7 +118,6 @@ common_aliases = { 'db': 'JupyterHub.db_url', } - aliases = { 'base-url': 'JupyterHub.base_url', 'y': 'JupyterHub.answer_yes', @@ -2129,6 +2127,7 @@ class JupyterHub(Application): name = spec['name'] # get/create orm orm_service = orm.Service.find(self.db, name=name) + allowed_roles = spec.get('allowed_roles', []) if orm_service is None: # not found, create a new one orm_service = orm.Service(name=name) @@ -2193,6 +2192,7 @@ class JupyterHub(Application): client_id=service.oauth_client_id, client_secret=service.api_token, redirect_uri=service.oauth_redirect_uri, + allowed_roles=allowed_roles, description="JupyterHub service %s" % service.name, ) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 17b3eead..052616a7 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -586,7 +586,9 @@ class JupyterHubOAuthServer(WebApplicationServer): self.db = db super().__init__(validator, *args, **kwargs) - def add_client(self, client_id, client_secret, redirect_uri, description=''): + def add_client( + self, client_id, client_secret, redirect_uri, allowed_roles, description='' + ): """Add a client hash its client_secret before putting it in the database. @@ -610,6 +612,7 @@ class JupyterHubOAuthServer(WebApplicationServer): orm_client.secret = hash_token(client_secret) if client_secret else "" orm_client.redirect_uri = redirect_uri orm_client.description = description + orm_client.allowed_roles = allowed_roles self.db.commit() def fetch_by_client_id(self, client_id): diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index c72ae382..380cddf8 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -50,6 +50,7 @@ from traitlets import default from traitlets import Dict from traitlets import HasTraits from traitlets import Instance +from traitlets import List from traitlets import Unicode from traitlets import validate from traitlets.config import LoggingConfigurable @@ -189,6 +190,13 @@ class Service(LoggingConfigurable): """ ).tag(input=True) + allowed_roles = List( + help="""OAuth allowed roles. + + List of roles that are passed to generated tokens if the service act as an OAuth client + on behalf of users""" + ).tag(input=True) + api_token = Unicode( help="""The API token to use for the service. diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index f538ff21..450640f1 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -13,6 +13,7 @@ from .. import roles from ..scopes import get_scopes_for from ..utils import maybe_future from .mocking import MockHub +from .test_scopes import create_temp_role from .utils import add_user from .utils import api_request @@ -898,3 +899,19 @@ async def test_valid_names(name, valid): else: with pytest.raises(ValueError): roles._validate_role_name(name) + + +async def test_oauth_allowed_roles(app, create_temp_role): + allowed_roles = ['oracle', 'goose'] + service = { + 'name': 'oas1', + 'api_token': 'some-token', + 'allowed_roles': ['oracle', 'goose'], + } + for role in allowed_roles: + create_temp_role('read:users', role_name=role) + app.services.append(service) + app.init_services() + app_service = app.services[0] + assert app_service['name'] == 'oas1' + assert set(app_service['allowed_roles']) == set(allowed_roles) From cb8c02366d4206a8eaf7de3a25ae8ceba5af6adf Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 23 Apr 2021 09:46:42 +0200 Subject: [PATCH 156/270] Placeholder for roles in spawner --- jupyterhub/oauth/provider.py | 4 +++- jupyterhub/user.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 052616a7..80e8140e 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -587,7 +587,7 @@ class JupyterHubOAuthServer(WebApplicationServer): super().__init__(validator, *args, **kwargs) def add_client( - self, client_id, client_secret, redirect_uri, allowed_roles, description='' + self, client_id, client_secret, redirect_uri, allowed_roles=None, description='' ): """Add a client @@ -609,6 +609,8 @@ class JupyterHubOAuthServer(WebApplicationServer): app_log.info(f'Creating oauth client {client_id}') else: app_log.info(f'Updating oauth client {client_id}') + if allowed_roles == None: + allowed_roles = [] orm_client.secret = hash_token(client_secret) if client_secret else "" orm_client.redirect_uri = redirect_uri orm_client.description = description diff --git a/jupyterhub/user.py b/jupyterhub/user.py index ce1dc300..a95c1a8c 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -568,7 +568,7 @@ class User: client_id, api_token, url_path_join(self.url, server_name, 'oauth_callback'), - description="Server at %s" + description="Server at %s" # todo: own server: 'users:servers!user={username} as allowed role? % (url_path_join(self.base_url, server_name) + '/'), ) db.commit() From f98dd0cdeb5cbbbac570b56b77b5c862c60bb8da Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 23 Apr 2021 11:01:16 +0200 Subject: [PATCH 157/270] Test for no expansion when !user=username filter instead of !user filter --- jupyterhub/tests/test_roles.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 83cf2163..f69a91cb 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -880,14 +880,16 @@ async def test_self_expansion(app, kind, has_user_scopes): @mark.role @mark.parametrize( - "scope_list, kind, test_token", + "scope_list, kind, test_for_token", [ (['users:activity!user'], 'users', False), (['users:activity!user', 'read:users'], 'users', False), + (['users:activity!user=otheruser', 'read:users'], 'users', False), (['users:activity!user'], 'users', True), + (['users:activity!user=otheruser', 'groups'], 'users', True), ], ) -async def test_user_filter_expansion(app, scope_list, kind, test_token): +async def test_user_filter_expansion(app, scope_list, kind, test_for_token): Class = orm.get_class(kind) orm_obj = Class(name=f'test_{kind}') app.db.add(orm_obj) @@ -896,17 +898,23 @@ async def test_user_filter_expansion(app, scope_list, kind, test_token): test_role = orm.Role(name='test_role', scopes=scope_list) orm_obj.roles.append(test_role) - if test_token: + if test_for_token: token = orm_obj.new_api_token(roles=['test_role']) orm_token = orm.APIToken.find(app.db, token) - scope_set = roles.expand_roles_to_scopes(orm_token) + expanded_scopes = roles.expand_roles_to_scopes(orm_token) else: - scope_set = roles.expand_roles_to_scopes(orm_obj) + expanded_scopes = roles.expand_roles_to_scopes(orm_obj) - for scope in scope_set: - if '!user' in scope: - assert not scope.endswith('!user') - assert scope.endswith(orm_obj.name) + for scope in scope_list: + base, _, filter = scope.partition('!') + for ex_scope in expanded_scopes: + ex_base, ex__, ex_filter = ex_scope.partition('!') + # check that the filter has been expanded to include the username if '!user' filter + if scope in ex_scope and filter == 'user': + assert ex_filter == f'{filter}={orm_obj.name}' + # make sure the filter has been left unchanged if other filter provided + elif scope in ex_scope and '=' in filter: + assert ex_filter == filter app.db.delete(orm_obj) app.db.delete(test_role) From 148257de12586d739d22be2db25767d6817affce Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 23 Apr 2021 14:12:46 +0200 Subject: [PATCH 158/270] DOC: details of oauth in jupyterhub --- docs/source/reference/oauth.md | 214 +++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 docs/source/reference/oauth.md diff --git a/docs/source/reference/oauth.md b/docs/source/reference/oauth.md new file mode 100644 index 00000000..a98c9293 --- /dev/null +++ b/docs/source/reference/oauth.md @@ -0,0 +1,214 @@ +# JupyterHub and OAuth + +JupyterHub uses OAuth 2 internally as a mechanism for authenticating users. +As such, JupyterHub itself always functions as an OAuth **provider**. +More on what that means below. + +Additionally, JupyterHub is _often_ deployed with [oauthenticator](https://oauthenticator.readthedocs.io), +where an external identity provider, such as GitHub or KeyCloak, is used to authenticate users. +When this is the case, there are \*two nested + +This means that when you are using JupyterHub, there is always _at least one_ and often two layers of OAuth involved in a user logging in and accessing their server. + +Some relevant points: + +- Single-user servers _never_ need to communicate with or be aware of the upstream provider. + As far as they are concerned, only JupyterHub is an OAuth provider, + and how users authenticate with the Hub itself is irrelevant. +- When talking to a single-user server, + there are ~always two tokens: + a token issued to the server itself to communicate with the Hub API, + and a second per-user token in the browser to represent the completed login process and authorized permissions. + More on this later. + +### Key OAuth terms + +- **provider** the entity responsible for managing. + JupyterHub is _always_ an oauth provider for its components. + When OAuthenticator is used, an external service, such as GitHub or KeyCloak, is also an oauth provider. +- **client** An entity that requests OAuth tokens on a user's behalf. + JupyterHub _services_ or single-user _servers_ are OAuth clients of the JupyterHub _provider_. + When OAuthenticator is used, JupyterHub is itself also an OAuth _client_ for the external oauth _provider_, e.g. GitHub. +- **browser** A user's web browser, which makes requests and stores things like cookies to +- **token** The secret value used to represent a user's authorization. This is the final product of the OAuth process + +### The oauth flow + +OAuth flow is what we call the sequence of HTTP requests involved in authenticating a user and issuing a token. + +It generally goes like this: + +1. A _browser_ makes an HTTP request to an oauth _client_. +2. There are no credentials, so the client _redirects_ the browser to an "authorize" page on the oauth _provider_ with some extra information: + - the oauth **client id** of the client itself + - the **redirect uri** to be redirected back to after completion + - the **scopes** requested, which the user should be presented with to confirm. + This is the "X would like to be able to Y on your behalf. Allow this?" page you see on all the "Login with ..." pages around the Internet. +3. During this authorize step, + the browser must be _authenticated_ with the provider. + This is often already stored in a cookie, + but if not the provider webapp must begin its _own_ authentication process before serving the authorization page. +4. After the user tells the provider that they want to proceed with the authorization, + the provider records this authorization in a short-lived record called an **oauth code**. +5. Finally, + the oauth provider redirects the browser _back_ to the oauth client's "redirect uri" + (or "oauth callback uri"), + with the oauth code in a url parameter. + +At this point: + +- The browser is authenticated with the _provider_ +- The user's authorized permissions are recorded in an _oauth code_ +- The _provider_ knows that the given oauth client's requested permissions have been granted, but the client doesn't know this yet. +- All requests so far have been made directly by the browser. + No requests have originated at the client or provider. + +Now we get to finish the OAuth process. +Let's dig into what the oauth client does when it handles +the oauth callback request with the + +- The OAuth client receives the _code_ and makes an API request to the _provider_ to exchange the code for a real _token_. + This is the first direct request between the OAuth _client_ and the _provider_. +- Once the token is retrieved, the client _usually_ + makes a second API request to the _provider_ + to retrieve information about the owner of the token (the user) +- Finally, the oauth client stores its own record that the user is authorized in a cookie. + This could be the token itself, or any other appropriate representation of successful authentication. + +_phew_ + +So that's _one_ OAuth process. + +## Full sequence of OAuth in JupyterHub + +Let's go through the above oauth process in Jupyter, +with specific examples of each HTTP request and what information is contained. + +Our starting point: + +- a user's single-user server is running. Let's call them `danez` +- jupyterhub is running with GitHub as an oauth provider, +- Danez has a fresh browser session with no cookies yet + +First request: + +- browser->single-user server +- `GET /user/danez/notebooks/mynotebook.ipynb` +- no credentials, so client starts oauth process with JupyterHub +- response: 302 redirect -> `/hub/api/oauth2/authorize` + with: + - client-id=`jupyterhub-user-danez` + - redirect-uri=`/user/danez/oauth_callback` (we'll come back later!) + +Second request, following redirect: + +- browser->jupyterhub +- `GET /hub/api/oauth2/authorize` +- no credentials, so jupyterhub starts oauth process _with GitHub_ +- response: 302 redirect -> `/hub/api/oauth2/authorize` + with: + - client-id=`jupyterhub-client-uuid` + - redirect-uri=`/hub/oauth_callback` (we'll come back later!) + +Third request, following redirect: + +- browser->GitHub +- `GET https://github.com/login/oauth/authorize` + +Prompts for login and asks for confirmation of authorization. + +After successful authorization +(either by looking up a pre-existing authorization, +or recording it via form submission) +GitHub issues oauth code and redirects to `/hub/oauth_callback?code=github-code` + +Next request: + +- browser->JupyterHub +- `GET /hub/oauth_callback?code=github-code` + +Inside the callback handler, JupyterHub makes two API requests: + +The first: + +- JupyterHub->GitHub +- `POST https://github.com/login/oauth/access_token` +- request made with oauth code from url parameter +- response includes an Access token + +The second: + +- JupyterHub->GitHub +- `GET https://api.github.com/user` +- request made with access token in the `Authorization` header +- response is the user model, including username, email, etc. + +Now the oauth callback request completes with: + +- set cookie on `/hub/` recording jupyterhub authentication so we don't need to do oauth with github again for a while +- redirect -> `/hub/api/oauth2/authorize` + +Now, we get our first repeated request: + +- browser->jupyterhub +- `GET /hub/api/oauth2/authorize` +- this time with credentials, + so jupyterhub either + 1. serves the authorization confirmation page, or + 2. automatically accepts authorization (shortcut taken when a user is visiting their own server) +- redirect -> `/user/danez/oauth_callback?code=jupyterhub-code` + +Here, we start the same oauth callback process as before, but at Danez's single-user server + +- browser->single-user server +- `GET /user/danez/oauth_callback` + +(in handler) + +Inside the callback handler, Danez's server makes two API requests to JupyterHub: + +The first: + +- single-user server->JupyterHub +- `POST /hub/api/oauth2/token` +- request made with oauth code from url parameter +- response includes an API token + +The second: + +- single-user server->JupyterHub +- `GET /hub/api/user` +- request made with token in the `Authorization` header +- response is the user model, including username, groups, etc. + +Finally completing `GET /user/danez/oauth_callback`: + +- response sets cookie, storing encrypted access token +- _finally_ redirects back to the original `/user/danez/notebooks/mynotebook.ipynb` + +Final request: + +- browser -> single-user server +- `GET /user/danez/notebooks/mynotebook.ipynb` +- encrypted jupyterhub token in cookie + +To authenticate this request, the single token stored in the encrypted cookie is passed to the Hub for verification: + +- single-user server -> Hub +- `GET /hub/api/user` +- browser's token in Authorization header +- response: user model with name, groups, etc. + +If the user model matches who should be allowed (e.g. Danez), +then the request is allowed. + +_the end_ + +## A tale of two tokens + +**TODO**: discuss API token issued to server at startup and oauth-issued token in cookie, and some details of how JupyterLab currently deals with that. +` + +## Notes + +- I omitted some information about the distinction between tokens issued to the server, due to RBAC changes. But they are different! From 0d637b49cbfe0bbfd371163c5eef1deadb3757b6 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 23 Apr 2021 16:43:21 +0200 Subject: [PATCH 159/270] Include horizontal scope filters check in resolving token permissions Avoids discarding token scopes with valid horizontal filters --- jupyterhub/scopes.py | 55 ++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index e93244c2..d29c806d 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -13,6 +13,42 @@ class Scope(Enum): ALL = True +def _intersect_scopes(token_scopes, owner_scopes): + """Compares the permissions of token and its owner including horizontal filters + Returns the intersection of the two sets of scopes""" + owner_parsed_scopes = parse_scopes(owner_scopes) + token_parsed_scopes = parse_scopes(token_scopes) + + common_bases = owner_parsed_scopes.keys() & token_parsed_scopes.keys() + + common_filters = {} + for base in common_bases: + if owner_parsed_scopes[base] == Scope.ALL: + common_filters[base] = token_parsed_scopes[base] + elif token_parsed_scopes[base] == Scope.ALL: + common_filters[base] = owner_parsed_scopes[base] + else: + common_entities = ( + owner_parsed_scopes[base].keys() & token_parsed_scopes[base].keys() + ) + common_filters[base] = { + entity: set(owner_parsed_scopes[base][entity]) + & set(token_parsed_scopes[base][entity]) + for entity in common_entities + } + + scopes = set() + for base in common_filters: + if common_filters[base] == Scope.ALL: + scopes.add(base) + else: + for entity, names_list in common_filters[base].items(): + for name in names_list: + scopes.add(f'{base}!{entity}={name}') + + return scopes + + def get_scopes_for(orm_object): """Find scopes for a given user or token and resolve permissions""" scopes = set() @@ -38,23 +74,8 @@ def get_scopes_for(orm_object): token_scopes.remove('all') token_scopes |= owner_scopes - # Ignore horizontal filters for comparison - token_base_scopes = {scope.partition('!')[0] for scope in token_scopes} - owner_base_scopes = {scope.partition('!')[0] for scope in owner_scopes} - - base_scopes = token_base_scopes & owner_base_scopes - discarded_token_scopes = token_base_scopes - base_scopes - - # Pass the token intersection scopes with original horizontal filters - scopes = set() - for scope in token_scopes: - base, _, filter = scope.partition('!') - for base_scope in base_scopes: - if base_scope == base: - scopes.add(scope) - - # scopes = token_scopes & owner_scopes - # discarded_token_scopes = token_scopes - scopes + scopes = _intersect_scopes(token_scopes, owner_scopes) + discarded_token_scopes = token_scopes - scopes # Not taking symmetric difference here because token owner can naturally have more scopes than token if discarded_token_scopes: From 71d3457adf5a39a2451d7e88b43e5747caf3040d Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Sat, 24 Apr 2021 12:10:25 +0200 Subject: [PATCH 160/270] Add test for resolving token scope permissions with horizontal filters --- jupyterhub/tests/test_scopes.py | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 7fc2e62e..4cf41e74 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -648,3 +648,62 @@ async def test_server_state_access( assert r.status_code == 403 app.db.delete(group) app.db.commit() + + +@mark.parametrize( + "name, user_scope, token_scope, discarded_own_scope, retained_owner_scope", + [ + ('no_filter', 'users:activity', 'users:activity', False, False), + ('valid_own_filter', 'users:activity', 'users:activity!user', False, False), + ( + 'valid_other_filter', + 'users:activity', + 'users:activity!user=otheruser', + False, + False, + ), + ('no_filter_owner_filter', 'users:activity!user', 'users:activity', True, True), + ( + 'valid_own_filter', + 'users:activity!user', + 'users:activity!user', + False, + False, + ), + ( + 'invalid_filter', + 'users:activity!user', + 'users:activity!user=otheruser', + True, + False, + ), + ], +) +async def test_resolve_token_permissions( + app, + create_user_with_scopes, + create_temp_role, + name, + user_scope, + token_scope, + discarded_own_scope, + retained_owner_scope, +): + + orm_user = create_user_with_scopes(user_scope).orm_user + create_temp_role([token_scope], 'active-posting') + api_token = orm_user.new_api_token(roles=['active-posting']) + orm_api_token = orm.APIToken.find(app.db, token=api_token) + + # get expanded !user filter scopes for check + user_scope = roles.expand_roles_to_scopes(orm_user) + token_scope = roles.expand_roles_to_scopes(orm_api_token) + + token_retained_scope = get_scopes_for(orm_api_token) + + if not discarded_own_scope and not retained_owner_scope: + assert token_retained_scope == token_scope + elif discarded_own_scope and not retained_owner_scope: + assert token_retained_scope == set() + elif discarded_own_scope and retained_owner_scope: + assert token_retained_scope == user_scope From bf9ca1d3be9c7e4a5ec9992a9f3a958c875d4705 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Sat, 24 Apr 2021 13:02:16 +0200 Subject: [PATCH 161/270] Test server token posting activity --- jupyterhub/tests/test_roles.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index f69a91cb..f7ee1bcc 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -12,6 +12,7 @@ from .. import orm from .. import roles from ..scopes import get_scopes_for from ..utils import maybe_future +from ..utils import utcnow from .mocking import MockHub from .utils import add_user from .utils import api_request @@ -963,3 +964,29 @@ async def test_server_token_role(app): assert user.api_tokens == [orm_server_token] await user.stop() + + +@mark.role +@mark.parametrize( + "token_role, response", + [ + ('server', 200), + ('token', 200), + ('no_role', 403), + ], +) +async def test_server_posting_activity(app, token_role, response): + user = add_user(app.db, app, name='test_user') + if token_role == 'no_role': + api_token = user.new_api_token(roles=[]) + else: + api_token = user.new_api_token(roles=[token_role]) + + r = await api_request( + app, + "users/{}/activity".format(user.name), + headers={"Authorization": "token {}".format(api_token)}, + data=json.dumps({"servers": {"": {"last_activity": utcnow().isoformat()}}}), + method="post", + ) + assert r.status_code == response From 91af87310e1294bbdd63a4bf1861ff27479da0a7 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 27 Apr 2021 09:51:40 +0200 Subject: [PATCH 162/270] Add more tests for server role --- jupyterhub/roles.py | 3 ++- jupyterhub/tests/test_roles.py | 44 +++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 7c81df94..cb807554 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -87,12 +87,13 @@ def _get_scope_hierarchy(): scopes = { 'self': None, 'all': None, - 'users': ['read:users', 'users:groups', 'users:activity'], + 'users': ['read:users', 'users:activity'], 'read:users': [ 'read:users:name', 'read:users:groups', 'read:users:activity', ], + 'users:activity': ['read:users:activity'], 'users:tokens': ['read:users:tokens'], 'admin:users': ['admin:users:auth_state'], 'admin:users:servers': ['admin:users:server_state'], diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index f7ee1bcc..4b5f2bd6 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -182,7 +182,6 @@ def test_orm_roles_delete_cascade(db): 'users', 'read:users', 'users:activity', - 'users:groups', 'read:users:name', 'read:users:groups', 'read:users:activity', @@ -968,25 +967,52 @@ async def test_server_token_role(app): @mark.role @mark.parametrize( - "token_role, response", + "token_role, api_method, api_endpoint, for_user, response", [ - ('server', 200), - ('token', 200), - ('no_role', 403), + ('server', 'post', 'activity', 'same_user', 200), + ('server', 'post', 'activity', 'other_user', 404), + ('server', 'get', 'users', 'same_user', 200), + ('token', 'post', 'activity', 'same_user', 200), + ('no_role', 'post', 'activity', 'same_user', 403), ], ) -async def test_server_posting_activity(app, token_role, response): +async def test_server_role_api_calls( + app, token_role, api_method, api_endpoint, for_user, response +): user = add_user(app.db, app, name='test_user') if token_role == 'no_role': api_token = user.new_api_token(roles=[]) else: api_token = user.new_api_token(roles=[token_role]) + if for_user == 'same_user': + username = user.name + else: + username = 'otheruser' + + if api_endpoint == 'activity': + path = "users/{}/activity".format(username) + data = json.dumps({"servers": {"": {"last_activity": utcnow().isoformat()}}}) + elif api_endpoint == 'users': + path = "users" + data = "" + r = await api_request( app, - "users/{}/activity".format(user.name), + path, headers={"Authorization": "token {}".format(api_token)}, - data=json.dumps({"servers": {"": {"last_activity": utcnow().isoformat()}}}), - method="post", + data=data, + method=api_method, ) assert r.status_code == response + + if api_endpoint == 'users' and token_role == 'server': + reply = r.json() + assert len(reply) == 1 + + user_model = reply[0] + assert user_model['name'] == username + assert 'last_activity' in user_model.keys() + assert ( + all(key for key in ['groups', 'roles', 'servers']) not in user_model.keys() + ) From b3887b07ba64dfc49e9f20b4e64dc99702289748 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 28 Apr 2021 16:52:59 +0200 Subject: [PATCH 163/270] Add more filter intersection tests, note and warning for containing filters --- jupyterhub/roles.py | 1 + jupyterhub/scopes.py | 22 +++++- jupyterhub/tests/test_roles.py | 2 +- jupyterhub/tests/test_scopes.py | 117 +++++++++++++++++++++++--------- 4 files changed, 108 insertions(+), 34 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index cb807554..7199b30f 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -99,6 +99,7 @@ def _get_scope_hierarchy(): 'admin:users:servers': ['admin:users:server_state'], 'groups': ['read:groups'], 'users:servers': ['read:users:servers'], + 'read:users:servers': ['read:users:name'], 'admin:groups': None, 'read:services': None, 'read:hub': None, diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index d29c806d..652573fd 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -15,13 +15,22 @@ class Scope(Enum): def _intersect_scopes(token_scopes, owner_scopes): """Compares the permissions of token and its owner including horizontal filters - Returns the intersection of the two sets of scopes""" + Returns the intersection of the two sets of scopes + + Note: Intersects correctly with ALL and exact filter matches + (i.e. users!user=x & read:users:name -> read:users:name!user=x) + + Does not currently intersect with containing filters + (i.e. users!group=x & users!user=y even if user y is in group x, + same for users:servers!user=x & users:servers!server=y) + """ owner_parsed_scopes = parse_scopes(owner_scopes) token_parsed_scopes = parse_scopes(token_scopes) common_bases = owner_parsed_scopes.keys() & token_parsed_scopes.keys() common_filters = {} + warn = False for base in common_bases: if owner_parsed_scopes[base] == Scope.ALL: common_filters[base] = token_parsed_scopes[base] @@ -31,12 +40,23 @@ def _intersect_scopes(token_scopes, owner_scopes): common_entities = ( owner_parsed_scopes[base].keys() & token_parsed_scopes[base].keys() ) + all_entities = ( + owner_parsed_scopes[base].keys() | token_parsed_scopes[base].keys() + ) + if 'user' in all_entities and ('group' or 'server' in all_entities): + warn = True + common_filters[base] = { entity: set(owner_parsed_scopes[base][entity]) & set(token_parsed_scopes[base][entity]) for entity in common_entities } + if warn: + app_log.warning( + "[!user=, !group=] or [!user=, !server=] combinations of filters present, intersection between not considered. May result in lower than intended permissions." + ) + scopes = set() for base in common_filters: if common_filters[base] == Scope.ALL: diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 4b5f2bd6..53103e9a 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -196,7 +196,7 @@ def test_orm_roles_delete_cascade(db): 'read:users:activity', }, ), - (['read:users:servers'], {'read:users:servers'}), + (['read:users:servers'], {'read:users:servers', 'read:users:name'}), (['admin:groups'], {'admin:groups'}), ( ['users:tokens!group=hobbits'], diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 4cf41e74..9d8b421e 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -651,31 +651,90 @@ async def test_server_state_access( @mark.parametrize( - "name, user_scope, token_scope, discarded_own_scope, retained_owner_scope", + "name, user_scopes, token_scopes, intersection_scopes", [ - ('no_filter', 'users:activity', 'users:activity', False, False), - ('valid_own_filter', 'users:activity', 'users:activity!user', False, False), ( - 'valid_other_filter', - 'users:activity', - 'users:activity!user=otheruser', - False, - False, + 'no_filter', + ['users:activity'], + ['users:activity'], + {'users:activity', 'read:users:activity'}, ), - ('no_filter_owner_filter', 'users:activity!user', 'users:activity', True, True), ( 'valid_own_filter', - 'users:activity!user', - 'users:activity!user', - False, - False, + ['read:users:activity'], + ['read:users:activity!user'], + {'read:users:activity!user=temp_user_1'}, + ), + ( + 'valid_other_filter', + ['read:users:activity'], + ['read:users:activity!user=otheruser'], + {'read:users:activity!user=otheruser'}, + ), + ( + 'no_filter_owner_filter', + ['read:users:activity!user'], + ['read:users:activity'], + {'read:users:activity!user=temp_user_1'}, + ), + ( + 'valid_own_filter', + ['read:users:activity!user'], + ['read:users:activity!user'], + {'read:users:activity!user=temp_user_1'}, ), ( 'invalid_filter', - 'users:activity!user', - 'users:activity!user=otheruser', - True, - False, + ['read:users:activity!user'], + ['read:users:activity!user=otheruser'], + set(), + ), + ( + 'subscopes_cross_filter', + ['users!user=x'], + ['read:users:name'], + {'read:users:name!user=x'}, + ), + ( + 'multiple_user_filter', + ['users!user=x', 'users!user=y'], + ['read:users:name!user=x'], + {'read:users:name!user=x'}, + ), + ( + 'no_intersection_group_user', + ['users!group=y'], + ['users!user=x'], + set(), + ), + ( + 'no_intersection_user_server', + ['users:servers!user=y'], + ['users:servers!server=x'], + set(), + ), + ( + 'users_and_groups_both', + ['users!group=x', 'users!user=y'], + ['read:users:name!group=x', 'read:users!user=y'], + { + 'read:users:name!group=x', + 'read:users!user=y', + 'read:users:name!user=y', + 'read:users:groups!user=y', + 'read:users:activity!user=y', + }, + ), + ( + 'users_and_groups_user_only', + ['users!group=x', 'users!user=y'], + ['read:users:name!group=z', 'read:users!user=y'], + { + 'read:users!user=y', + 'read:users:name!user=y', + 'read:users:groups!user=y', + 'read:users:activity!user=y', + }, ), ], ) @@ -684,26 +743,20 @@ async def test_resolve_token_permissions( create_user_with_scopes, create_temp_role, name, - user_scope, - token_scope, - discarded_own_scope, - retained_owner_scope, + user_scopes, + token_scopes, + intersection_scopes, ): - orm_user = create_user_with_scopes(user_scope).orm_user - create_temp_role([token_scope], 'active-posting') + orm_user = create_user_with_scopes(*user_scopes).orm_user + create_temp_role(token_scopes, 'active-posting') api_token = orm_user.new_api_token(roles=['active-posting']) orm_api_token = orm.APIToken.find(app.db, token=api_token) # get expanded !user filter scopes for check - user_scope = roles.expand_roles_to_scopes(orm_user) - token_scope = roles.expand_roles_to_scopes(orm_api_token) + user_scopes = roles.expand_roles_to_scopes(orm_user) + token_scopes = roles.expand_roles_to_scopes(orm_api_token) - token_retained_scope = get_scopes_for(orm_api_token) + token_retained_scopes = get_scopes_for(orm_api_token) - if not discarded_own_scope and not retained_owner_scope: - assert token_retained_scope == token_scope - elif discarded_own_scope and not retained_owner_scope: - assert token_retained_scope == set() - elif discarded_own_scope and retained_owner_scope: - assert token_retained_scope == user_scope + assert token_retained_scopes == intersection_scopes From cdc99580deab22a51bb2929b35824187cf0a004c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 28 Apr 2021 17:19:52 +0200 Subject: [PATCH 164/270] Update scope hierarchy in roles.py and tests --- jupyterhub/roles.py | 12 +++++++----- jupyterhub/tests/test_roles.py | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 6ea75a89..afb4f4f0 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -87,18 +87,20 @@ def _get_scope_hierarchy(): scopes = { 'self': None, 'all': None, - 'users': ['read:users', 'users:groups', 'users:activity'], + 'admin:users': ['admin:users:auth_state', 'users'], + 'users': ['read:users', 'users:activity'], 'read:users': [ 'read:users:name', 'read:users:groups', 'read:users:activity', ], + 'users:activity': ['read:users:activity'], 'users:tokens': ['read:users:tokens'], - 'admin:users': ['admin:users:auth_state'], - 'admin:users:servers': ['admin:users:server_state'], - 'groups': ['read:groups'], + 'admin:users:servers': ['admin:users:server_state', 'users:servers'], 'users:servers': ['read:users:servers'], - 'admin:groups': None, + 'read:users:servers': ['read:users:name'], + 'admin:groups': ['groups'], + 'groups': ['read:groups'], 'read:services': None, 'read:hub': None, 'proxy': None, diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index f538ff21..30e442dc 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -175,13 +175,25 @@ def test_orm_roles_delete_cascade(db): @mark.parametrize( "scopes, subscopes", [ + ( + ['admin:users'], + { + 'admin:users', + 'admin:users:auth_state', + 'users', + 'read:users', + 'users:activity', + 'read:users:name', + 'read:users:groups', + 'read:users:activity', + }, + ), ( ['users'], { 'users', 'read:users', 'users:activity', - 'users:groups', 'read:users:name', 'read:users:groups', 'read:users:activity', @@ -196,8 +208,8 @@ def test_orm_roles_delete_cascade(db): 'read:users:activity', }, ), - (['read:users:servers'], {'read:users:servers'}), - (['admin:groups'], {'admin:groups'}), + (['read:users:servers'], {'read:users:servers', 'read:users:name'}), + (['admin:groups'], {'admin:groups', 'groups', 'read:groups'}), ( ['users:tokens!group=hobbits'], {'users:tokens!group=hobbits', 'read:users:tokens!group=hobbits'}, From b2c286691521a25608438079303497cc7c38cd57 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 28 Apr 2021 17:34:19 +0200 Subject: [PATCH 165/270] Update admin role scopes list --- jupyterhub/roles.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index afb4f4f0..a685e1cd 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -23,13 +23,9 @@ def get_default_roles(): 'name': 'admin', 'description': 'Admin privileges (currently can do everything)', 'scopes': [ - 'all', - 'users', - 'users:servers', - 'users:tokens', 'admin:users', 'admin:users:servers', - 'groups', + 'users:tokens', 'admin:groups', 'read:services', 'read:hub', From 60c73de8b2bf1e90109fa4f866c8aa36a4c699ec Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 29 Apr 2021 09:23:43 +0200 Subject: [PATCH 166/270] Change read:users(services):admin scope to read:users(services):roles --- jupyterhub/roles.py | 4 +++- jupyterhub/scopes.py | 4 ++-- jupyterhub/tests/test_roles.py | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index a685e1cd..b07591be 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -64,6 +64,7 @@ def expand_self_scope(name): 'users', 'users:name', 'users:groups', + 'users:roles', 'users:activity', 'users:servers', 'users:tokens', @@ -88,6 +89,7 @@ def _get_scope_hierarchy(): 'read:users': [ 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', ], 'users:activity': ['read:users:activity'], @@ -97,7 +99,7 @@ def _get_scope_hierarchy(): 'read:users:servers': ['read:users:name'], 'admin:groups': ['groups'], 'groups': ['read:groups'], - 'read:services': None, + 'read:services': ['read:services:name', 'read:services:roles'], 'read:hub': None, 'proxy': None, 'shutdown': None, diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index c5e6365c..ac68f6e6 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -208,11 +208,11 @@ def identify_scopes(obj): if isinstance(obj, orm.User): return { f"read:users:{field}!user={obj.name}" - for field in {"name", "admin", "groups"} + for field in {"name", "roles", "groups"} } elif isinstance(obj, orm.Service): return { - f"read:services:{field}!service={obj.name}" for field in {"name", "admin"} + f"read:services:{field}!service={obj.name}" for field in {"name", "roles"} } else: raise TypeError(f"Expected orm.User or orm.Service, got {obj!r}") diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 30e442dc..9fede4bd 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -185,6 +185,7 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', }, ), @@ -196,6 +197,7 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', }, ), @@ -205,6 +207,7 @@ def test_orm_roles_delete_cascade(db): 'read:users', 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', }, ), From 7022a4c558bd21721b8d0a05659dc0966d6b3317 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 29 Apr 2021 10:03:25 +0200 Subject: [PATCH 167/270] Fixed review comments and added allowed roles to spawner configuration --- jupyterhub/app.py | 3 +-- jupyterhub/services/service.py | 2 +- jupyterhub/spawner.py | 5 +++++ jupyterhub/tests/test_roles.py | 4 ++-- jupyterhub/tests/test_spawner.py | 6 ++++++ jupyterhub/user.py | 3 ++- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 6da806ad..d7ab38f2 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2127,7 +2127,6 @@ class JupyterHub(Application): name = spec['name'] # get/create orm orm_service = orm.Service.find(self.db, name=name) - allowed_roles = spec.get('allowed_roles', []) if orm_service is None: # not found, create a new one orm_service = orm.Service(name=name) @@ -2192,7 +2191,7 @@ class JupyterHub(Application): client_id=service.oauth_client_id, client_secret=service.api_token, redirect_uri=service.oauth_redirect_uri, - allowed_roles=allowed_roles, + allowed_roles=service.oauth_roles, description="JupyterHub service %s" % service.name, ) diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index 380cddf8..acea33f6 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -190,7 +190,7 @@ class Service(LoggingConfigurable): """ ).tag(input=True) - allowed_roles = List( + oauth_roles = List( help="""OAuth allowed roles. List of roles that are passed to generated tokens if the service act as an OAuth client diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index ead537d6..2c4d4581 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -219,6 +219,11 @@ class Spawner(LoggingConfigurable): oauth_client_id = Unicode() handler = Any() + allowed_roles = List( + help="""OAuth allowed roles for single-user servers + """ + ).tag(input=True) + will_resume = Bool( False, help="""Whether the Spawner will resume on next start diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 450640f1..e1576ae5 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -906,7 +906,7 @@ async def test_oauth_allowed_roles(app, create_temp_role): service = { 'name': 'oas1', 'api_token': 'some-token', - 'allowed_roles': ['oracle', 'goose'], + 'oauth_roles': ['oracle', 'goose'], } for role in allowed_roles: create_temp_role('read:users', role_name=role) @@ -914,4 +914,4 @@ async def test_oauth_allowed_roles(app, create_temp_role): app.init_services() app_service = app.services[0] assert app_service['name'] == 'oas1' - assert set(app_service['allowed_roles']) == set(allowed_roles) + assert set(app_service['oauth_roles']) == set(allowed_roles) diff --git a/jupyterhub/tests/test_spawner.py b/jupyterhub/tests/test_spawner.py index b73fb052..9d06a0e4 100644 --- a/jupyterhub/tests/test_spawner.py +++ b/jupyterhub/tests/test_spawner.py @@ -426,3 +426,9 @@ async def test_hub_connect_url(db): env["JUPYTERHUB_ACTIVITY_URL"] == "https://example.com/api/users/%s/activity" % name ) + + +async def test_spawner_oauth_roles(app): + allowed_roles = ['lotsa', 'roles'] + spawner = new_spawner(app.db, allowed_roles=allowed_roles) + assert spawner.allowed_roles == allowed_roles diff --git a/jupyterhub/user.py b/jupyterhub/user.py index a95c1a8c..9c31da6b 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -568,7 +568,8 @@ class User: client_id, api_token, url_path_join(self.url, server_name, 'oauth_callback'), - description="Server at %s" # todo: own server: 'users:servers!user={username} as allowed role? + allowed_roles=spawner.allowed_roles, + description="Server at %s" % (url_path_join(self.base_url, server_name) + '/'), ) db.commit() From 1337a53a9f7d4a6af15431b99d774294cbb56cf9 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 29 Apr 2021 12:58:16 +0200 Subject: [PATCH 168/270] consistent docstrings, config for services/spawner oauth_roles --- jupyterhub/services/service.py | 12 +++++++++--- jupyterhub/spawner.py | 17 +++++++++++++---- jupyterhub/tests/test_spawner.py | 4 ++-- jupyterhub/user.py | 7 ++++++- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index acea33f6..f556b6da 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -192,9 +192,15 @@ class Service(LoggingConfigurable): oauth_roles = List( help="""OAuth allowed roles. - - List of roles that are passed to generated tokens if the service act as an OAuth client - on behalf of users""" + + This sets the maximum and default roles + assigned to oauth tokens issued for this service + (i.e. tokens stored in browsers after authenticating with the server), + defining what actions the service can take on behalf of logged-in users. + + Default is an empty list, meaning minimal permissions to identify users, + no actions can be taken on their behalf. + """ ).tag(input=True) api_token = Unicode( diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index 2c4d4581..d96dd54d 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -219,10 +219,19 @@ class Spawner(LoggingConfigurable): oauth_client_id = Unicode() handler = Any() - allowed_roles = List( - help="""OAuth allowed roles for single-user servers - """ - ).tag(input=True) + oauth_roles = Union( + [Callable(), List()], + help="""Allowed roles for oauth tokens. + + This sets the maximum and default roles + assigned to oauth tokens issued by a single-user server's + oauth client (i.e. tokens stored in browsers after authenticating with the server), + defining what actions the server can take on behalf of logged-in users. + + Default is an empty list, meaning minimal permissions to identify users, + no actions can be taken on their behalf. + """, + ).tag(config=True) will_resume = Bool( False, diff --git a/jupyterhub/tests/test_spawner.py b/jupyterhub/tests/test_spawner.py index 9d06a0e4..3721ccb4 100644 --- a/jupyterhub/tests/test_spawner.py +++ b/jupyterhub/tests/test_spawner.py @@ -430,5 +430,5 @@ async def test_hub_connect_url(db): async def test_spawner_oauth_roles(app): allowed_roles = ['lotsa', 'roles'] - spawner = new_spawner(app.db, allowed_roles=allowed_roles) - assert spawner.allowed_roles == allowed_roles + spawner = new_spawner(app.db, oauth_roles=allowed_roles) + assert spawner.oauth_roles == allowed_roles diff --git a/jupyterhub/user.py b/jupyterhub/user.py index 9c31da6b..fce76a89 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -564,11 +564,16 @@ class User: oauth_client = oauth_provider.fetch_by_client_id(client_id) # create a new OAuth client + secret on every launch # containers that resume will be updated below + + allowed_roles = spawner.oauth_roles + if callable(allowed_roles): + allowed_roles = allowed_roles(spawner) + oauth_provider.add_client( client_id, api_token, url_path_join(self.url, server_name, 'oauth_callback'), - allowed_roles=spawner.allowed_roles, + allowed_roles=allowed_roles, description="Server at %s" % (url_path_join(self.base_url, server_name) + '/'), ) From cc35d84f257cfa037cb1e9a67acfad8c455c1c1c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 30 Apr 2021 15:13:29 +0200 Subject: [PATCH 169/270] Revert "Change read:users(services):admin scope to read:users(services):roles" read:users(services):roles scopes will be added together with changes to api handlers --- jupyterhub/roles.py | 4 +--- jupyterhub/scopes.py | 4 ++-- jupyterhub/tests/test_roles.py | 3 --- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index b07591be..a685e1cd 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -64,7 +64,6 @@ def expand_self_scope(name): 'users', 'users:name', 'users:groups', - 'users:roles', 'users:activity', 'users:servers', 'users:tokens', @@ -89,7 +88,6 @@ def _get_scope_hierarchy(): 'read:users': [ 'read:users:name', 'read:users:groups', - 'read:users:roles', 'read:users:activity', ], 'users:activity': ['read:users:activity'], @@ -99,7 +97,7 @@ def _get_scope_hierarchy(): 'read:users:servers': ['read:users:name'], 'admin:groups': ['groups'], 'groups': ['read:groups'], - 'read:services': ['read:services:name', 'read:services:roles'], + 'read:services': None, 'read:hub': None, 'proxy': None, 'shutdown': None, diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index ac68f6e6..c5e6365c 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -208,11 +208,11 @@ def identify_scopes(obj): if isinstance(obj, orm.User): return { f"read:users:{field}!user={obj.name}" - for field in {"name", "roles", "groups"} + for field in {"name", "admin", "groups"} } elif isinstance(obj, orm.Service): return { - f"read:services:{field}!service={obj.name}" for field in {"name", "roles"} + 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}") diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 9fede4bd..30e442dc 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -185,7 +185,6 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', - 'read:users:roles', 'read:users:activity', }, ), @@ -197,7 +196,6 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', - 'read:users:roles', 'read:users:activity', }, ), @@ -207,7 +205,6 @@ def test_orm_roles_delete_cascade(db): 'read:users', 'read:users:name', 'read:users:groups', - 'read:users:roles', 'read:users:activity', }, ), From c61b8e60c2ca2ae7dbfabc6f389f81de1e6d3925 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 30 Apr 2021 17:27:26 +0200 Subject: [PATCH 170/270] Removed configuration options to assign roles to tokens --- jupyterhub/app.py | 12 --- jupyterhub/roles.py | 19 ---- jupyterhub/tests/test_roles.py | 163 --------------------------------- 3 files changed, 194 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index d7ab38f2..9249ce75 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -333,7 +333,6 @@ class JupyterHub(Application): 'scopes': ['users', 'groups'], 'users': ['cyclops', 'gandalf'], 'services': [], - 'tokens': [], 'groups': [] } ] @@ -2013,9 +2012,6 @@ class JupyterHub(Application): for bearer in role_bearers: roles.check_for_default_roles(db, bearer) - # now add roles to tokens if their owner's permissions allow - roles.add_predef_roles_tokens(db, self.load_roles) - # check tokens for default roles roles.check_for_default_roles(db, bearer='tokens') @@ -2058,13 +2054,6 @@ class JupyterHub(Application): db.add(obj) db.commit() self.log.info("Adding API token for %s: %s", kind, name) - # If we have roles in the configuration file, they will be added later - # Todo: works but ugly - config_roles = None - for config_role in self.load_roles: - if 'tokens' in config_role and token in config_role['tokens']: - config_roles = [] - break try: # set generated=False to ensure that user-provided tokens # get extra hashing (don't trust entropy of user-provided tokens) @@ -2072,7 +2061,6 @@ class JupyterHub(Application): token, note="from config", generated=self.trust_user_provided_tokens, - roles=config_roles, ) except Exception: if created: diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 7199b30f..b79941ed 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -479,25 +479,6 @@ def update_roles(db, entity, roles): grant_role(db, entity=entity, rolename=rolename) -def add_predef_roles_tokens(db, predef_roles): - - """Adds tokens to predefined roles in config file - if their permissions allow""" - - for predef_role in predef_roles: - if 'tokens' in predef_role.keys(): - token_role = orm.Role.find(db, name=predef_role['name']) - for token_name in predef_role['tokens']: - token = orm.APIToken.find(db, token_name) - if token is None: - raise ValueError( - "Token %r does not exist and cannot assign it to role %r" - % (token_name, token_role.name) - ) - else: - update_roles(db, token, roles=[token_role.name]) - - def check_for_default_roles(db, bearer): """Checks that role bearers have at least one role (default if none). diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 41d5ed12..3ef14a0d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -589,7 +589,6 @@ async def test_load_roles_user_tokens(tmpdir, request): 'name': 'reader', 'description': 'Read all users models', 'scopes': ['read:users'], - 'tokens': ['super-secret-token'], }, ] kwargs = { @@ -608,11 +607,6 @@ async def test_load_roles_user_tokens(tmpdir, request): await hub.init_api_tokens() await hub.init_roles() - # test if gandalf's token has the 'reader' role - reader_role = orm.Role.find(db, 'reader') - token = orm.APIToken.find(db, 'super-secret-token') - assert reader_role in token.roles - # test if all other tokens have default 'user' role token_role = orm.Role.find(db, 'token') secret_token = orm.APIToken.find(db, 'secret-token') @@ -630,163 +624,6 @@ async def test_load_roles_user_tokens(tmpdir, request): roles.delete_role(db, role['name']) -@mark.role -async def test_load_roles_user_tokens_not_allowed(tmpdir, request): - user_tokens = { - 'secret-token': 'bilbo', - } - roles_to_load = [ - { - 'name': 'user-creator', - 'description': 'Creates/deletes any user', - 'scopes': ['admin:users'], - 'tokens': ['secret-token'], - }, - ] - kwargs = { - 'load_roles': roles_to_load, - 'api_tokens': user_tokens, - } - ssl_enabled = getattr(request.module, "ssl_enabled", False) - if ssl_enabled: - kwargs['internal_certs_location'] = str(tmpdir) - hub = MockHub(**kwargs) - hub.init_db() - db = hub.db - hub.authenticator.allowed_users = ['bilbo'] - await hub.init_users() - await hub.init_api_tokens() - - response = 'allowed' - # bilbo has only default 'user' role - # while bilbo's token is requesting role with higher permissions - with pytest.raises(ValueError): - await hub.init_roles() - - # delete the test tokens - for token in db.query(orm.APIToken): - db.delete(token) - db.commit() - - # delete the test roles - for role in roles_to_load: - roles.delete_role(db, role['name']) - - -@mark.role -async def test_load_roles_service_tokens(tmpdir, request): - services = [ - {'name': 'idle-culler', 'api_token': 'another-secret-token'}, - ] - service_tokens = { - 'another-secret-token': 'idle-culler', - } - roles_to_load = [ - { - 'name': 'idle-culler', - 'description': 'Cull idle servers', - 'scopes': [ - 'read:users:name', - 'read:users:activity', - 'read:users:servers', - 'users:servers', - ], - 'services': ['idle-culler'], - 'tokens': ['another-secret-token'], - }, - ] - kwargs = { - 'load_roles': roles_to_load, - 'services': services, - 'service_tokens': service_tokens, - } - ssl_enabled = getattr(request.module, "ssl_enabled", False) - if ssl_enabled: - kwargs['internal_certs_location'] = str(tmpdir) - hub = MockHub(**kwargs) - hub.init_db() - db = hub.db - await hub.init_api_tokens() - await hub.init_roles() - - # test if another-secret-token has idle-culler role - service = orm.Service.find(db, 'idle-culler') - culler_role = orm.Role.find(db, 'idle-culler') - token = orm.APIToken.find(db, 'another-secret-token') - assert len(token.roles) == 1 - assert culler_role in token.roles - - # delete the test services - for service in db.query(orm.Service): - db.delete(service) - db.commit() - - # delete the test tokens - for token in db.query(orm.APIToken): - db.delete(token) - db.commit() - - # delete the test roles - for role in roles_to_load: - roles.delete_role(db, role['name']) - - -@mark.role -async def test_load_roles_service_tokens_not_allowed(tmpdir, request): - services = [{'name': 'some-service', 'api_token': 'secret-token'}] - service_tokens = { - 'secret-token': 'some-service', - } - roles_to_load = [ - { - 'name': 'user-reader', - 'description': 'Read-only user models', - 'scopes': ['read:users'], - 'services': ['some-service'], - }, - # 'idle-culler' role has higher permissions that the token's owner 'some-service' - { - 'name': 'idle-culler', - 'description': 'Cull idle servers', - 'scopes': [ - 'read:users:name', - 'read:users:activity', - 'read:users:servers', - 'users:servers', - ], - 'tokens': ['secret-token'], - }, - ] - kwargs = { - 'load_roles': roles_to_load, - 'services': services, - 'service_tokens': service_tokens, - } - ssl_enabled = getattr(request.module, "ssl_enabled", False) - if ssl_enabled: - kwargs['internal_certs_location'] = str(tmpdir) - hub = MockHub(**kwargs) - hub.init_db() - db = hub.db - await hub.init_api_tokens() - with pytest.raises(ValueError): - await hub.init_roles() - - # delete the test services - for service in db.query(orm.Service): - db.delete(service) - db.commit() - - # delete the test tokens - for token in db.query(orm.APIToken): - db.delete(token) - db.commit() - - # delete the test roles - for role in roles_to_load: - roles.delete_role(db, role['name']) - - @mark.role @mark.parametrize( "headers, rolename, scopes, status", From 863b4c7d50c00617ff5c7a67b176aa8ea0727317 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 23 Apr 2021 14:02:50 +0200 Subject: [PATCH 171/270] Deprecate and remove some old auth bits - remove long-deprecated `POST /api/authorizations/token` for creating tokens - deprecate but do not remove `GET /api/authorizations/token/:token` in favor of GET /api/user - remove shared-cookie auth for services from HubAuth, rely on OAuth for browser-auth instead - use `/hub/api/user` to resolve user instead of `/authorizations/token` which is now deprecated --- docs/source/reference/services.md | 11 +- examples/service-whoami-flask/README.md | 4 +- .../service-whoami-flask/jupyterhub_config.py | 14 +- examples/service-whoami-flask/whoami-flask.py | 47 ++++- examples/service-whoami-flask/whoami-oauth.py | 72 ------- jupyterhub/apihandlers/auth.py | 52 +---- jupyterhub/apihandlers/users.py | 5 + jupyterhub/scopes.py | 3 + jupyterhub/services/auth.py | 87 ++++----- jupyterhub/singleuser/mixins.py | 1 - jupyterhub/tests/test_api.py | 65 +------ jupyterhub/tests/test_services_auth.py | 178 +----------------- 12 files changed, 112 insertions(+), 427 deletions(-) delete mode 100644 examples/service-whoami-flask/whoami-oauth.py diff --git a/docs/source/reference/services.md b/docs/source/reference/services.md index f3f0e83f..aa8caa64 100644 --- a/docs/source/reference/services.md +++ b/docs/source/reference/services.md @@ -203,8 +203,6 @@ To use HubAuth, you must set the `.api_token`, either programmatically when cons or via the `JUPYTERHUB_API_TOKEN` environment variable. Most of the logic for authentication implementation is found in the -[`HubAuth.user_for_cookie`][hubauth.user_for_cookie] -and in the [`HubAuth.user_for_token`][hubauth.user_for_token] methods, which makes a request of the Hub, and returns: @@ -241,11 +239,11 @@ from urllib.parse import quote from flask import Flask, redirect, request, Response -from jupyterhub.services.auth import HubAuth +from jupyterhub.services.auth import HubOAuth prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/') -auth = HubAuth( +auth = HubOAuth( api_token=os.environ['JUPYTERHUB_API_TOKEN'], cache_max_age=60, ) @@ -257,11 +255,8 @@ def authenticated(f): """Decorator for authenticating with the Hub""" @wraps(f) def decorated(*args, **kwargs): - cookie = request.cookies.get(auth.cookie_name) token = request.headers.get(auth.auth_header_name) - if cookie: - user = auth.user_for_cookie(cookie) - elif token: + if token: user = auth.user_for_token(token) else: user = None diff --git a/examples/service-whoami-flask/README.md b/examples/service-whoami-flask/README.md index 75555b24..b90f4f44 100644 --- a/examples/service-whoami-flask/README.md +++ b/examples/service-whoami-flask/README.md @@ -1,6 +1,6 @@ # Authenticating a flask service with JupyterHub -Uses `jupyterhub.services.HubAuth` to authenticate requests with the Hub in a [flask][] application. +Uses `jupyterhub.services.HubOAuth` to authenticate requests with the Hub in a [flask][] application. ## Run @@ -8,7 +8,7 @@ Uses `jupyterhub.services.HubAuth` to authenticate requests with the Hub in a [f jupyterhub --ip=127.0.0.1 -2. Visit http://127.0.0.1:8000/services/whoami/ or http://127.0.0.1:8000/services/whoami-oauth/ +2. Visit http://127.0.0.1:8000/services/whoami/ After logging in with your local-system credentials, you should see a JSON dump of your user info: diff --git a/examples/service-whoami-flask/jupyterhub_config.py b/examples/service-whoami-flask/jupyterhub_config.py index 63ddaa38..71e890d9 100644 --- a/examples/service-whoami-flask/jupyterhub_config.py +++ b/examples/service-whoami-flask/jupyterhub_config.py @@ -5,10 +5,12 @@ c.JupyterHub.services = [ 'command': ['flask', 'run', '--port=10101'], 'environment': {'FLASK_APP': 'whoami-flask.py'}, }, - { - 'name': 'whoami-oauth', - 'url': 'http://127.0.0.1:10201', - 'command': ['flask', 'run', '--port=10201'], - 'environment': {'FLASK_APP': 'whoami-oauth.py'}, - }, ] + +# dummy auth and simple spawner for testing +# any username and password will work +c.JupyterHub.spawner_class = 'simple' +c.JupyterHub.authenticator_class = 'dummy' + +# listen only on localhost while testing with wide-open auth +c.JupyterHub.ip = '127.0.0.1' diff --git a/examples/service-whoami-flask/whoami-flask.py b/examples/service-whoami-flask/whoami-flask.py index b3353ae5..139925c9 100644 --- a/examples/service-whoami-flask/whoami-flask.py +++ b/examples/service-whoami-flask/whoami-flask.py @@ -4,42 +4,48 @@ whoami service authentication with the Hub """ import json import os +import secrets from functools import wraps -from urllib.parse import quote from flask import Flask +from flask import make_response from flask import redirect from flask import request from flask import Response +from flask import session -from jupyterhub.services.auth import HubAuth +from jupyterhub.services.auth import HubOAuth prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/') -auth = HubAuth(api_token=os.environ['JUPYTERHUB_API_TOKEN'], cache_max_age=60) +auth = HubOAuth(api_token=os.environ['JUPYTERHUB_API_TOKEN'], cache_max_age=60) app = Flask(__name__) +# encryption key for session cookies +app.secret_key = secrets.token_bytes(32) def authenticated(f): - """Decorator for authenticating with the Hub""" + """Decorator for authenticating with the Hub via OAuth""" @wraps(f) def decorated(*args, **kwargs): - cookie = request.cookies.get(auth.cookie_name) - token = request.headers.get(auth.auth_header_name) - if cookie: - user = auth.user_for_cookie(cookie) - elif token: + token = session.get("token") + + if token: user = auth.user_for_token(token) else: user = None + if user: return f(user, *args, **kwargs) else: # redirect to login url on failed auth - return redirect(auth.login_url + '?next=%s' % quote(request.path)) + state = auth.generate_state(next_url=request.path) + response = make_response(redirect(auth.login_url + '&state=%s' % state)) + response.set_cookie(auth.state_cookie_name, state) + return response return decorated @@ -50,3 +56,24 @@ def whoami(user): return Response( json.dumps(user, indent=1, sort_keys=True), mimetype='application/json' ) + + +@app.route(prefix + 'oauth_callback') +def oauth_callback(): + code = request.args.get('code', None) + if code is None: + return 403 + + # validate state field + arg_state = request.args.get('state', None) + cookie_state = request.cookies.get(auth.state_cookie_name) + if arg_state is None or arg_state != cookie_state: + # state doesn't match + return 403 + + token = auth.token_for_code(code) + # store token in session cookie + session["token"] = token + next_url = auth.get_next_url(cookie_state) or prefix + response = make_response(redirect(next_url)) + return response diff --git a/examples/service-whoami-flask/whoami-oauth.py b/examples/service-whoami-flask/whoami-oauth.py deleted file mode 100644 index 26837dcd..00000000 --- a/examples/service-whoami-flask/whoami-oauth.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -""" -whoami service authentication with the Hub -""" -import json -import os -from functools import wraps - -from flask import Flask -from flask import make_response -from flask import redirect -from flask import request -from flask import Response - -from jupyterhub.services.auth import HubOAuth - - -prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/') - -auth = HubOAuth(api_token=os.environ['JUPYTERHUB_API_TOKEN'], cache_max_age=60) - -app = Flask(__name__) - - -def authenticated(f): - """Decorator for authenticating with the Hub via OAuth""" - - @wraps(f) - def decorated(*args, **kwargs): - token = request.cookies.get(auth.cookie_name) - if token: - user = auth.user_for_token(token) - else: - user = None - if user: - return f(user, *args, **kwargs) - else: - # redirect to login url on failed auth - state = auth.generate_state(next_url=request.path) - response = make_response(redirect(auth.login_url + '&state=%s' % state)) - response.set_cookie(auth.state_cookie_name, state) - return response - - return decorated - - -@app.route(prefix) -@authenticated -def whoami(user): - return Response( - json.dumps(user, indent=1, sort_keys=True), mimetype='application/json' - ) - - -@app.route(prefix + 'oauth_callback') -def oauth_callback(): - code = request.args.get('code', None) - if code is None: - return 403 - - # validate state field - arg_state = request.args.get('state', None) - cookie_state = request.cookies.get(auth.state_cookie_name) - if arg_state is None or arg_state != cookie_state: - # state doesn't match - return 403 - - token = auth.token_for_code(code) - next_url = auth.get_next_url(cookie_state) or prefix - response = make_response(redirect(next_url)) - response.set_cookie(auth.cookie_name, token) - return response diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index e7f72880..ed548add 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -14,7 +14,6 @@ from tornado import web from .. import orm from .. import scopes -from ..user import User from ..utils import token_authenticated from .base import APIHandler from .base import BaseHandler @@ -24,7 +23,7 @@ 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? + # TODO: require specific scope for this deprecated API, applied to service tokens only? self.log.warning( "/authorizations/token/:token endpoint is deprecated in JupyterHub 2.0. Use /api/user" ) @@ -55,53 +54,20 @@ class TokenAPIHandler(APIHandler): self.write(json.dumps(model)) async def post(self): - warn_msg = ( - "Using deprecated token creation endpoint %s." - " Use /hub/api/users/:user/tokens instead." - ) % self.request.uri - self.log.warning(warn_msg) - requester = user = self.current_user - if user is None: - # allow requesting a token with username and password - # for authenticators where that's possible - data = self.get_json_body() - try: - requester = user = await self.login_user(data) - except Exception as e: - self.log.error("Failure trying to authenticate with form data: %s" % e) - user = None - if user is None: - raise web.HTTPError(403) - else: - data = self.get_json_body() - # admin users can request tokens for other users - if data and data.get('username'): - user = self.find_user(data['username']) - if user is not requester and not requester.admin: - raise web.HTTPError( - 403, "Only admins can request tokens for other users." - ) - if requester.admin and user is None: - raise web.HTTPError(400, "No such user '%s'" % data['username']) - - note = (data or {}).get('note') - if not note: - note = "Requested via deprecated api" - if requester is not user: - kind = 'user' if isinstance(user, User) else 'service' - note += " by %s %s" % (kind, requester.name) - - api_token = user.new_api_token(note=note) - self.write( - json.dumps( - {'token': api_token, 'warning': warn_msg, 'user': self.user_model(user)} - ) + raise web.HTTPError( + 404, + "Deprecated endpoint /hub/api/authorizations/token is removed in JupyterHub 2.0." + " Use /hub/api/users/:user/tokens instead.", ) class CookieAPIHandler(APIHandler): @token_authenticated def get(self, cookie_name, cookie_value=None): + self.log.warning( + "/authorizations/cookie endpoint is deprecated in JupyterHub 2.0. Use /api/user with OAuth tokens." + ) + cookie_name = quote(cookie_name, safe='') if cookie_value is None: self.log.warning( diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index ac2a6461..2c2a4ae8 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -44,6 +44,11 @@ class SelfAPIHandler(APIHandler): self.raw_scopes.update(scopes.identify_scopes(user.orm_user)) self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) model = self.user_model(user) + # validate return, should have at least kind and name, + # otherwise our filters did something wrong + for key in ("kind", "name"): + if key not in model: + raise ValueError(f"Missing identify model for {user}: {model}") self.write(json.dumps(model)) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 652573fd..4a3c4f1a 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -269,6 +269,9 @@ def identify_scopes(obj): for field in {"name", "admin", "groups"} } elif isinstance(obj, orm.Service): + # FIXME: need sub-scopes for services + # until then, we have just one service scope: + return {f"read:services!service={obj.name}"} return { f"read:services:{field}!service={obj.name}" for field in {"name", "admin"} } diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index bcc8a57b..4f8e0524 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -1,7 +1,7 @@ """Authenticating services with JupyterHub. -Cookies are sent to the Hub for verification. The Hub replies with a JSON -model describing the authenticated user. +Tokens are sent to the Hub for verification. +The Hub replies with a JSON model describing the authenticated user. ``HubAuth`` can be used in any application, even outside tornado. @@ -10,6 +10,7 @@ authenticate with the Hub. """ import base64 +import hashlib import json import os import random @@ -20,7 +21,6 @@ import time import uuid import warnings from unittest import mock -from urllib.parse import quote from urllib.parse import urlencode import requests @@ -113,9 +113,15 @@ class HubAuth(SingletonConfigurable): This can be used by any application. + Use this base class only for direct, token-authenticated applications + (web APIs). + For applications that support direct visits from browsers, + use HubOAuth to enable OAuth redirect-based authentication. + + If using tornado, use via :class:`HubAuthenticated` mixin. - If using manually, use the ``.user_for_cookie(cookie_value)`` method - to identify the user corresponding to a given cookie value. + If using manually, use the ``.user_for_token(token_value)`` method + to identify the user owning a given token. The following config must be set: @@ -129,15 +135,12 @@ class HubAuth(SingletonConfigurable): - cookie_cache_max_age: the number of seconds responses from the Hub should be cached. - login_url (the *public* ``/hub/login`` URL of the Hub). - - cookie_name: the name of the cookie I should be using, - if different from the default (unlikely). - """ hub_host = Unicode( '', help="""The public host of JupyterHub - + Only used if JupyterHub is spreading servers across subdomains. """, ).tag(config=True) @@ -239,10 +242,6 @@ class HubAuth(SingletonConfigurable): """, ).tag(config=True) - cookie_name = Unicode( - 'jupyterhub-services', help="""The name of the cookie I should be looking for""" - ).tag(config=True) - cookie_options = Dict( help="""Additional options to pass when setting cookies. @@ -286,12 +285,12 @@ class HubAuth(SingletonConfigurable): def _default_cache(self): return _ExpiringDict(self.cache_max_age) - def _check_hub_authorization(self, url, cache_key=None, use_cache=True): + def _check_hub_authorization(self, url, api_token, cache_key=None, use_cache=True): """Identify a user with the Hub Args: url (str): The API URL to check the Hub for authorization - (e.g. http://127.0.0.1:8081/hub/api/authorizations/token/abc-def) + (e.g. http://127.0.0.1:8081/hub/api/user) cache_key (str): The key for checking the cache use_cache (bool): Specify use_cache=False to skip cached cookie values (default: True) @@ -309,7 +308,12 @@ class HubAuth(SingletonConfigurable): except KeyError: app_log.debug("HubAuth cache miss: %s", cache_key) - data = self._api_request('GET', url, allow_404=True) + data = self._api_request( + 'GET', + url, + headers={"Authorization": "token " + api_token}, + allow_403=True, + ) if data is None: app_log.warning("No Hub user identified for request") else: @@ -321,7 +325,7 @@ class HubAuth(SingletonConfigurable): def _api_request(self, method, url, **kwargs): """Make an API request""" - allow_404 = kwargs.pop('allow_404', False) + allow_403 = kwargs.pop('allow_403', False) headers = kwargs.setdefault('headers', {}) headers.setdefault('Authorization', 'token %s' % self.api_token) if "cert" not in kwargs and self.certfile and self.keyfile: @@ -345,7 +349,7 @@ class HubAuth(SingletonConfigurable): raise HTTPError(500, msg) data = None - if r.status_code == 404 and allow_404: + if r.status_code == 403 and allow_403: pass elif r.status_code == 403: app_log.error( @@ -389,26 +393,9 @@ class HubAuth(SingletonConfigurable): return data def user_for_cookie(self, encrypted_cookie, use_cache=True, session_id=''): - """Ask the Hub to identify the user for a given cookie. - - Args: - encrypted_cookie (str): the cookie value (not decrypted, the Hub will do that) - use_cache (bool): Specify use_cache=False to skip cached cookie values (default: True) - - Returns: - user_model (dict): The user model, if a user is identified, None if authentication fails. - - The 'name' field contains the user's name. - """ - return self._check_hub_authorization( - url=url_path_join( - self.api_url, - "authorizations/cookie", - self.cookie_name, - quote(encrypted_cookie, safe=''), - ), - cache_key='cookie:{}:{}'.format(session_id, encrypted_cookie), - use_cache=use_cache, + """Deprecated and removed. Use HubOAuth to authenticate browsers.""" + raise RuntimeError( + "Identifying users by shared cookie is removed in JupyterHub 2.0. Use OAuth tokens." ) def user_for_token(self, token, use_cache=True, session_id=''): @@ -425,14 +412,19 @@ class HubAuth(SingletonConfigurable): """ return self._check_hub_authorization( url=url_path_join( - self.api_url, "authorizations/token", quote(token, safe='') + self.api_url, + "user", + ), + api_token=token, + cache_key='token:{}:{}'.format( + session_id, + hashlib.sha256(token.encode("utf8", "replace")).hexdigest(), ), - cache_key='token:{}:{}'.format(session_id, token), use_cache=use_cache, ) auth_header_name = 'Authorization' - auth_header_pat = re.compile(r'token\s+(.+)', re.IGNORECASE) + auth_header_pat = re.compile(r'(?:token|bearer)\s+(.+)', re.IGNORECASE) def get_token(self, handler): """Get the user token from a request @@ -453,10 +445,8 @@ class HubAuth(SingletonConfigurable): def _get_user_cookie(self, handler): """Get the user model from a cookie""" - encrypted_cookie = handler.get_cookie(self.cookie_name) - session_id = self.get_session_id(handler) - if encrypted_cookie: - return self.user_for_cookie(encrypted_cookie, session_id=session_id) + # overridden in HubOAuth to store the access token after oauth + return None def get_session_id(self, handler): """Get the jupyterhub session id @@ -509,6 +499,9 @@ class HubAuth(SingletonConfigurable): class HubOAuth(HubAuth): """HubAuth using OAuth for login instead of cookies set by the Hub. + Use this class if you want users to be able to visit your service with a browser. + They will be authenticated via OAuth with the Hub. + .. versionadded: 0.8 """ @@ -557,7 +550,7 @@ class HubOAuth(HubAuth): oauth_client_id = Unicode( help="""The OAuth client ID for this application. - + Use JUPYTERHUB_CLIENT_ID by default. """ ).tag(config=True) @@ -574,7 +567,7 @@ class HubOAuth(HubAuth): oauth_redirect_uri = Unicode( help="""OAuth redirect URI - + Should generally be /base_url/oauth_callback """ ).tag(config=True) diff --git a/jupyterhub/singleuser/mixins.py b/jupyterhub/singleuser/mixins.py index 0e5bc06f..b0e64de0 100755 --- a/jupyterhub/singleuser/mixins.py +++ b/jupyterhub/singleuser/mixins.py @@ -141,7 +141,6 @@ class OAuthCallbackHandlerMixin(HubOAuthCallbackHandler): aliases = { 'user': 'SingleUserNotebookApp.user', 'group': 'SingleUserNotebookApp.group', - 'cookie-name': 'HubAuth.cookie_name', 'hub-prefix': 'SingleUserNotebookApp.hub_prefix', 'hub-host': 'SingleUserNotebookApp.hub_host', 'hub-api-url': 'SingleUserNotebookApp.hub_api_url', diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 9bd66be9..f8330f08 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1176,76 +1176,13 @@ async def test_check_token(app): assert r.status_code == 404 -@mark.parametrize("headers, status", [({}, 200), ({'Authorization': 'token bad'}, 403)]) +@mark.parametrize("headers, status", [({}, 404), ({'Authorization': 'token bad'}, 404)]) async def test_get_new_token_deprecated(app, headers, status): # request a new token r = await api_request( app, 'authorizations', 'token', method='post', headers=headers ) assert r.status_code == status - if status != 200: - return - reply = r.json() - assert 'token' in reply - r = await api_request(app, 'authorizations', 'token', reply['token']) - r.raise_for_status() - reply = r.json() - assert reply['name'] == 'admin' - - -async def test_token_formdata_deprecated(app): - """Create a token for a user with formdata and no auth header""" - data = {'username': 'fake', 'password': 'fake'} - r = await api_request( - app, - 'authorizations', - 'token', - method='post', - data=json.dumps(data) if data else None, - noauth=True, - ) - assert r.status_code == 200 - reply = r.json() - assert 'token' in reply - r = await api_request(app, 'authorizations', 'token', reply['token']) - r.raise_for_status() - reply = r.json() - assert reply['name'] == data['username'] - - -@mark.parametrize( - "as_user, for_user, status", - [ - ('admin', 'other', 200), - ('admin', 'missing', 400), - ('user', 'other', 403), - ('user', 'user', 200), - ], -) -async def test_token_as_user_deprecated(app, as_user, for_user, status): - # ensure both users exist - u = add_user(app.db, app, name=as_user) - if for_user != 'missing': - for_user_obj = add_user(app.db, app, name=for_user) - data = {'username': for_user} - headers = {'Authorization': 'token %s' % u.new_api_token()} - r = await api_request( - app, - 'authorizations', - 'token', - method='post', - data=json.dumps(data), - headers=headers, - ) - assert r.status_code == status - reply = r.json() - if status != 200: - return - assert 'token' in reply - r = await api_request(app, 'authorizations', 'token', reply['token']) - r.raise_for_status() - reply = r.json() - assert reply['name'] == data['username'] @mark.parametrize( diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index ac10661e..3ed5d628 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -26,8 +26,8 @@ from tornado.web import RequestHandler from .. import orm from ..services.auth import _ExpiringDict -from ..services.auth import HubAuth -from ..services.auth import HubAuthenticated +from ..services.auth import HubOAuth +from ..services.auth import HubOAuthenticated from ..utils import url_path_join from .mocking import public_host from .mocking import public_url @@ -76,178 +76,6 @@ def test_expiring_dict(): assert cache.get('key', 'default') == 'cached value' -def test_hub_auth(): - auth = HubAuth(cookie_name='foo') - mock_model = {'name': 'onyxia'} - url = url_path_join(auth.api_url, "authorizations/cookie/foo/bar") - with requests_mock.Mocker() as m: - m.get(url, text=json.dumps(mock_model)) - user_model = auth.user_for_cookie('bar') - assert user_model == mock_model - # check cache - user_model = auth.user_for_cookie('bar') - assert user_model == mock_model - - with requests_mock.Mocker() as m: - m.get(url, status_code=404) - user_model = auth.user_for_cookie('bar', use_cache=False) - assert user_model is None - - # invalidate cache with timer - mock_model = {'name': 'willow'} - with monotonic_future, requests_mock.Mocker() as m: - m.get(url, text=json.dumps(mock_model)) - user_model = auth.user_for_cookie('bar') - assert user_model == mock_model - - with requests_mock.Mocker() as m: - m.get(url, status_code=500) - with raises(HTTPError) as exc_info: - user_model = auth.user_for_cookie('bar', use_cache=False) - assert exc_info.value.status_code == 502 - - with requests_mock.Mocker() as m: - m.get(url, status_code=400) - with raises(HTTPError) as exc_info: - user_model = auth.user_for_cookie('bar', use_cache=False) - assert exc_info.value.status_code == 500 - - -def test_hub_authenticated(request): - auth = HubAuth(cookie_name='jubal') - mock_model = {'name': 'jubalearly', 'groups': ['lions']} - cookie_url = url_path_join(auth.api_url, "authorizations/cookie", auth.cookie_name) - good_url = url_path_join(cookie_url, "early") - bad_url = url_path_join(cookie_url, "late") - - class TestHandler(HubAuthenticated, RequestHandler): - hub_auth = auth - - @authenticated - def get(self): - self.finish(self.get_current_user()) - - # start hub-authenticated service in a thread: - port = 50505 - q = Queue() - - def run(): - asyncio.set_event_loop(asyncio.new_event_loop()) - app = Application([('/*', TestHandler)], login_url=auth.login_url) - - http_server = HTTPServer(app) - http_server.listen(port) - loop = IOLoop.current() - loop.add_callback(lambda: q.put(loop)) - loop.start() - - t = Thread(target=run) - t.start() - - def finish_thread(): - loop.add_callback(loop.stop) - t.join(timeout=30) - assert not t.is_alive() - - request.addfinalizer(finish_thread) - - # wait for thread to start - loop = q.get(timeout=10) - - with requests_mock.Mocker(real_http=True) as m: - # no cookie - r = requests.get('http://127.0.0.1:%i' % port, allow_redirects=False) - r.raise_for_status() - assert r.status_code == 302 - assert auth.login_url in r.headers['Location'] - - # wrong cookie - m.get(bad_url, status_code=404) - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'late'}, - allow_redirects=False, - ) - r.raise_for_status() - assert r.status_code == 302 - assert auth.login_url in r.headers['Location'] - - # clear the cache because we are going to request - # the same url again with a different result - auth.cache.clear() - - # upstream 403 - m.get(bad_url, status_code=403) - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'late'}, - allow_redirects=False, - ) - assert r.status_code == 500 - - m.get(good_url, text=json.dumps(mock_model)) - - # no specific allowed user - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'early'}, - allow_redirects=False, - ) - r.raise_for_status() - assert r.status_code == 200 - - # pass allowed user - TestHandler.hub_users = {'jubalearly'} - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'early'}, - allow_redirects=False, - ) - r.raise_for_status() - assert r.status_code == 200 - - # no pass allowed ser - TestHandler.hub_users = {'kaylee'} - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'early'}, - allow_redirects=False, - ) - assert r.status_code == 403 - - # pass allowed group - TestHandler.hub_groups = {'lions'} - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'early'}, - allow_redirects=False, - ) - r.raise_for_status() - assert r.status_code == 200 - - # no pass allowed group - TestHandler.hub_groups = {'tigers'} - r = requests.get( - 'http://127.0.0.1:%i' % port, - cookies={'jubal': 'early'}, - allow_redirects=False, - ) - assert r.status_code == 403 - - -async def test_hubauth_cookie(app, mockservice_url): - """Test HubAuthenticated service with user cookies""" - cookies = await app.login_user('badger') - r = await async_requests.get( - public_url(app, mockservice_url) + '/whoami/', cookies=cookies - ) - r.raise_for_status() - print(r.text) - reply = r.json() - sub_reply = {key: reply.get(key, 'missing') for key in ['name', 'admin']} - assert sub_reply == {'name': 'badger', 'admin': False} - - async def test_hubauth_token(app, mockservice_url): """Test HubAuthenticated service with user API tokens""" u = add_user(app.db, name='river') @@ -295,8 +123,10 @@ async def test_hubauth_service_token(app, mockservice_url): r = await async_requests.get( public_url(app, mockservice_url) + '/whoami/', headers={'Authorization': 'token %s' % token}, + allow_redirects=False, ) r.raise_for_status() + assert r.status_code == 200 reply = r.json() assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} assert not r.cookies From 0eb5e3b6ce586e91c5c70f9446780bec0d558626 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 7 May 2021 15:31:03 +0200 Subject: [PATCH 172/270] Split role creation and role assignment --- jupyterhub/app.py | 29 +++++++++++++++++------------ jupyterhub/tests/test_roles.py | 17 +++++++++-------- jupyterhub/tests/test_scopes.py | 2 +- jupyterhub/tests/test_services.py | 4 ++-- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 9249ce75..d47085f6 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -329,7 +329,7 @@ class JupyterHub(Application): load_roles = [ { 'name': 'teacher', - 'description': 'Access users information, servers and groups without create/delete privileges', + 'description': 'Access to users' information, servers and groups', 'scopes': ['users', 'groups'], 'users': ['cyclops', 'gandalf'], 'services': [], @@ -1965,25 +1965,27 @@ class JupyterHub(Application): group.users.append(user) db.commit() - async def init_roles(self): + async def init_role_creation(self): """Load default and predefined roles into the database""" - db = self.db - # tokens are added separately - role_bearers = ['users', 'services', 'groups'] - - # load default roles self.log.debug('Loading default roles to database') default_roles = roles.get_default_roles() for role in default_roles: - roles.create_role(db, role) + roles.create_role(self.db, role) + async def init_role_assignment(self): + # tokens are added separately + role_bearers = ['users', 'services', 'groups'] + + db = self.db # load predefined roles from config file self.log.debug('Loading predefined roles from config file to database') for predef_role in self.load_roles: roles.create_role(db, predef_role) + predef_role_obj = orm.Role.find(db, name=predef_role['name']) # add users, services, and/or groups, # tokens need to be checked for permissions for bearer in role_bearers: + orm_role_bearers = [] if bearer in predef_role.keys(): for bname in predef_role[bearer]: if bearer == 'users': @@ -1999,9 +2001,11 @@ class JupyterHub(Application): ) Class = orm.get_class(bearer) orm_obj = Class.find(db, bname) - roles.grant_role( - db, entity=orm_obj, rolename=predef_role['name'] - ) + orm_role_bearers.append(orm_obj) + # roles.grant_role( + # db, entity=orm_obj, rolename=predef_role['name'] + # ) + setattr(predef_role_obj, bearer, orm_role_bearers) # make sure that on no admin situation, all roles are reset admin_role = orm.Role.find(db, name='admin') if not admin_role.users: @@ -2606,11 +2610,12 @@ class JupyterHub(Application): self.init_hub() self.init_proxy() self.init_oauth() + await self.init_role_creation() await self.init_users() await self.init_groups() self.init_services() await self.init_api_tokens() - await self.init_roles() + await self.init_role_assignment() self.init_tornado_settings() self.init_handlers() self.init_tornado_application() diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index f7b644fb..ba664b8f 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -237,7 +237,7 @@ async def test_load_default_roles(tmpdir, request): hub = MockHub(**kwargs) hub.init_db() db = hub.db - await hub.init_roles() + await hub.init_role_creation() # test default roles loaded to database default_roles = roles.get_default_roles() for role in default_roles: @@ -435,8 +435,8 @@ async def test_load_roles_users(tmpdir, request): hub.authenticator.admin_users = ['admin'] hub.authenticator.allowed_users = ['cyclops', 'gandalf', 'bilbo', 'gargamel'] await hub.init_users() - await hub.init_roles() - + await hub.init_role_creation() + await hub.init_role_assignment() admin_role = orm.Role.find(db, 'admin') user_role = orm.Role.find(db, 'user') # test if every user has a role (and no duplicates) @@ -502,8 +502,8 @@ async def test_load_roles_services(tmpdir, request): admin_service = orm.Service.find(db, 'admin_service') admin_service.admin = True db.commit() - await hub.init_roles() - + await hub.init_role_creation() + await hub.init_role_assignment() # test if every service has a role (and no duplicates) admin_role = orm.Role.find(db, name='admin') user_role = orm.Role.find(db, name='user') @@ -571,7 +571,8 @@ async def test_load_roles_groups(tmpdir, request): hub.init_db() db = hub.db await hub.init_groups() - await hub.init_roles() + await hub.init_role_creation() + await hub.init_role_assignment() assist_role = orm.Role.find(db, name='assistant') head_role = orm.Role.find(db, name='head') @@ -618,8 +619,8 @@ async def test_load_roles_user_tokens(tmpdir, request): hub.authenticator.allowed_users = ['cyclops', 'gandalf'] await hub.init_users() await hub.init_api_tokens() - await hub.init_roles() - + await hub.init_role_creation() + await hub.init_role_assignment() # test if all other tokens have default 'user' role token_role = orm.Role.find(db, 'token') secret_token = orm.APIToken.find(db, 'secret-token') diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 9d8b421e..acd9ab8e 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -619,7 +619,7 @@ async def test_server_state_access( ) service = create_service_with_scopes(*scopes) api_token = service.new_api_token() - await app.init_roles() + await app.init_role_creation() headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', user.name, headers=headers) r.raise_for_status() diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 0ac0421c..266f4a07 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -89,10 +89,10 @@ async def test_external_service(app): } ] await maybe_future(app.init_services()) - await maybe_future(app.init_roles()) + await maybe_future(app.init_role_creation()) await app.init_api_tokens() await app.proxy.add_all_services(app._service_map) - await app.init_roles() + await app.init_role_creation() service = app._service_map[name] api_token = service.orm.api_tokens[0] From 988bc376ac7254072e7db32cd37c7b17c5dc7189 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 7 May 2021 16:20:16 +0200 Subject: [PATCH 173/270] Added tests for user role configuration --- jupyterhub/tests/test_roles.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index ba664b8f..eff091dc 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -884,3 +884,34 @@ async def test_oauth_allowed_roles(app, create_temp_role): app_service = app.services[0] assert app_service['name'] == 'oas1' assert set(app_service['oauth_roles']) == set(allowed_roles) + + +async def test_config_role_assignment(): + role_name = 'painter' + user_name = 'benny' + other_users = ['agnetha', 'bjorn', 'anni-frid'] + roles_to_load = [ + { + 'name': role_name, + 'description': 'painting with colors', + 'scopes': ['users', 'groups'], + 'users': other_users, + }, + ] + for user_in_config in [False, True]: + if user_in_config: + roles_to_load[0]['users'].append(user_name) + kwargs = {'load_roles': roles_to_load} + hub = MockHub(**kwargs, clean_db=False) + hub.init_db() + hub.authenticator.admin_users = ['admin'] + hub.authenticator.allowed_users = other_users + [user_name] + await hub.init_users() + await hub.init_role_creation() + await hub.init_role_assignment() + user = orm.User.find(hub.db, name=user_name) + role = orm.Role.find(hub.db, name=role_name) + if user_in_config: + assert role in user.roles + else: + assert role not in user.roles From b2b040da6cf61cb04256fa1c0c8a89d07cbc4706 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 7 May 2021 16:49:29 +0200 Subject: [PATCH 174/270] Added scope for reading roles, test setup --- jupyterhub/apihandlers/base.py | 1 + jupyterhub/roles.py | 3 ++- jupyterhub/scopes.py | 4 ++-- jupyterhub/tests/test_roles.py | 3 +++ jupyterhub/tests/test_scopes.py | 13 ++++++++++++- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index f630e350..917485af 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -249,6 +249,7 @@ class APIHandler(BaseHandler): 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, + 'read:users:roles': {'kind', 'name', 'roles'}, 'admin:users:auth_state': {'kind', 'name', 'auth_state'}, } self.log.debug( diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index d6ade30c..6e3f1c90 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -89,6 +89,7 @@ def _get_scope_hierarchy(): 'read:users:name', 'read:users:groups', 'read:users:activity', + 'read:users:roles', ], 'users:activity': ['read:users:activity'], 'users:tokens': ['read:users:tokens'], @@ -97,7 +98,7 @@ def _get_scope_hierarchy(): 'read:users:servers': ['read:users:name'], 'admin:groups': ['groups'], 'groups': ['read:groups'], - 'read:services': None, + 'read:services': ['read:services:name', 'read:services:roles'], 'read:hub': None, 'proxy': None, 'shutdown': None, diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 652573fd..a50fb370 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -266,11 +266,11 @@ def identify_scopes(obj): if isinstance(obj, orm.User): return { f"read:users:{field}!user={obj.name}" - for field in {"name", "admin", "groups"} + for field in {"name", "roles", "groups"} } elif isinstance(obj, orm.Service): return { - f"read:services:{field}!service={obj.name}" for field in {"name", "admin"} + f"read:services:{field}!service={obj.name}" for field in {"name", "roles"} } else: raise TypeError(f"Expected orm.User or orm.Service, got {obj!r}") diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 4fcf806a..daf68c1a 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -187,6 +187,7 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', }, ), @@ -198,6 +199,7 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', }, ), @@ -207,6 +209,7 @@ def test_orm_roles_delete_cascade(db): 'read:users', 'read:users:name', 'read:users:groups', + 'read:users:roles', 'read:users:activity', }, ), diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 9d8b421e..5569a29f 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -747,7 +747,6 @@ async def test_resolve_token_permissions( token_scopes, intersection_scopes, ): - orm_user = create_user_with_scopes(*user_scopes).orm_user create_temp_role(token_scopes, 'active-posting') api_token = orm_user.new_api_token(roles=['active-posting']) @@ -760,3 +759,15 @@ async def test_resolve_token_permissions( token_retained_scopes = get_scopes_for(orm_api_token) assert token_retained_scopes == intersection_scopes + + +async def test_roles_access(app, create_user_with_scopes): + pass + + +async def test_service_model_filtering(app, create_user_with_scopes): + pass + + +async def test_group_model_filtering(app, create_user_with_scopes): + pass From 8408e3aa766b56423e403c4184f800268b669de1 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 11 May 2021 11:09:43 +0200 Subject: [PATCH 175/270] update tests after merge into rbac --- jupyterhub/tests/test_api.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 4635e660..6c90c1bd 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -198,7 +198,11 @@ async def test_get_users(app): users = sorted(r.json(), key=lambda d: d['name']) users = [normalize_user(u) for u in users] - assert users == [fill_user({'name': 'user', 'admin': False})] + assert users == [ + fill_user( + {'name': 'user', 'admin': False, 'auth_state': None, 'roles': ['user']} + ) + ] r = await api_request(app, 'users?offset=20') assert r.status_code == 200 @@ -210,7 +214,11 @@ async def test_get_users(app): users = sorted(r.json(), key=lambda d: d['name']) users = [normalize_user(u) for u in users] - assert users == [fill_user({'name': 'admin', 'admin': True})] + assert users == [ + fill_user( + {'name': 'admin', 'admin': True, 'auth_state': None, 'roles': ['admin']} + ) + ] r = await api_request(app, 'users?limit=0') assert r.status_code == 200 @@ -1440,7 +1448,7 @@ async def test_groups_list(app): r.raise_for_status() reply = r.json() assert r.status_code == 200 - assert reply == [{'kind': 'group', 'name': 'alphaflight', 'users': []}] + assert reply == [{'kind': 'group', 'name': 'alphaflight', 'users': [], 'roles': []}] r = await api_request(app, "groups?limit=0") r.raise_for_status() From 915fa4bfcc8d41c18ce5c6826b3a81c492593bdf Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 12 May 2021 11:05:47 +0200 Subject: [PATCH 176/270] Apply suggestions from code review thanks Carol! Co-authored-by: Carol Willing --- docs/source/reference/oauth.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/source/reference/oauth.md b/docs/source/reference/oauth.md index a98c9293..185239cd 100644 --- a/docs/source/reference/oauth.md +++ b/docs/source/reference/oauth.md @@ -24,20 +24,21 @@ Some relevant points: ### Key OAuth terms - **provider** the entity responsible for managing. - JupyterHub is _always_ an oauth provider for its components. + JupyterHub is _always_ an oauth provider for JupyterHub's components. When OAuthenticator is used, an external service, such as GitHub or KeyCloak, is also an oauth provider. - **client** An entity that requests OAuth tokens on a user's behalf. JupyterHub _services_ or single-user _servers_ are OAuth clients of the JupyterHub _provider_. When OAuthenticator is used, JupyterHub is itself also an OAuth _client_ for the external oauth _provider_, e.g. GitHub. -- **browser** A user's web browser, which makes requests and stores things like cookies to -- **token** The secret value used to represent a user's authorization. This is the final product of the OAuth process +- **browser** A user's web browser, which makes requests and stores things like cookies +- **token** The secret value used to represent a user's authorization. This is the final product of the OAuth process. ### The oauth flow -OAuth flow is what we call the sequence of HTTP requests involved in authenticating a user and issuing a token. +OAuth flow is what we call the sequence of HTTP requests involved in authenticating a user and issuing a token, ultimately used for authorized access to a service or single-user server. It generally goes like this: +#### Oauth request and redirect 1. A _browser_ makes an HTTP request to an oauth _client_. 2. There are no credentials, so the client _redirects_ the browser to an "authorize" page on the oauth _provider_ with some extra information: - the oauth **client id** of the client itself @@ -55,6 +56,7 @@ It generally goes like this: (or "oauth callback uri"), with the oauth code in a url parameter. +#### State after redirect At this point: - The browser is authenticated with the _provider_ @@ -63,6 +65,7 @@ At this point: - All requests so far have been made directly by the browser. No requests have originated at the client or provider. +#### OAuth Client Handles Callback Request Now we get to finish the OAuth process. Let's dig into what the oauth client does when it handles the oauth callback request with the @@ -92,7 +95,7 @@ Our starting point: First request: -- browser->single-user server +- browser->single-user server running JupyterLab or Jupyter Classic - `GET /user/danez/notebooks/mynotebook.ipynb` - no credentials, so client starts oauth process with JupyterHub - response: 302 redirect -> `/hub/api/oauth2/authorize` @@ -134,7 +137,7 @@ The first: - JupyterHub->GitHub - `POST https://github.com/login/oauth/access_token` - request made with oauth code from url parameter -- response includes an Access token +- response includes an access token The second: From a13813e61f41011085271222754d562606910b11 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 11 May 2021 14:57:44 +0200 Subject: [PATCH 177/270] add scopes.unparse_scopes, refine intersect_scopes and fix warning condition for intersection overlap - only warn when there's a group only on one side and a user or server only on the other, otherwise there is no lost information to warn about (group and/or defined on both sides) - correctly resolve servers as sub-scopes of user --- jupyterhub/scopes.py | 118 +++++++++++++++++++++----------- jupyterhub/tests/test_scopes.py | 80 +++++++++++++++++++++- 2 files changed, 158 insertions(+), 40 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 4a3c4f1a..859f6958 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -1,5 +1,7 @@ +"""General scope definitions and utilities""" import functools import inspect +import warnings from enum import Enum from tornado import web @@ -13,60 +15,85 @@ class Scope(Enum): ALL = True -def _intersect_scopes(token_scopes, owner_scopes): - """Compares the permissions of token and its owner including horizontal filters - Returns the intersection of the two sets of scopes +def _intersect_scopes(scopes_a, scopes_b): + """Intersect two sets of scopes + + Compares the permissions of two sets of scopes, + including horizontal filters, + and returns the intersected scopes. Note: Intersects correctly with ALL and exact filter matches (i.e. users!user=x & read:users:name -> read:users:name!user=x) Does not currently intersect with containing filters - (i.e. users!group=x & users!user=y even if user y is in group x, - same for users:servers!user=x & users:servers!server=y) + (i.e. users!group=x & users!user=y even if user y is in group x) """ - owner_parsed_scopes = parse_scopes(owner_scopes) - token_parsed_scopes = parse_scopes(token_scopes) + parsed_scopes_a = parse_scopes(scopes_a) + parsed_scopes_b = parse_scopes(scopes_b) - common_bases = owner_parsed_scopes.keys() & token_parsed_scopes.keys() + common_bases = parsed_scopes_a.keys() & parsed_scopes_b.keys() common_filters = {} - warn = False + warned = False for base in common_bases: - if owner_parsed_scopes[base] == Scope.ALL: - common_filters[base] = token_parsed_scopes[base] - elif token_parsed_scopes[base] == Scope.ALL: - common_filters[base] = owner_parsed_scopes[base] + filters_a = parsed_scopes_a[base] + filters_b = parsed_scopes_b[base] + if filters_a == Scope.ALL: + common_filters[base] = filters_b + elif filters_b == Scope.ALL: + common_filters[base] = filters_a else: - common_entities = ( - owner_parsed_scopes[base].keys() & token_parsed_scopes[base].keys() - ) - all_entities = ( - owner_parsed_scopes[base].keys() | token_parsed_scopes[base].keys() - ) - if 'user' in all_entities and ('group' or 'server' in all_entities): - warn = True + # warn *if* there are non-overlapping user= and group= filters + common_entities = filters_a.keys() & filters_b.keys() + all_entities = filters_a.keys() | filters_b.keys() + if ( + not warned + and 'group' in all_entities + and ('user' in all_entities or 'server' in all_entities) + ): + # this could resolve wrong if there's a user or server only on one side and a group only on the other + # check both directions: A has group X not in B group list AND B has user Y not in A user list + for a, b in [(filters_a, filters_b), (filters_b, filters_a)]: + for b_key in ('user', 'server'): + if ( + not warned + and "group" in a + and b_key in b + and set(a["group"]).difference(b.get("group", [])) + and set(b[b_key]).difference(a.get(b_key, [])) + ): + warnings.warn( + f"{base}[!{b_key}={b[b_key]}, !group={a['group']}] combinations of filters present," + " intersection between not considered. May result in lower than intended permissions.", + UserWarning, + ) + warned = True common_filters[base] = { - entity: set(owner_parsed_scopes[base][entity]) - & set(token_parsed_scopes[base][entity]) + entity: set(parsed_scopes_a[base][entity]) + & set(parsed_scopes_b[base][entity]) for entity in common_entities } - if warn: - app_log.warning( - "[!user=, !group=] or [!user=, !server=] combinations of filters present, intersection between not considered. May result in lower than intended permissions." - ) + if 'server' in all_entities and 'user' in all_entities: + if filters_a.get('server') == filters_b.get('server'): + continue - scopes = set() - for base in common_filters: - if common_filters[base] == Scope.ALL: - scopes.add(base) - else: - for entity, names_list in common_filters[base].items(): - for name in names_list: - scopes.add(f'{base}!{entity}={name}') + additional_servers = set() + # resolve user/server hierarchy in both directions + for a, b in [(filters_a, filters_b), (filters_b, filters_a)]: + if 'server' in a and 'user' in b: + for server in a['server']: + username, _, servername = server.partition("/") + if username in b['user']: + additional_servers.add(server) - return scopes + if additional_servers: + if "server" not in common_filters[base]: + common_filters[base]["server"] = set() + common_filters[base]["server"].update(additional_servers) + + return unparse_scopes(common_filters) def get_scopes_for(orm_object): @@ -176,7 +203,7 @@ def parse_scopes(scope_list): """ Parses scopes and filters in something akin to JSON style - For instance, scope list ["users", "groups!group=foo", "users:servers!server=bar", "users:servers!server=baz"] + For instance, scope list ["users", "groups!group=foo", "users:servers!server=user/bar", "users:servers!server=user/baz"] would lead to scope model { "users":scope.ALL, @@ -187,8 +214,8 @@ def parse_scopes(scope_list): }, "users:servers":{ "server":[ - "bar", - "baz" + "user/bar", + "user/baz" ] } } @@ -208,6 +235,19 @@ def parse_scopes(scope_list): return parsed_scopes +def unparse_scopes(parsed_scopes): + """Turn a parsed_scopes dictionary back into a scopes set""" + scopes = set() + for base, filters in parsed_scopes.items(): + if filters == Scope.ALL: + scopes.add(base) + else: + for entity, names_list in filters.items(): + for name in names_list: + scopes.add(f'{base}!{entity}={name}') + return scopes + + def needs_scope(*scopes): """Decorator to restrict access to users or services with the required scope""" diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 9d8b421e..8ad1c310 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -1,5 +1,4 @@ """Test scopes for API handlers""" -import json from unittest import mock import pytest @@ -11,6 +10,7 @@ from .. import orm from .. import roles from ..handlers import BaseHandler from ..scopes import _check_scope +from ..scopes import _intersect_scopes from ..scopes import get_scopes_for from ..scopes import needs_scope from ..scopes import parse_scopes @@ -760,3 +760,81 @@ async def test_resolve_token_permissions( token_retained_scopes = get_scopes_for(orm_api_token) assert token_retained_scopes == intersection_scopes + + +@pytest.mark.parametrize( + "left, right, expected, should_warn", + [ + (set(), set(), set(), False), + (set(), set(["users"]), set(), False), + # no warning if users and groups only on the same side + ( + set(["users!user=x", "users!group=y"]), + set([]), + set([]), + False, + ), + # no warning if users are on both sizes + ( + set(["users!user=x", "users!user=y", "users!group=y"]), + set(["users!user=x"]), + set(["users!user=x"]), + False, + ), + # no warning if users and groups are both defined + # on both sides + ( + set(["users!user=x", "users!group=y"]), + set(["users!user=x", "users!group=y", "users!user=z"]), + set(["users!user=x", "users!group=y"]), + False, + ), + # warn if there's a user on one side and a group on the other + # which *may* intersect + ( + set(["users!group=y", "users!user=z"]), + set(["users!user=x"]), + set([]), + True, + ), + # same for group->server + ( + set(["users!group=y", "users!user=z"]), + set(["users!server=x/y"]), + set([]), + True, + ), + # this one actually shouldn't warn because server=x/y is under user=x, + # but we don't need to overcomplicate things just for a warning + ( + set(["users!group=y", "users!user=x"]), + set(["users!server=x/y"]), + set(["users!server=x/y"]), + True, + ), + # resolves server under user, without warning + ( + set(["read:users:servers!user=abc"]), + set(["read:users:servers!server=abc/xyz"]), + set(["read:users:servers!server=abc/xyz"]), + False, + ), + # user->server, no match + ( + set(["read:users:servers!user=abc"]), + set(["read:users:servers!server=abcd/xyz"]), + set([]), + False, + ), + ], +) +def test_intersect_scopes(left, right, expected, should_warn, recwarn): + # run every test in both directions, to ensure symmetry of the inputs + for a, b in [(left, right), (right, left)]: + intersection = _intersect_scopes(set(left), set(right)) + assert intersection == set(expected) + + if should_warn: + assert len(recwarn) == 1 + else: + assert len(recwarn) == 0 From fdf57b271ec1f7f7d325052bc203a693cf02e9f4 Mon Sep 17 00:00:00 2001 From: Eric Charles Date: Thu, 20 May 2021 11:58:42 +0200 Subject: [PATCH 178/270] Fix Service oauth client ids must start with 'service-' --- examples/external-oauth/jupyterhub_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/external-oauth/jupyterhub_config.py b/examples/external-oauth/jupyterhub_config.py index d44fe7d1..75f141ea 100644 --- a/examples/external-oauth/jupyterhub_config.py +++ b/examples/external-oauth/jupyterhub_config.py @@ -13,7 +13,7 @@ if not api_token: c.JupyterHub.services = [ { 'name': 'external-oauth', - 'oauth_client_id': "whoami-oauth-client-test", + 'oauth_client_id': "service-oauth-client-test", 'api_token': api_token, 'oauth_redirect_uri': 'http://127.0.0.1:5555/oauth_callback', } From 16636ce3c042429d258ad4c40795aabf401a3c78 Mon Sep 17 00:00:00 2001 From: Eric Charles Date: Thu, 20 May 2021 12:00:56 +0200 Subject: [PATCH 179/270] Fix Service oauth client ids must start with 'service-' in the service launcher --- examples/external-oauth/launch-service-basic.sh | 2 +- examples/external-oauth/launch-service.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/external-oauth/launch-service-basic.sh b/examples/external-oauth/launch-service-basic.sh index dc2ab9eb..2392f48a 100644 --- a/examples/external-oauth/launch-service-basic.sh +++ b/examples/external-oauth/launch-service-basic.sh @@ -9,7 +9,7 @@ if [[ -z "${JUPYTERHUB_API_TOKEN}" ]]; then fi # 2. oauth client ID -export JUPYTERHUB_CLIENT_ID='whoami-oauth-client-test' +export JUPYTERHUB_CLIENT_ID='service-oauth-client-test' # 3. where the Hub is export JUPYTERHUB_URL='http://127.0.0.1:8000' diff --git a/examples/external-oauth/launch-service.sh b/examples/external-oauth/launch-service.sh index 8218e036..d9b07b75 100644 --- a/examples/external-oauth/launch-service.sh +++ b/examples/external-oauth/launch-service.sh @@ -9,7 +9,7 @@ if [[ -z "${JUPYTERHUB_API_TOKEN}" ]]; then fi # 2. oauth client ID -export JUPYTERHUB_CLIENT_ID="whoami-oauth-client-test" +export JUPYTERHUB_CLIENT_ID="service-oauth-client-test" # 3. what URL to run on export JUPYTERHUB_SERVICE_PREFIX='/' export JUPYTERHUB_SERVICE_URL='http://127.0.0.1:5555' From 6e2c4d8357deb1c32349691665dfc7719396da47 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 20 May 2021 13:27:42 +0200 Subject: [PATCH 180/270] handle async functions in check_db_locks check_db_locks checks for db lock state after the end of a function, but wasn't properly waiting when it wrapped an async function, meaning it would run the check while the async function was still outstanding, causing possible spurious failures --- jupyterhub/tests/utils.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 73ddcf51..fb51bc3b 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -1,4 +1,5 @@ import asyncio +import inspect import os from concurrent.futures import ThreadPoolExecutor @@ -80,14 +81,23 @@ def check_db_locks(func): """ def new_func(app, *args, **kwargs): - retval = func(app, *args, **kwargs) + maybe_future = func(app, *args, **kwargs) - temp_session = app.session_factory() - temp_session.execute('CREATE TABLE dummy (foo INT)') - temp_session.execute('DROP TABLE dummy') - temp_session.close() + def _check(_=None): + with app.session_factory() as temp_session: + temp_session.execute('CREATE TABLE dummy (foo INT)') + temp_session.execute('DROP TABLE dummy') - return retval + async def await_then_check(): + result = await maybe_future + _check() + return result + + if inspect.isawaitable(maybe_future): + return await_then_check() + else: + _check() + return maybe_future return new_func From af6884bb7d15b149c4b9696e0cf70aabc3c27dc1 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 20 May 2021 13:33:02 +0200 Subject: [PATCH 181/270] oldest suppported sqlalchemy doesn't have session context managers --- jupyterhub/tests/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index fb51bc3b..d300c84a 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -84,9 +84,12 @@ def check_db_locks(func): maybe_future = func(app, *args, **kwargs) def _check(_=None): - with app.session_factory() as temp_session: + temp_session = app.session_factory() + try: temp_session.execute('CREATE TABLE dummy (foo INT)') temp_session.execute('DROP TABLE dummy') + finally: + temp_session.close() async def await_then_check(): result = await maybe_future From 02619b687f58f2427d61cdbccd40edebf6708368 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 20 May 2021 13:48:37 +0200 Subject: [PATCH 182/270] cleanup after failure to create token due to permisison errors have to delete tokens explicitly if we fail to finish creating them --- jupyterhub/orm.py | 24 ++++++++++++++++++------ jupyterhub/roles.py | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index e78fcc02..02529f1a 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -3,6 +3,7 @@ # Distributed under the terms of the Modified BSD License. import enum import json +import warnings from base64 import decodebytes from base64 import encodebytes from datetime import datetime @@ -674,18 +675,29 @@ class APIToken(Hashed, Base): orm_token.service = service if expires_in is not None: orm_token.expires_at = cls.now() + timedelta(seconds=expires_in) + db.add(orm_token) - # load default roles if they haven't been initiated - # correct to have this here? otherwise some tests fail token_role = Role.find(db, 'token') if not token_role: + # FIXME: remove this. + # Creating a token before the db has roles defined should raise an error. + # PR #3460 should let us fix it by ensuring default roles are define + + warnings.warn( + "Token created before default roles!", RuntimeWarning, stacklevel=2 + ) default_roles = get_default_roles() for role in default_roles: create_role(db, role) - if roles is not None: - update_roles(db, entity=orm_token, roles=roles) - else: - assign_default_roles(db, entity=orm_token) + try: + if roles is not None: + update_roles(db, entity=orm_token, roles=roles) + else: + assign_default_roles(db, entity=orm_token) + except Exception: + db.delete(orm_token) + db.commit() + raise db.commit() return token diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index d6ade30c..dbd2e75a 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -435,11 +435,11 @@ def assign_default_roles(db, entity): """Assigns the default roles to an entity: users and services get 'user' role, or admin role if they have admin flag Tokens get 'token' role""" - default_token_role = orm.Role.find(db, 'token') if isinstance(entity, orm.Group): pass elif isinstance(entity, orm.APIToken): app_log.debug('Assigning default roles to tokens') + default_token_role = orm.Role.find(db, 'token') if not entity.roles and (entity.user or entity.service) is not None: default_token_role.tokens.append(entity) app_log.info('Added role %s to token %s', default_token_role.name, entity) From 5a10107da8bdea22f7301f1b95ba755245177cea Mon Sep 17 00:00:00 2001 From: "Bruno P. Kinoshita" Date: Mon, 17 May 2021 14:45:35 +1200 Subject: [PATCH 183/270] (docs) Fix DummyAuthenticator class --- docs/source/reference/authenticators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/authenticators.md b/docs/source/reference/authenticators.md index c1899922..068fc248 100644 --- a/docs/source/reference/authenticators.md +++ b/docs/source/reference/authenticators.md @@ -37,7 +37,7 @@ with any provider, is also available. ## The Dummy Authenticator When testing, it may be helpful to use the -:class:`~jupyterhub.auth.DummyAuthenticator`. This allows for any username and +{class}`jupyterhub.auth.DummyAuthenticator`. This allows for any username and password unless if a global password has been set. Once set, any username will still be accepted but the correct password will need to be provided. From 65f3933da4ce7b332bef1c451d2b21b34f8a0529 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 20 May 2021 14:36:21 +0200 Subject: [PATCH 184/270] Create scope dictionary --- docs/source/rbac/scopedict.py | 97 +++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 docs/source/rbac/scopedict.py diff --git a/docs/source/rbac/scopedict.py b/docs/source/rbac/scopedict.py new file mode 100644 index 00000000..25c3eec9 --- /dev/null +++ b/docs/source/rbac/scopedict.py @@ -0,0 +1,97 @@ +"""Scope definitions""" + + +def get_scope_dict(): + """Returns a nested dictionary of all available scopes: + + {scopename: {'description': description, + 'subscopes': [immediate subscopes]}, + } + + without 'subscopes' key if the scope has no subscopes. + """ + scope_dict = { + '(no_scope)': {'description': 'Allows for only identifying the owning entity.'}, + 'self': { + 'description': 'Metascope, grants access to user’s own resources only; resolves to (no_scope) for services.' + }, + 'all': { + 'description': 'Metascope, valid for tokens only. Grants access to everything that the token’s owning entity can access.' + }, + 'admin:users': { + 'description': 'Grants read, write, create and delete access to users and their authentication state but not their servers or tokens.', + 'subscopes': ['admin:users:auth_state', 'users'], + }, + 'admin:users:auth_state': { + 'description': 'Grants access to users’ authentication state only.' + }, + 'users': { + 'description': 'Grants read and write permissions to users’ models apart from servers, tokens and authentication state.', + 'subscopes': ['read:users', 'users:activity'], + }, + 'read:users': { + 'description': 'Read-only access to users’ models apart from servers, tokens and authentication state.', + 'subscopes': [ + 'read:users:name', + 'read:users:groups', + 'read:users:activity', + 'read:users:roles', + ], + }, + 'read:users:name': {'description': 'Read-only access to users’ names.'}, + 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, + 'read:users:roles': {'description': 'Read-only access to users’ role names.'}, + 'read:users:activity': { + 'description': 'Read-only access to users’ last activity.' + }, + 'users:activity': { + 'description': 'Grants access to read and post users’ last activity only.', + 'subscopes': ['read:users:activity'], + }, + 'admin:users:servers': { + 'description': 'Grants read, start/stop, create and delete permissions to users’ servers and their state.', + 'subscopes': ['admin:users:server_state', 'users:servers'], + }, + 'admin:users:server_state': { + 'description': 'Grants access to servers’ state only.' + }, + 'users:servers': { + 'description': 'Allows for starting/stopping users’ servers in addition to read access to their models. Does not include the server state.', + 'subscopes': ['read:users:servers'], + }, + 'read:users:servers': { + 'description': 'Read-only access to users’ names and their server models. Does not include the server state.', + 'subscopes': ['read:users:name'], + }, + 'users:tokens': { + 'description': 'Grants read, write, create and delete permissions to users’ tokens.', + 'subscopes': ['read:users:tokens'], + }, + 'read:users:tokens': {'description': 'Read-only access to users’ tokens.'}, + 'admin:groups': { + 'description': 'Grants read, write, create and delete access to groups.', + 'subscopes': ['groups'], + }, + 'groups': { + 'description': 'Grants read and write permissions to groups, including adding/removing users to/from groups.', + 'subscopes': ['read:groups'], + }, + 'read:groups': {'description': 'Read-only access to groups’ models.'}, + 'read:services': { + 'description': 'Read-only access to service models.', + 'subscopes': ['read:services:name', 'read:services:roles'], + }, + 'read:services:name': {'description': 'Read-only access to service names.'}, + 'read:services:roles': { + 'description': 'Read-only access to service role names.' + }, + 'read:hub': { + 'description': 'Read-only access to detailed information about the Hub.' + }, + 'proxy': { + 'description': 'Allows for obtaining information about the proxy’s routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy.' + }, + 'shutdown': {'description': 'Grants access to shutdown the hub.'}, + } + + return scope_dict From 948179ee0e360a1f643d99b62e8b4856f8e09f6c Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 20 May 2021 14:49:28 +0200 Subject: [PATCH 185/270] Generate scope table in separate markdown file --- docs/source/rbac/generate-scope-table.py | 95 ++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 docs/source/rbac/generate-scope-table.py diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py new file mode 100644 index 00000000..5024eb48 --- /dev/null +++ b/docs/source/rbac/generate-scope-table.py @@ -0,0 +1,95 @@ +import os +from collections import defaultdict + +from pytablewriter import MarkdownTableWriter +from scopedict import get_scope_dict + +HERE = os.path.abspath(os.path.dirname(__file__)) + + +class ScopeTableGenerator: + def __init__(self): + self.scopes = get_scope_dict() + + @classmethod + def create_writer(cls, table_name, headers, values): + writer = MarkdownTableWriter() + writer.table_name = table_name + writer.headers = headers + writer.value_matrix = values + writer.margin = 1 + return writer + + def _get_scope_relationships(self): + """Returns a tuple of dictionary of all scope-subscope pairs and a list of just subscopes: + + ({scope: subscope}, [subscopes]) + + used for creating hierarchical scope table in _parse_scopes() + """ + pairs = [] + for scope in self.scopes.keys(): + if self.scopes[scope].get('subscopes'): + for subscope in self.scopes[scope]['subscopes']: + pairs.append((scope, subscope)) + else: + pairs.append((scope, None)) + subscopes = [pair[1] for pair in pairs] + pairs_dict = defaultdict(list) + for scope, subscope in pairs: + pairs_dict[scope].append(subscope) + return pairs_dict, subscopes + + def _get_top_scopes(self, subscopes): + """Returns a list of highest level scopes + (not a subscope of any other scopes)""" + top_scopes = [] + for scope in self.scopes.keys(): + if scope not in subscopes: + top_scopes.append(scope) + return top_scopes + + def _parse_scopes(self): + """Returns a list of table rows where row: + [indented scopename string, scope description string]""" + scope_pairs, subscopes = self._get_scope_relationships() + top_scopes = self._get_top_scopes(subscopes) + + table_rows = [] + md_indent = "   " + + def _add_subscopes(table_rows, scopename, depth=0): + description = self.scopes[scopename]['description'] + table_row = [f"{md_indent*depth}`{scopename}`", description] + table_rows.append(table_row) + for subscope in scope_pairs[scopename]: + if subscope: + _add_subscopes(table_rows, subscope, depth + 1) + + for scope in top_scopes: + _add_subscopes(table_rows, scope) + + return table_rows + + def write_table(self): + """Generates the scope table in markdown format and writes it into scope-table.md file""" + filename = f"{HERE}/scope-table.md" + table_name = "" + headers = ["Scope", "Description"] + values = self._parse_scopes() + writer = self.create_writer(table_name, headers, values) + + title = "Table 1. Available scopes and their hierarchy" + content = f"{title}\n{writer.dumps()}" + with open(filename, 'w') as f: + f.write(content) + print(f"Generated {filename}.") + + +def main(): + table_generator = ScopeTableGenerator() + table_generator.write_table() + + +if __name__ == "__main__": + main() From 7914c010998f1cd222be8f4d892f389de0a809e7 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 20 May 2021 14:52:28 +0200 Subject: [PATCH 186/270] Call scope table generation in makefile and include in scopes.md --- docs/Makefile | 7 ++++++- docs/source/rbac/scopes.md | 35 ++++------------------------------- 2 files changed, 10 insertions(+), 32 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 5e61789e..f36da011 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -66,7 +66,12 @@ metrics: source/reference/metrics.rst source/reference/metrics.rst: generate-metrics.py python3 generate-metrics.py -html: rest-api metrics +scopes: source/rbac/scope-table.md + +source/rbac/scope-table.md: source/rbac/generate-scope-table.py source/rbac/scopedict.py + python3 source/rbac/generate-scope-table.py + +html: rest-api metrics scopes $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index 9478525d..6827f56c 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -81,37 +81,10 @@ The payload of an API call can be filtered both horizontally and vertically simu ## Available scopes Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them. -% TODO: Automatically generate this table from code when creating docs -Table 1. Available scopes and their hierarchy -| Scope name | Description | -| :--------- | :---------- | -| (no scope) | Allows for only identifying the owning entity. | -| `self` | Metascope, grants access to user's own resources; resolves to (no scope) for services. | -| `all` | Metascope, valid for tokens only. Grants access to everything that the token's owning entity can do. | -| `admin:users` | Grants read, write, create and delete access to users and their authentication state _but not their servers or tokens._ | -|    `admin:users:auth_state` | Grants access to users' authentication state only. | -|    `users` | Grants read and write permissions to users' models _apart from servers, tokens and authentication state_. | -|       `users:activity` | Grants access to read and post users' activity only. | -|       `read:users` | Read-only access to users' models _apart from servers, tokens and authentication state_. | -|          `read:users:name` | Read-only access to users' names. | -|          `read:users:roles` | Read-only access to a list of users' roles names. | -|          `read:users:groups` | Read-only access to a list of users' group names. | -|          `read:users:activity` | Read-only access to users' activity. | -| `admin:users:servers` | Grants read, start/stop, create and delete permissions to users' servers and their state. | -|    `admin:users:server_state` | Grants access to servers' state only. | -|    `users:servers` | Allows for starting/stopping users' servers in addition to read access to their models. _Does not include the server state_. | -|       `read:users:servers` | Read-only access to users' server models. _Does not include the server state_. | -| `users:tokens` | Grants read, write, create and delete permissions to users' tokens. | -|    `read:users:tokens` | Read-only access to users' tokens. | -| `admin:groups` | Grants read, write, create and delete access to groups. | -|    `groups` | Grants read and write permissions to groups, including adding/removing users to/from groups. | -|       `read:groups` | Read-only access to groups. | -| `read:services` | Read-only access to service models. | -|    `read:services:name` | Read-only access to service names. | -|    `read:services:roles` | Read-only access to a list of service roles names. | -| `read:hub` | Read-only access to detailed information about the Hub. | -| `proxy` | Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. | -| `shutdown` | Grants access to shutdown the hub. | + +```{include} scope-table.md + +``` ```{Caution} Note that only the {ref}`horizontal filtering ` can be added to scopes to customize them. \ From e61cacf5e8b9838ee74168cec44b01e300c87b5b Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 20 May 2021 14:59:49 +0200 Subject: [PATCH 187/270] Add message to run make clean before make html --- docs/source/rbac/generate-scope-table.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index 5024eb48..2934f058 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -84,6 +84,9 @@ class ScopeTableGenerator: with open(filename, 'w') as f: f.write(content) print(f"Generated {filename}.") + print( + "Run 'make clean' before 'make html' to ensure the built scopes.html contains latest scope table changes." + ) def main(): From 478ae8a744272758035ae9e62d47cb871054d888 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 21 May 2021 15:36:14 +0200 Subject: [PATCH 188/270] typo in comment Co-authored-by: Ivana --- jupyterhub/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 02529f1a..b16926ac 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -681,7 +681,7 @@ class APIToken(Hashed, Base): if not token_role: # FIXME: remove this. # Creating a token before the db has roles defined should raise an error. - # PR #3460 should let us fix it by ensuring default roles are define + # PR #3460 should let us fix it by ensuring default roles are defined warnings.warn( "Token created before default roles!", RuntimeWarning, stacklevel=2 From 3fde458c0725988f40f4c987eacad93ca3b68f64 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 21 May 2021 16:43:51 +0200 Subject: [PATCH 189/270] fix appending group roles to user roles ensure we are using a fresh list before calling extend otherwise, we are extending the user's own roles --- jupyterhub/roles.py | 7 ++-- jupyterhub/tests/test_roles.py | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index dbd2e75a..b51bb84d 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -164,13 +164,12 @@ def expand_roles_to_scopes(orm_object): if not isinstance(orm_object, orm.Base): raise TypeError(f"Only orm objects allowed, got {orm_object}") - pass_roles = orm_object.roles + pass_roles = [] + pass_roles.extend(orm_object.roles) if isinstance(orm_object, orm.User): - groups_roles = [] for group in orm_object.groups: - groups_roles.extend(group.roles) - pass_roles.extend(groups_roles) + pass_roles.extend(group.roles) scopes = _get_subscopes(*pass_roles, owner=orm_object) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 4fcf806a..661af326 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1046,3 +1046,71 @@ async def test_oauth_allowed_roles(app, create_temp_role): app_service = app.services[0] assert app_service['name'] == 'oas1' assert set(app_service['oauth_roles']) == set(allowed_roles) + + +async def test_user_group_roles(app, create_temp_role): + user = add_user(app.db, app, name='jack') + another_user = add_user(app.db, app, name='jill') + + group = orm.Group.find(app.db, name='A') + if not group: + group = orm.Group(name='A') + app.db.add(group) + app.db.commit() + + if group not in user.groups: + user.groups.append(group) + app.db.commit() + + if group not in another_user.groups: + another_user.groups.append(group) + app.db.commit() + + group_role = orm.Role.find(app.db, 'student-a') + if not group_role: + create_temp_role(['read:groups!group=A'], 'student-a') + roles.grant_role(app.db, group, rolename='student-a') + group_role = orm.Role.find(app.db, 'student-a') + + # repeat check to ensure group roles don't get added to the user more than once + # regression test for #3472 + roles_before = list(user.roles) + for i in range(3): + roles.expand_roles_to_scopes(user.orm_user) + user_roles = list(user.roles) + assert user_roles == roles_before + + # jack's API token + token = user.new_api_token() + + headers = {'Authorization': 'token %s' % token} + r = await api_request(app, 'users', method='get', headers=headers) + assert r.status_code == 200 + r.raise_for_status() + reply = r.json() + + print(reply) + + assert len(reply[0]['roles']) == 1 + assert reply[0]['name'] == 'jack' + assert group_role.name not in reply[0]['roles'] + + headers = {'Authorization': 'token %s' % token} + r = await api_request(app, 'groups', method='get', headers=headers) + assert r.status_code == 200 + r.raise_for_status() + reply = r.json() + + print(reply) + + headers = {'Authorization': 'token %s' % token} + r = await api_request(app, 'users', method='get', headers=headers) + assert r.status_code == 200 + r.raise_for_status() + reply = r.json() + + print(reply) + + assert len(reply[0]['roles']) == 1 + assert reply[0]['name'] == 'jack' + assert group_role.name not in reply[0]['roles'] From 4a1459195e59de33d54a6026c121651d3f8761ab Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 21 May 2021 16:58:45 +0200 Subject: [PATCH 190/270] Move scope_definitions dict to jupyterhub/scopes.py --- docs/Makefile | 2 +- docs/source/rbac/generate-scope-table.py | 5 +- docs/source/rbac/scopedict.py | 97 ------------------------ jupyterhub/scopes.py | 81 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 100 deletions(-) delete mode 100644 docs/source/rbac/scopedict.py diff --git a/docs/Makefile b/docs/Makefile index f36da011..694d5a35 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -68,7 +68,7 @@ source/reference/metrics.rst: generate-metrics.py scopes: source/rbac/scope-table.md -source/rbac/scope-table.md: source/rbac/generate-scope-table.py source/rbac/scopedict.py +source/rbac/scope-table.md: source/rbac/generate-scope-table.py python3 source/rbac/generate-scope-table.py html: rest-api metrics scopes diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index 2934f058..b282e642 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -2,14 +2,15 @@ import os from collections import defaultdict from pytablewriter import MarkdownTableWriter -from scopedict import get_scope_dict + +from jupyterhub.scopes import scope_definitions HERE = os.path.abspath(os.path.dirname(__file__)) class ScopeTableGenerator: def __init__(self): - self.scopes = get_scope_dict() + self.scopes = scope_definitions @classmethod def create_writer(cls, table_name, headers, values): diff --git a/docs/source/rbac/scopedict.py b/docs/source/rbac/scopedict.py deleted file mode 100644 index 25c3eec9..00000000 --- a/docs/source/rbac/scopedict.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Scope definitions""" - - -def get_scope_dict(): - """Returns a nested dictionary of all available scopes: - - {scopename: {'description': description, - 'subscopes': [immediate subscopes]}, - } - - without 'subscopes' key if the scope has no subscopes. - """ - scope_dict = { - '(no_scope)': {'description': 'Allows for only identifying the owning entity.'}, - 'self': { - 'description': 'Metascope, grants access to user’s own resources only; resolves to (no_scope) for services.' - }, - 'all': { - 'description': 'Metascope, valid for tokens only. Grants access to everything that the token’s owning entity can access.' - }, - 'admin:users': { - 'description': 'Grants read, write, create and delete access to users and their authentication state but not their servers or tokens.', - 'subscopes': ['admin:users:auth_state', 'users'], - }, - 'admin:users:auth_state': { - 'description': 'Grants access to users’ authentication state only.' - }, - 'users': { - 'description': 'Grants read and write permissions to users’ models apart from servers, tokens and authentication state.', - 'subscopes': ['read:users', 'users:activity'], - }, - 'read:users': { - 'description': 'Read-only access to users’ models apart from servers, tokens and authentication state.', - 'subscopes': [ - 'read:users:name', - 'read:users:groups', - 'read:users:activity', - 'read:users:roles', - ], - }, - 'read:users:name': {'description': 'Read-only access to users’ names.'}, - 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, - 'read:users:roles': {'description': 'Read-only access to users’ role names.'}, - 'read:users:activity': { - 'description': 'Read-only access to users’ last activity.' - }, - 'users:activity': { - 'description': 'Grants access to read and post users’ last activity only.', - 'subscopes': ['read:users:activity'], - }, - 'admin:users:servers': { - 'description': 'Grants read, start/stop, create and delete permissions to users’ servers and their state.', - 'subscopes': ['admin:users:server_state', 'users:servers'], - }, - 'admin:users:server_state': { - 'description': 'Grants access to servers’ state only.' - }, - 'users:servers': { - 'description': 'Allows for starting/stopping users’ servers in addition to read access to their models. Does not include the server state.', - 'subscopes': ['read:users:servers'], - }, - 'read:users:servers': { - 'description': 'Read-only access to users’ names and their server models. Does not include the server state.', - 'subscopes': ['read:users:name'], - }, - 'users:tokens': { - 'description': 'Grants read, write, create and delete permissions to users’ tokens.', - 'subscopes': ['read:users:tokens'], - }, - 'read:users:tokens': {'description': 'Read-only access to users’ tokens.'}, - 'admin:groups': { - 'description': 'Grants read, write, create and delete access to groups.', - 'subscopes': ['groups'], - }, - 'groups': { - 'description': 'Grants read and write permissions to groups, including adding/removing users to/from groups.', - 'subscopes': ['read:groups'], - }, - 'read:groups': {'description': 'Read-only access to groups’ models.'}, - 'read:services': { - 'description': 'Read-only access to service models.', - 'subscopes': ['read:services:name', 'read:services:roles'], - }, - 'read:services:name': {'description': 'Read-only access to service names.'}, - 'read:services:roles': { - 'description': 'Read-only access to service role names.' - }, - 'read:hub': { - 'description': 'Read-only access to detailed information about the Hub.' - }, - 'proxy': { - 'description': 'Allows for obtaining information about the proxy’s routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy.' - }, - 'shutdown': {'description': 'Grants access to shutdown the hub.'}, - } - - return scope_dict diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 859f6958..21058416 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -11,6 +11,87 @@ from . import orm from . import roles +scope_definitions = { + '(no_scope)': {'description': 'Allows for only identifying the owning entity.'}, + 'self': { + 'description': 'Metascope, grants access to user’s own resources only; resolves to (no_scope) for services.' + }, + 'all': { + 'description': 'Metascope, valid for tokens only. Grants access to everything that the token’s owning entity can access.' + }, + 'admin:users': { + 'description': 'Grants read, write, create and delete access to users and their authentication state but not their servers or tokens.', + 'subscopes': ['admin:users:auth_state', 'users'], + }, + 'admin:users:auth_state': { + 'description': 'Grants access to users’ authentication state only.' + }, + 'users': { + 'description': 'Grants read and write permissions to users’ models apart from servers, tokens and authentication state.', + 'subscopes': ['read:users', 'users:activity'], + }, + 'read:users': { + 'description': 'Read-only access to users’ models apart from servers, tokens and authentication state.', + 'subscopes': [ + 'read:users:name', + 'read:users:groups', + 'read:users:activity', + 'read:users:roles', + ], + }, + 'read:users:name': {'description': 'Read-only access to users’ names.'}, + 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, + 'read:users:roles': {'description': 'Read-only access to users’ role names.'}, + 'read:users:activity': {'description': 'Read-only access to users’ last activity.'}, + 'users:activity': { + 'description': 'Grants access to read and post users’ last activity only.', + 'subscopes': ['read:users:activity'], + }, + 'admin:users:servers': { + 'description': 'Grants read, start/stop, create and delete permissions to users’ servers and their state.', + 'subscopes': ['admin:users:server_state', 'users:servers'], + }, + 'admin:users:server_state': { + 'description': 'Grants access to servers’ state only.' + }, + 'users:servers': { + 'description': 'Allows for starting/stopping users’ servers in addition to read access to their models. Does not include the server state.', + 'subscopes': ['read:users:servers'], + }, + 'read:users:servers': { + 'description': 'Read-only access to users’ names and their server models. Does not include the server state.', + 'subscopes': ['read:users:name'], + }, + 'users:tokens': { + 'description': 'Grants read, write, create and delete permissions to users’ tokens.', + 'subscopes': ['read:users:tokens'], + }, + 'read:users:tokens': {'description': 'Read-only access to users’ tokens.'}, + 'admin:groups': { + 'description': 'Grants read, write, create and delete access to groups.', + 'subscopes': ['groups'], + }, + 'groups': { + 'description': 'Grants read and write permissions to groups, including adding/removing users to/from groups.', + 'subscopes': ['read:groups'], + }, + 'read:groups': {'description': 'Read-only access to groups’ models.'}, + 'read:services': { + 'description': 'Read-only access to service models.', + 'subscopes': ['read:services:name', 'read:services:roles'], + }, + 'read:services:name': {'description': 'Read-only access to service names.'}, + 'read:services:roles': {'description': 'Read-only access to service role names.'}, + 'read:hub': { + 'description': 'Read-only access to detailed information about the Hub.' + }, + 'proxy': { + 'description': 'Allows for obtaining information about the proxy’s routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy.' + }, + 'shutdown': {'description': 'Grants access to shutdown the hub.'}, +} + + class Scope(Enum): ALL = True From 800f3cf79f547e4e0044473e872c3ea0da9a1d2a Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 21 May 2021 17:03:24 +0200 Subject: [PATCH 191/270] Add trigger to conf.py to call generate-scope-table --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index a53fbbfc..3da73605 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -212,7 +212,7 @@ if on_rtd: # build both metrics and rest-api, since RTD doesn't run make from subprocess import check_call as sh - sh(['make', 'metrics', 'rest-api'], cwd=docs) + sh(['make', 'metrics', 'rest-api', 'scopes'], cwd=docs) # -- Spell checking ------------------------------------------------------- From e0439bc3105433e74266864e78b15cf76b1876f0 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 23 May 2021 11:38:53 +0200 Subject: [PATCH 192/270] Apply suggestions from code review Co-authored-by: Ivana --- jupyterhub/tests/test_roles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 661af326..9ea326ea 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1072,7 +1072,7 @@ async def test_user_group_roles(app, create_temp_role): roles.grant_role(app.db, group, rolename='student-a') group_role = orm.Role.find(app.db, 'student-a') - # repeat check to ensure group roles don't get added to the user more than once + # repeat check to ensure group roles don't get added to the user at all # regression test for #3472 roles_before = list(user.roles) for i in range(3): From 915fee2734796fe3bb46f038a7c138248cc18594 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 24 May 2021 13:36:59 +0200 Subject: [PATCH 193/270] Added strict admin check to role assignment --- jupyterhub/app.py | 26 +++++++++++++++++++------- jupyterhub/roles.py | 1 - 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index a9985c08..c33e8910 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -329,7 +329,7 @@ class JupyterHub(Application): load_roles = [ { 'name': 'teacher', - 'description': 'Access to users' information, servers and groups', + 'description': 'Access to users' information and group membership', 'scopes': ['users', 'groups'], 'users': ['cyclops', 'gandalf'], 'services': [], @@ -1978,7 +1978,15 @@ class JupyterHub(Application): """Load default and predefined roles into the database""" self.log.debug('Loading default roles to database') default_roles = roles.get_default_roles() - for role in default_roles: + default_role_names = [r['name'] for r in default_roles] + init_roles = default_roles + self.load_roles + if not orm.Role.find(self.db, name='admin'): + self._rbac_upgrade = True + for role in self.db.query(orm.Role): + if role.name not in default_role_names: + self.db.delete(role) + self.db.commit() + for role in init_roles: roles.create_role(self.db, role) async def init_role_assignment(self): @@ -1987,9 +1995,13 @@ class JupyterHub(Application): db = self.db # load predefined roles from config file + for entity in self.users + self.services: + if entity.admin: + roles.grant_role(db, entity, 'admin') + else: + roles.strip_role(db, entity, 'admin') self.log.debug('Loading predefined roles from config file to database') for predef_role in self.load_roles: - roles.create_role(db, predef_role) predef_role_obj = orm.Role.find(db, name=predef_role['name']) # add users, services, and/or groups, # tokens need to be checked for permissions @@ -2015,11 +2027,11 @@ class JupyterHub(Application): # db, entity=orm_obj, rolename=predef_role['name'] # ) setattr(predef_role_obj, bearer, orm_role_bearers) - # make sure that on no admin situation, all roles are reset - admin_role = orm.Role.find(db, name='admin') - if not admin_role.users: + # make sure that on hub upgrade, all roles are reset + + if not getattr(self, '_rbac_upgrade', False): app_log.warning( - "No admin users found; assuming hub upgrade. Initializing default roles for all entities" + "No admin role found; assuming hub upgrade. Initializing default roles for all entities" ) # make sure all users, services and tokens have at least one role (update with default) for bearer in role_bearers: diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 27c2c30c..2dc10177 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -446,7 +446,6 @@ def assign_default_roles(db, entity): db.commit() # users and services can have 'user' or 'admin' roles as default else: - # todo: when we deprecate admin flag: replace with role check app_log.debug('Assigning default roles to %s', type(entity).__name__) _switch_default_role(db, entity, entity.admin) From 5a5cdb418e8691188dd0cedb5c434cae1583ada2 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 24 May 2021 14:53:20 +0200 Subject: [PATCH 194/270] (wip): update role init process --- jupyterhub/app.py | 19 +++++--- jupyterhub/tests/test_roles.py | 84 ++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index c33e8910..7ee594ca 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1894,7 +1894,7 @@ class JupyterHub(Application): ) # add allowed users to the db - for name in allowed_users: + for name in allowed_users: # fixme: Do we add standard roles here? user = orm.User.find(db, name) if user is None: user = orm.User(name=name) @@ -1995,11 +1995,6 @@ class JupyterHub(Application): db = self.db # load predefined roles from config file - for entity in self.users + self.services: - if entity.admin: - roles.grant_role(db, entity, 'admin') - else: - roles.strip_role(db, entity, 'admin') self.log.debug('Loading predefined roles from config file to database') for predef_role in self.load_roles: predef_role_obj = orm.Role.find(db, name=predef_role['name']) @@ -2027,6 +2022,18 @@ class JupyterHub(Application): # db, entity=orm_obj, rolename=predef_role['name'] # ) setattr(predef_role_obj, bearer, orm_role_bearers) + for entity in db.query(orm.Service): + if entity.admin: + roles.grant_role(db, entity, 'admin') + else: + roles.assign_default_roles(db, entity) + for entity in db.query( + orm.User + ): # fixme: why can't I combine these expressions? + if entity.admin: + roles.grant_role(db, entity, 'admin') + else: + roles.assign_default_roles(db, entity) # make sure that on hub upgrade, all roles are reset if not getattr(self, '_rbac_upgrade', False): diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index eff091dc..d3d66365 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -434,8 +434,8 @@ async def test_load_roles_users(tmpdir, request): db = hub.db hub.authenticator.admin_users = ['admin'] hub.authenticator.allowed_users = ['cyclops', 'gandalf', 'bilbo', 'gargamel'] - await hub.init_users() await hub.init_role_creation() + await hub.init_users() await hub.init_role_assignment() admin_role = orm.Role.find(db, 'admin') user_role = orm.Role.find(db, 'user') @@ -570,8 +570,8 @@ async def test_load_roles_groups(tmpdir, request): hub = MockHub(**kwargs) hub.init_db() db = hub.db - await hub.init_groups() await hub.init_role_creation() + await hub.init_groups() await hub.init_role_assignment() assist_role = orm.Role.find(db, name='assistant') @@ -617,9 +617,9 @@ async def test_load_roles_user_tokens(tmpdir, request): db = hub.db hub.authenticator.admin_users = ['admin'] hub.authenticator.allowed_users = ['cyclops', 'gandalf'] + await hub.init_role_creation() await hub.init_users() await hub.init_api_tokens() - await hub.init_role_creation() await hub.init_role_assignment() # test if all other tokens have default 'user' role token_role = orm.Role.find(db, 'token') @@ -886,32 +886,70 @@ async def test_oauth_allowed_roles(app, create_temp_role): assert set(app_service['oauth_roles']) == set(allowed_roles) -async def test_config_role_assignment(): +async def test_config_role_list(): + roles_to_load = [ + { + 'name': 'elephant', + 'description': 'pacing about', + 'scopes': ['read:hub'], + }, + { + 'name': 'tiger', + 'description': 'pouncing stuff', + 'scopes': ['shutdown'], + }, + ] + kwargs = {'load_roles': roles_to_load} + hub = MockHub(**kwargs) + hub.init_db() + hub.authenticator.admin_users = ['admin'] + await hub.init_role_creation() + for role_conf in roles_to_load: + assert orm.Role.find(hub.db, name=role_conf['name']) + # Now reload and see if user is removed from role list + roles_to_load.pop(0) + hub.load_roles = roles_to_load + await hub.init_role_creation() + print(hub.db.query(orm.Role).all()) + assert orm.Role.find(hub.db, name='tiger') + assert not orm.Role.find(hub.db, name='elephant') + + +async def test_config_role_users(): role_name = 'painter' user_name = 'benny' - other_users = ['agnetha', 'bjorn', 'anni-frid'] + user_names = ['agnetha', 'bjorn', 'anni-frid', user_name] roles_to_load = [ { 'name': role_name, 'description': 'painting with colors', 'scopes': ['users', 'groups'], - 'users': other_users, + 'users': user_names, + }, + { + 'name': role_name, + 'description': 'painting with colors', + 'scopes': ['users', 'groups'], + 'users': user_names, }, ] - for user_in_config in [False, True]: - if user_in_config: - roles_to_load[0]['users'].append(user_name) - kwargs = {'load_roles': roles_to_load} - hub = MockHub(**kwargs, clean_db=False) - hub.init_db() - hub.authenticator.admin_users = ['admin'] - hub.authenticator.allowed_users = other_users + [user_name] - await hub.init_users() - await hub.init_role_creation() - await hub.init_role_assignment() - user = orm.User.find(hub.db, name=user_name) - role = orm.Role.find(hub.db, name=role_name) - if user_in_config: - assert role in user.roles - else: - assert role not in user.roles + kwargs = {'load_roles': roles_to_load} + hub = MockHub(**kwargs) + hub.init_db() + hub.authenticator.admin_users = ['admin'] + hub.authenticator.allowed_users = user_names + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + user = orm.User.find(hub.db, name=user_name) + role = orm.Role.find(hub.db, name=role_name) + assert role in user.roles + # Now reload and see if user is removed from role list + roles_to_load[0]['users'].remove(user_name) + hub.load_roles = roles_to_load + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + user = orm.User.find(hub.db, name=user_name) + role = orm.Role.find(hub.db, name=role_name) + assert role not in user.roles From 1a01302e27ea2d2498f535122f6f1eeee2d49472 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 25 May 2021 11:16:15 +0200 Subject: [PATCH 195/270] Fixed bug in scope test fixture teardown --- jupyterhub/tests/test_scopes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 43fe9f79..5bd3825e 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -311,7 +311,7 @@ def create_user_with_scopes(app, create_temp_role): def create_service_with_scopes(app, create_temp_role): """Generate a temporary service with specific scopes. Convenience function that provides setup, database handling and teardown""" - temp_service = [] + temp_services = [] counter = 0 role_function = create_temp_role @@ -325,11 +325,12 @@ def create_service_with_scopes(app, create_temp_role): app.init_services() orm_service = orm.Service.find(app.db, name) app.db.commit() + temp_services.append(orm_service) roles.update_roles(app.db, orm_service, roles=[role.name]) return orm_service yield temp_service_creator - for service in temp_service: + for service in temp_services: app.db.delete(service) app.db.commit() From c13ad804fe3b5278df022b947c2588a7734b948a Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 25 May 2021 13:51:43 +0200 Subject: [PATCH 196/270] Added default roles for users and unified admin check --- jupyterhub/app.py | 44 +++++++++++++++++++-------------- jupyterhub/auth.py | 2 +- jupyterhub/tests/test_roles.py | 8 +++++- jupyterhub/tests/test_scopes.py | 1 - 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 7ee594ca..816dd06c 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1894,7 +1894,7 @@ class JupyterHub(Application): ) # add allowed users to the db - for name in allowed_users: # fixme: Do we add standard roles here? + for name in allowed_users: user = orm.User.find(db, name) if user is None: user = orm.User(name=name) @@ -1995,6 +1995,14 @@ class JupyterHub(Application): db = self.db # load predefined roles from config file + for role_spec in self.load_roles: + if role_spec['name'] == 'admin' and self.admin_users: + app_log.info( + "Extending admin role assignment with config admin users: %s", + str(self.admin_users), + ) + role_spec['users'].extend(self.admin_users) + role_spec['users'] = set(role_spec['users']) self.log.debug('Loading predefined roles from config file to database') for predef_role in self.load_roles: predef_role_obj = orm.Role.find(db, name=predef_role['name']) @@ -2018,24 +2026,22 @@ class JupyterHub(Application): Class = orm.get_class(bearer) orm_obj = Class.find(db, bname) orm_role_bearers.append(orm_obj) - # roles.grant_role( - # db, entity=orm_obj, rolename=predef_role['name'] - # ) + # Ensure all with admin role have admin flag + if predef_role['name'] == 'admin': + orm_obj.admin = True setattr(predef_role_obj, bearer, orm_role_bearers) - for entity in db.query(orm.Service): - if entity.admin: - roles.grant_role(db, entity, 'admin') - else: - roles.assign_default_roles(db, entity) - for entity in db.query( - orm.User - ): # fixme: why can't I combine these expressions? - if entity.admin: - roles.grant_role(db, entity, 'admin') - else: - roles.assign_default_roles(db, entity) - # make sure that on hub upgrade, all roles are reset + db.commit() + allowed_users = db.query(orm.User).filter( + orm.User.name.in_(self.authenticator.allowed_users) + ) + for user in allowed_users: + roles.grant_role(db, user, 'user') + for admin_user in db.query(orm.User).filter_by(admin=True): + roles.grant_role(db, admin_user, 'admin') + for admin_service in db.query(orm.Service).filter_by(admin=True): + roles.grant_role(db, admin_service, 'admin') + # make sure that on hub upgrade, all roles are reset if not getattr(self, '_rbac_upgrade', False): app_log.warning( "No admin role found; assuming hub upgrade. Initializing default roles for all entities" @@ -2150,7 +2156,9 @@ class JupyterHub(Application): if orm_service is None: # not found, create a new one orm_service = orm.Service(name=name) - if spec.get('admin', False): + if spec.get( + 'admin', False + ): # Todo: fix double assignment of admin roles roles.update_roles(self.db, entity=orm_service, roles=['admin']) self.db.add(orm_service) orm_service.admin = spec.get('admin', False) diff --git a/jupyterhub/auth.py b/jupyterhub/auth.py index c4151d18..a62c1103 100644 --- a/jupyterhub/auth.py +++ b/jupyterhub/auth.py @@ -112,7 +112,7 @@ class Authenticator(LoggingConfigurable): Use this with supported authenticators to restrict which users can log in. This is an additional list that further restricts users, beyond whatever restrictions the - authenticator has in place. + authenticator has in place. Any user in this list is granted the 'user' role on hub startup. If empty, does not perform any additional restriction. diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index d3d66365..93071a40 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -446,7 +446,7 @@ async def test_load_roles_users(tmpdir, request): assert len(user.roles) == len(set(user.roles)) if user.admin: assert admin_role in user.roles - assert user_role not in user.roles + assert user_role in user.roles # test if predefined roles loaded and assigned teacher_role = orm.Role.find(db, name='teacher') @@ -953,3 +953,9 @@ async def test_config_role_users(): user = orm.User.find(hub.db, name=user_name) role = orm.Role.find(hub.db, name=role_name) assert role not in user.roles + + +# todo: test admin flag -> admin role and other way around +# todo: test custom user role reset on startup +# todo: test removal from config -> removal from database +# todo: test customizing user scopes -/> membership changes diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 5bd3825e..1d501a17 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -620,7 +620,6 @@ async def test_server_state_access( ) service = create_service_with_scopes(*scopes) api_token = service.new_api_token() - await app.init_role_creation() headers = {'Authorization': 'token %s' % api_token} r = await api_request(app, 'users', user.name, headers=headers) r.raise_for_status() From d39673eea23238757f1360a53246db9b6bc90e47 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 26 May 2021 12:28:59 +0200 Subject: [PATCH 197/270] Flesh out oauth details doc adress review, add emoji, expand details, examlpes, and add discussion of caching and revocation. --- docs/source/rbac/scopes.md | 2 +- docs/source/reference/index.rst | 1 + docs/source/reference/oauth.md | 238 ++++++++++++++++++++++++++------ 3 files changed, 199 insertions(+), 42 deletions(-) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index 9478525d..74ee6d30 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -1,4 +1,4 @@ -# Scopes +# Scopes in JupyterHub A scope has a syntax-based design that reveals which resources it provides access to. Resources are objects with a type, associated data, relationships to other resources, and a set of methods that operate on them (see [RESTful API](https://restful-api-design.readthedocs.io/en/latest/resources.html) documentation for more information). diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst index ed478fa1..76177072 100644 --- a/docs/source/reference/index.rst +++ b/docs/source/reference/index.rst @@ -26,3 +26,4 @@ what happens under-the-hood when you deploy and configure your JupyterHub. config-proxy config-sudo config-reference + oauth diff --git a/docs/source/reference/oauth.md b/docs/source/reference/oauth.md index 185239cd..a658eb90 100644 --- a/docs/source/reference/oauth.md +++ b/docs/source/reference/oauth.md @@ -2,45 +2,60 @@ JupyterHub uses OAuth 2 internally as a mechanism for authenticating users. As such, JupyterHub itself always functions as an OAuth **provider**. -More on what that means below. +More on what that means [below](oauth-terms). Additionally, JupyterHub is _often_ deployed with [oauthenticator](https://oauthenticator.readthedocs.io), where an external identity provider, such as GitHub or KeyCloak, is used to authenticate users. -When this is the case, there are \*two nested +When this is the case, there are _two_ nested oauth flows: +an _internal_ oauth flow where JupyterHub is the **provider**, +and and _external_ oauth flow, where JupyterHub is a **client**. This means that when you are using JupyterHub, there is always _at least one_ and often two layers of OAuth involved in a user logging in and accessing their server. Some relevant points: -- Single-user servers _never_ need to communicate with or be aware of the upstream provider. +- Single-user servers _never_ need to communicate with or be aware of the upstream provider configured in your Authenticator. As far as they are concerned, only JupyterHub is an OAuth provider, and how users authenticate with the Hub itself is irrelevant. - When talking to a single-user server, there are ~always two tokens: a token issued to the server itself to communicate with the Hub API, and a second per-user token in the browser to represent the completed login process and authorized permissions. - More on this later. + More on this [later](two-tokens). -### Key OAuth terms +(oauth-terms)= -- **provider** the entity responsible for managing. +## Key OAuth terms + +Here are some key definitions to keep in mind when we are talking about OAuth. +You can also read more detail [here](https://www.oauth.com/oauth2-servers/definitions/). + +- **provider** the entity responsible for managing identity and authorization, + always a web server. JupyterHub is _always_ an oauth provider for JupyterHub's components. When OAuthenticator is used, an external service, such as GitHub or KeyCloak, is also an oauth provider. -- **client** An entity that requests OAuth tokens on a user's behalf. - JupyterHub _services_ or single-user _servers_ are OAuth clients of the JupyterHub _provider_. - When OAuthenticator is used, JupyterHub is itself also an OAuth _client_ for the external oauth _provider_, e.g. GitHub. +- **client** An entity that requests OAuth **tokens** on a user's behalf, + generally a web server of some kind. + OAuth **clients** are services that _delegate_ authentication and/or authorization + to an OAuth **provider**. + JupyterHub _services_ or single-user _servers_ are OAuth **clients** of the JupyterHub **provider**. + When OAuthenticator is used, JupyterHub is itself _also_ an OAuth **client** for the external oauth **provider**, e.g. GitHub. - **browser** A user's web browser, which makes requests and stores things like cookies - **token** The secret value used to represent a user's authorization. This is the final product of the OAuth process. +- **code** A short-lived temporary secret that the **client** exchanges + for a **token** at the conclusion of oauth, + in what's generally called the "oauth callback handler." -### The oauth flow +## One oauth flow -OAuth flow is what we call the sequence of HTTP requests involved in authenticating a user and issuing a token, ultimately used for authorized access to a service or single-user server. +OAuth **flow** is what we call the sequence of HTTP requests involved in authenticating a user and issuing a token, ultimately used for authorized access to a service or single-user server. -It generally goes like this: +A single oauth flow generally goes like this: -#### Oauth request and redirect -1. A _browser_ makes an HTTP request to an oauth _client_. -2. There are no credentials, so the client _redirects_ the browser to an "authorize" page on the oauth _provider_ with some extra information: +### OAuth request and redirect + +1. A **browser** makes an HTTP request to an oauth **client**. +2. There are no credentials, so the client _redirects_ the browser to an "authorize" page on the oauth **provider** with some extra information: - the oauth **client id** of the client itself - the **redirect uri** to be redirected back to after completion - the **scopes** requested, which the user should be presented with to confirm. @@ -49,14 +64,17 @@ It generally goes like this: the browser must be _authenticated_ with the provider. This is often already stored in a cookie, but if not the provider webapp must begin its _own_ authentication process before serving the authorization page. + This _may_ even begin another oauth flow! 4. After the user tells the provider that they want to proceed with the authorization, the provider records this authorization in a short-lived record called an **oauth code**. -5. Finally, - the oauth provider redirects the browser _back_ to the oauth client's "redirect uri" +5. Finally, the oauth provider redirects the browser _back_ to the oauth client's "redirect uri" (or "oauth callback uri"), with the oauth code in a url parameter. -#### State after redirect +That's the end of the requests made between the **browser** and the **provider**. + +### State after redirect + At this point: - The browser is authenticated with the _provider_ @@ -65,7 +83,8 @@ At this point: - All requests so far have been made directly by the browser. No requests have originated at the client or provider. -#### OAuth Client Handles Callback Request +### OAuth Client Handles Callback Request + Now we get to finish the OAuth process. Let's dig into what the oauth client does when it handles the oauth callback request with the @@ -74,30 +93,44 @@ the oauth callback request with the This is the first direct request between the OAuth _client_ and the _provider_. - Once the token is retrieved, the client _usually_ makes a second API request to the _provider_ - to retrieve information about the owner of the token (the user) + to retrieve information about the owner of the token (the user). + This is the step where behavior diverges for different OAuth providers. + Up to this point, all oauth providers are the same, following the oauth specification. + However, oauth does not define a standard for exchanging tokens for information about their owner or permissions ([OpenID Connect](https://openid.net/connect/) does that), + so this step may be different for each OAuth provider. - Finally, the oauth client stores its own record that the user is authorized in a cookie. This could be the token itself, or any other appropriate representation of successful authentication. +- Last of all, now that credentials have been established, + the browser can be redirected to the _original_ URL where it started, + to try the request again. + If the client wasn't able to keep track of the original URL all this time + (not always easy!), + you might end up back at a default landing page instead of where you started the login process. This is frustrating! -_phew_ +😮‍💨 _phew_. So that's _one_ OAuth process. ## Full sequence of OAuth in JupyterHub -Let's go through the above oauth process in Jupyter, +Let's go through the above oauth process in JupyterHub, with specific examples of each HTTP request and what information is contained. +For bonus points, we are using the double-oauth example of JupyterHub configured with GitHubOAuthenticator. + +To disambiguate, we will call the OAuth process where JupyterHub is the **provider** "internal oauth," +and the one with JupyterHub as a **client** "external oauth." Our starting point: - a user's single-user server is running. Let's call them `danez` -- jupyterhub is running with GitHub as an oauth provider, +- jupyterhub is running with GitHub as an oauth provider (this means two full instances of oauth), - Danez has a fresh browser session with no cookies yet First request: - browser->single-user server running JupyterLab or Jupyter Classic - `GET /user/danez/notebooks/mynotebook.ipynb` -- no credentials, so client starts oauth process with JupyterHub +- no credentials, so single-user server (as an oauth **client**) starts internal oauth process with JupyterHub (the **provider**) - response: 302 redirect -> `/hub/api/oauth2/authorize` with: - client-id=`jupyterhub-user-danez` @@ -107,23 +140,38 @@ Second request, following redirect: - browser->jupyterhub - `GET /hub/api/oauth2/authorize` -- no credentials, so jupyterhub starts oauth process _with GitHub_ -- response: 302 redirect -> `/hub/api/oauth2/authorize` +- no credentials, so jupyterhub starts external oauth process _with GitHub_ +- response: 302 redirect -> `https://github.com/login/oauth/authorize` with: - client-id=`jupyterhub-client-uuid` - redirect-uri=`/hub/oauth_callback` (we'll come back later!) +_pause_ This is where JupyterHub configuration comes into play. +Recall, in this case JupyterHub is using: + +```python +c.JupyterHub.authenticator_class = 'github' +``` + +That means authenticating a request to the Hub itself starts +a _second_, external oauth process with GitHub as a provider. +This external oauth process is optional, though. +If you were using the default username+password PAMAuthenticator, +this redirect would have been to `/hub/login` instead, to present the user +with a login form. + Third request, following redirect: - browser->GitHub - `GET https://github.com/login/oauth/authorize` -Prompts for login and asks for confirmation of authorization. +Here, GitHub prompts for login and asks for confirmation of authorization +(more redirects if you aren't logged in to GitHub yet, but ultimately back to this `/authorize` URL). After successful authorization (either by looking up a pre-existing authorization, or recording it via form submission) -GitHub issues oauth code and redirects to `/hub/oauth_callback?code=github-code` +GitHub issues an **oauth code** and redirects to `/hub/oauth_callback?code=github-code` Next request: @@ -136,39 +184,42 @@ The first: - JupyterHub->GitHub - `POST https://github.com/login/oauth/access_token` -- request made with oauth code from url parameter -- response includes an access token +- request made with oauth **code** from url parameter +- response includes an access **token** The second: - JupyterHub->GitHub - `GET https://api.github.com/user` -- request made with access token in the `Authorization` header +- request made with access **token** in the `Authorization` header - response is the user model, including username, email, etc. -Now the oauth callback request completes with: +Now the external oauth callback request completes with: -- set cookie on `/hub/` recording jupyterhub authentication so we don't need to do oauth with github again for a while +- set cookie on `/hub/` path, recording jupyterhub authentication so we don't need to do external oauth with GitHub again for a while - redirect -> `/hub/api/oauth2/authorize` +🎉 At this point, we have completed our first OAuth flow! 🎉 + Now, we get our first repeated request: - browser->jupyterhub - `GET /hub/api/oauth2/authorize` - this time with credentials, so jupyterhub either - 1. serves the authorization confirmation page, or + 1. serves the internal authorization confirmation page, or 2. automatically accepts authorization (shortcut taken when a user is visiting their own server) - redirect -> `/user/danez/oauth_callback?code=jupyterhub-code` -Here, we start the same oauth callback process as before, but at Danez's single-user server +Here, we start the same oauth callback process as before, but at Danez's single-user server for the _internal_ oauth - browser->single-user server - `GET /user/danez/oauth_callback` (in handler) -Inside the callback handler, Danez's server makes two API requests to JupyterHub: +Inside the internal oauth callback handler, +Danez's server makes two API requests to JupyterHub: The first: @@ -204,14 +255,119 @@ To authenticate this request, the single token stored in the encrypted cookie is If the user model matches who should be allowed (e.g. Danez), then the request is allowed. +See {doc}`../rbac/scopes` for how JupyterHub uses scopes to determine authorized access to servers and services. _the end_ -## A tale of two tokens +## Token caches and expiry -**TODO**: discuss API token issued to server at startup and oauth-issued token in cookie, and some details of how JupyterLab currently deals with that. -` +Because tokens represent information from an external source, +they can become 'stale,' +or the information they represent may no longer be accurate. +For example: a user's GitHub account may no longer be authorized to use JupyterHub, +that should ultimately propagate to revoking access and force logging in again. -## Notes +To handle this, OAuth tokens and the various places they are stored can _expire_, +which should have the same effect as no credentials, +and trigger the authorization process again. -- I omitted some information about the distinction between tokens issued to the server, due to RBAC changes. But they are different! +In JupyterHub's internal oauth, we have these layers of information that can go stale: + +- The oauth client has a **cache** of Hub responses for tokens, + so it doesn't need to make API requests to the Hub for every request it receives. + This cache has an expiry of five minutes by default, + and is governed by the configuration `HubAuth.cache_max_age` in the single-user server. +- The internal oauth token is stored in a cookie, which has its own expiry (default: 14 days), + governed by `JupyterHub.cookie_max_age_days`. +- The internal oauth token can also itself expire, + which is by default the same as the cookie expiry, + since it makes sense for the token itself and the place it is stored to expire at the same time. + This is governed by `JupyterHub.cookie_max_age_days` first, + or can overridden by `JupyterHub.oauth_token_expires_in`. + +That's all for _internal_ auth storage, +but the information from the _external_ authentication provider +(could be PAM or GitHub OAuth, etc.) can also expire. +Authenticator configuration governs when JupyterHub needs to ask again, +triggering the external login process anew before letting a user proceed. + +- `jupyterhub-hub-login` cookie stores that a browser is authenticated with the Hub. + This expires according to `JupyterHub.cookie_max_age_days` configuration, + with a default of 14 days. + The `jupyterhub-hub-login` cookie is encrypted with `JupyterHub.cookie_secret` + configuration. +- {meth}`.Authenticator.refresh_user` is a method to refresh a user's auth info. + By default, it does nothing, but it can return an updated user model if a user's information has changed, + or force a full login process again if needed. +- {attr}`.Authenticator.auth_refresh_age` configuration governs how often + `refresh_user()` will be called to check if a user must login again (default: 300 seconds). +- {attr}`.Authenticator.refresh_pre_spawn` configuration governs whether + `refresh_user()` should be called prior to spawning a server, + to force fresh auth info when a server is launched (default: False). + This can be useful when Authenticators pass access tokens to spawner environments, to ensure they aren't getting a stale token that's about to expire. + +**So what happens when these things expire or get stale?** + +- If the HubAuth **token response cache** expires, + when a request is made with a token, + the Hub is asked for the latest information about the token. + This usually has no visible effect, since it is just refreshing a cache. + If it turns out that the token itself has expired or been revoked, + the request will be denied. +- If the token has expired, but is still in the cookie: + when the token response cache expires, + the next time the server asks the hub about the token, + no user will be identified and the internal oauth process begins again. +- If the token _cookie_ expires, the next browser request will be made with no credentials, + and the internal oauth process will begin again. + This will usually have the form of a transparent redirect browsers won't notice. + However, if this occurs on an API request in a long-lived page visit + such as a JupyterLab session, the API request may fail and require + a page refresh to get renewed credentials. +- If the _JupyterHub_ cookie expires, the next time the browser makes a request to the Hub, + the Hub's authorization process must begin again (e.g. login with GitHub). + Hub cookie expiry on its own **does not** mean that a user can no longer access their single-user server! +- If credentials from the upstream provider (e.g. GitHub) become stale or outdated, + these will not be refreshed until/unless `refresh_user` is called + _and_ `refresh_user()` on the given Authenticator is implemented to perform such a check. + At this point, few Authenticators implement `refresh_user` to support this feature. + If your Authenticator does not or cannot implement `refresh_user`, + the only way to force a check is to reset the `JupyterHub.cookie_secret` encryption key, + which invalidates the `jupyterhub-hub-login` cookie for all users. + +### Logging out + +Logging out of JupyterHub means clearing and revoking many of these credentials: + +- The `jupyterhub-hub-login` cookie is revoked, meaning the next request to the Hub itself will require a new login. +- The token stored in the `jupyterhub-user-username` cookie for the single-user server + will be revoked, based on its associaton with `jupyterhub-session-id`, but the _cookie itself cannot be cleared at this point_ +- The shared `jupyterhub-session-id` is cleared, which ensures that the HubAuth **token response cache** will not be used, + and the next request with the expired token will ask the Hub, which will inform the single-user server that the token has expired + +## Extra bits + +(two-tokens)= + +### A tale of two tokens + +**TODO**: discuss API token issued to server at startup ($JUPYTERHUB_API_TOKEN) +and oauth-issued token in the cookie, +and some details of how JupyterLab currently deals with that. +They are different, and JupyterLab should be making requests using the token from the cookie, +not the token from the server, +but that is not currently the case. + +### Redirect loops + +In general, an authenticated web endpoint has this behavior, +based on the authentication/authorization state of the browser: + +- If authorized, allow the request to happen +- If authenticated (I know who you are) but not authorized (you are not allowed), fail with a 403 permission denied error +- If not authenticated, start a redirect process to establish authorization, + which should end in a redirect back to the original URL to try again. + **This is why problems in authentication result in redirect loops!** + If the second request fails to detect the authentication that should have been established during the redirect, + it will start the authentication redirect process over again, + and keep redirecting in a loop until the browser balks. From 3ba8e11553f614bc8da083efe918f54dccdb60a0 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 26 May 2021 15:39:45 +0200 Subject: [PATCH 198/270] Added tests and fixed bugs --- jupyterhub/app.py | 48 ++++++++---- jupyterhub/tests/test_roles.py | 129 ++++++++++++++++++++++++++++++--- 2 files changed, 152 insertions(+), 25 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 816dd06c..5fbc2f36 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -21,6 +21,7 @@ from datetime import timezone from functools import partial from getpass import getuser from glob import glob +from itertools import chain from operator import itemgetter from textwrap import dedent from urllib.parse import unquote @@ -1978,13 +1979,15 @@ class JupyterHub(Application): """Load default and predefined roles into the database""" self.log.debug('Loading default roles to database') default_roles = roles.get_default_roles() - default_role_names = [r['name'] for r in default_roles] - init_roles = default_roles + self.load_roles + config_role_names = [r['name'] for r in self.load_roles] + init_roles = self.load_roles.copy() + for role_spec in default_roles: + if role_spec['name'] not in config_role_names: + init_roles.append(role_spec) if not orm.Role.find(self.db, name='admin'): self._rbac_upgrade = True - for role in self.db.query(orm.Role): - if role.name not in default_role_names: - self.db.delete(role) + self.db.query(orm.Role).delete() + app_log.info("Deleting all roles in database") self.db.commit() for role in init_roles: roles.create_role(self.db, role) @@ -1992,20 +1995,23 @@ class JupyterHub(Application): async def init_role_assignment(self): # tokens are added separately role_bearers = ['users', 'services', 'groups'] - + config_admin_users = set(self.admin_users) | self.authenticator.admin_users db = self.db # load predefined roles from config file for role_spec in self.load_roles: - if role_spec['name'] == 'admin' and self.admin_users: + if role_spec['name'] == 'admin' and config_admin_users: app_log.info( "Extending admin role assignment with config admin users: %s", - str(self.admin_users), + str(config_admin_users), ) - role_spec['users'].extend(self.admin_users) - role_spec['users'] = set(role_spec['users']) + role_spec['users'] = set(role_spec.get('users', [])) + role_spec['users'] |= config_admin_users self.log.debug('Loading predefined roles from config file to database') + has_admin_role_spec = False for predef_role in self.load_roles: predef_role_obj = orm.Role.find(db, name=predef_role['name']) + if predef_role['name'] == 'admin': + has_admin_role_spec = bool(predef_role.get('users', False)) # add users, services, and/or groups, # tokens need to be checked for permissions for bearer in role_bearers: @@ -2036,11 +2042,23 @@ class JupyterHub(Application): ) for user in allowed_users: roles.grant_role(db, user, 'user') - for admin_user in db.query(orm.User).filter_by(admin=True): - roles.grant_role(db, admin_user, 'admin') - for admin_service in db.query(orm.Service).filter_by(admin=True): - roles.grant_role(db, admin_service, 'admin') - + admin_role = orm.Role.find(db, 'admin') + admin_objs = chain( + db.query(orm.User).filter_by(admin=True), + db.query(orm.Service).filter_by(admin=True), + ) + for admin_obj in admin_objs: + if has_admin_role_spec: + app_log.debug( + "Admin users explicitly specified in config, so previous db state is ignored" + ) + admin_obj.admin = admin_role in admin_obj.roles + else: + app_log.debug( + "Admin users not specified in config, elevate to admin based on previous db state" + ) + roles.grant_role(db, admin_obj, 'admin') + db.commit() # make sure that on hub upgrade, all roles are reset if not getattr(self, '_rbac_upgrade', False): app_log.warning( diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index e2883500..a3d41830 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -967,18 +967,16 @@ async def test_config_role_list(): 'scopes': ['shutdown'], }, ] - kwargs = {'load_roles': roles_to_load} - hub = MockHub(**kwargs) + hub = MockHub(load_roles=roles_to_load) hub.init_db() hub.authenticator.admin_users = ['admin'] await hub.init_role_creation() for role_conf in roles_to_load: assert orm.Role.find(hub.db, name=role_conf['name']) - # Now reload and see if user is removed from role list + # Now remove elephant from config and see if it is removed from database roles_to_load.pop(0) hub.load_roles = roles_to_load await hub.init_role_creation() - print(hub.db.query(orm.Role).all()) assert orm.Role.find(hub.db, name='tiger') assert not orm.Role.find(hub.db, name='elephant') @@ -1001,8 +999,7 @@ async def test_config_role_users(): 'users': user_names, }, ] - kwargs = {'load_roles': roles_to_load} - hub = MockHub(**kwargs) + hub = MockHub(load_roles=roles_to_load) hub.init_db() hub.authenticator.admin_users = ['admin'] hub.authenticator.allowed_users = user_names @@ -1023,7 +1020,119 @@ async def test_config_role_users(): assert role not in user.roles -# todo: test admin flag -> admin role and other way around -# todo: test custom user role reset on startup -# todo: test removal from config -> removal from database -# todo: test customizing user scopes -/> membership changes +async def test_admin_role_and_flag(): + admin_role_spec = [ + { + 'name': 'admin', + 'users': ['eddy'], + } + ] + hub = MockHub(load_roles=admin_role_spec) + hub.init_db() + hub.authenticator.admin_users = ['admin'] + hub.authenticator.allowed_users = ['eddy'] + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + admin_role = orm.Role.find(hub.db, name='admin') + for user_name in ['eddy', 'admin']: + user = orm.User.find(hub.db, name=user_name) + assert user.admin + assert admin_role in user.roles + admin_role_spec[0]['users'].remove('eddy') + hub.load_roles = admin_role_spec + await hub.init_users() + await hub.init_role_assignment() + user = orm.User.find(hub.db, name='eddy') + assert not user.admin + assert admin_role not in user.roles + + +async def test_custom_role_reset(): + user_role_spec = [ + { + 'name': 'user', + 'scopes': ['self', 'shutdown'], + 'users': ['eddy'], + } + ] + hub = MockHub(load_roles=user_role_spec) + hub.init_db() + hub.authenticator.allowed_users = ['eddy'] + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + user_role = orm.Role.find(hub.db, name='user') + user = orm.User.find(hub.db, name='eddy') + assert user_role in user.roles + assert 'shutdown' in user_role.scopes + hub.load_roles = [] + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + user_role = orm.Role.find(hub.db, name='user') + user = orm.User.find(hub.db, name='eddy') + assert user_role in user.roles + assert 'shutdown' not in user_role.scopes + + +async def test_removal_config_to_db(): + role_spec = [ + { + 'name': 'user', + 'scopes': ['self', 'shutdown'], + }, + { + 'name': 'wizard', + 'scopes': ['self', 'read:groups'], + }, + ] + hub = MockHub(load_roles=role_spec) + hub.init_db() + await hub.init_role_creation() + assert orm.Role.find(hub.db, 'user') + assert orm.Role.find(hub.db, 'wizard') + hub.load_roles = [] + await hub.init_role_creation() + assert orm.Role.find(hub.db, 'user') + assert not orm.Role.find(hub.db, 'wizard') + + +async def test_user_config_respects_memberships(): + role_spec = [ + { + 'name': 'user', + 'scopes': ['self', 'shutdown'], + } + ] + user_names = ['eddy', 'carol'] + hub = MockHub(load_roles=role_spec) + hub.init_db() + hub.authenticator.allowed_users = user_names + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + user_role = orm.Role.find(hub.db, 'user') + for user_name in user_names: + user = orm.User.find(hub.db, user_name) + assert user in user_role.users + + +async def test_admin_role_respects_config(): + role_spec = [ + { + 'name': 'admin', + 'scopes': ['self', 'shutdown'], + } + ] + admin_users = ['eddy', 'carol'] + hub = MockHub(load_roles=role_spec) + hub.init_db() + hub.authenticator.admin_users = admin_users + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + admin_role = orm.Role.find(hub.db, 'admin') + for user_name in admin_users: + user = orm.User.find(hub.db, user_name) + assert user in admin_role.users From b399158060517eabadc968313f0ee0ee7d384337 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 26 May 2021 16:45:53 +0200 Subject: [PATCH 199/270] Create scope_hierarchy dict automatically from scope_definitions --- jupyterhub/roles.py | 48 ++++++++++++++++++++------------------------ jupyterhub/scopes.py | 10 +++++---- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index b51bb84d..e446582b 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -8,6 +8,7 @@ from sqlalchemy import func from tornado.log import app_log from . import orm +from . import scopes def get_default_roles(): @@ -75,35 +76,30 @@ def expand_self_scope(name): def _get_scope_hierarchy(): """ - Returns a dictionary of scopes: - scopes.keys() = scopes of highest level and scopes that have their own subscopes - scopes.values() = a list of first level subscopes or None + Returns: + scope hierarchy (dict): dictionary of available scopes and their hierarchy where + scopes.keys() = top level scopes and scopes that have their own subscopes + scopes.values() = list of immediate subscopes or None """ + subscope_lists = [ + value['subscopes'] + for value in scopes.scope_definitions.values() + if 'subscopes' in value + ] - scopes = { - 'self': None, - 'all': None, - 'admin:users': ['admin:users:auth_state', 'users'], - 'users': ['read:users', 'users:activity'], - 'read:users': [ - 'read:users:name', - 'read:users:groups', - 'read:users:activity', - ], - 'users:activity': ['read:users:activity'], - 'users:tokens': ['read:users:tokens'], - 'admin:users:servers': ['admin:users:server_state', 'users:servers'], - 'users:servers': ['read:users:servers'], - 'read:users:servers': ['read:users:name'], - 'admin:groups': ['groups'], - 'groups': ['read:groups'], - 'read:services': None, - 'read:hub': None, - 'proxy': None, - 'shutdown': None, - } + scope_hierarchy = {} + for scope in scopes.scope_definitions.keys(): - return scopes + has_subscopes = scopes.scope_definitions[scope].get('subscopes') + is_subscope = any(scope in subscope_list for subscope_list in subscope_lists) + + if has_subscopes: + scope_hierarchy[scope] = scopes.scope_definitions[scope]['subscopes'] + else: + if not is_subscope: + scope_hierarchy[scope] = None + + return scope_hierarchy def horizontal_filter(func): diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 21058416..eaf86273 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -36,13 +36,13 @@ scope_definitions = { 'read:users:name', 'read:users:groups', 'read:users:activity', - 'read:users:roles', ], + # TODO: add read:users:admin and read:users:roles as subscopes here once implemented }, 'read:users:name': {'description': 'Read-only access to users’ names.'}, 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, - 'read:users:roles': {'description': 'Read-only access to users’ role names.'}, 'read:users:activity': {'description': 'Read-only access to users’ last activity.'}, + # TODO: add read:users:admin and read:users:roles once implemented 'users:activity': { 'description': 'Grants access to read and post users’ last activity only.', 'subscopes': ['read:users:activity'], @@ -78,10 +78,12 @@ scope_definitions = { 'read:groups': {'description': 'Read-only access to groups’ models.'}, 'read:services': { 'description': 'Read-only access to service models.', - 'subscopes': ['read:services:name', 'read:services:roles'], + 'subscopes': ['read:services:name'], + # TODO: add read:services:admin and read:services:roles as subscopes here once implemented }, 'read:services:name': {'description': 'Read-only access to service names.'}, - 'read:services:roles': {'description': 'Read-only access to service role names.'}, + # TODO: add read:services:admin and read:services:roles once implemented + #'read:services:roles': {'description': 'Read-only access to service role names.'}, 'read:hub': { 'description': 'Read-only access to detailed information about the Hub.' }, From 290a697df2ab5565e51b2b385c22a8f3f13870b1 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 26 May 2021 16:55:20 +0200 Subject: [PATCH 200/270] Fixed service admin declaration --- jupyterhub/app.py | 65 ++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 5fbc2f36..3cf2c1ae 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1995,23 +1995,34 @@ class JupyterHub(Application): async def init_role_assignment(self): # tokens are added separately role_bearers = ['users', 'services', 'groups'] + admin_role_objects = ['users', 'services'] config_admin_users = set(self.admin_users) | self.authenticator.admin_users db = self.db # load predefined roles from config file - for role_spec in self.load_roles: - if role_spec['name'] == 'admin' and config_admin_users: - app_log.info( - "Extending admin role assignment with config admin users: %s", - str(config_admin_users), - ) - role_spec['users'] = set(role_spec.get('users', [])) - role_spec['users'] |= config_admin_users + if config_admin_users: + for role_spec in self.load_roles: + if role_spec['name'] == 'admin': + app_log.info( + "Extending admin role assignment with config admin users: %s", + str(config_admin_users), + ) + role_spec['users'] = set(role_spec.get('users', [])) + role_spec['users'] |= config_admin_users self.log.debug('Loading predefined roles from config file to database') - has_admin_role_spec = False + has_admin_role_spec = {role_bearer: False for role_bearer in admin_role_objects} for predef_role in self.load_roles: predef_role_obj = orm.Role.find(db, name=predef_role['name']) - if predef_role['name'] == 'admin': - has_admin_role_spec = bool(predef_role.get('users', False)) + for bearer in admin_role_objects: + if predef_role['name'] == 'admin': + has_admin_role_spec[bearer] = bool(predef_role.get(bearer, False)) + if has_admin_role_spec[bearer]: + app_log.debug( + f"Admin {bearer} explicitly specified in config, so previous db state is ignored" + ) + else: + app_log.debug( + f"Admin {bearer} not specified in config, elevate to admin based on previous db state" + ) # add users, services, and/or groups, # tokens need to be checked for permissions for bearer in role_bearers: @@ -2043,21 +2054,13 @@ class JupyterHub(Application): for user in allowed_users: roles.grant_role(db, user, 'user') admin_role = orm.Role.find(db, 'admin') - admin_objs = chain( - db.query(orm.User).filter_by(admin=True), - db.query(orm.Service).filter_by(admin=True), - ) - for admin_obj in admin_objs: - if has_admin_role_spec: - app_log.debug( - "Admin users explicitly specified in config, so previous db state is ignored" - ) - admin_obj.admin = admin_role in admin_obj.roles - else: - app_log.debug( - "Admin users not specified in config, elevate to admin based on previous db state" - ) - roles.grant_role(db, admin_obj, 'admin') + for bearer in admin_role_objects: + Class = orm.get_class(bearer) + for admin_obj in db.query(Class).filter_by(admin=True): + if has_admin_role_spec[bearer]: + admin_obj.admin = admin_role in admin_obj.roles + else: + roles.grant_role(db, admin_obj, 'admin') db.commit() # make sure that on hub upgrade, all roles are reset if not getattr(self, '_rbac_upgrade', False): @@ -2174,9 +2177,13 @@ class JupyterHub(Application): if orm_service is None: # not found, create a new one orm_service = orm.Service(name=name) - if spec.get( - 'admin', False - ): # Todo: fix double assignment of admin roles + if spec.get('admin', False): + self.log.warning( + f"Service {name} sets `admin: True`, which is deprecated in JupyterHub 2.0." + " You can assign now assign roles via `JupyterHub.load_roles` configuration." + " If you specify services in the admin role configuration, " + "the Service admin flag will be ignored." + ) roles.update_roles(self.db, entity=orm_service, roles=['admin']) self.db.add(orm_service) orm_service.admin = spec.get('admin', False) From 587ea28581e63bd3d8e538b473d252785947319b Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 27 May 2021 10:36:23 +0200 Subject: [PATCH 201/270] Added error for duplicate roles --- jupyterhub/app.py | 5 +++++ jupyterhub/tests/test_roles.py | 30 ++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 3cf2c1ae..04de33f3 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1981,6 +1981,11 @@ class JupyterHub(Application): default_roles = roles.get_default_roles() config_role_names = [r['name'] for r in self.load_roles] init_roles = self.load_roles.copy() + for role_name in config_role_names: + if config_role_names.count(role_name) > 1: + raise AttributeError( + f"Role {role_name} multiply defined. Please check the `load_roles` configuration" + ) for role_spec in default_roles: if role_spec['name'] not in config_role_names: init_roles.append(role_spec) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index a3d41830..f2e370f4 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -992,12 +992,6 @@ async def test_config_role_users(): 'scopes': ['users', 'groups'], 'users': user_names, }, - { - 'name': role_name, - 'description': 'painting with colors', - 'scopes': ['users', 'groups'], - 'users': user_names, - }, ] hub = MockHub(load_roles=roles_to_load) hub.init_db() @@ -1020,6 +1014,30 @@ async def test_config_role_users(): assert role not in user.roles +async def test_duplicate_role_users(): + role_name = 'painter' + user_name = 'benny' + user_names = ['agnetha', 'bjorn', 'anni-frid', user_name] + roles_to_load = [ + { + 'name': role_name, + 'description': 'painting with colors', + 'scopes': ['users', 'groups'], + 'users': user_names, + }, + { + 'name': role_name, + 'description': 'painting with colors', + 'scopes': ['users', 'groups'], + 'users': user_names, + }, + ] + hub = MockHub(load_roles=roles_to_load) + hub.init_db() + with pytest.raises(AttributeError): + await hub.init_role_creation() + + async def test_admin_role_and_flag(): admin_role_spec = [ { From 320ad75b123a924a7c9bd15f846aa57152e05335 Mon Sep 17 00:00:00 2001 From: Ivana Date: Thu, 27 May 2021 11:04:46 +0200 Subject: [PATCH 202/270] Update jupyterhub/roles.py Co-authored-by: Min RK --- jupyterhub/roles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index e446582b..b9f36a45 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -88,7 +88,7 @@ def _get_scope_hierarchy(): ] scope_hierarchy = {} - for scope in scopes.scope_definitions.keys(): + for scope, definition in scopes.scope_definitions.items(): has_subscopes = scopes.scope_definitions[scope].get('subscopes') is_subscope = any(scope in subscope_list for subscope_list in subscope_lists) From 05f6892e37b027719c74579380be69a815734806 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Thu, 27 May 2021 18:11:33 +0200 Subject: [PATCH 203/270] Get subscopes directly from scopes.scope_definitions no need for _get_scope_hierarchy() --- jupyterhub/roles.py | 88 +++++++++------------------------- jupyterhub/scopes.py | 8 ++-- jupyterhub/tests/test_roles.py | 10 ++++ 3 files changed, 37 insertions(+), 69 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index b9f36a45..7229790c 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -74,34 +74,6 @@ def expand_self_scope(name): return {"{}!user={}".format(scope, name) for scope in scope_list} -def _get_scope_hierarchy(): - """ - Returns: - scope hierarchy (dict): dictionary of available scopes and their hierarchy where - scopes.keys() = top level scopes and scopes that have their own subscopes - scopes.values() = list of immediate subscopes or None - """ - subscope_lists = [ - value['subscopes'] - for value in scopes.scope_definitions.values() - if 'subscopes' in value - ] - - scope_hierarchy = {} - for scope, definition in scopes.scope_definitions.items(): - - has_subscopes = scopes.scope_definitions[scope].get('subscopes') - is_subscope = any(scope in subscope_list for subscope_list in subscope_lists) - - if has_subscopes: - scope_hierarchy[scope] = scopes.scope_definitions[scope]['subscopes'] - else: - if not is_subscope: - scope_hierarchy[scope] = None - - return scope_hierarchy - - def horizontal_filter(func): """Decorator to account for horizontal filtering in scope syntax""" @@ -129,29 +101,17 @@ def horizontal_filter(func): def _expand_scope(scopename): """Returns a set of all subscopes""" - scopes = _get_scope_hierarchy() - subscopes = [scopename] + expanded_scope = [] - def _expand_subscopes(index): + def _add_subscopes(scopename): + expanded_scope.append(scopename) + if scopes.scope_definitions[scopename].get('subscopes'): + for subscope in scopes.scope_definitions[scopename].get('subscopes'): + _add_subscopes(subscope) - more_subscopes = list( - filter(lambda scope: scope in scopes.keys(), subscopes[index:]) - ) - for scope in more_subscopes: - subscopes.extend(scopes[scope]) + _add_subscopes(scopename) - if scopename in scopes.keys() and scopes[scopename] is not None: - subscopes.extend(scopes[scopename]) - # record the index from where it should check for "subscopes of sub-subscopes" - index_for_sssc = len(subscopes) - # check for "subscopes of subscopes" - _expand_subscopes(index=1) - # check for "subscopes of sub-subscopes" - _expand_subscopes(index=index_for_sssc) - - expanded_scope = set(subscopes) - - return expanded_scope + return set(expanded_scope) def expand_roles_to_scopes(orm_object): @@ -205,29 +165,27 @@ def _get_subscopes(*args, owner=None): return scopes -def _check_scopes(*args): +def _check_scopes(*args, rolename=None): """Check if provided scopes exist""" - allowed_scopes = _get_scope_hierarchy() + allowed_scopes = set(scopes.scope_definitions.keys()) allowed_filters = ['!user=', '!service=', '!group=', '!server=', '!user'] - subscopes = set( - chain.from_iterable([x for x in allowed_scopes.values() if x is not None]) - ) + + if rolename: + log_role = f"for role {rolename}" + else: + log_role = "" for scope in args: - # check the ! filters - if '!' in scope: - if any(filter in scope for filter in allowed_filters): - scope = scope.split('!', 1)[0] - else: + scopename, _, filter_ = scope.partition('!') + if scopename not in allowed_scopes: + raise NameError(f"Scope '{scope}' {log_role} does not exist") + if filter_: + full_filter = f"!{filter_}" + if not any(full_filter in scope for full_filter in allowed_filters): raise NameError( - 'Scope filter %r in scope %r does not exist', - scope.split('!', 1)[1], - scope, + f"Scope filter '{full_filter}' in scope '{scope}' {log_role} does not exist" ) - # check if the actual scope syntax exists - if scope not in allowed_scopes.keys() and scope not in subscopes: - raise NameError('Scope %r does not exist', scope) def _overwrite_role(role, role_dict): @@ -284,7 +242,7 @@ def create_role(db, role_dict): # check if the provided scopes exist if scopes: - _check_scopes(*scopes) + _check_scopes(*scopes, rolename=role_dict['name']) if role is None: if not scopes: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index eaf86273..80679107 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -37,12 +37,12 @@ scope_definitions = { 'read:users:groups', 'read:users:activity', ], - # TODO: add read:users:admin and read:users:roles as subscopes here once implemented + # TODO: add read:users:roles as subscopes here once implemented }, 'read:users:name': {'description': 'Read-only access to users’ names.'}, 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, 'read:users:activity': {'description': 'Read-only access to users’ last activity.'}, - # TODO: add read:users:admin and read:users:roles once implemented + # TODO: add read:users:roles once implemented 'users:activity': { 'description': 'Grants access to read and post users’ last activity only.', 'subscopes': ['read:users:activity'], @@ -79,10 +79,10 @@ scope_definitions = { 'read:services': { 'description': 'Read-only access to service models.', 'subscopes': ['read:services:name'], - # TODO: add read:services:admin and read:services:roles as subscopes here once implemented + # TODO: add read:services:roles as subscopes here once implemented }, 'read:services:name': {'description': 'Read-only access to service names.'}, - # TODO: add read:services:admin and read:services:roles once implemented + # TODO: add read:services:roles once implemented #'read:services:roles': {'description': 'Read-only access to service role names.'}, 'read:hub': { 'description': 'Read-only access to detailed information about the Hub.' diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 9ea326ea..949d3e28 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -212,6 +212,16 @@ def test_orm_roles_delete_cascade(db): ), (['read:users:servers'], {'read:users:servers', 'read:users:name'}), (['admin:groups'], {'admin:groups', 'groups', 'read:groups'}), + ( + ['admin:groups', 'read:users:servers'], + { + 'admin:groups', + 'groups', + 'read:groups', + 'read:users:servers', + 'read:users:name', + }, + ), ( ['users:tokens!group=hobbits'], {'users:tokens!group=hobbits', 'read:users:tokens!group=hobbits'}, From 03f968fea027b1f4c4f785de865cc8d9eee2d604 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 1 Jun 2021 12:41:29 +0200 Subject: [PATCH 204/270] wip: fixing errors and suggestions --- jupyterhub/app.py | 62 ++++++++++++++++++------------- jupyterhub/roles.py | 12 ++++-- jupyterhub/tests/test_roles.py | 18 +++++++-- jupyterhub/tests/test_services.py | 2 +- 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 04de33f3..d536a85b 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1980,19 +1980,21 @@ class JupyterHub(Application): self.log.debug('Loading default roles to database') default_roles = roles.get_default_roles() config_role_names = [r['name'] for r in self.load_roles] - init_roles = self.load_roles.copy() + init_roles = default_roles for role_name in config_role_names: if config_role_names.count(role_name) > 1: - raise AttributeError( + raise ValueError( f"Role {role_name} multiply defined. Please check the `load_roles` configuration" ) - for role_spec in default_roles: - if role_spec['name'] not in config_role_names: - init_roles.append(role_spec) + for role_spec in self.load_roles: + init_roles.append(role_spec) if not orm.Role.find(self.db, name='admin'): self._rbac_upgrade = True - self.db.query(orm.Role).delete() - app_log.info("Deleting all roles in database") + for role in self.db.query(orm.Role).filter( + orm.Role.name.in_(config_role_names) + ): + app_log.info(f"Deleting role {role.name}") + role.delete() self.db.commit() for role in init_roles: roles.create_role(self.db, role) @@ -2001,15 +2003,18 @@ class JupyterHub(Application): # tokens are added separately role_bearers = ['users', 'services', 'groups'] admin_role_objects = ['users', 'services'] - config_admin_users = set(self.admin_users) | self.authenticator.admin_users + config_admin_users = set(self.authenticator.admin_users) db = self.db # load predefined roles from config file if config_admin_users: for role_spec in self.load_roles: if role_spec['name'] == 'admin': + app_log.warning( + "Configuration specifies both admin_users and users in the admin role specification" + "If admin role is present in config, it should contain all admin users." + ) app_log.info( - "Extending admin role assignment with config admin users: %s", - str(config_admin_users), + "Merging admin_users set with users list in admin role" ) role_spec['users'] = set(role_spec.get('users', [])) role_spec['users'] |= config_admin_users @@ -2017,16 +2022,14 @@ class JupyterHub(Application): has_admin_role_spec = {role_bearer: False for role_bearer in admin_role_objects} for predef_role in self.load_roles: predef_role_obj = orm.Role.find(db, name=predef_role['name']) - for bearer in admin_role_objects: - if predef_role['name'] == 'admin': - has_admin_role_spec[bearer] = bool(predef_role.get(bearer, False)) + if predef_role['name'] == 'admin': + for bearer in admin_role_objects: + has_admin_role_spec[bearer] = bearer in predef_role if has_admin_role_spec[bearer]: - app_log.debug( - f"Admin {bearer} explicitly specified in config, so previous db state is ignored" - ) + app_log.info(f"Admin role specifies static {bearer} list") else: - app_log.debug( - f"Admin {bearer} not specified in config, elevate to admin based on previous db state" + app_log.info( + f"Admin role does not specify {bearer}, preserving admin membership in database" ) # add users, services, and/or groups, # tokens need to be checked for permissions @@ -2045,14 +2048,21 @@ class JupyterHub(Application): "Username %r is not in Authenticator.allowed_users" % bname ) - Class = orm.get_class(bearer) - orm_obj = Class.find(db, bname) + Class = orm.get_class(bearer) + orm_obj = Class.find(db, bname) + if orm_obj: orm_role_bearers.append(orm_obj) - # Ensure all with admin role have admin flag - if predef_role['name'] == 'admin': - orm_obj.admin = True - setattr(predef_role_obj, bearer, orm_role_bearers) - db.commit() + else: + app_log.warning( + f"User {bname} not added, only found in role definition" + ) + # Todo: Add users to allowed_users + # Ensure all with admin role have admin flag + if predef_role['name'] == 'admin': + orm_obj.admin = True + setattr(predef_role_obj, bearer, orm_role_bearers) + + db.commit() allowed_users = db.query(orm.User).filter( orm.User.name.in_(self.authenticator.allowed_users) ) @@ -2068,7 +2078,7 @@ class JupyterHub(Application): roles.grant_role(db, admin_obj, 'admin') db.commit() # make sure that on hub upgrade, all roles are reset - if not getattr(self, '_rbac_upgrade', False): + if getattr(self, '_rbac_upgrade', False): app_log.warning( "No admin role found; assuming hub upgrade. Initializing default roles for all entities" ) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 1f9ad65c..fad31c6f 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -239,10 +239,14 @@ def _overwrite_role(role, role_dict): for attr in role_dict.keys(): if attr == 'description' or attr == 'scopes': - if role.name == 'admin' and role_dict[attr] != getattr(role, attr): - raise ValueError( - 'admin role description or scopes cannot be overwritten' - ) + if role.name == 'admin': + admin_role_spec = [ + r for r in get_default_roles() if r['name'] == 'admin' + ][0] + if role_dict[attr] != admin_role_spec[attr]: + raise ValueError( + 'admin role description or scopes cannot be overwritten' + ) else: if role_dict[attr] != getattr(role, attr): setattr(role, attr, role_dict[attr]) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index f2e370f4..0eeb6a1c 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -497,12 +497,12 @@ async def test_load_roles_services(tmpdir, request): hub = MockHub(**kwargs) hub.init_db() db = hub.db + await hub.init_role_creation() await hub.init_api_tokens() # make 'admin_service' admin admin_service = orm.Service.find(db, 'admin_service') admin_service.admin = True db.commit() - await hub.init_role_creation() await hub.init_role_assignment() # test if every service has a role (and no duplicates) admin_role = orm.Role.find(db, name='admin') @@ -1034,7 +1034,7 @@ async def test_duplicate_role_users(): ] hub = MockHub(load_roles=roles_to_load) hub.init_db() - with pytest.raises(AttributeError): + with pytest.raises(ValueError): await hub.init_role_creation() @@ -1116,6 +1116,14 @@ async def test_removal_config_to_db(): assert not orm.Role.find(hub.db, 'wizard') +async def test_no_admin_role_change(): + role_spec = [{'name': 'admin', 'scopes': ['shutdown']}] + hub = MockHub(load_roles=role_spec) + hub.init_db() + with pytest.raises(ValueError): + await hub.init_role_creation() + + async def test_user_config_respects_memberships(): role_spec = [ { @@ -1140,7 +1148,6 @@ async def test_admin_role_respects_config(): role_spec = [ { 'name': 'admin', - 'scopes': ['self', 'shutdown'], } ] admin_users = ['eddy', 'carol'] @@ -1154,3 +1161,8 @@ async def test_admin_role_respects_config(): for user_name in admin_users: user = orm.User.find(hub.db, user_name) assert user in admin_role.users + + +# todo: add test for empty user list and for no user list present +# Todo: Add test for rbac_upgrade behaviour flag +# Todo: test token roles are not reassigned if they are deleted diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 266f4a07..fd922273 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -92,7 +92,7 @@ async def test_external_service(app): await maybe_future(app.init_role_creation()) await app.init_api_tokens() await app.proxy.add_all_services(app._service_map) - await app.init_role_creation() + await app.init_role_assignment() service = app._service_map[name] api_token = service.orm.api_tokens[0] From 2bf8e57e2c8617d7f434a68de96937032d40301c Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 1 Jun 2021 13:27:49 +0200 Subject: [PATCH 205/270] Fixed whitespace bug --- jupyterhub/app.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index d536a85b..dd07b2c8 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1991,10 +1991,10 @@ class JupyterHub(Application): if not orm.Role.find(self.db, name='admin'): self._rbac_upgrade = True for role in self.db.query(orm.Role).filter( - orm.Role.name.in_(config_role_names) + orm.Role.name.notin_(config_role_names) ): app_log.info(f"Deleting role {role.name}") - role.delete() + self.db.delete(role) self.db.commit() for role in init_roles: roles.create_role(self.db, role) @@ -2010,7 +2010,7 @@ class JupyterHub(Application): for role_spec in self.load_roles: if role_spec['name'] == 'admin': app_log.warning( - "Configuration specifies both admin_users and users in the admin role specification" + "Configuration specifies both admin_users and users in the admin role specification. " "If admin role is present in config, it should contain all admin users." ) app_log.info( @@ -2048,20 +2048,19 @@ class JupyterHub(Application): "Username %r is not in Authenticator.allowed_users" % bname ) - Class = orm.get_class(bearer) - orm_obj = Class.find(db, bname) - if orm_obj: - orm_role_bearers.append(orm_obj) - else: - app_log.warning( - f"User {bname} not added, only found in role definition" - ) - # Todo: Add users to allowed_users - # Ensure all with admin role have admin flag - if predef_role['name'] == 'admin': - orm_obj.admin = True - setattr(predef_role_obj, bearer, orm_role_bearers) - + Class = orm.get_class(bearer) + orm_obj = Class.find(db, bname) + if orm_obj: + orm_role_bearers.append(orm_obj) + else: + app_log.warning( + f"User {bname} not added, only found in role definition" + ) + # Todo: Add users to allowed_users + # Ensure all with admin role have admin flag + if predef_role['name'] == 'admin': + orm_obj.admin = True + setattr(predef_role_obj, bearer, orm_role_bearers) db.commit() allowed_users = db.query(orm.User).filter( orm.User.name.in_(self.authenticator.allowed_users) From 246ce6797cd9db4aee669222ea45e53601815ec0 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 1 Jun 2021 15:35:04 +0200 Subject: [PATCH 206/270] Fixed some bugs and implemented suggestions, save one weird test case --- jupyterhub/app.py | 10 +++-- jupyterhub/tests/test_roles.py | 77 ++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index dd07b2c8..ad591b57 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1980,6 +1980,7 @@ class JupyterHub(Application): self.log.debug('Loading default roles to database') default_roles = roles.get_default_roles() config_role_names = [r['name'] for r in self.load_roles] + init_roles = default_roles for role_name in config_role_names: if config_role_names.count(role_name) > 1: @@ -1988,10 +1989,11 @@ class JupyterHub(Application): ) for role_spec in self.load_roles: init_roles.append(role_spec) + init_role_names = [r['name'] for r in init_roles] if not orm.Role.find(self.db, name='admin'): self._rbac_upgrade = True for role in self.db.query(orm.Role).filter( - orm.Role.name.notin_(config_role_names) + orm.Role.name.notin_(init_role_names) ): app_log.info(f"Deleting role {role.name}") self.db.delete(role) @@ -2011,7 +2013,7 @@ class JupyterHub(Application): if role_spec['name'] == 'admin': app_log.warning( "Configuration specifies both admin_users and users in the admin role specification. " - "If admin role is present in config, it should contain all admin users." + "If admin role is present in config, c.authenticator.admin_users should not be used." ) app_log.info( "Merging admin_users set with users list in admin role" @@ -2076,17 +2078,17 @@ class JupyterHub(Application): else: roles.grant_role(db, admin_obj, 'admin') db.commit() - # make sure that on hub upgrade, all roles are reset + # make sure that on hub upgrade, all users, services and tokens have at least one role (update with default) if getattr(self, '_rbac_upgrade', False): app_log.warning( "No admin role found; assuming hub upgrade. Initializing default roles for all entities" ) - # make sure all users, services and tokens have at least one role (update with default) for bearer in role_bearers: roles.check_for_default_roles(db, bearer) # check tokens for default roles roles.check_for_default_roles(db, bearer='tokens') + self._rbac_upgrade = False async def _add_tokens(self, token_dict, kind): """Add tokens for users or services to the database""" diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 07c4ef33..56b3d12d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1173,6 +1173,77 @@ async def test_admin_role_respects_config(): assert user in admin_role.users -# todo: add test for empty user list and for no user list present -# Todo: Add test for rbac_upgrade behaviour flag -# Todo: test token roles are not reassigned if they are deleted +async def test_empty_admin_spec(): + role_spec = [{'name': 'admin', 'users': []}] + hub = MockHub(load_roles=role_spec) + hub.init_db() + hub.authenticator.admin_users = [] + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + admin_role = orm.Role.find(hub.db, 'admin') + assert not admin_role.users + + +async def test_hub_upgrade_detection(): + role_spec = [{'name': 'admin', 'users': []}] + service = {'name': 'sheep_counter', 'api_token': 'some-token'} + hub = MockHub(load_roles=role_spec) + hub.init_db() + await hub.init_role_creation() + await hub.init_users() + await hub.init_api_tokens() + + assert hub._rbac_upgrade + await hub.init_role_assignment() + orm_service = orm.Service.find(hub.db, 'sheep_counter') + user_role = orm.Role.find(hub.db, 'user') + assert user_role in orm_service.roles + # Restart hub, now we are no longer in upgrade mode + hub = MockHub(load_roles=role_spec, services=[service]) + hub.test_clean_db = False + hub.init_db() + await hub.init_role_creation() + assert not getattr(hub, '_rbac_upgrade', False) + hub.db.delete(orm_service) + hub.db.commit() + + +async def test_token_keep_roles_on_restart(): + role_spec = [ + { + 'name': 'bloop', + 'scopes': ['read:users'], + } + ] + + hub = MockHub(load_roles=role_spec) + hub.init_db() + hub.authenticator.admin_users = ['ben'] + await hub.init_role_creation() + await hub.init_users() + await hub.init_role_assignment() + user = orm.User.find(hub.db, name='ben') + for _ in range(3): + user.new_api_token() + happy_token, content_token, sad_token = user.api_tokens + roles.grant_role(hub.db, happy_token, 'bloop') + roles.strip_role(hub.db, sad_token, 'token') + assert len(happy_token.roles) == 2 + assert len(content_token.roles) == 1 + assert len(sad_token.roles) == 0 + # Restart hub and see if roles are as expected + hub.load_roles = [] + await hub.init_role_creation() + await hub.init_users() + await hub.init_api_tokens() + await hub.init_role_assignment() + user = orm.User.find(hub.db, name='ben') + happy_token, content_token, sad_token = user.api_tokens + assert len(happy_token.roles) == 1 + assert len(content_token.roles) == 1 + print(sad_token.roles) + assert len(sad_token.roles) == 0 + for token in user.api_tokens: + hub.db.delete(token) + hub.db.commit() From 8f2bbd4d1184bbd95cb7792987bf984a784a6465 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 1 Jun 2021 23:42:50 +0200 Subject: [PATCH 207/270] Test still fails, issue with emulating hub restart --- jupyterhub/tests/test_roles.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 56b3d12d..5b9d166f 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1188,23 +1188,20 @@ async def test_empty_admin_spec(): async def test_hub_upgrade_detection(): role_spec = [{'name': 'admin', 'users': []}] service = {'name': 'sheep_counter', 'api_token': 'some-token'} - hub = MockHub(load_roles=role_spec) - hub.init_db() - await hub.init_role_creation() - await hub.init_users() - await hub.init_api_tokens() - - assert hub._rbac_upgrade - await hub.init_role_assignment() + hub = MockHub(load_roles=role_spec, services=[service]) + await hub.initialize() orm_service = orm.Service.find(hub.db, 'sheep_counter') user_role = orm.Role.find(hub.db, 'user') assert user_role in orm_service.roles + orm_service.roles = [] + hub.db.commit() # Restart hub, now we are no longer in upgrade mode - hub = MockHub(load_roles=role_spec, services=[service]) - hub.test_clean_db = False - hub.init_db() - await hub.init_role_creation() + hub = MockHub(load_roles=role_spec, services=[service], db=hub.db) + await hub.initialize() + # Fixme: How to respect db state? assert not getattr(hub, '_rbac_upgrade', False) + orm_service = orm.Service.find(hub.db, 'sheep_counter') + assert not orm_service.roles hub.db.delete(orm_service) hub.db.commit() From d6bb1e631879e980454dbfc9e5b8d3a28f88a98b Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 3 Jun 2021 13:26:06 +0200 Subject: [PATCH 208/270] Fixed upgrade test --- jupyterhub/app.py | 3 +- jupyterhub/tests/test_roles.py | 60 ++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index ad591b57..d10d0065 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1992,6 +1992,8 @@ class JupyterHub(Application): init_role_names = [r['name'] for r in init_roles] if not orm.Role.find(self.db, name='admin'): self._rbac_upgrade = True + else: + self._rbac_upgrade = False for role in self.db.query(orm.Role).filter( orm.Role.name.notin_(init_role_names) ): @@ -2088,7 +2090,6 @@ class JupyterHub(Application): # check tokens for default roles roles.check_for_default_roles(db, bearer='tokens') - self._rbac_upgrade = False async def _add_tokens(self, token_dict, kind): """Add tokens for users or services to the database""" diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 5b9d166f..07efdc4b 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -2,11 +2,13 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import json +import os from itertools import chain import pytest from pytest import mark from tornado.log import app_log +from traitlets.config import Config from .. import orm from .. import roles @@ -1185,26 +1187,56 @@ async def test_empty_admin_spec(): assert not admin_role.users -async def test_hub_upgrade_detection(): - role_spec = [{'name': 'admin', 'users': []}] - service = {'name': 'sheep_counter', 'api_token': 'some-token'} - hub = MockHub(load_roles=role_spec, services=[service]) +# Todo: Test that services don't get default roles on any startup + + +async def test_hub_upgrade_detection(tmpdir): + db_url = f"sqlite:///{tmpdir.join('jupyterhub.sqlite')}" + os.environ['JUPYTERHUB_TEST_DB_URL'] = db_url + # Create hub with users and tokens + hub = MockHub(db_url=db_url) await hub.initialize() - orm_service = orm.Service.find(hub.db, 'sheep_counter') + user_names = ['patricia', 'quentin'] user_role = orm.Role.find(hub.db, 'user') - assert user_role in orm_service.roles - orm_service.roles = [] + for name in user_names: + user = add_user(hub.db, name=name) + user.new_api_token() + assert user_role in user.roles + for role in hub.db.query(orm.Role): + hub.db.delete(role) hub.db.commit() - # Restart hub, now we are no longer in upgrade mode - hub = MockHub(load_roles=role_spec, services=[service], db=hub.db) + # Restart hub in emulated upgrade mode: default roles for all entities + hub.test_clean_db = False await hub.initialize() - # Fixme: How to respect db state? - assert not getattr(hub, '_rbac_upgrade', False) - orm_service = orm.Service.find(hub.db, 'sheep_counter') - assert not orm_service.roles - hub.db.delete(orm_service) + assert getattr(hub, '_rbac_upgrade', False) + user_role = orm.Role.find(hub.db, 'user') + token_role = orm.Role.find(hub.db, 'token') + for name in user_names: + user = orm.User.find(hub.db, name) + assert user_role in user.roles + assert token_role in user.api_tokens[0].roles + # Strip all roles and see if it sticks + user_role.users = [] + token_role.tokens = [] hub.db.commit() + hub.init_db() + hub.init_hub() + await hub.init_role_creation() + await hub.init_users() + hub.authenticator.allowed_users = ['patricia'] + await hub.init_api_tokens() + await hub.init_role_assignment() + assert not getattr(hub, '_rbac_upgrade', False) + user_role = orm.Role.find(hub.db, 'user') + token_role = orm.Role.find(hub.db, 'token') + allowed_user = orm.User.find(hub.db, 'patricia') + rem_user = orm.User.find(hub.db, 'quentin') + assert user_role in allowed_user.roles + assert token_role not in allowed_user.api_tokens[0].roles + assert user_role not in rem_user.roles + assert token_role not in rem_user.roles + async def test_token_keep_roles_on_restart(): role_spec = [ From 2ab6c61e9aebecbcdb9f62114657e38fbde66ca8 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 25 May 2021 09:50:01 +0200 Subject: [PATCH 209/270] Synchronize scope variable nomenclature and docstrings across rbac utils --- jupyterhub/roles.py | 106 +++++++++++++++++++++++++++++-------------- jupyterhub/scopes.py | 58 +++++++++++++++-------- 2 files changed, 113 insertions(+), 51 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 316448e9..781fd65c 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -12,8 +12,14 @@ from . import scopes def get_default_roles(): - """Returns a list of default role dictionaries""" - + """Returns: + default roles (list): default role definitions as dictionaries: + { + 'name': role name, + 'description': role description, + 'scopes': list of scopes, + } + """ default_roles = [ { 'name': 'user', @@ -37,9 +43,7 @@ def get_default_roles(): { 'name': 'server', 'description': 'Post activity only', - 'scopes': [ - 'users:activity!user' - ], # TO DO - fix scope to refer to only self once implemented + 'scopes': ['users:activity!user'], }, { 'name': 'token', @@ -60,6 +64,12 @@ def expand_self_scope(name): users:activity users:servers users:tokens + + Arguments: + name (str): user name + + Returns: + expanded scopes (set): set of expanded scopes covering standard user privileges """ scope_list = [ 'users', @@ -99,8 +109,13 @@ def horizontal_filter(func): @horizontal_filter def _expand_scope(scopename): - """Returns a set of all subscopes""" + """Returns a set of all subscopes + Arguments: + scopename (str): name of the scope to expand + Returns: + expanded scope (set): set of all scope's subscopes including the scope itself + """ expanded_scope = [] def _add_subscopes(scopename): @@ -116,7 +131,14 @@ def _expand_scope(scopename): def expand_roles_to_scopes(orm_object): """Get the scopes listed in the roles of the User/Service/Group/Token - If User, take into account the user's groups roles as well""" + If User, take into account the user's groups roles as well + + Arguments: + orm_object: orm.User, orm.Service, orm.Group or orm.APIToken + + Returns: + expanded scopes (set): set of all expanded scopes for the orm object + """ if not isinstance(orm_object, orm.Base): raise TypeError(f"Only orm objects allowed, got {orm_object}") @@ -127,26 +149,35 @@ def expand_roles_to_scopes(orm_object): for group in orm_object.groups: pass_roles.extend(group.roles) - scopes = _get_subscopes(*pass_roles, owner=orm_object) + expanded_scopes = _get_subscopes(*pass_roles, owner=orm_object) - return scopes + return expanded_scopes def _get_subscopes(*args, owner=None): - """Returns a set of all available subscopes for a specified role or list of roles""" + """Returns a set of all available subscopes for a specified role or list of roles + Arguments: + role (obj): orm.Role + or + roles (list): list of orm.Roles + owner (obj, optional): orm.User or orm.Service as owner of orm.APIToken + + Returns: + expanded scopes (set): set of all expanded scopes for the role(s) + """ scope_list = [] for role in args: scope_list.extend(role.scopes) - scopes = set(chain.from_iterable(list(map(_expand_scope, scope_list)))) + expanded_scopes = set(chain.from_iterable(list(map(_expand_scope, scope_list)))) # transform !user filter to !user=ownername - for scope in scopes: + for scope in expanded_scopes: base_scope, _, filter = scope.partition('!') if filter == 'user': - scopes.remove(scope) + expanded_scopes.remove(scope) if isinstance(owner, orm.APIToken): token_owner = owner.user if token_owner is None: @@ -155,18 +186,26 @@ def _get_subscopes(*args, owner=None): else: name = owner.name trans_scope = f'{base_scope}!user={name}' - scopes.add(trans_scope) + expanded_scopes.add(trans_scope) - if 'self' in scopes: - scopes.remove('self') + if 'self' in expanded_scopes: + expanded_scopes.remove('self') if owner and isinstance(owner, orm.User): - scopes |= expand_self_scope(owner.name) + expanded_scopes |= expand_self_scope(owner.name) - return scopes + return expanded_scopes def _check_scopes(*args, rolename=None): - """Check if provided scopes exist""" + """Check if provided scopes exist + + Arguments: + scope (str): name of the scope to check + or + scopes (list): list of scopes to check + + Raises NameError if scope does not exist + """ allowed_scopes = set(scopes.scope_definitions.keys()) allowed_filters = ['!user=', '!service=', '!group=', '!server=', '!user'] @@ -190,7 +229,6 @@ def _check_scopes(*args, rolename=None): def _overwrite_role(role, role_dict): """Overwrites role's description and/or scopes with role_dict if role not 'admin'""" - for attr in role_dict.keys(): if attr == 'description' or attr == 'scopes': if role.name == 'admin': @@ -231,7 +269,6 @@ def _validate_role_name(name): def create_role(db, role_dict): """Adds a new role to database or modifies an existing one""" - default_roles = get_default_roles() if 'name' not in role_dict.keys(): @@ -264,7 +301,6 @@ def create_role(db, role_dict): def delete_role(db, rolename): """Removes a role from database""" - # default roles are not removable default_roles = get_default_roles() if any(role['name'] == rolename for role in default_roles): @@ -298,7 +334,7 @@ def existing_only(func): @existing_only def grant_role(db, entity, rolename): - """Adds a role for users, services or tokens""" + """Adds a role for users, services, groups or tokens""" if isinstance(entity, orm.APIToken): entity_repr = entity else: @@ -317,7 +353,7 @@ def grant_role(db, entity, rolename): @existing_only def strip_role(db, entity, rolename): - """Removes a role for users, services or tokens""" + """Removes a role for users, services, groups or tokens""" if isinstance(entity, orm.APIToken): entity_repr = entity else: @@ -352,10 +388,12 @@ def _switch_default_role(db, obj, admin): def _token_allowed_role(db, token, role): + """Checks if requested role for token does not grant the token + higher permissions than the token's owner has - """Returns True if token allowed to have requested role through - comparing the requested scopes with the set of token's owner scopes""" - + Returns: + True if requested permissions are within the owner's permissions, False otherwise + """ owner = token.user if owner is None: owner = token.service @@ -389,9 +427,10 @@ def _token_allowed_role(db, token, role): def assign_default_roles(db, entity): - """Assigns the default roles to an entity: + """Assigns default role to an entity: users and services get 'user' role, or admin role if they have admin flag - Tokens get 'token' role""" + tokens get 'token' role + """ if isinstance(entity, orm.Group): pass elif isinstance(entity, orm.APIToken): @@ -408,7 +447,9 @@ def assign_default_roles(db, entity): def update_roles(db, entity, roles): - """Updates object's roles""" + """Updates object's roles checking for requested permissions + if object is orm.APIToken + """ standard_permissions = {'all', 'read:all'} for rolename in roles: if isinstance(entity, orm.APIToken): @@ -432,10 +473,9 @@ def update_roles(db, entity, roles): def check_for_default_roles(db, bearer): - """Checks that role bearers have at least one role (default if none). - Groups can be without a role""" - + Groups can be without a role + """ Class = orm.get_class(bearer) if Class == orm.Group: pass diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 80679107..47b6ff29 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -1,4 +1,14 @@ -"""General scope definitions and utilities""" +""" +General scope definitions and utilities + +Scope variable nomenclature +--------------------------- +scopes: list of scopes with abbreviations (e.g., in role definition) +expanded scopes: set of expanded scopes without abbreviations (i.e., resolved metascopes, filters and subscopes) +parsed scopes: dictionary JSON like format of expanded scopes +intersection : set of expanded scopes as intersection of 2 expanded scope sets +identify scopes: set of expanded scopes needed for identify (whoami) endpoints +""" import functools import inspect import warnings @@ -99,11 +109,13 @@ class Scope(Enum): def _intersect_scopes(scopes_a, scopes_b): - """Intersect two sets of scopes + """Intersect two sets of expanded scopes by comparing their permissions - Compares the permissions of two sets of scopes, - including horizontal filters, - and returns the intersected scopes. + Arguments: + scopes_a, scopes_b: sets of expanded scopes + + Returns: + intersection: set of expanded scopes as intersection of the arguments Note: Intersects correctly with ALL and exact filter matches (i.e. users!user=x & read:users:name -> read:users:name!user=x) @@ -180,10 +192,19 @@ def _intersect_scopes(scopes_a, scopes_b): def get_scopes_for(orm_object): - """Find scopes for a given user or token and resolve permissions""" - scopes = set() + """Find scopes for a given user or token and resolve permissions + + Arguments: + orm_object: orm object or User wrapper + + Returns: + expanded scopes (set) for the orm object + or + intersection (set) if orm_object == orm.APIToken + """ + expanded_scopes = set() if orm_object is None: - return scopes + return expanded_scopes if not isinstance(orm_object, orm.Base): from .user import User @@ -204,8 +225,8 @@ def get_scopes_for(orm_object): token_scopes.remove('all') token_scopes |= owner_scopes - scopes = _intersect_scopes(token_scopes, owner_scopes) - discarded_token_scopes = token_scopes - scopes + intersection = _intersect_scopes(token_scopes, owner_scopes) + discarded_token_scopes = token_scopes - intersection # Not taking symmetric difference here because token owner can naturally have more scopes than token if discarded_token_scopes: @@ -213,9 +234,10 @@ def get_scopes_for(orm_object): "discarding scopes [%s], not present in owner roles" % ", ".join(discarded_token_scopes) ) + expanded_scopes = intersection else: - scopes = roles.expand_roles_to_scopes(orm_object) - return scopes + expanded_scopes = roles.expand_roles_to_scopes(orm_object) + return expanded_scopes def _needs_scope_expansion(filter_, filter_value, sub_scope): @@ -319,16 +341,16 @@ def parse_scopes(scope_list): def unparse_scopes(parsed_scopes): - """Turn a parsed_scopes dictionary back into a scopes set""" - scopes = set() + """Turn a parsed_scopes dictionary back into a expanded scopes set""" + expanded_scopes = set() for base, filters in parsed_scopes.items(): if filters == Scope.ALL: - scopes.add(base) + expanded_scopes.add(base) else: for entity, names_list in filters.items(): for name in names_list: - scopes.add(f'{base}!{entity}={name}') - return scopes + expanded_scopes.add(f'{base}!{entity}={name}') + return expanded_scopes def needs_scope(*scopes): @@ -384,7 +406,7 @@ def identify_scopes(obj): obj: orm.User or orm.Service Returns: - scopes (set): set of scopes needed for 'identify' endpoints + identify scopes (set): set of scopes needed for 'identify' endpoints """ if isinstance(obj, orm.User): return { From e6845a68f5bbd9978146afe3a2840f9e63426513 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 26 May 2021 12:04:21 +0200 Subject: [PATCH 210/270] Clarify some function names in rbac utils --- jupyterhub/apihandlers/users.py | 2 +- jupyterhub/handlers/base.py | 4 ++-- jupyterhub/scopes.py | 10 +++++----- jupyterhub/tests/test_scopes.py | 28 +++++++++++++++------------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index a0dfbe2f..210a1f70 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -336,7 +336,7 @@ class UserTokenListAPIHandler(APIHandler): # couldn't identify requester raise web.HTTPError(403) self._jupyterhub_user = requester - self._resolve_scopes() + self._resolve_roles_and_scopes() user = self.find_user(user_name) kind = 'user' if isinstance(requester, User) else 'service' scope_filter = self.get_scope_filter('users:tokens') diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 3c49577c..59c2ae57 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -87,7 +87,7 @@ class BaseHandler(RequestHandler): except Exception: self.log.exception("Failed to get current user") self._jupyterhub_user = None - self._resolve_scopes() + self._resolve_roles_and_scopes() return await maybe_future(super().prepare()) @property @@ -416,7 +416,7 @@ class BaseHandler(RequestHandler): self.log.exception("Error getting current user") return self._jupyterhub_user - def _resolve_scopes(self): + def _resolve_roles_and_scopes(self): self.raw_scopes = set() app_log.debug("Loading and parsing scopes") if self.current_user: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 47b6ff29..370b601f 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -108,7 +108,7 @@ class Scope(Enum): ALL = True -def _intersect_scopes(scopes_a, scopes_b): +def _intersect_expanded_scopes(scopes_a, scopes_b): """Intersect two sets of expanded scopes by comparing their permissions Arguments: @@ -192,7 +192,7 @@ def _intersect_scopes(scopes_a, scopes_b): def get_scopes_for(orm_object): - """Find scopes for a given user or token and resolve permissions + """Find scopes for a given user or token from their roles and resolve permissions Arguments: orm_object: orm object or User wrapper @@ -225,7 +225,7 @@ def get_scopes_for(orm_object): token_scopes.remove('all') token_scopes |= owner_scopes - intersection = _intersect_scopes(token_scopes, owner_scopes) + intersection = _intersect_expanded_scopes(token_scopes, owner_scopes) discarded_token_scopes = token_scopes - intersection # Not taking symmetric difference here because token owner can naturally have more scopes than token @@ -263,7 +263,7 @@ def _check_user_in_expanded_scope(handler, user_name, scope_group_names): return bool(set(scope_group_names) & group_names) -def _check_scope(api_handler, req_scope, **kwargs): +def _check_scope_access(api_handler, req_scope, **kwargs): """Check if scopes satisfy requirements Returns True for (potentially restricted) access, False for refused access """ @@ -375,7 +375,7 @@ def needs_scope(*scopes): s_kwargs[resource] = resource_value for scope in scopes: app_log.debug("Checking access via scope %s", scope) - has_access = _check_scope(self, scope, **s_kwargs) + has_access = _check_scope_access(self, scope, **s_kwargs) if has_access: return func(self, *args, **kwargs) try: diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 1d501a17..69f5e38c 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -9,8 +9,8 @@ from tornado.httputil import HTTPServerRequest from .. import orm from .. import roles from ..handlers import BaseHandler -from ..scopes import _check_scope -from ..scopes import _intersect_scopes +from ..scopes import _check_scope_access +from ..scopes import _intersect_expanded_scopes from ..scopes import get_scopes_for from ..scopes import needs_scope from ..scopes import parse_scopes @@ -49,37 +49,39 @@ def test_scope_precendence(): def test_scope_check_present(): handler = get_handler_with_scopes(['read:users']) - assert _check_scope(handler, 'read:users') - assert _check_scope(handler, 'read:users', user='maeby') + assert _check_scope_access(handler, 'read:users') + assert _check_scope_access(handler, 'read:users', user='maeby') def test_scope_check_not_present(): handler = get_handler_with_scopes(['read:users!user=maeby']) - assert _check_scope(handler, 'read:users') + assert _check_scope_access(handler, 'read:users') with pytest.raises(web.HTTPError): - _check_scope(handler, 'read:users', user='gob') + _check_scope_access(handler, 'read:users', user='gob') with pytest.raises(web.HTTPError): - _check_scope(handler, 'read:users', user='gob', server='server') + _check_scope_access(handler, 'read:users', user='gob', server='server') def test_scope_filters(): handler = get_handler_with_scopes( ['read:users', 'read:users!group=bluths', 'read:users!user=maeby'] ) - assert _check_scope(handler, 'read:users', group='bluth') - assert _check_scope(handler, 'read:users', user='maeby') + assert _check_scope_access(handler, 'read:users', group='bluth') + assert _check_scope_access(handler, 'read:users', user='maeby') def test_scope_multiple_filters(): handler = get_handler_with_scopes(['read:users!user=george_michael']) - assert _check_scope(handler, 'read:users', user='george_michael', group='bluths') + assert _check_scope_access( + handler, 'read:users', user='george_michael', group='bluths' + ) def test_scope_parse_server_name(): handler = get_handler_with_scopes( ['users:servers!server=maeby/server1', 'read:users!user=maeby'] ) - assert _check_scope(handler, 'users:servers', user='maeby', server='server1') + assert _check_scope_access(handler, 'users:servers', user='maeby', server='server1') class MockAPIHandler: @@ -828,10 +830,10 @@ async def test_resolve_token_permissions( ), ], ) -def test_intersect_scopes(left, right, expected, should_warn, recwarn): +def test_intersect_expanded_scopes(left, right, expected, should_warn, recwarn): # run every test in both directions, to ensure symmetry of the inputs for a, b in [(left, right), (right, left)]: - intersection = _intersect_scopes(set(left), set(right)) + intersection = _intersect_expanded_scopes(set(left), set(right)) assert intersection == set(expected) if should_warn: From 335320fd14e71f5c60040c3a0c8ee6a5905f103a Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 28 May 2021 11:08:34 +0200 Subject: [PATCH 211/270] Rename raw_scopes attr for base handler to expanded_scopes --- jupyterhub/apihandlers/auth.py | 4 ++-- jupyterhub/apihandlers/base.py | 2 +- jupyterhub/apihandlers/users.py | 9 +++++---- jupyterhub/handlers/base.py | 12 ++++++------ jupyterhub/roles.py | 15 ++++++++------- jupyterhub/scopes.py | 6 +++--- jupyterhub/tests/test_scopes.py | 8 ++++---- 7 files changed, 29 insertions(+), 27 deletions(-) diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index ed548add..4e7673f2 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -35,8 +35,8 @@ class TokenAPIHandler(APIHandler): 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) + self.expanded_scopes.update(scopes.identify_scopes(owner)) + self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) # record activity whenever we see a token now = orm_token.last_activity = datetime.utcnow() diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 3ead420f..3dc8073b 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -254,7 +254,7 @@ class APIHandler(BaseHandler): self.log.debug( "Asking for user model of %s with scopes [%s]", user.name, - ", ".join(self.raw_scopes), + ", ".join(self.expanded_scopes), ) allowed_keys = set() for scope in access_map: diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 210a1f70..a33bef20 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -37,12 +37,13 @@ class SelfAPIHandler(APIHandler): raise web.HTTPError(403) if isinstance(user, orm.Service): # ensure we have the minimal 'identify' scopes for the token owner - self.raw_scopes.update(scopes.identify_scopes(user)) - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + self.expanded_scopes.update(scopes.identify_scopes(user)) + self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) model = self.service_model(user) else: - self.raw_scopes.update(scopes.identify_scopes(user.orm_user)) - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) + self.expanded_scopes.update(scopes.identify_scopes(user.orm_user)) + print('Expanded scopes in selfapihandler') + self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) model = self.user_model(user) # validate return, should have at least kind and name, # otherwise our filters did something wrong diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 59c2ae57..3b8ea3f2 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -81,7 +81,7 @@ class BaseHandler(RequestHandler): The current user (None if not logged in) may be accessed via the `self.current_user` property during the handling of any request. """ - self.raw_scopes = set() + self.expanded_scopes = set() try: await self.get_current_user() except Exception: @@ -417,16 +417,16 @@ class BaseHandler(RequestHandler): return self._jupyterhub_user def _resolve_roles_and_scopes(self): - self.raw_scopes = set() + self.expanded_scopes = set() app_log.debug("Loading and parsing scopes") if self.current_user: orm_token = self.get_token() if orm_token: - self.raw_scopes = scopes.get_scopes_for(orm_token) + self.expanded_scopes = scopes.get_scopes_for(orm_token) else: - self.raw_scopes = scopes.get_scopes_for(self.current_user) - self.parsed_scopes = scopes.parse_scopes(self.raw_scopes) - app_log.debug("Found scopes [%s]", ",".join(self.raw_scopes)) + self.expanded_scopes = scopes.get_scopes_for(self.current_user) + self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) + app_log.debug("Found scopes [%s]", ",".join(self.expanded_scopes)) @property def current_user(self): diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 781fd65c..73c171dd 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -401,21 +401,22 @@ def _token_allowed_role(db, token, role): if owner is None: raise ValueError(f"Owner not found for {token}") - token_scopes = _get_subscopes(role, owner=owner) + expanded_scopes = _get_subscopes(role, owner=owner) implicit_permissions = {'all', 'read:all'} - explicit_scopes = token_scopes - implicit_permissions + explicit_scopes = expanded_scopes - implicit_permissions # ignore horizontal filters - raw_scopes = { + no_filter_scopes = { scope.split('!', 1)[0] if '!' in scope else scope for scope in explicit_scopes } # find the owner's scopes - owner_scopes = expand_roles_to_scopes(owner) + expanded_owner_scopes = expand_roles_to_scopes(owner) # ignore horizontal filters - raw_owner_scopes = { - scope.split('!', 1)[0] if '!' in scope else scope for scope in owner_scopes + no_filter_owner_scopes = { + scope.split('!', 1)[0] if '!' in scope else scope + for scope in expanded_owner_scopes } - disallowed_scopes = raw_scopes.difference(raw_owner_scopes) + disallowed_scopes = no_filter_scopes.difference(no_filter_owner_scopes) if not disallowed_scopes: # no scopes requested outside owner's own scopes return True diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 370b601f..a0c94d8a 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -363,8 +363,8 @@ def needs_scope(*scopes): bound_sig = sig.bind(self, *args, **kwargs) bound_sig.apply_defaults() # Load scopes in case they haven't been loaded yet - if not hasattr(self, 'raw_scopes'): - self.raw_scopes = {} + if not hasattr(self, 'expanded_scopes'): + self.expanded_scopes = {} self.parsed_scopes = {} s_kwargs = {} @@ -384,7 +384,7 @@ def needs_scope(*scopes): end_point = self.__name__ app_log.warning( "Not authorizing access to {}. Requires any of [{}], not derived from scopes [{}]".format( - end_point, ", ".join(scopes), ", ".join(self.raw_scopes) + end_point, ", ".join(scopes), ", ".join(self.expanded_scopes) ) ) raise web.HTTPError( diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 69f5e38c..6652e0be 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -86,14 +86,14 @@ def test_scope_parse_server_name(): class MockAPIHandler: def __init__(self): - self.raw_scopes = {'users'} + self.expanded_scopes = {'users'} self.parsed_scopes = {} self.request = mock.Mock(spec=HTTPServerRequest) self.request.path = '/path' def set_scopes(self, *scopes): - self.raw_scopes = set(scopes) - self.parsed_scopes = parse_scopes(self.raw_scopes) + self.expanded_scopes = set(scopes) + self.parsed_scopes = parse_scopes(self.expanded_scopes) @needs_scope('users') def user_thing(self, user_name): @@ -195,7 +195,7 @@ def test_scope_method_access(mock_handler, scopes, method, arguments, is_allowed def test_double_scoped_method_succeeds(mock_handler): mock_handler.current_user = mock.Mock(name='lucille') mock_handler.set_scopes('users', 'read:services') - mock_handler.parsed_scopes = parse_scopes(mock_handler.raw_scopes) + mock_handler.parsed_scopes = parse_scopes(mock_handler.expanded_scopes) assert mock_handler.secret_thing() From 563146445f8ecb4689e5e588ca71a4843af35bd4 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 12 May 2021 14:46:15 +0200 Subject: [PATCH 212/270] add scopes.check_scope_filter Extracted from APIHandler.get_scope_filter for easier re-use and mve get_scope_filter to BaseHandler from APIHandler since it will be needed on oauth --- jupyterhub/apihandlers/base.py | 48 ++-------------------------------- jupyterhub/handlers/base.py | 19 ++++++++++++++ jupyterhub/scopes.py | 40 +++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 49 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 3dc8073b..8e55fb4b 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -1,19 +1,14 @@ """Base API handlers""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -import functools import json -import re -from datetime import datetime from http.client import responses from sqlalchemy.exc import SQLAlchemyError from tornado import web from .. import orm -from .. import scopes from ..handlers import BaseHandler -from ..user import User from ..utils import isoformat from ..utils import url_path_join @@ -66,46 +61,6 @@ class APIHandler(BaseHandler): return False return True - @functools.lru_cache() - def get_scope_filter(self, req_scope): - """Produce a filter for `*ListAPIHandlers* so that GET method knows which models to return. - Filter is a callable that takes a resource name and outputs true or false""" - - def no_access(orm_resource, kind): - return False - - if req_scope not in self.parsed_scopes: - return no_access - sub_scope = self.parsed_scopes[req_scope] - - def has_access_to(orm_resource, kind): - """ - param orm_resource: User or Service or Group or spawner - param kind: 'user' or 'service' or 'group' or 'server'. - """ - if sub_scope == scopes.Scope.ALL: - return True - elif orm_resource.name in sub_scope.get(kind, []): - return True - if kind == 'server': - server_format = f"{orm_resource.user.name}/{orm_resource.name}" - if server_format in sub_scope.get(kind, []): - return True - # Fall back on checking if we have user access - if orm_resource.user.name in sub_scope.get('user', []): - return True - # Fall back on checking if we have group access for this user - orm_resource = orm_resource.user - kind = 'user' - if kind == 'user' and 'group' in sub_scope: - group_names = {group.name for group in orm_resource.groups} - user_in_group = bool(group_names & set(sub_scope['group'])) - if user_in_group: - return True - return False - - return has_access_to - def get_current_user_cookie(self): """Override get_user_cookie to check Referer header""" cookie_user = super().get_current_user_cookie() @@ -213,7 +168,8 @@ class APIHandler(BaseHandler): 'last_activity': isoformat(token.last_activity), 'expires_at': isoformat(token.expires_at), 'note': token.note, - 'oauth_client': token.client.description or token.client.client_id, + 'oauth_client': token.oauth_client.description + or token.oauth_client.identifier, } return model diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 3b8ea3f2..30bd81ac 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -2,6 +2,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import asyncio +import functools import json import math import random @@ -428,6 +429,24 @@ class BaseHandler(RequestHandler): self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) app_log.debug("Found scopes [%s]", ",".join(self.expanded_scopes)) + @functools.lru_cache() + def get_scope_filter(self, req_scope): + """Produce a filter function for req_scope on resources + + Returns `has_access_to(orm_resource, kind)` which returns True or False + for whether the current request has access to req_scope on the given resource. + """ + + def no_access(orm_resource, kind): + return False + + if req_scope not in self.parsed_scopes: + return no_access + + sub_scope = self.parsed_scopes[req_scope] + + return functools.partial(scopes.check_scope_filter, sub_scope) + @property def current_user(self): """Override .current_user accessor from tornado diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index a0c94d8a..1c73108e 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -332,11 +332,13 @@ def parse_scopes(scope_list): parsed_scopes[base_scope] = Scope.ALL elif base_scope not in parsed_scopes: parsed_scopes[base_scope] = {} + if parsed_scopes[base_scope] != Scope.ALL: - key, _, val = filter_.partition('=') + key, _, value = filter_.partition('=') if key not in parsed_scopes[base_scope]: - parsed_scopes[base_scope][key] = [] - parsed_scopes[base_scope][key].append(val) + parsed_scopes[base_scope][key] = set([value]) + else: + parsed_scopes[base_scope][key].add(value) return parsed_scopes @@ -422,3 +424,35 @@ def identify_scopes(obj): } else: raise TypeError(f"Expected orm.User or orm.Service, got {obj!r}") + + +def check_scope_filter(sub_scope, orm_resource, kind): + """Return whether a sub_scope filter applies to a given resource. + + param sub_scope: parsed_scopes filter (i.e. dict or Scope.ALL) + param orm_resource: User or Service or Group or Spawner + param kind: 'user' or 'service' or 'group' or 'server'. + + Returns True or False + """ + if sub_scope is Scope.ALL: + return True + elif kind in sub_scope and orm_resource.name in sub_scope[kind]: + return True + + if kind == 'server': + server_format = f"{orm_resource.user.name}/{orm_resource.name}" + if server_format in sub_scope.get(kind, []): + return True + # Fall back on checking if we have user access + if 'user' in sub_scope and orm_resource.user.name in sub_scope['user']: + return True + # Fall back on checking if we have group access for this user + orm_resource = orm_resource.user + kind = 'user' + elif kind == 'user' and 'group' in sub_scope: + group_names = {group.name for group in orm_resource.groups} + user_in_group = bool(group_names & set(sub_scope['group'])) + if user_in_group: + return True + return False From 7e46d5d0fc64ea11707d327b95fad7e715ef1085 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 12 May 2021 14:48:16 +0200 Subject: [PATCH 213/270] store relationship between oauth client and service/spawner so that we can look up the spawner/service from the oauth client and vice versa --- .../alembic/versions/833da8570507_rbac.py | 32 +++++++++++++++++- jupyterhub/app.py | 15 ++++++--- jupyterhub/handlers/pages.py | 6 ++-- jupyterhub/oauth/provider.py | 2 -- jupyterhub/orm.py | 33 ++++++++++++++++++- jupyterhub/tests/test_api.py | 2 +- jupyterhub/tests/test_orm.py | 6 ++-- jupyterhub/tests/test_pages.py | 2 +- jupyterhub/user.py | 9 ++--- 9 files changed, 85 insertions(+), 22 deletions(-) diff --git a/jupyterhub/alembic/versions/833da8570507_rbac.py b/jupyterhub/alembic/versions/833da8570507_rbac.py index b76fc707..dbf6fc0b 100644 --- a/jupyterhub/alembic/versions/833da8570507_rbac.py +++ b/jupyterhub/alembic/versions/833da8570507_rbac.py @@ -1,4 +1,4 @@ -"""rbac +"""RBAC Revision ID: 833da8570507 Revises: 4dc2d5a8c53c @@ -16,6 +16,30 @@ import sqlalchemy as sa def upgrade(): + # associate spawners and services with their oauth clients + op.add_column( + 'services', sa.Column('oauth_client_id', sa.Unicode(length=255), nullable=True) + ) + op.create_foreign_key( + None, + 'services', + 'oauth_clients', + ['oauth_client_id'], + ['identifier'], + ondelete='SET NULL', + ) + op.add_column( + 'spawners', sa.Column('oauth_client_id', sa.Unicode(length=255), nullable=True) + ) + op.create_foreign_key( + None, + 'spawners', + 'oauth_clients', + ['oauth_client_id'], + ['identifier'], + ondelete='SET NULL', + ) + # FIXME, maybe: currently drops all api tokens and forces recreation! # this ensures a consistent database, but requires: # 1. all servers to be stopped for upgrade (maybe unavoidable anyway) @@ -33,6 +57,12 @@ def upgrade(): def downgrade(): + + op.drop_constraint(None, 'spawners', type_='foreignkey') + op.drop_column('spawners', 'oauth_client_id') + op.drop_constraint(None, 'services', type_='foreignkey') + op.drop_column('services', 'oauth_client_id') + # delete OAuth tokens for non-jupyterhub clients # drop new columns from api tokens op.drop_constraint(None, 'api_tokens', type_='foreignkey') diff --git a/jupyterhub/app.py b/jupyterhub/app.py index d10d0065..7fb3a775 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -394,7 +394,7 @@ class JupyterHub(Application): even if your Hub authentication is still valid. If your Hub authentication is valid, logging in may be a transparent redirect as you refresh the page. - + This does not affect JupyterHub API tokens in general, which do not expire by default. Only tokens issued during the oauth flow @@ -887,7 +887,7 @@ class JupyterHub(Application): "/", help=""" The routing prefix for the Hub itself. - + Override to send only a subset of traffic to the Hub. Default is to use the Hub as the default route for all requests. @@ -899,7 +899,7 @@ class JupyterHub(Application): may want to handle these events themselves, in which case they can register their own default target with the proxy and set e.g. `hub_routespec = /hub/` to serve only the hub's own pages, or even `/hub/api/` for api-only operation. - + Note: hub_routespec must include the base_url, if any. .. versionadded:: 1.4 @@ -1484,7 +1484,7 @@ class JupyterHub(Application): Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler object: :: - + def default_url_fn(handler): user = handler.current_user if user and user.admin: @@ -1956,6 +1956,7 @@ class JupyterHub(Application): for name, usernames in self.load_groups.items(): group = orm.Group.find(db, name) if group is None: + self.log.info(f"Creating group {name}") group = orm.Group(name=name) db.add(group) for username in usernames: @@ -1970,8 +1971,10 @@ class JupyterHub(Application): if user is None: if not self.authenticator.validate_username(username): raise ValueError("Group username %r is not valid" % username) + self.log.info(f"Creating user {username} for group {name}") user = orm.User(name=username) db.add(user) + self.log.debug(f"Adding user {username} to group {name}") group.users.append(user) db.commit() @@ -2264,6 +2267,10 @@ class JupyterHub(Application): allowed_roles=service.oauth_roles, description="JupyterHub service %s" % service.name, ) + service.orm.oauth_client_id = service.oauth_client_id + else: + if service.oauth_client: + self.db.delete(service.oauth_client) self._service_map[name] = service diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index 3d2b03f6..78d847cf 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -10,7 +10,6 @@ from http.client import responses from jinja2 import TemplateNotFound from tornado import web from tornado.httputil import url_concat -from tornado.httputil import urlparse from .. import __version__ from .. import orm @@ -590,8 +589,9 @@ class TokenPageHandler(BaseHandler): token = tokens[0] oauth_clients.append( { - 'client': token.client, - 'description': token.client.description or token.client.identifier, + 'client': token.oauth_client, + 'description': token.oauth_client.description + or token.oauth_client.identifier, 'created': created, 'last_activity': last_activity, 'tokens': tokens, diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 80e8140e..8f21b3bb 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -2,8 +2,6 @@ implements https://oauthlib.readthedocs.io/en/latest/oauth2/server.html """ -from datetime import timedelta - from oauthlib import uri_validate from oauthlib.oauth2 import RequestValidator from oauthlib.oauth2 import WebApplicationServer diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index b16926ac..342abfae 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -326,6 +326,21 @@ class Spawner(Base): last_activity = Column(DateTime, nullable=True) user_options = Column(JSONDict) + # added in 2.0 + oauth_client_id = Column( + Unicode(255), + ForeignKey( + 'oauth_clients.identifier', + ondelete='SET NULL', + ), + ) + oauth_client = relationship( + 'OAuthClient', + backref=backref("spawner", uselist=False), + cascade="all, delete-orphan", + single_parent=True, + ) + # properties on the spawner wrapper # some APIs get these low-level objects # when the spawner isn't running, @@ -377,6 +392,21 @@ class Service(Base): ) pid = Column(Integer) + # added in 2.0 + oauth_client_id = Column( + Unicode(255), + ForeignKey( + 'oauth_clients.identifier', + ondelete='SET NULL', + ), + ) + oauth_client = relationship( + 'OAuthClient', + backref=backref("service", uselist=False), + cascade="all, delete-orphan", + single_parent=True, + ) + def new_api_token(self, token=None, **kwargs): """Create a new API token If `token` is given, load that token. @@ -567,6 +597,7 @@ class APIToken(Hashed, Base): ondelete='CASCADE', ), ) + # FIXME: refresh_tokens not implemented # should be a relation to another token table # refresh_token = Column( @@ -746,7 +777,7 @@ class OAuthClient(Base): return self.identifier access_tokens = relationship( - APIToken, backref='client', cascade='all, delete-orphan' + APIToken, backref='oauth_client', cascade='all, delete-orphan' ) codes = relationship(OAuthCode, backref='client', cascade='all, delete-orphan') diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 03f45bc6..0b6b8014 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -307,7 +307,7 @@ async def test_get_self(app): db.commit() oauth_token = orm.APIToken( user=u.orm_user, - client=oauth_client, + oauth_client=oauth_client, token=token, ) db.add(oauth_token) diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index 389137b5..6c1be117 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -364,7 +364,7 @@ def test_user_delete_cascade(db): oauth_code = orm.OAuthCode(client=oauth_client, user=user) db.add(oauth_code) oauth_token = orm.APIToken( - client=oauth_client, + oauth_client=oauth_client, user=user, ) db.add(oauth_token) @@ -401,7 +401,7 @@ def test_oauth_client_delete_cascade(db): oauth_code = orm.OAuthCode(client=oauth_client, user=user) db.add(oauth_code) oauth_token = orm.APIToken( - client=oauth_client, + oauth_client=oauth_client, user=user, ) db.add(oauth_token) @@ -525,7 +525,7 @@ def test_expiring_oauth_token(app, user): db.add(client) orm_token = orm.APIToken( token=token, - client=client, + oauth_client=client, user=user, expires_at=now() + timedelta(seconds=30), ) diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index 1bba9926..4fe1dfb9 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -870,7 +870,7 @@ async def test_oauth_token_page(app): client = orm.OAuthClient(identifier='token') app.db.add(client) oauth_token = orm.APIToken( - client=client, + oauth_client=client, user=user, ) app.db.add(oauth_token) diff --git a/jupyterhub/user.py b/jupyterhub/user.py index 85e1b88b..5f10f54e 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -590,15 +590,11 @@ class User: client_id = spawner.oauth_client_id oauth_provider = self.settings.get('oauth_provider') if oauth_provider: - oauth_client = oauth_provider.fetch_by_client_id(client_id) - # create a new OAuth client + secret on every launch - # containers that resume will be updated below - allowed_roles = spawner.oauth_roles if callable(allowed_roles): allowed_roles = allowed_roles(spawner) - oauth_provider.add_client( + oauth_client = oauth_provider.add_client( client_id, api_token, url_path_join(self.url, server_name, 'oauth_callback'), @@ -606,6 +602,7 @@ class User: description="Server at %s" % (url_path_join(self.base_url, server_name) + '/'), ) + spawner.orm_spawner.oauth_client = oauth_client db.commit() # trigger pre-spawn hook on authenticator @@ -614,7 +611,7 @@ class User: spawner._start_pending = True if authenticator: - # pre_spawn_start can thow errors that can lead to a redirect loop + # pre_spawn_start can throw errors that can lead to a redirect loop # if left uncaught (see https://github.com/jupyterhub/jupyterhub/issues/2683) await maybe_future(authenticator.pre_spawn_start(self, spawner)) From 57f4c084929f69b76c4e5d9a05ae3971c0a8699d Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 12 May 2021 16:41:56 +0200 Subject: [PATCH 214/270] get upgrade working on sqlite with foreign key naming convention --- .../alembic/versions/833da8570507_rbac.py | 85 ++++++++++++------- jupyterhub/orm.py | 14 ++- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/jupyterhub/alembic/versions/833da8570507_rbac.py b/jupyterhub/alembic/versions/833da8570507_rbac.py index dbf6fc0b..2abecea9 100644 --- a/jupyterhub/alembic/versions/833da8570507_rbac.py +++ b/jupyterhub/alembic/versions/833da8570507_rbac.py @@ -1,4 +1,5 @@ -"""RBAC +""" +rbac changes for jupyterhub 2.0 Revision ID: 833da8570507 Revises: 4dc2d5a8c53c @@ -14,31 +15,40 @@ depends_on = None from alembic import op import sqlalchemy as sa +from jupyterhub import orm + + +naming_convention = orm.meta.naming_convention + def upgrade(): # associate spawners and services with their oauth clients - op.add_column( - 'services', sa.Column('oauth_client_id', sa.Unicode(length=255), nullable=True) - ) - op.create_foreign_key( - None, - 'services', - 'oauth_clients', - ['oauth_client_id'], - ['identifier'], - ondelete='SET NULL', - ) - op.add_column( - 'spawners', sa.Column('oauth_client_id', sa.Unicode(length=255), nullable=True) - ) - op.create_foreign_key( - None, - 'spawners', - 'oauth_clients', - ['oauth_client_id'], - ['identifier'], - ondelete='SET NULL', - ) + # op.add_column( + # 'services', sa.Column('oauth_client_id', sa.Unicode(length=255), nullable=True) + # ) + for table_name in ('services', 'spawners'): + column_name = "oauth_client_id" + target_table = "oauth_clients" + target_column = "identifier" + with op.batch_alter_table( + table_name, + schema=None, + ) as batch_op: + batch_op.add_column( + sa.Column('oauth_client_id', sa.Unicode(length=255), nullable=True), + ) + batch_op.create_foreign_key( + naming_convention["fk"] + % dict( + table_name=table_name, + column_0_name=column_name, + referred_table_name=target_table, + ), + target_table, + [column_name], + [target_column], + ondelete='SET NULL', + ) # FIXME, maybe: currently drops all api tokens and forces recreation! # this ensures a consistent database, but requires: @@ -57,17 +67,32 @@ def upgrade(): def downgrade(): + for table_name in ('services', 'spawners'): + column_name = "oauth_client_id" + target_table = "oauth_clients" + target_column = "identifier" - op.drop_constraint(None, 'spawners', type_='foreignkey') - op.drop_column('spawners', 'oauth_client_id') - op.drop_constraint(None, 'services', type_='foreignkey') - op.drop_column('services', 'oauth_client_id') + with op.batch_alter_table( + table_name, + schema=None, + naming_convention=orm.meta.naming_convention, + ) as batch_op: + batch_op.drop_constraint( + naming_convention["fk"] + % dict( + table_name=table_name, + column_0_name=column_name, + referred_table_name=target_table, + ), + type_='foreignkey', + ) + batch_op.drop_column(column_name) # delete OAuth tokens for non-jupyterhub clients # drop new columns from api tokens - op.drop_constraint(None, 'api_tokens', type_='foreignkey') - op.drop_column('api_tokens', 'session_id') - op.drop_column('api_tokens', 'client_id') + # op.drop_constraint(None, 'api_tokens', type_='foreignkey') + # op.drop_column('api_tokens', 'session_id') + # op.drop_column('api_tokens', 'client_id') # FIXME: only drop tokens whose client id is not 'jupyterhub' # until then, drop all tokens diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 342abfae..8f6e2833 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -16,12 +16,12 @@ from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import create_engine from sqlalchemy import DateTime -from sqlalchemy import Enum from sqlalchemy import event from sqlalchemy import exc from sqlalchemy import ForeignKey from sqlalchemy import inspect from sqlalchemy import Integer +from sqlalchemy import MetaData from sqlalchemy import or_ from sqlalchemy import select from sqlalchemy import Table @@ -115,7 +115,17 @@ class JSONList(JSONDict): return value -Base = declarative_base() +meta = MetaData( + naming_convention={ + "ix": "ix_%(column_0_label)s", + "uq": "uq_%(table_name)s_%(column_0_name)s", + "ck": "ck_%(table_name)s_%(constraint_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s", + } +) + +Base = declarative_base(metadata=meta) Base.log = app_log From e5198b403976f2737f70b410b7ff35520402a347 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 21 May 2021 12:51:03 +0200 Subject: [PATCH 215/270] create boolean columns with create_constraint=False matches new default behavior in sqlalchemy 1.4 --- jupyterhub/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 8f6e2833..26219c72 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -274,7 +274,7 @@ class User(Base): def orm_spawners(self): return {s.name: s for s in self._orm_spawners} - admin = Column(Boolean, default=False) + admin = Column(Boolean(create_constraint=False), default=False) created = Column(DateTime, default=datetime.utcnow) last_activity = Column(DateTime, nullable=True) @@ -386,7 +386,7 @@ class Service(Base): # common user interface: name = Column(Unicode(255), unique=True) - admin = Column(Boolean, default=False) + admin = Column(Boolean(create_constraint=False), default=False) api_tokens = relationship( "APIToken", backref="service", cascade="all, delete-orphan" From e2076e6c91d6bc8dd939b86dbf60ab44e8ee1276 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 12 May 2021 14:49:06 +0200 Subject: [PATCH 216/270] implement access scopes - access:services for services - access:users:servers for servers - tokens automatically have access to their issuing client (if their owner does, too) - Check access scope in HubAuth integration --- .../external/jupyterhub_config.py | 24 ++++- .../external/shared-notebook-service | 8 +- jupyterhub/apihandlers/auth.py | 25 +++++ jupyterhub/apihandlers/users.py | 32 ++++--- jupyterhub/roles.py | 16 +++- jupyterhub/scopes.py | 23 +++++ jupyterhub/services/auth.py | 91 ++++++++++++++++++- jupyterhub/services/service.py | 13 +++ jupyterhub/spawner.py | 12 +++ jupyterhub/tests/mockservice.py | 5 +- jupyterhub/tests/test_services_auth.py | 91 ++++++++++++++++--- 11 files changed, 304 insertions(+), 36 deletions(-) diff --git a/examples/service-notebook/external/jupyterhub_config.py b/examples/service-notebook/external/jupyterhub_config.py index 3b2ef52e..c6157253 100644 --- a/examples/service-notebook/external/jupyterhub_config.py +++ b/examples/service-notebook/external/jupyterhub_config.py @@ -1,15 +1,33 @@ # our user list -c.Authenticator.whitelist = ['minrk', 'ellisonbg', 'willingc'] +c.Authenticator.allowed_users = ['minrk', 'ellisonbg', 'willingc'] # ellisonbg and willingc have access to a shared server: -c.JupyterHub.load_groups = {'shared': ['ellisonbg', 'willingc']} +c.JupyterHub.load_groups = {'shared-notebook-grp': ['ellisonbg', 'willingc']} + +c.JupyterHub.load_roles = [ + { + "name": "shared-notebook", + "groups": ["shared-notebook-grp"], + "scopes": ["access:services!service=shared-notebook"], + }, + # by default, the user role has access to all services + # we want to limit that, so give users only access to 'self' + { + "name": "user", + "scopes": ["self"], + }, +] # start the notebook server as a service c.JupyterHub.services = [ { 'name': 'shared-notebook', 'url': 'http://127.0.0.1:9999', - 'api_token': 'super-secret', + 'api_token': 'c3a29e5d386fd7c9aa1e8fe9d41c282ec8b', } ] + +# dummy spawner and authenticator for testing, don't actually use these! +c.JupyterHub.authenticator_class = 'dummy' +c.JupyterHub.spawner_class = 'simple' diff --git a/examples/service-notebook/external/shared-notebook-service b/examples/service-notebook/external/shared-notebook-service index 20206e92..3510c0a6 100755 --- a/examples/service-notebook/external/shared-notebook-service +++ b/examples/service-notebook/external/shared-notebook-service @@ -1,9 +1,11 @@ #!/bin/bash -l set -e -export JUPYTERHUB_API_TOKEN=super-secret +# these must match the values in jupyterhub_config.py +export JUPYTERHUB_API_TOKEN=c3a29e5d386fd7c9aa1e8fe9d41c282ec8b export JUPYTERHUB_SERVICE_URL=http://127.0.0.1:9999 export JUPYTERHUB_SERVICE_NAME=shared-notebook +export JUPYTERHUB_SERVICE_PREFIX="/services/${JUPYTERHUB_SERVICE_NAME}/" +export JUPYTERHUB_CLIENT_ID="service-${JUPYTERHUB_SERVICE_NAME}" -jupyterhub-singleuser \ - --group='shared' +jupyterhub-singleuser diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index 4e7673f2..7506dd40 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -216,6 +216,31 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): ) credentials = self.add_credentials(credentials) client = self.oauth_provider.fetch_by_client_id(credentials['client_id']) + allowed = False + + # check for access to target resource + if client.spawner: + scope_filter = self.get_scope_filter("access:users:servers") + allowed = scope_filter(client.spawner, kind='server') + elif client.service: + scope_filter = self.get_scope_filter("access:services") + allowed = scope_filter(client.service, kind='service') + else: + # client is not associated with a service or spawner. + # This shouldn't happen, but it might if this is a stale or forged request + # from a service or spawner that's since been deleted + self.log.error( + f"OAuth client {client} has no service or spawner, cannot resolve scopes." + ) + raise web.HTTPError(500, "OAuth configuration error") + + if not allowed: + self.log.error( + f"User {self.current_user} not allowed to access {client.description}" + ) + raise web.HTTPError( + 403, f"You do not have permission to access {client.description}" + ) if not self.needs_oauth_confirm(self.current_user, client): self.log.debug( "Skipping oauth confirmation for %s accessing %s", diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index a33bef20..9bb379ed 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -35,21 +35,31 @@ class SelfAPIHandler(APIHandler): user = self.current_user if user is None: raise web.HTTPError(403) + + _added_scopes = set() if isinstance(user, orm.Service): # ensure we have the minimal 'identify' scopes for the token owner - self.expanded_scopes.update(scopes.identify_scopes(user)) - self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) - model = self.service_model(user) + identify_scopes = scopes.identify_scopes(user) + get_model = self.service_model else: - self.expanded_scopes.update(scopes.identify_scopes(user.orm_user)) - print('Expanded scopes in selfapihandler') + identify_scopes = scopes.identify_scopes(user.orm_user) + get_model = self.user_model + + # ensure we have permission to identify ourselves + # all tokens can do this on this endpoint + for scope in identify_scopes: + if scope not in self.expanded_scopes: + _added_scopes.add(scope) + self.expanded_scopes.add(scope) + if _added_scopes: + # re-parse with new scopes self.parsed_scopes = scopes.parse_scopes(self.expanded_scopes) - model = self.user_model(user) - # validate return, should have at least kind and name, - # otherwise our filters did something wrong - for key in ("kind", "name"): - if key not in model: - raise ValueError(f"Missing identify model for {user}: {model}") + + model = get_model(user) + + # add scopes to identify model, + # but not the scopes we added to ensure we could read our own model + model["scopes"] = sorted(self.expanded_scopes.difference(_added_scopes)) self.write(json.dumps(model)) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 73c171dd..6417a3e6 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -24,11 +24,13 @@ def get_default_roles(): { 'name': 'user', 'description': 'Standard user privileges', - 'scopes': ['self'], + 'scopes': [ + 'self', + ], }, { 'name': 'admin', - 'description': 'Admin privileges (currently can do everything)', + 'description': 'Admin privileges (can do everything)', 'scopes': [ 'admin:users', 'admin:users:servers', @@ -38,12 +40,17 @@ def get_default_roles(): 'read:hub', 'proxy', 'shutdown', + 'access:services', + 'access:users:servers', ], }, { 'name': 'server', 'description': 'Post activity only', - 'scopes': ['users:activity!user'], + 'scopes': [ + 'users:activity!user', + 'access:users:servers!user', + ], }, { 'name': 'token', @@ -64,6 +71,7 @@ def expand_self_scope(name): users:activity users:servers users:tokens + access:users:servers Arguments: name (str): user name @@ -80,6 +88,8 @@ def expand_self_scope(name): 'users:tokens', ] read_scope_list = ['read:' + scope for scope in scope_list] + # access doesn't want the 'read:' prefix + scope_list.append('access:users:servers') scope_list.extend(read_scope_list) return {"{}!user={}".format(scope, name) for scope in scope_list} diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 1c73108e..afce5974 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -97,6 +97,12 @@ scope_definitions = { 'read:hub': { 'description': 'Read-only access to detailed information about the Hub.' }, + 'access:users:servers': { + 'description': 'Access user servers via API or browser.', + }, + 'access:services': { + 'description': 'Access services via API or browser.', + }, 'proxy': { 'description': 'Allows for obtaining information about the proxy’s routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy.' }, @@ -220,6 +226,23 @@ def get_scopes_for(orm_object): app_log.warning(f"Authenticated with token {orm_object}") owner = orm_object.user or orm_object.service token_scopes = roles.expand_roles_to_scopes(orm_object) + if orm_object.client_id != "jupyterhub": + # oauth tokens can be used to access the service issuing the token, + # assuming the owner itself still has permission to do so + spawner = orm_object.oauth_client.spawner + if spawner: + token_scopes.add( + f"access:users:servers!server={spawner.user.name}/{spawner.name}" + ) + else: + service = orm_object.oauth_client.service + if service: + token_scopes.add(f"access:services!service={service.name}") + else: + app_log.warning( + f"Token {orm_object} has no associated service or spawner!" + ) + owner_scopes = roles.expand_roles_to_scopes(owner) if 'all' in token_scopes: token_scopes.remove('all') diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index 4f8e0524..1066a9d7 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -33,13 +33,50 @@ from traitlets import Dict from traitlets import Instance from traitlets import Integer from traitlets import observe +from traitlets import Set from traitlets import Unicode from traitlets import validate from traitlets.config import SingletonConfigurable +from ..scopes import _intersect_scopes from ..utils import url_path_join +def check_scopes(required_scopes, scopes): + """Check that required_scope(s) are in scopes + + Returns the subset of scopes matching required_scopes, + which is truthy if any scopes match any required scopes. + + Correctly resolves scope filters *except* for groups -> user, + e.g. require: access:server!user=x, have: access:server!group=y + will not grant access to user x even if user x is in group y. + + Parameters + ---------- + + required_scopes: set + The set of scopes required. + scopes: set + The set (or list) of scopes to check against required_scopes + + Returns + ------- + relevant_scopes: set + The set of scopes in required_scopes that are present in scopes, + which is truthy if any required scopes are present, + and falsy otherwise. + """ + if isinstance(required_scopes, str): + required_scopes = {required_scopes} + + intersection = _intersect_scopes(required_scopes, scopes) + # re-intersect with required_scopes in case the intersection + # applies stricter filters than required_scopes declares + # e.g. required_scopes = {'read:users'} and intersection has only {'read:users!user=x'} + return set(required_scopes) & intersection + + class _ExpiringDict(dict): """Dict-like cache for Hub API requests @@ -285,6 +322,24 @@ class HubAuth(SingletonConfigurable): def _default_cache(self): return _ExpiringDict(self.cache_max_age) + oauth_scopes = Set( + Unicode(), + help="""OAuth scopes to use for allowing access. + + Get from $JUPYTERHUB_OAUTH_SCOPES by default. + """, + ).tag(config=True) + + @default('oauth_scopes') + def _default_scopes(self): + env_scopes = os.getenv('JUPYTERHUB_OAUTH_SCOPES') + if env_scopes: + return set(json.loads(env_scopes)) + service_name = os.getenv("JUPYTERHUB_SERVICE_NAME") + if service_name: + return {f'access:services!service={service_name}'} + return set() + def _check_hub_authorization(self, url, api_token, cache_key=None, use_cache=True): """Identify a user with the Hub @@ -495,6 +550,10 @@ class HubAuth(SingletonConfigurable): app_log.debug("No user identified") return user_model + def check_scopes(self, required_scopes, user): + """Check whether the user has required scope(s)""" + return check_scopes(required_scopes, set(user["scopes"])) + class HubOAuth(HubAuth): """HubAuth using OAuth for login instead of cookies set by the Hub. @@ -771,6 +830,7 @@ class HubAuthenticated(object): A handler that mixes this in must have the following attributes/properties: - .hub_auth: A HubAuth instance + - .hub_scopes: A set of JupyterHub 2.0 OAuth scopes to allow. - .hub_users: A set of usernames to allow. If left unspecified or None, username will not be checked. - .hub_groups: A set of group names to allow. @@ -795,13 +855,19 @@ class HubAuthenticated(object): hub_groups = None # set of allowed groups allow_admin = False # allow any admin user access + @property + def hub_scopes(self): + """Set of allowed scopes (use hub_auth.oauth_scopes by default)""" + return self.hub_auth.oauth_scopes or None + @property def allow_all(self): """Property indicating that all successfully identified user or service should be allowed. """ return ( - self.hub_services is None + self.hub_scopes is None + and self.hub_services is None and self.hub_users is None and self.hub_groups is None ) @@ -842,22 +908,41 @@ class HubAuthenticated(object): Returns the input if the user should be allowed, None otherwise. - Override if you want to check anything other than the username's presence in hub_users list. + Override for custom logic in authenticating users. Args: - model (dict): the user or service model returned from :class:`HubAuth` + user_model (dict): the user or service model returned from :class:`HubAuth` Returns: user_model (dict): The user model if the user should be allowed, None otherwise. """ name = model['name'] kind = model.setdefault('kind', 'user') + if self.allow_all: app_log.debug( "Allowing Hub %s %s (all Hub users and services allowed)", kind, name ) return model + if self.hub_scopes: + scopes = self.hub_auth.check_scopes(self.hub_scopes, model) + if scopes: + app_log.debug( + f"Allowing Hub {kind} {name} based on oauth scopes {scopes}" + ) + return model + else: + app_log.warning( + f"Not allowing Hub {kind} {name}: missing required scopes" + ) + app_log.debug( + f"Hub {kind} {name} needs scope(s) {self.hub_scopes}, has scope(s) {model['scopes']}" + ) + # if hub_scopes are used, *only* hub_scopes are used + # note: this means successful authentication, but insufficient permission + raise UserNotAllowed(model) + if self.allow_admin and model.get('admin', False): app_log.debug("Allowing Hub admin %s", name) return model diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index f556b6da..24d19592 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -98,6 +98,14 @@ class _ServiceSpawner(LocalProcessSpawner): cwd = Unicode() cmd = Command(minlen=0) + _service_name = Unicode() + + @default("oauth_scopes") + def _default_oauth_scopes(self): + return [ + "access:services", + f"access:services!service={self._service_name}", + ] def make_preexec_fn(self, name): if not name: @@ -330,6 +338,10 @@ class Service(LoggingConfigurable): """ return bool(self.server is not None or self.oauth_redirect_uri) + @property + def oauth_client(self): + return self.orm.oauth_client + @property def server(self): if self.orm.server: @@ -384,6 +396,7 @@ class Service(LoggingConfigurable): environment=env, api_token=self.api_token, oauth_client_id=self.oauth_client_id, + _service_name=self.name, cookie_options=self.cookie_options, cwd=self.cwd, hub=self.hub, diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index fd18386c..39b50133 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -216,6 +216,16 @@ class Spawner(LoggingConfigurable): admin_access = Bool(False) api_token = Unicode() oauth_client_id = Unicode() + + oauth_scopes = List(Unicode()) + + @default("oauth_scopes") + def _default_oauth_scopes(self): + return [ + f"access:users:server!server={self.user.name}/{self.name}", + f"access:users:server!user={self.user.name}", + ] + handler = Any() oauth_roles = Union( @@ -803,6 +813,8 @@ class Spawner(LoggingConfigurable): self.user.url, self.name, 'oauth_callback' ) + env['JUPYTERHUB_OAUTH_SCOPES'] = json.dumps(self.oauth_scopes) + # Info previously passed on args env['JUPYTERHUB_USER'] = self.user.name env['JUPYTERHUB_SERVER_NAME'] = self.name diff --git a/jupyterhub/tests/mockservice.py b/jupyterhub/tests/mockservice.py index 415f512f..082aa65d 100644 --- a/jupyterhub/tests/mockservice.py +++ b/jupyterhub/tests/mockservice.py @@ -21,6 +21,7 @@ from urllib.parse import urlparse import requests from tornado import httpserver from tornado import ioloop +from tornado import log from tornado import web from jupyterhub.services.auth import HubAuthenticated @@ -114,7 +115,9 @@ def main(): if __name__ == '__main__': - from tornado.options import parse_command_line + from tornado.options import parse_command_line, options parse_command_line() + options.logging = 'debug' + log.enable_pretty_logging() main() diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 3ed5d628..158bdbf9 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -25,6 +25,7 @@ from tornado.web import HTTPError from tornado.web import RequestHandler from .. import orm +from .. import roles from ..services.auth import _ExpiringDict from ..services.auth import HubOAuth from ..services.auth import HubOAuthenticated @@ -87,6 +88,7 @@ async def test_hubauth_token(app, mockservice_url): public_url(app, mockservice_url) + '/whoami/', headers={'Authorization': 'token %s' % token}, ) + r.raise_for_status() reply = r.json() sub_reply = {key: reply.get(key, 'missing') for key in ['name', 'admin']} assert sub_reply == {'name': 'river', 'admin': False} @@ -111,36 +113,101 @@ async def test_hubauth_token(app, mockservice_url): assert path.endswith('/hub/login') -async def test_hubauth_service_token(app, mockservice_url): +@pytest.mark.parametrize( + "scopes, allowed", + [ + ( + [ + "access:services", + ], + True, + ), + ( + [ + "access:services!service=$service", + ], + True, + ), + ( + [ + "access:services!service=other-service", + ], + False, + ), + ( + [ + "access:users:servers!user=$service", + ], + False, + ), + ], +) +async def test_hubauth_service_token(request, app, mockservice_url, scopes, allowed): """Test HubAuthenticated service with service API tokens""" + scopes = [scope.replace('$service', mockservice_url.name) for scope in scopes] + token = hexlify(os.urandom(5)).decode('utf8') name = 'test-api-service' app.service_tokens[token] = name await app.init_api_tokens() + orm_service = app.db.query(orm.Service).filter_by(name=name).one() + role_name = "test-hubauth-service-token" + + roles.create_role( + app.db, + { + "name": role_name, + "description": "role for test", + "scopes": scopes, + }, + ) + request.addfinalizer(lambda: roles.delete_role(app.db, role_name)) + roles.grant_role(app.db, orm_service, role_name) + # token in Authorization header r = await async_requests.get( - public_url(app, mockservice_url) + '/whoami/', + public_url(app, mockservice_url) + 'whoami/', headers={'Authorization': 'token %s' % token}, allow_redirects=False, ) - r.raise_for_status() - assert r.status_code == 200 - reply = r.json() - assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} - assert not r.cookies + if allowed: + r.raise_for_status() + assert r.status_code == 200 + reply = r.json() + assert reply == { + 'kind': 'service', + 'name': name, + 'admin': False, + 'roles': [role_name], + 'scopes': scopes, + } + assert not r.cookies + else: + assert r.status_code == 403 # token in ?token parameter r = await async_requests.get( - public_url(app, mockservice_url) + '/whoami/?token=%s' % token + public_url(app, mockservice_url) + 'whoami/?token=%s' % token ) - r.raise_for_status() - reply = r.json() - assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} + if allowed: + r.raise_for_status() + assert r.status_code == 200 + reply = r.json() + assert reply == { + 'kind': 'service', + 'name': name, + 'admin': False, + 'roles': [role_name], + 'scopes': scopes, + } + assert not r.cookies + else: + assert r.status_code == 403 r = await async_requests.get( - public_url(app, mockservice_url) + '/whoami/?token=no-such-token', + public_url(app, mockservice_url) + 'whoami/?token=no-such-token', allow_redirects=False, ) assert r.status_code == 302 From 72b1dd22046b799b79a6ea1727b85115b4f8c51f Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 20 May 2021 09:45:22 +0200 Subject: [PATCH 217/270] oauth: use client_id for description if empty that way description can never be empty on retrieval --- jupyterhub/oauth/provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 8f21b3bb..8bcfe0cb 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -611,7 +611,7 @@ class JupyterHubOAuthServer(WebApplicationServer): allowed_roles = [] orm_client.secret = hash_token(client_secret) if client_secret else "" orm_client.redirect_uri = redirect_uri - orm_client.description = description + orm_client.description = description or client_id orm_client.allowed_roles = allowed_roles self.db.commit() From 0ba222b28835ad53a3ea8565abd35bda306a153b Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 20 May 2021 10:21:33 +0200 Subject: [PATCH 218/270] move role/scope fixtures to conftest so they can be more easily reused --- jupyterhub/tests/conftest.py | 78 ++++++++++++++++++++++++++++++++- jupyterhub/tests/test_roles.py | 2 - jupyterhub/tests/test_scopes.py | 77 -------------------------------- 3 files changed, 76 insertions(+), 81 deletions(-) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index f439bfb0..a51bf858 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -27,7 +27,6 @@ Fixtures to add functionality or spawning behavior # Distributed under the terms of the Modified BSD License. import asyncio import inspect -import logging import os import sys from getpass import getuser @@ -50,7 +49,6 @@ from ..utils import random_port from .mocking import MockHub from .test_services import mockservice_cmd from .utils import add_user -from .utils import ssl_setup # global db session object _db = None @@ -339,3 +337,79 @@ def slow_bad_spawn(app): app.tornado_settings, {'spawner_class': mocking.SlowBadSpawner} ): yield + + +@fixture +def create_temp_role(app): + """Generate a temporary role with certain scopes. + Convenience function that provides setup, database handling and teardown""" + temp_roles = [] + index = [1] + + def temp_role_creator(scopes, role_name=None): + if not role_name: + role_name = f'temp_role_{index[0]}' + index[0] += 1 + temp_role = orm.Role(name=role_name, scopes=list(scopes)) + temp_roles.append(temp_role) + app.db.add(temp_role) + app.db.commit() + return temp_role + + yield temp_role_creator + for role in temp_roles: + app.db.delete(role) + app.db.commit() + + +@fixture +def create_user_with_scopes(app, create_temp_role): + """Generate a temporary user with specific scopes. + Convenience function that provides setup, database handling and teardown""" + temp_users = [] + counter = 0 + get_role = create_temp_role + + def temp_user_creator(*scopes, name=None): + nonlocal counter + if name is None: + counter += 1 + name = f"temp_user_{counter}" + role = get_role(scopes) + orm_user = orm.User(name=name) + app.db.add(orm_user) + app.db.commit() + temp_users.append(orm_user) + update_roles(app.db, orm_user, roles=[role.name]) + return app.users[orm_user.id] + + yield temp_user_creator + for user in temp_users: + app.users.delete(user) + + +@fixture +def create_service_with_scopes(app, create_temp_role): + """Generate a temporary service with specific scopes. + Convenience function that provides setup, database handling and teardown""" + temp_service = [] + counter = 0 + role_function = create_temp_role + + def temp_service_creator(*scopes, name=None): + nonlocal counter + if name is None: + counter += 1 + name = f"temp_service_{counter}" + role = role_function(scopes) + app.services.append({'name': name}) + app.init_services() + orm_service = orm.Service.find(app.db, name) + app.db.commit() + update_roles(app.db, orm_service, roles=[role.name]) + return orm_service + + yield temp_service_creator + for service in temp_service: + app.db.delete(service) + app.db.commit() diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 07efdc4b..72a68476 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -13,10 +13,8 @@ from traitlets.config import Config from .. import orm from .. import roles from ..scopes import get_scopes_for -from ..utils import maybe_future from ..utils import utcnow from .mocking import MockHub -from .test_scopes import create_temp_role from .utils import add_user from .utils import api_request diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 6652e0be..81642cba 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -260,83 +260,6 @@ async def test_by_fake_user(app): err_message = "No access to resources or resources not found" -@pytest.fixture -def create_temp_role(app): - """Generate a temporary role with certain scopes. - Convenience function that provides setup, database handling and teardown""" - temp_roles = [] - index = [1] - - def temp_role_creator(scopes, role_name=None): - if not role_name: - role_name = f'temp_role_{index[0]}' - index[0] += 1 - temp_role = orm.Role(name=role_name, scopes=list(scopes)) - temp_roles.append(temp_role) - app.db.add(temp_role) - app.db.commit() - return temp_role - - yield temp_role_creator - for role in temp_roles: - app.db.delete(role) - app.db.commit() - - -@pytest.fixture -def create_user_with_scopes(app, create_temp_role): - """Generate a temporary user with specific scopes. - Convenience function that provides setup, database handling and teardown""" - temp_users = [] - counter = 0 - get_role = create_temp_role - - def temp_user_creator(*scopes, name=None): - nonlocal counter - if name is None: - counter += 1 - name = f"temp_user_{counter}" - role = get_role(scopes) - orm_user = orm.User(name=name) - app.db.add(orm_user) - app.db.commit() - temp_users.append(orm_user) - roles.update_roles(app.db, orm_user, roles=[role.name]) - return app.users[orm_user.id] - - yield temp_user_creator - for user in temp_users: - app.users.delete(user) - - -@pytest.fixture -def create_service_with_scopes(app, create_temp_role): - """Generate a temporary service with specific scopes. - Convenience function that provides setup, database handling and teardown""" - temp_services = [] - counter = 0 - role_function = create_temp_role - - def temp_service_creator(*scopes, name=None): - nonlocal counter - if name is None: - counter += 1 - name = f"temp_service_{counter}" - role = role_function(scopes) - app.services.append({'name': name}) - app.init_services() - orm_service = orm.Service.find(app.db, name) - app.db.commit() - temp_services.append(orm_service) - roles.update_roles(app.db, orm_service, roles=[role.name]) - return orm_service - - yield temp_service_creator - for service in temp_services: - app.db.delete(service) - app.db.commit() - - async def test_request_fake_user(app, create_user_with_scopes): fake_user = 'annyong' user = create_user_with_scopes('read:users!group=stuff') From 69d2839ba300f2bfa960af7755a004e5efcac4e2 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 20 May 2021 11:28:27 +0200 Subject: [PATCH 219/270] test access scopes in authorize handler - provider.add_client returns the client - fix Spawner access scopes - debug logging in mock spawners - Assign service access scopes --- jupyterhub/oauth/provider.py | 1 + jupyterhub/orm.py | 10 ++- jupyterhub/spawner.py | 4 +- jupyterhub/tests/mocking.py | 5 ++ jupyterhub/tests/test_services_auth.py | 119 +++++++++++++++++++------ jupyterhub/tests/test_singleuser.py | 70 +++++++++++++-- 6 files changed, 168 insertions(+), 41 deletions(-) diff --git a/jupyterhub/oauth/provider.py b/jupyterhub/oauth/provider.py index 8bcfe0cb..7594131a 100644 --- a/jupyterhub/oauth/provider.py +++ b/jupyterhub/oauth/provider.py @@ -614,6 +614,7 @@ class JupyterHubOAuthServer(WebApplicationServer): orm_client.description = description or client_id orm_client.allowed_roles = allowed_roles self.db.commit() + return orm_client def fetch_by_client_id(self, client_id): """Find a client by its id""" diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 26219c72..c38feff7 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -514,9 +514,7 @@ class Hashed(Expiring): @classmethod def check_token(cls, db, token): """Check if a token is acceptable""" - print("checking", cls, token, len(token), cls.min_length) if len(token) < cls.min_length: - print("raising") raise ValueError( "Tokens must be at least %i characters, got %r" % (cls.min_length, token) @@ -773,6 +771,11 @@ class OAuthCode(Expiring, Base): .first() ) + def __repr__(self): + return ( + f"<{self.__class__.__name__}(id={self.id}, client_id={self.client_id!r})>" + ) + class OAuthClient(Base): __tablename__ = 'oauth_clients' @@ -795,6 +798,9 @@ class OAuthClient(Base): # *not* the roles of the client itself allowed_roles = relationship('Role', secondary='oauth_client_role_map') + def __repr__(self): + return f"<{self.__class__.__name__}(identifier={self.identifier!r})>" + # General database utilities diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index 39b50133..22fbe451 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -222,8 +222,8 @@ class Spawner(LoggingConfigurable): @default("oauth_scopes") def _default_oauth_scopes(self): return [ - f"access:users:server!server={self.user.name}/{self.name}", - f"access:users:server!user={self.user.name}", + f"access:users:servers!server={self.user.name}/{self.name}", + f"access:users:servers!user={self.user.name}", ] handler = Any() diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 5acb039a..723e7bd1 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -388,6 +388,10 @@ class MockSingleUserServer(SingleUserNotebookApp): def init_signal(self): pass + @default("log_level") + def _default_log_level(self): + return 10 + class StubSingleUserSpawner(MockSpawner): """Spawner that starts a MockSingleUserServer in a thread.""" @@ -425,6 +429,7 @@ class StubSingleUserSpawner(MockSpawner): app.initialize(args) assert app.hub_auth.oauth_client_id assert app.hub_auth.api_token + assert app.hub_auth.oauth_scopes app.start() self._thread = threading.Thread(target=_run) diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 158bdbf9..165a7ad2 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -1,36 +1,20 @@ """Tests for service authentication""" -import asyncio import copy -import json import os import sys from binascii import hexlify -from functools import partial -from queue import Queue -from threading import Thread from unittest import mock from urllib.parse import parse_qs from urllib.parse import urlparse import pytest -import requests -import requests_mock from pytest import raises -from tornado.httpserver import HTTPServer from tornado.httputil import url_concat -from tornado.ioloop import IOLoop -from tornado.web import Application -from tornado.web import authenticated -from tornado.web import HTTPError -from tornado.web import RequestHandler from .. import orm from .. import roles from ..services.auth import _ExpiringDict -from ..services.auth import HubOAuth -from ..services.auth import HubOAuthenticated from ..utils import url_path_join -from .mocking import public_host from .mocking import public_url from .test_api import add_user from .utils import async_requests @@ -77,21 +61,29 @@ def test_expiring_dict(): assert cache.get('key', 'default') == 'cached value' -async def test_hubauth_token(app, mockservice_url): +async def test_hubauth_token(app, mockservice_url, create_user_with_scopes): """Test HubAuthenticated service with user API tokens""" - u = add_user(app.db, name='river') + u = create_user_with_scopes("access:services") token = u.new_api_token() + no_access_token = u.new_api_token(roles=[]) app.db.commit() + # token without sufficient permission in Authorization header + r = await async_requests.get( + public_url(app, mockservice_url) + '/whoami/', + headers={'Authorization': f'token {no_access_token}'}, + ) + assert r.status_code == 403 + # token in Authorization header r = await async_requests.get( public_url(app, mockservice_url) + '/whoami/', - headers={'Authorization': 'token %s' % token}, + headers={'Authorization': f'token {token}'}, ) r.raise_for_status() reply = r.json() sub_reply = {key: reply.get(key, 'missing') for key in ['name', 'admin']} - assert sub_reply == {'name': 'river', 'admin': False} + assert sub_reply == {'name': u.name, 'admin': 'missing'} # token in ?token parameter r = await async_requests.get( @@ -100,7 +92,7 @@ async def test_hubauth_token(app, mockservice_url): r.raise_for_status() reply = r.json() sub_reply = {key: reply.get(key, 'missing') for key in ['name', 'admin']} - assert sub_reply == {'name': 'river', 'admin': False} + assert sub_reply == {'name': u.name, 'admin': 'missing'} r = await async_requests.get( public_url(app, mockservice_url) + '/whoami/?token=no-such-token', @@ -237,14 +229,15 @@ async def test_hubauth_service_token(request, app, mockservice_url, scopes, allo (["token", "user"], ["identify"], []), # any item outside the list isn't allowed (["token", "user"], ["token", "server"], None), - # reuesting subset + # requesting subset (["admin", "user"], ["user"], ["user"]), (["user", "token", "server"], ["token", "user"], ["token", "user"]), ], ) -async def test_oauth_service( +async def test_oauth_service_roles( app, mockservice_url, + create_user_with_scopes, client_allowed_roles, request_roles, expected_roles, @@ -262,7 +255,9 @@ async def test_oauth_service( url = url_path_join(public_url(app, mockservice_url) + 'owhoami/?arg=x') # first request is only going to login and get us to the oauth form page s = AsyncSession() - name = 'link' + user = create_user_with_scopes("access:services") + roles.grant_role(app.db, user, "user") + name = user.name s.cookies = await app.login_user(name) r = await s.get(url) @@ -298,7 +293,7 @@ async def test_oauth_service( assert r.status_code == 200 reply = r.json() sub_reply = {key: reply.get(key, 'missing') for key in ('kind', 'name')} - assert sub_reply == {'name': 'link', 'kind': 'user'} + assert sub_reply == {'name': user.name, 'kind': 'user'} # token-authenticated request to HubOAuth token = app.users[name].new_api_token() @@ -318,12 +313,78 @@ async def test_oauth_service( assert reply['name'] == name -async def test_oauth_cookie_collision(app, mockservice_url): +@pytest.mark.parametrize( + "access_scopes, expect_success", + [ + (["access:services"], True), + (["access:services!service=$service"], True), + (["access:services!service=other-service"], False), + (["self"], False), + ([], False), + ], +) +async def test_oauth_access_scopes( + app, + mockservice_url, + create_user_with_scopes, + access_scopes, + expect_success, +): + """Check that oauth/authorize validates access scopes""" + service = mockservice_url + access_scopes = [s.replace("$service", service.name) for s in access_scopes] + url = url_path_join(public_url(app, mockservice_url) + 'owhoami/?arg=x') + # first request is only going to login and get us to the oauth form page + s = AsyncSession() + user = create_user_with_scopes(*access_scopes) + name = user.name + s.cookies = await app.login_user(name) + + r = await s.get(url) + if not expect_success: + assert r.status_code == 403 + return + r.raise_for_status() + # we should be looking at the oauth confirmation page + assert urlparse(r.url).path == app.base_url + 'hub/api/oauth2/authorize' + # verify oauth state cookie was set at some point + assert set(r.history[0].cookies.keys()) == {'service-%s-oauth-state' % service.name} + + # submit the oauth form to complete authorization + r = await s.post(r.url, headers={'Referer': r.url}) + r.raise_for_status() + assert r.url == url + # verify oauth cookie is set + assert 'service-%s' % service.name in set(s.cookies.keys()) + # verify oauth state cookie has been consumed + assert 'service-%s-oauth-state' % service.name not in set(s.cookies.keys()) + + # second request should be authenticated, which means no redirects + r = await s.get(url, allow_redirects=False) + r.raise_for_status() + assert r.status_code == 200 + reply = r.json() + sub_reply = {key: reply.get(key, 'missing') for key in ('kind', 'name')} + assert sub_reply == {'name': name, 'kind': 'user'} + + # revoke user access, should result in 403 + user.roles = [] + app.db.commit() + + # reset session id to avoid cached response + s.cookies.pop('jupyterhub-session-id') + + r = await s.get(url, allow_redirects=False) + assert r.status_code == 403 + + +async def test_oauth_cookie_collision(app, mockservice_url, create_user_with_scopes): service = mockservice_url url = url_path_join(public_url(app, mockservice_url), 'owhoami/') print(url) s = AsyncSession() name = 'mypha' + user = create_user_with_scopes("access:services", name=name) s.cookies = await app.login_user(name) state_cookie_name = 'service-%s-oauth-state' % service.name service_cookie_name = 'service-%s' % service.name @@ -376,7 +437,7 @@ async def test_oauth_cookie_collision(app, mockservice_url): assert state_cookies == [] -async def test_oauth_logout(app, mockservice_url): +async def test_oauth_logout(app, mockservice_url, create_user_with_scopes): """Verify that logout via the Hub triggers logout for oauth services 1. clears session id cookie @@ -390,11 +451,11 @@ async def test_oauth_logout(app, mockservice_url): # first request is only going to set login cookie s = AsyncSession() name = 'propha' - app_user = add_user(app.db, app=app, name=name) + user = create_user_with_scopes("access:services", name=name) def auth_tokens(): """Return list of OAuth access tokens for the user""" - return list(app.db.query(orm.APIToken).filter_by(user_id=app_user.id)) + return list(app.db.query(orm.APIToken).filter_by(user_id=user.id)) # ensure we start empty assert auth_tokens() == [] diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index ddf080f0..0b0eef5a 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -3,6 +3,8 @@ import sys from subprocess import check_output from urllib.parse import urlparse +import pytest + import jupyterhub from ..utils import url_path_join from .mocking import public_url @@ -11,7 +13,32 @@ from .utils import async_requests from .utils import AsyncSession -async def test_singleuser_auth(app): +@pytest.mark.parametrize( + "access_scopes, server_name, expect_success", + [ + (["access:users:servers"], "", True), + (["access:users:servers"], "named", True), + (["access:users:servers!user=$user"], "", True), + (["access:users:servers!user=$user"], "named", True), + (["access:users:servers!server=$server"], "", True), + (["access:users:servers!server=$server"], "named-server", True), + (["access:users:servers!server=$user/other"], "", False), + (["access:users:servers!server=$user/other"], "some-name", False), + (["access:users:servers!user=$other"], "", False), + (["access:users:servers!user=$other"], "named", False), + (["access:services"], "", False), + (["self"], "named", False), + (["admin"], "", False), + ([], "", False), + ], +) +async def test_singleuser_auth( + app, + create_user_with_scopes, + access_scopes, + server_name, + expect_success, +): # use StubSingleUserSpawner to launch a single-user app in a thread app.spawner_class = StubSingleUserSpawner app.tornado_settings['spawner_class'] = StubSingleUserSpawner @@ -19,10 +46,11 @@ async def test_singleuser_auth(app): # login, start the server cookies = await app.login_user('nandy') user = app.users['nandy'] - if not user.running: - await user.spawn() - await app.proxy.add_user(user) - url = public_url(app, user) + if server_name not in user.spawners or not user.spawners[server_name].active: + await user.spawn(server_name) + await app.proxy.add_user(user, server_name) + spawner = user.spawners[server_name] + url = url_path_join(public_url(app, user), server_name) # no cookies, redirects to login page r = await async_requests.get(url) @@ -40,7 +68,11 @@ async def test_singleuser_auth(app): assert ( urlparse(r.url) .path.rstrip('/') - .endswith(url_path_join('/user/nandy', user.spawner.default_url or "/tree")) + .endswith( + url_path_join( + f'/user/{user.name}', spawner.name, spawner.default_url or "/tree" + ) + ) ) assert r.status_code == 200 @@ -49,17 +81,39 @@ async def test_singleuser_auth(app): assert len(r.cookies) == 0 # accessing another user's server hits the oauth confirmation page + access_scopes = [s.replace("$user", user.name) for s in access_scopes] + access_scopes = [ + s.replace("$server", f"{user.name}/{server_name}") for s in access_scopes + ] + other_user = create_user_with_scopes(*access_scopes, name="burgess") + cookies = await app.login_user('burgess') s = AsyncSession() s.cookies = cookies r = await s.get(url) assert urlparse(r.url).path.endswith('/oauth2/authorize') + if not expect_success: + # user isn't authorized, should raise 403 + assert r.status_code == 403 + return + r.raise_for_status() # submit the oauth form to complete authorization r = await s.post(r.url, data={'scopes': ['identify']}, headers={'Referer': r.url}) final_url = urlparse(r.url).path.rstrip('/') - final_path = url_path_join('/user/nandy', user.spawner.default_url or "/tree") + final_path = url_path_join( + '/user/', user.name, spawner.name, spawner.default_url or "/tree" + ) assert final_url.endswith(final_path) - # user isn't authorized, should raise 403 + r.raise_for_status() + + # revoke user access, should result in 403 + other_user.roles = [] + app.db.commit() + + # reset session id to avoid cached response + s.cookies.pop('jupyterhub-session-id') + + r = await s.get(r.url, allow_redirects=False) assert r.status_code == 403 assert 'burgess' in r.text From 40de16e0e1e493156dbe58123e77749bd6590820 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 21 May 2021 10:17:57 +0200 Subject: [PATCH 220/270] Update service examples and documentation with access scopes and roles --- docs/source/reference/services.md | 114 +++++++++--------- examples/postgres/hub/jupyterhub_config.py | 4 +- examples/service-announcement/README.md | 44 ++++--- examples/service-announcement/announcement.py | 3 - .../service-announcement/jupyterhub_config.py | 27 ++++- examples/service-fastapi/README.md | 18 ++- examples/service-fastapi/app/models.py | 6 +- examples/service-fastapi/app/security.py | 20 ++- examples/service-fastapi/jupyterhub_config.py | 15 ++- .../external/jupyterhub_config.py | 36 +++--- .../managed/jupyterhub_config.py | 28 ++++- examples/service-whoami/README.md | 62 +++++++++- examples/service-whoami/jupyterhub_config.py | 15 ++- examples/service-whoami/whoami-oauth.py | 9 +- examples/service-whoami/whoami.py | 11 +- jupyterhub/services/auth.py | 17 ++- 16 files changed, 291 insertions(+), 138 deletions(-) diff --git a/docs/source/reference/services.md b/docs/source/reference/services.md index 408b396a..ab7d8da0 100644 --- a/docs/source/reference/services.md +++ b/docs/source/reference/services.md @@ -86,10 +86,18 @@ Hub-Managed Service would include: This example would be configured as follows in `jupyterhub_config.py`: ```python +c.JupyterHub.load_roles = [ + { + "name": "idle-culler", + "scopes": [ + "users:servers", + # also 'admin:users' if culling idle users as well + ] + } + c.JupyterHub.services = [ { 'name': 'idle-culler', - 'admin': True, 'command': [sys.executable, '-m', 'jupyterhub_idle_culler', '--timeout=3600'] } ] @@ -114,6 +122,7 @@ JUPYTERHUB_BASE_URL: Base URL of the Hub (https://mydomain[:port]/) JUPYTERHUB_SERVICE_PREFIX: URL path prefix of this service (/services/:service-name/) JUPYTERHUB_SERVICE_URL: Local URL where the service is expected to be listening. Only for proxied web services. +JUPYTERHUB_OAUTH_SCOPES: JSON-serialized list of scopes to use for allowing access to the service. ``` For the previous 'cull idle' Service example, these environment variables @@ -231,50 +240,8 @@ service. See the `service-whoami-flask` example in the [JupyterHub GitHub repo](https://github.com/jupyterhub/jupyterhub/tree/HEAD/examples/service-whoami-flask) for more details. -```python -from functools import wraps -import json -import os -from urllib.parse import quote - -from flask import Flask, redirect, request, Response - -from jupyterhub.services.auth import HubOAuth - -prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/') - -auth = HubOAuth( - api_token=os.environ['JUPYTERHUB_API_TOKEN'], - cache_max_age=60, -) - -app = Flask(__name__) - - -def authenticated(f): - """Decorator for authenticating with the Hub""" - @wraps(f) - def decorated(*args, **kwargs): - token = request.headers.get(auth.auth_header_name) - if token: - user = auth.user_for_token(token) - else: - user = None - if user: - return f(user, *args, **kwargs) - else: - # redirect to login url on failed auth - return redirect(auth.login_url + '?next=%s' % quote(request.path)) - return decorated - - -@app.route(prefix) -@authenticated -def whoami(user): - return Response( - json.dumps(user, indent=1, sort_keys=True), - mimetype='application/json', - ) +```{literalinclude} ../../../examples/service-whoami-flask/whoami-flask.py +:language: python ``` ### Authenticating tornado services with JupyterHub @@ -315,25 +282,38 @@ undefined, then any user will be allowed. If you don't want to use the reference implementation (e.g. you find the implementation a poor fit for your Flask app), you can implement authentication via the Hub yourself. -We recommend looking at the [`HubAuth`][hubauth] class implementation for reference, +JupyterHub is a standard OAuth2 provider, +so you can any OAuth 2 implementation appropriate for +See the [FastAPI example][] for an example of using JupyterHub as an OAuth provider with fastapi, +without using any code imported from JupyterHub. + +On completion of OAuth, you will have an access token for JupyterHub, +which can be used to identify the user and the permissions (scopes) +the user has authorized for your service. + +You will only get to this stage if the user has the required `access:services!service=$service-name` scope. + +To retrieve the user model for the token, make a request to `GET /hub/api/user` with the token in the Authorization header. +For example, using flask: + +```{literal-include} ../../../examples/service-whoami-flask/whoami-flask.py +:language: python +``` + +We recommend looking at the [`HubOAuth`][huboauth] class implementation for reference, and taking note of the following process: -1. retrieve the cookie `jupyterhub-services` from the request. -2. Make an API request `GET /hub/api/authorizations/cookie/jupyterhub-services/cookie-value`, - where cookie-value is the url-encoded value of the `jupyterhub-services` cookie. - This request must be authenticated with a Hub API token in the `Authorization` header, - for example using the `api_token` from your [external service's configuration](#externally-managed-services). +1. retrieve the token from the request. +2. Make an API request `GET /hub/api/user`, + with the token in the `Authorization` header. For example, with [requests][]: ```python r = requests.get( - '/'.join(["http://127.0.0.1:8081/hub/api", - "authorizations/cookie/jupyterhub-services", - quote(encrypted_cookie, safe=''), - ]), + "http://127.0.0.1:8081/hub/api/user", headers = { - 'Authorization' : 'token %s' % api_token, + 'Authorization' : f'token {api_token}', }, ) r.raise_for_status() @@ -342,13 +322,27 @@ and taking note of the following process: 3. On success, the reply will be a JSON model describing the user: - ```json + ```python { "name": "inara", - "groups": ["serenity", "guild"] + # groups may be omitted, depending on permissions + "groups": ["serenity", "guild"], + # scopes is new in JupyterHub 2.0 + "scopes": [ + "access:services", + "read:users:name", + "read:users!user=inara", + "..." + ] } ``` +The `scopes` field can be used to manage access. +Note: a user will have access to a service to complete oauth access to the service for the first time. +Individual permissions may be revoked at any later point without revoking the token, +in which case the `scopes` field in this model should be checked on each access. +The default required scopes for access are available from `hub_auth.oauth_scopes` or `$JUPYTERHUB_OAUTH_SCOPES`. + An example of using an Externally-Managed Service and authentication is in [nbviewer README][nbviewer example] section on securing the notebook viewer, and an example of its configuration is found [here](https://github.com/jupyter/nbviewer/blob/ed942b10a52b6259099e2dd687930871dc8aac22/nbviewer/providers/base.py#L95). @@ -357,9 +351,9 @@ section on securing the notebook viewer. [requests]: http://docs.python-requests.org/en/master/ [services_auth]: ../api/services.auth.html -[hubauth]: ../api/services.auth.html#jupyterhub.services.auth.HubAuth -[hubauth.user_for_cookie]: ../api/services.auth.html#jupyterhub.services.auth.HubAuth.user_for_cookie +[huboauth]: ../api/services.auth.html#jupyterhub.services.auth.HubOAuth [hubauth.user_for_token]: ../api/services.auth.html#jupyterhub.services.auth.HubAuth.user_for_token [hubauthenticated]: ../api/services.auth.html#jupyterhub.services.auth.HubAuthenticated [nbviewer example]: https://github.com/jupyter/nbviewer#securing-the-notebook-viewer +[fastapi example]: https://github.com/jupyterhub/jupyterhub/tree/HEAD/examples/service-fastapi [jupyterhub_idle_culler]: https://github.com/jupyterhub/jupyterhub-idle-culler diff --git a/examples/postgres/hub/jupyterhub_config.py b/examples/postgres/hub/jupyterhub_config.py index 9482657b..4a8efaef 100644 --- a/examples/postgres/hub/jupyterhub_config.py +++ b/examples/postgres/hub/jupyterhub_config.py @@ -1,10 +1,10 @@ # Configuration file for jupyterhub (postgres example). -c = get_config() +c = get_config() # noqa # Add some users. c.JupyterHub.admin_users = {'rhea'} -c.Authenticator.whitelist = {'ganymede', 'io', 'rhea'} +c.Authenticator.allowed_users = {'ganymede', 'io', 'rhea'} # These environment variables are automatically supplied by the linked postgres # container. diff --git a/examples/service-announcement/README.md b/examples/service-announcement/README.md index cff87ec3..4be75b57 100644 --- a/examples/service-announcement/README.md +++ b/examples/service-announcement/README.md @@ -6,15 +6,17 @@ that appear when JupyterHub renders pages. To run the service as a hub-managed service simply include in your JupyterHub configuration file something like: - c.JupyterHub.services = [ - { - 'name': 'announcement', - 'url': 'http://127.0.0.1:8888', - 'command': [sys.executable, "-m", "announcement"], - } - ] +```python +c.JupyterHub.services = [ + { + 'name': 'announcement', + 'url': 'http://127.0.0.1:8888', + 'command': [sys.executable, "-m", "announcement", "--port", "8888"], + } +] +``` -This starts the announcements service up at `/services/announcement` when +This starts the announcements service up at `/services/announcement/` when JupyterHub launches. By default the announcement text is empty. The `announcement` module has a configurable port (default 8888) and an API @@ -23,15 +25,28 @@ that environment variable is set or `/` if it is not. ## Managing the Announcement -Admin users can set the announcement text with an API token: +Users with permission can set the announcement text with an API token: $ curl -X POST -H "Authorization: token " \ -d '{"announcement":"JupyterHub will be upgraded on August 14!"}' \ - https://.../services/announcement + https://.../services/announcement/ + +To grant permission, add a role (JupyterHub 2.0) with access to the announcement service: + +```python +# grant the 'announcer' permission to access the announcement service +c.JupyterHub.load_roles = [ + { + "name": "announcers", + "users": ["announcer"], # or groups + "scopes": ["access:services!service=announcement"], + } +] +``` Anyone can read the announcement: - $ curl https://.../services/announcement | python -m json.tool + $ curl https://.../services/announcement/ | python -m json.tool { announcement: "JupyterHub will be upgraded on August 14!", timestamp: "...", @@ -41,10 +56,11 @@ Anyone can read the announcement: The time the announcement was posted is recorded in the `timestamp` field and the user who posted the announcement is recorded in the `user` field. -To clear the announcement text, just DELETE. Only admin users can do this. +To clear the announcement text, send a DELETE request. +This has the same permissionOnly admin users can do this. - $ curl -X POST -H "Authorization: token " \ - https://.../services/announcement + $ curl -X DELETE -H "Authorization: token " \ + https://.../services/announcement/ ## Seeing the Announcement in JupyterHub diff --git a/examples/service-announcement/announcement.py b/examples/service-announcement/announcement.py index a0cf5964..6a50c33d 100644 --- a/examples/service-announcement/announcement.py +++ b/examples/service-announcement/announcement.py @@ -13,9 +13,6 @@ from jupyterhub.services.auth import HubAuthenticated class AnnouncementRequestHandler(HubAuthenticated, web.RequestHandler): """Dynamically manage page announcements""" - hub_users = [] - allow_admin = True - def initialize(self, storage): """Create storage for announcement text""" self.storage = storage diff --git a/examples/service-announcement/jupyterhub_config.py b/examples/service-announcement/jupyterhub_config.py index 069a76d7..9bca9809 100644 --- a/examples/service-announcement/jupyterhub_config.py +++ b/examples/service-announcement/jupyterhub_config.py @@ -2,11 +2,18 @@ import sys # To run the announcement service managed by the hub, add this. +port = 9999 c.JupyterHub.services = [ { 'name': 'announcement', - 'url': 'http://127.0.0.1:8888', - 'command': [sys.executable, "-m", "announcement"], + 'url': f'http://127.0.0.1:{port}', + 'command': [ + sys.executable, + "-m", + "announcement", + '--port', + str(port), + ], } ] @@ -14,3 +21,19 @@ c.JupyterHub.services = [ # for an example of how to do this. c.JupyterHub.template_paths = ["templates"] + +c.Authenticator.allowed_users = {"announcer", "otheruser"} + +# grant the 'announcer' permission to access the announcement service +c.JupyterHub.load_roles = [ + { + "name": "announcers", + "users": ["announcer"], + "scopes": ["access:services!service=announcement"], + } +] + +# dummy spawner and authenticator for testing, don't actually use these! +c.JupyterHub.authenticator_class = 'dummy' +c.JupyterHub.spawner_class = 'simple' +c.JupyterHub.ip = '127.0.0.1' # let's just run on localhost while dummy auth is enabled diff --git a/examples/service-fastapi/README.md b/examples/service-fastapi/README.md index b2167228..26fb6a7b 100644 --- a/examples/service-fastapi/README.md +++ b/examples/service-fastapi/README.md @@ -16,6 +16,7 @@ jupyterhub --ip=127.0.0.1 ``` 2. Visit http://127.0.0.1:8000/services/fastapi or http://127.0.0.1:8000/services/fastapi/docs + Login with username 'test-user' and any password. 3. Try interacting programmatically. If you create a new token in your control panel or pull out the `JUPYTERHUB_API_TOKEN` in the single user environment, you can skip the third step here. @@ -24,10 +25,10 @@ $ curl -X GET http://127.0.0.1:8000/services/fastapi/ {"Hello":"World"} $ curl -X GET http://127.0.0.1:8000/services/fastapi/me -{"detail":"Must login with token parameter, cookie, or header"} +{"detail":"Must login with token parameter, or Authorization bearer header"} -$ curl -X POST http://127.0.0.1:8000/hub/api/authorizations/token \ - -d '{"username": "myname", "password": "mypasswd!"}' \ +$ curl -X POST http://127.0.0.1:8000/hub/api/users/test-user/tokens \ + -d '{"auth": {"username": "test-user", "password": "mypasswd!"}}' \ | jq '.token' "3fee13ce6d2845da9bd5f2c2170d3428" @@ -35,13 +36,18 @@ $ curl -X GET http://127.0.0.1:8000/services/fastapi/me \ -H "Authorization: Bearer 3fee13ce6d2845da9bd5f2c2170d3428" \ | jq . { - "name": "myname", + "name": "test-user", "admin": false, "groups": [], "server": null, "pending": null, - "last_activity": "2021-04-07T18:05:11.587638+00:00", - "servers": null + "last_activity": "2021-05-21T09:13:00.514309+00:00", + "servers": null, + "scopes": [ + "access:services", + "access:users:servers!user=test-user", + "...", + ] } ``` diff --git a/examples/service-fastapi/app/models.py b/examples/service-fastapi/app/models.py index c3751053..33fdab68 100644 --- a/examples/service-fastapi/app/models.py +++ b/examples/service-fastapi/app/models.py @@ -1,5 +1,6 @@ from datetime import datetime from typing import Any +from typing import Dict from typing import List from typing import Optional @@ -22,11 +23,12 @@ class Server(BaseModel): class User(BaseModel): name: str admin: bool - groups: List[str] + groups: Optional[List[str]] server: Optional[str] pending: Optional[str] last_activity: datetime - servers: Optional[List[Server]] + servers: Optional[Dict[str, Server]] + scopes: List[str] # https://stackoverflow.com/questions/64501193/fastapi-how-to-use-httpexception-in-responses diff --git a/examples/service-fastapi/app/security.py b/examples/service-fastapi/app/security.py index 0f1c79bd..62b2ea5e 100644 --- a/examples/service-fastapi/app/security.py +++ b/examples/service-fastapi/app/security.py @@ -1,3 +1,4 @@ +import json import os from fastapi import HTTPException @@ -27,6 +28,12 @@ auth_by_header = OAuth2AuthorizationCodeBearer( ### our client_secret (JUPYTERHUB_API_TOKEN) and that code to get an ### access_token, which it returns to browser, which places in Authorization header. +if os.environ.get("JUPYTERHUB_OAUTH_SCOPES"): + # typically ["access:services", "access:services!service=$service_name"] + access_scopes = json.loads(os.environ["JUPYTERHUB_OAUTH_SCOPES"]) +else: + access_scopes = ["access:services"] + ### For consideration: optimize performance with a cache instead of ### always hitting the Hub api? async def get_current_user( @@ -58,4 +65,15 @@ async def get_current_user( }, ) user = User(**resp.json()) - return user + if any(scope in user.scopes for scope in access_scopes): + return user + else: + raise HTTPException( + status.HTTP_403_FORBIDDEN, + detail={ + "msg": f"User not authorized: {user.name}", + "request_url": str(resp.request.url), + "token": token, + "user": resp.json(), + }, + ) diff --git a/examples/service-fastapi/jupyterhub_config.py b/examples/service-fastapi/jupyterhub_config.py index 9fb054ec..f8f9e864 100644 --- a/examples/service-fastapi/jupyterhub_config.py +++ b/examples/service-fastapi/jupyterhub_config.py @@ -24,8 +24,21 @@ c.JupyterHub.services = [ "name": service_name, "url": "http://127.0.0.1:10202", "command": ["uvicorn", "app:app", "--port", "10202"], - "admin": True, "oauth_redirect_uri": oauth_redirect_uri, "environment": {"PUBLIC_HOST": public_host}, } ] + +c.JupyterHub.load_roles = [ + { + "name": "user", + # grant all users access to services + "scopes": ["self", "access:services"], + }, +] + + +# dummy for testing, create test-user +c.Authenticator.allowed_users = {"test-user"} +c.JupyterHub.authenticator_class = "dummy" +c.JupyterHub.spawner_class = "simple" diff --git a/examples/service-notebook/external/jupyterhub_config.py b/examples/service-notebook/external/jupyterhub_config.py index c6157253..21911fc8 100644 --- a/examples/service-notebook/external/jupyterhub_config.py +++ b/examples/service-notebook/external/jupyterhub_config.py @@ -1,33 +1,35 @@ # our user list c.Authenticator.allowed_users = ['minrk', 'ellisonbg', 'willingc'] -# ellisonbg and willingc have access to a shared server: +service_name = 'shared-notebook' +service_port = 9999 +group_name = 'shared' -c.JupyterHub.load_groups = {'shared-notebook-grp': ['ellisonbg', 'willingc']} +# ellisonbg and willingc are in a group that will access the shared server: -c.JupyterHub.load_roles = [ - { - "name": "shared-notebook", - "groups": ["shared-notebook-grp"], - "scopes": ["access:services!service=shared-notebook"], - }, - # by default, the user role has access to all services - # we want to limit that, so give users only access to 'self' - { - "name": "user", - "scopes": ["self"], - }, -] +c.JupyterHub.load_groups = {group_name: ['ellisonbg', 'willingc']} # start the notebook server as a service c.JupyterHub.services = [ { - 'name': 'shared-notebook', - 'url': 'http://127.0.0.1:9999', + 'name': service_name, + 'url': 'http://127.0.0.1:{}'.format(service_port), 'api_token': 'c3a29e5d386fd7c9aa1e8fe9d41c282ec8b', } ] +# This "role assignment" is what grants members of the group +# access to the service +c.JupyterHub.load_roles = [ + { + "name": "shared-notebook", + "groups": [group_name], + "scopes": [f"access:services!service={service_name}"], + }, +] + + # dummy spawner and authenticator for testing, don't actually use these! c.JupyterHub.authenticator_class = 'dummy' c.JupyterHub.spawner_class = 'simple' +c.JupyterHub.ip = '127.0.0.1' # let's just run on localhost while dummy auth is enabled diff --git a/examples/service-notebook/managed/jupyterhub_config.py b/examples/service-notebook/managed/jupyterhub_config.py index f9ef721f..10b95ef0 100644 --- a/examples/service-notebook/managed/jupyterhub_config.py +++ b/examples/service-notebook/managed/jupyterhub_config.py @@ -1,19 +1,35 @@ # our user list -c.Authenticator.whitelist = ['minrk', 'ellisonbg', 'willingc'] - -# ellisonbg and willingc have access to a shared server: - -c.JupyterHub.load_groups = {'shared': ['ellisonbg', 'willingc']} +c.Authenticator.allowed_users = ['minrk', 'ellisonbg', 'willingc'] service_name = 'shared-notebook' service_port = 9999 group_name = 'shared' +# ellisonbg and willingc have access to a shared server: + +c.JupyterHub.load_groups = {group_name: ['ellisonbg', 'willingc']} + # start the notebook server as a service c.JupyterHub.services = [ { 'name': service_name, 'url': 'http://127.0.0.1:{}'.format(service_port), - 'command': ['jupyterhub-singleuser', '--group=shared', '--debug'], + 'command': ['jupyterhub-singleuser', '--debug'], } ] + +# This "role assignment" is what grants members of the group +# access to the service +c.JupyterHub.load_roles = [ + { + "name": "shared-notebook", + "groups": [group_name], + "scopes": [f"access:services!service={service_name}"], + }, +] + + +# dummy spawner and authenticator for testing, don't actually use these! +c.JupyterHub.authenticator_class = 'dummy' +c.JupyterHub.spawner_class = 'simple' +c.JupyterHub.ip = '127.0.0.1' # let's just run on localhost while dummy auth is enabled diff --git a/examples/service-whoami/README.md b/examples/service-whoami/README.md index 2a94385e..2fb59f02 100644 --- a/examples/service-whoami/README.md +++ b/examples/service-whoami/README.md @@ -2,15 +2,15 @@ Uses `jupyterhub.services.HubAuthenticated` to authenticate requests with the Hub. -There is an implementation each of cookie-based `HubAuthenticated` and OAuth-based `HubOAuthenticated`. +There is an implementation each of api-token-based `HubAuthenticated` and OAuth-based `HubOAuthenticated`. ## Run -1. Launch JupyterHub and the `whoami service` with +1. Launch JupyterHub and the `whoami` services with jupyterhub --ip=127.0.0.1 -2. Visit http://127.0.0.1:8000/services/whoami or http://127.0.0.1:8000/services/whoami-oauth +2. Visit http://127.0.0.1:8000/services/whoami-oauth After logging in with your local-system credentials, you should see a JSON dump of your user info: @@ -24,15 +24,65 @@ After logging in with your local-system credentials, you should see a JSON dump } ``` +The `whoami-api` service powered by the base `HubAuthenticated` class only supports token-authenticated API requests, +not browser visits, because it does not implement OAuth. Visit it by requesting an api token from the tokens page, +and making a direct request: + +```bash +$ curl -H "Authorization: token 8630bbd8ef064c48b22c7f122f0cd8ad" http://127.0.0.1:8000/services/whoami-api/ | jq . +{ + "admin": false, + "created": "2021-05-21T09:47:41.299400Z", + "groups": [], + "kind": "user", + "last_activity": "2021-05-21T09:49:08.290745Z", + "name": "test", + "pending": null, + "roles": [ + "user" + ], + "scopes": [ + "access:services", + "access:users:servers!user=test", + "read:users!user=test", + "read:users:activity!user=test", + "read:users:groups!user=test", + "read:users:name!user=test", + "read:users:servers!user=test", + "read:users:tokens!user=test", + "users!user=test", + "users:activity!user=test", + "users:groups!user=test", + "users:name!user=test", + "users:servers!user=test", + "users:tokens!user=test" + ], + "server": null +} +``` + This relies on the Hub starting the whoami services, via config (see [jupyterhub_config.py](./jupyterhub_config.py)). -You may set the `hub_users` configuration in the service script -to restrict access to the service to a whitelist of allowed users. -By default, any authenticated user is allowed. +To govern access to the services, create **roles** with the scope `access:services!service=$service-name`, +and assign users to the scope. + +The jupyterhub_config.py grants access for all users to all services via the default 'user' role, with: + +```python +c.JupyterHub.load_roles = [ + { + "name": "user", + # grant all users access to all services + "scopes": ["access:services", "self"], + } +] +``` A similar service could be run externally, by setting the JupyterHub service environment variables: JUPYTERHUB_API_TOKEN JUPYTERHUB_SERVICE_PREFIX + JUPYTERHUB_OAUTH_SCOPES + JUPYTERHUB_CLIENT_ID # for whoami-oauth only or instantiating and configuring a HubAuth object yourself, and attaching it as `self.hub_auth` in your HubAuthenticated handlers. diff --git a/examples/service-whoami/jupyterhub_config.py b/examples/service-whoami/jupyterhub_config.py index 1d1f9435..c1363e62 100644 --- a/examples/service-whoami/jupyterhub_config.py +++ b/examples/service-whoami/jupyterhub_config.py @@ -2,7 +2,7 @@ import sys c.JupyterHub.services = [ { - 'name': 'whoami', + 'name': 'whoami-api', 'url': 'http://127.0.0.1:10101', 'command': [sys.executable, './whoami.py'], }, @@ -12,3 +12,16 @@ c.JupyterHub.services = [ 'command': [sys.executable, './whoami-oauth.py'], }, ] + +c.JupyterHub.load_roles = [ + { + "name": "user", + # grant all users access to all services + "scopes": ["access:services", "self"], + } +] + +# dummy spawner and authenticator for testing, don't actually use these! +c.JupyterHub.authenticator_class = 'dummy' +c.JupyterHub.spawner_class = 'simple' +c.JupyterHub.ip = '127.0.0.1' # let's just run on localhost while dummy auth is enabled diff --git a/examples/service-whoami/whoami-oauth.py b/examples/service-whoami/whoami-oauth.py index 72c97dda..b2158e51 100644 --- a/examples/service-whoami/whoami-oauth.py +++ b/examples/service-whoami/whoami-oauth.py @@ -1,6 +1,6 @@ """An example service authenticating with the Hub. -This example service serves `/services/whoami/`, +This example service serves `/services/whoami-oauth/`, authenticated with the Hub, showing the user their own info. """ @@ -20,13 +20,6 @@ from jupyterhub.utils import url_path_join class WhoAmIHandler(HubOAuthenticated, RequestHandler): - # hub_users can be a set of users who are allowed to access the service - # `getuser()` here would mean only the user who started the service - # can access the service: - - # from getpass import getuser - # hub_users = {getuser()} - @authenticated def get(self): user_model = self.get_current_user() diff --git a/examples/service-whoami/whoami.py b/examples/service-whoami/whoami.py index 2a5a3373..435ff329 100644 --- a/examples/service-whoami/whoami.py +++ b/examples/service-whoami/whoami.py @@ -1,6 +1,8 @@ """An example service authenticating with the Hub. -This serves `/services/whoami/`, authenticated with the Hub, showing the user their own info. +This serves `/services/whoami-api/`, authenticated with the Hub, showing the user their own info. + +HubAuthenticated only supports token-based access. """ import json import os @@ -16,13 +18,6 @@ from jupyterhub.services.auth import HubAuthenticated class WhoAmIHandler(HubAuthenticated, RequestHandler): - # hub_users can be a set of users who are allowed to access the service - # `getuser()` here would mean only the user who started the service - # can access the service: - - # from getpass import getuser - # hub_users = {getuser()} - @authenticated def get(self): user_model = self.get_current_user() diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index 1066a9d7..0127883e 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -824,13 +824,26 @@ class UserNotAllowed(Exception): ) -class HubAuthenticated(object): +class HubAuthenticated: """Mixin for tornado handlers that are authenticated with JupyterHub A handler that mixes this in must have the following attributes/properties: - .hub_auth: A HubAuth instance - .hub_scopes: A set of JupyterHub 2.0 OAuth scopes to allow. + Default comes from .hub_auth.oauth_scopes, + which in turn is set by $JUPYTERHUB_OAUTH_SCOPES + Default values include: + - 'access:services', 'access:services!service={service_name}' for services + - 'access:users:servers', 'access:users:servers!user={user}', + 'access:users:servers!server={user}/{server_name}' + for single-user servers + + If hub_scopes is not used (e.g. JupyterHub 1.x), + these additional properties can be used: + + - .allow_admin: If True, allow any admin user. + Default: False. - .hub_users: A set of usernames to allow. If left unspecified or None, username will not be checked. - .hub_groups: A set of group names to allow. @@ -943,6 +956,8 @@ class HubAuthenticated(object): # note: this means successful authentication, but insufficient permission raise UserNotAllowed(model) + # proceed with the pre-2.0 way if hub_scopes is not set + if self.allow_admin and model.get('admin', False): app_log.debug("Allowing Hub admin %s", name) return model From fbea31d00a0c1f5f72d119def72322c1246dd54a Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 21 May 2021 15:23:31 +0200 Subject: [PATCH 221/270] support groups in _intersect_scopes Requires db resolution --- jupyterhub/scopes.py | 119 +++++++++++++++++++++------- jupyterhub/services/auth.py | 4 +- jupyterhub/tests/test_scopes.py | 78 ++++++++++++++++++ jupyterhub/tests/test_singleuser.py | 14 ++++ 4 files changed, 184 insertions(+), 31 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index afce5974..32276a20 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -13,7 +13,9 @@ import functools import inspect import warnings from enum import Enum +from functools import lru_cache +import sqlalchemy as sa from tornado import web from tornado.log import app_log @@ -114,21 +116,38 @@ class Scope(Enum): ALL = True -def _intersect_expanded_scopes(scopes_a, scopes_b): - """Intersect two sets of expanded scopes by comparing their permissions +def _intersect_expanded_scopes(scopes_a, scopes_b, db=None): + """Intersect two sets of scopes by comparing their permissions Arguments: scopes_a, scopes_b: sets of expanded scopes + db (optional): db connection for resolving group membership Returns: intersection: set of expanded scopes as intersection of the arguments - Note: Intersects correctly with ALL and exact filter matches - (i.e. users!user=x & read:users:name -> read:users:name!user=x) - - Does not currently intersect with containing filters - (i.e. users!group=x & users!user=y even if user y is in group x) + If db is given, group membership will be accounted for in intersections, + Otherwise, it can result in lower than intended permissions, + (i.e. users!group=x & users!user=y will be empty, even if user y is in group x.) """ + empty_set = frozenset() + + # cached lookups for group membership of users and servers + @lru_cache() + def groups_for_user(username): + """Get set of group names for a given username""" + user = db.query(orm.User).filter_by(name=username).first() + if user is None: + return empty_set + else: + return {group.name for group in user.groups} + + @lru_cache() + def groups_for_server(server): + """Get set of group names for a given server""" + username, _, servername = server.partition("/") + return groups_for_user(username) + parsed_scopes_a = parse_scopes(scopes_a) parsed_scopes_b = parse_scopes(scopes_b) @@ -144,11 +163,14 @@ def _intersect_expanded_scopes(scopes_a, scopes_b): elif filters_b == Scope.ALL: common_filters[base] = filters_a else: - # warn *if* there are non-overlapping user= and group= filters common_entities = filters_a.keys() & filters_b.keys() all_entities = filters_a.keys() | filters_b.keys() + + # if we don't have a db session, we can't check group membership + # warn *if* there are non-overlapping user= and group= filters that we can't check if ( - not warned + db is None + and not warned and 'group' in all_entities and ('user' in all_entities or 'server' in all_entities) ): @@ -160,39 +182,67 @@ def _intersect_expanded_scopes(scopes_a, scopes_b): not warned and "group" in a and b_key in b - and set(a["group"]).difference(b.get("group", [])) - and set(b[b_key]).difference(a.get(b_key, [])) + and a["group"].difference(b.get("group", [])) + and b[b_key].difference(a.get(b_key, [])) ): warnings.warn( f"{base}[!{b_key}={b[b_key]}, !group={a['group']}] combinations of filters present," - " intersection between not considered. May result in lower than intended permissions.", + " without db access. Intersection between not considered." + " May result in lower than intended permissions.", UserWarning, ) warned = True common_filters[base] = { - entity: set(parsed_scopes_a[base][entity]) - & set(parsed_scopes_b[base][entity]) + entity: filters_a[entity] & filters_b[entity] for entity in common_entities } - if 'server' in all_entities and 'user' in all_entities: - if filters_a.get('server') == filters_b.get('server'): - continue + # resolve hierarchies (group/user/server) in both directions + common_servers = common_filters[base].get("server", set()) + common_users = common_filters[base].get("user", set()) - additional_servers = set() - # resolve user/server hierarchy in both directions - for a, b in [(filters_a, filters_b), (filters_b, filters_a)]: - if 'server' in a and 'user' in b: - for server in a['server']: + for a, b in [(filters_a, filters_b), (filters_b, filters_a)]: + if 'server' in a and b.get('server') != a['server']: + # skip already-added servers (includes overlapping servers) + servers = a['server'].difference(common_servers) + + # resolve user/server hierarchy + if servers and 'user' in b: + for server in servers: username, _, servername = server.partition("/") if username in b['user']: - additional_servers.add(server) + common_servers.add(server) - if additional_servers: - if "server" not in common_filters[base]: - common_filters[base]["server"] = set() - common_filters[base]["server"].update(additional_servers) + # resolve group/server hierarchy if db available + servers = servers.difference(common_servers) + if db is not None and servers and 'group' in b: + for server in servers: + server_groups = groups_for_server(server) + if server_groups & b['group']: + common_servers.add(server) + + # resolve group/user hierarchy if db available and user sets aren't identical + if ( + db is not None + and 'user' in a + and 'group' in b + and b.get('user') != a['user'] + ): + # skip already-added users (includes overlapping users) + users = a['user'].difference(common_users) + for username in users: + groups = groups_for_user(username) + if groups & b["group"]: + common_users.add(username) + + # add server filter if there wasn't one before + if common_servers and "server" not in common_filters[base]: + common_filters[base]["server"] = common_servers + + # add user filter if it's non-empty and there wasn't one before + if common_users and "user" not in common_filters[base]: + common_filters[base]["user"] = common_users return unparse_scopes(common_filters) @@ -244,11 +294,21 @@ def get_scopes_for(orm_object): ) owner_scopes = roles.expand_roles_to_scopes(owner) + + if token_scopes == {'all'}: + # token_scopes is only 'all', return owner scopes as-is + # short-circuit common case where we don't need to compute an intersection + return owner_scopes + if 'all' in token_scopes: token_scopes.remove('all') token_scopes |= owner_scopes - intersection = _intersect_expanded_scopes(token_scopes, owner_scopes) + intersection = _intersect_expanded_scopes( + token_scopes, + owner_scopes, + db=sa.inspect(orm_object).session, + ) discarded_token_scopes = token_scopes - intersection # Not taking symmetric difference here because token owner can naturally have more scopes than token @@ -473,7 +533,8 @@ def check_scope_filter(sub_scope, orm_resource, kind): # Fall back on checking if we have group access for this user orm_resource = orm_resource.user kind = 'user' - elif kind == 'user' and 'group' in sub_scope: + + if kind == 'user' and 'group' in sub_scope: group_names = {group.name for group in orm_resource.groups} user_in_group = bool(group_names & set(sub_scope['group'])) if user_in_group: diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index 0127883e..64080723 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -38,7 +38,7 @@ from traitlets import Unicode from traitlets import validate from traitlets.config import SingletonConfigurable -from ..scopes import _intersect_scopes +from ..scopes import _intersect_expanded_scopes from ..utils import url_path_join @@ -70,7 +70,7 @@ def check_scopes(required_scopes, scopes): if isinstance(required_scopes, str): required_scopes = {required_scopes} - intersection = _intersect_scopes(required_scopes, scopes) + intersection = _intersect_expanded_scopes(required_scopes, scopes) # re-intersect with required_scopes in case the intersection # applies stricter filters than required_scopes declares # e.g. required_scopes = {'read:users'} and intersection has only {'read:users!user=x'} diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 81642cba..305112f7 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -763,3 +763,81 @@ def test_intersect_expanded_scopes(left, right, expected, should_warn, recwarn): assert len(recwarn) == 1 else: assert len(recwarn) == 0 + + +@pytest.mark.parametrize( + "left, right, expected, groups", + [ + ( + ["users!group=gx"], + ["users!user=ux"], + ["users!user=ux"], + {"gx": ["ux"]}, + ), + ( + ["read:users!group=gx"], + ["read:users!user=nosuchuser"], + [], + {}, + ), + ( + ["read:users!group=gx"], + ["read:users!server=nosuchuser/server"], + [], + {}, + ), + ( + ["read:users!group=gx"], + ["read:users!server=ux/server"], + ["read:users!server=ux/server"], + {"gx": ["ux"]}, + ), + ( + ["read:users!group=gx"], + ["read:users!server=ux/server", "read:users!user=uy"], + ["read:users!server=ux/server"], + {"gx": ["ux"], "gy": ["uy"]}, + ), + ( + ["read:users!group=gy"], + ["read:users!server=ux/server", "read:users!user=uy"], + ["read:users!user=uy"], + {"gx": ["ux"], "gy": ["uy"]}, + ), + ], +) +def test_intersect_groups(request, db, left, right, expected, groups): + if isinstance(left, str): + left = set([left]) + if isinstance(right, str): + right = set([right]) + + # if we have a db connection, we can actually resolve + created = [] + for groupname, members in groups.items(): + group = orm.Group.find(db, name=groupname) + if not group: + group = orm.Group(name=groupname) + db.add(group) + created.append(group) + db.commit() + for username in members: + user = orm.User.find(db, name=username) + if user is None: + user = orm.User(name=username) + db.add(user) + created.append(user) + user.groups.append(group) + db.commit() + + def _cleanup(): + for obj in created: + db.delete(obj) + db.commit() + + request.addfinalizer(_cleanup) + + # run every test in both directions, to ensure symmetry of the inputs + for a, b in [(left, right), (right, left)]: + intersection = _intersect_expanded_scopes(set(left), set(right), db) + assert intersection == set(expected) diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index 0b0eef5a..d2fe3657 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -6,6 +6,7 @@ from urllib.parse import urlparse import pytest import jupyterhub +from .. import orm from ..utils import url_path_join from .mocking import public_url from .mocking import StubSingleUserSpawner @@ -16,6 +17,8 @@ from .utils import AsyncSession @pytest.mark.parametrize( "access_scopes, server_name, expect_success", [ + (["access:users:servers!group=$group"], "", True), + (["access:users:servers!group=other-group"], "", False), (["access:users:servers"], "", True), (["access:users:servers"], "named", True), (["access:users:servers!user=$user"], "", True), @@ -46,6 +49,16 @@ async def test_singleuser_auth( # login, start the server cookies = await app.login_user('nandy') user = app.users['nandy'] + + group = orm.Group.find(app.db, name="visitors") + if group is None: + group = orm.Group(name="visitors") + app.db.add(group) + app.db.commit() + if group not in user.groups: + user.groups.append(group) + app.db.commit() + if server_name not in user.spawners or not user.spawners[server_name].active: await user.spawn(server_name) await app.proxy.add_user(user, server_name) @@ -85,6 +98,7 @@ async def test_singleuser_auth( access_scopes = [ s.replace("$server", f"{user.name}/{server_name}") for s in access_scopes ] + access_scopes = [s.replace("$group", f"{group.name}") for s in access_scopes] other_user = create_user_with_scopes(*access_scopes, name="burgess") cookies = await app.login_user('burgess') From 3270bc76afe4ae36b916c774910da8851dc644b7 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 26 May 2021 07:18:18 +0000 Subject: [PATCH 222/270] readme typo Co-authored-by: Ivana --- examples/service-announcement/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/service-announcement/README.md b/examples/service-announcement/README.md index 4be75b57..0582facc 100644 --- a/examples/service-announcement/README.md +++ b/examples/service-announcement/README.md @@ -57,7 +57,7 @@ The time the announcement was posted is recorded in the `timestamp` field and the user who posted the announcement is recorded in the `user` field. To clear the announcement text, send a DELETE request. -This has the same permissionOnly admin users can do this. +This has the same permission requirement. $ curl -X DELETE -H "Authorization: token " \ https://.../services/announcement/ From 4a0fed1a5b7c8640e83e6138bcd033409b3e53a9 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 26 May 2021 09:19:02 +0200 Subject: [PATCH 223/270] address review in services doc --- docs/source/reference/services.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/source/reference/services.md b/docs/source/reference/services.md index ab7d8da0..a78e8707 100644 --- a/docs/source/reference/services.md +++ b/docs/source/reference/services.md @@ -90,8 +90,9 @@ c.JupyterHub.load_roles = [ { "name": "idle-culler", "scopes": [ - "users:servers", - # also 'admin:users' if culling idle users as well + "read:users:activity", # read user last_activity + "users:servers", # start and stop servers + # 'admin:users' # needed if culling idle users as well ] } @@ -283,8 +284,8 @@ If you don't want to use the reference implementation (e.g. you find the implementation a poor fit for your Flask app), you can implement authentication via the Hub yourself. JupyterHub is a standard OAuth2 provider, -so you can any OAuth 2 implementation appropriate for -See the [FastAPI example][] for an example of using JupyterHub as an OAuth provider with fastapi, +so you can use any OAuth 2 client implementation appropriate for your toolkit. +See the [FastAPI example][] for an example of using JupyterHub as an OAuth provider with [FastAPI][], without using any code imported from JupyterHub. On completion of OAuth, you will have an access token for JupyterHub, @@ -356,4 +357,5 @@ section on securing the notebook viewer. [hubauthenticated]: ../api/services.auth.html#jupyterhub.services.auth.HubAuthenticated [nbviewer example]: https://github.com/jupyter/nbviewer#securing-the-notebook-viewer [fastapi example]: https://github.com/jupyterhub/jupyterhub/tree/HEAD/examples/service-fastapi +[fastapi]: https://fastapi.tiangolo.com [jupyterhub_idle_culler]: https://github.com/jupyterhub/jupyterhub-idle-culler From 1dab57af6fc492b24b85052827ca88169fd9fdf8 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 8 Jun 2021 09:48:11 +0200 Subject: [PATCH 224/270] remove invalid access scope test --- jupyterhub/tests/test_singleuser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index d2fe3657..bf3b0905 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -31,7 +31,6 @@ from .utils import AsyncSession (["access:users:servers!user=$other"], "named", False), (["access:services"], "", False), (["self"], "named", False), - (["admin"], "", False), ([], "", False), ], ) From 2ac1cfe4ace49ed12a7b2ef9e371d879dac46ffc Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 8 Jun 2021 14:01:04 +0200 Subject: [PATCH 225/270] finegrained service model access --- jupyterhub/apihandlers/base.py | 28 ++++++++++++++++++---------- jupyterhub/apihandlers/users.py | 2 ++ jupyterhub/roles.py | 1 + jupyterhub/tests/test_scopes.py | 2 ++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 917485af..b8a72dbf 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -293,16 +293,24 @@ class APIHandler(BaseHandler): def service_model(self, service): """Get the JSON model for a Service object""" - model = {} - scope_filter = self.get_scope_filter('read:services') - if scope_filter(service, kind='service'): - model = { - 'kind': 'service', - 'name': service.name, - 'roles': [r.name for r in service.roles], - 'admin': service.admin, - } - # todo: Remove once we replace admin flag with role check + model = { + 'kind': 'service', + 'name': service.name, + 'roles': [r.name for r in service.roles], + 'admin': service.admin, + } + # todo: remove admin key now we have roles? + access_map = { + 'read:services': {'kind', 'name', 'roles', 'admin'}, + 'read:services:name': {'kind', 'name'}, + 'read:services:roles': {'kind', 'name', 'roles'}, + } + allowed_keys = set() + for scope in access_map: + scope_filter = self.get_scope_filter(scope) + if scope_filter(service, kind='service'): + allowed_keys |= access_map[scope] + model = {key: model[key] for key in allowed_keys} return model _user_model_types = { diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index ac2a6461..e3171538 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -62,6 +62,7 @@ class UserListAPIHandler(APIHandler): 'read:users:servers', 'read:users:groups', 'read:users:activity', + 'read:users:roles', ) def get(self): state_filter = self.get_argument("state", None) @@ -176,6 +177,7 @@ class UserAPIHandler(APIHandler): 'read:users:servers', 'read:users:groups', 'read:users:activity', + 'read:users:roles', ) async def get(self, user_name): user = self.find_user(user_name) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 6e3f1c90..493f625d 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -67,6 +67,7 @@ def expand_self_scope(name): 'users:activity', 'users:servers', 'users:tokens', + 'users:roles', ] read_scope_list = ['read:' + scope for scope in scope_list] scope_list.extend(read_scope_list) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 5569a29f..46dabc70 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -722,6 +722,7 @@ async def test_server_state_access( 'read:users!user=y', 'read:users:name!user=y', 'read:users:groups!user=y', + 'read:users:roles!user=y', 'read:users:activity!user=y', }, ), @@ -733,6 +734,7 @@ async def test_server_state_access( 'read:users!user=y', 'read:users:name!user=y', 'read:users:groups!user=y', + 'read:users:roles!user=y', 'read:users:activity!user=y', }, ), From 18623dc9de0a666fe011f564dfc1e8a3fbbbdd19 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 8 Jun 2021 15:18:57 +0200 Subject: [PATCH 226/270] Unified service model --- jupyterhub/apihandlers/base.py | 9 +++++- jupyterhub/apihandlers/services.py | 26 +++------------- jupyterhub/tests/test_api.py | 2 ++ jupyterhub/tests/test_scopes.py | 42 +++++++++++++++++++++----- jupyterhub/tests/test_services_auth.py | 5 +-- 5 files changed, 51 insertions(+), 33 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index b8a72dbf..45d03852 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -298,10 +298,17 @@ class APIHandler(BaseHandler): 'name': service.name, 'roles': [r.name for r in service.roles], 'admin': service.admin, + 'url': getattr(service, 'url', ''), + 'prefix': service.server.base_url if getattr(service, 'server', '') else '', + 'command': getattr(service, 'command', ''), + 'pid': service.proc.pid if getattr(service, 'proc', '') else 0, + 'info': getattr(service, 'info', ''), + 'display': getattr(service, 'display', ''), } # todo: remove admin key now we have roles? + # todo: More default keys present? access_map = { - 'read:services': {'kind', 'name', 'roles', 'admin'}, + 'read:services': set(model.keys()), 'read:services:name': {'kind', 'name'}, 'read:services:roles': {'kind', 'name', 'roles'}, } diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index f0b87c30..7db84ccc 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -6,34 +6,16 @@ Currently GET-only, no actions can be taken to modify services. # Distributed under the terms of the Modified BSD License. import json -from tornado import web - -from .. import orm from ..scopes import needs_scope from .base import APIHandler -def service_model(service): - """Produce the model for a service""" - return { - 'name': service.name, - 'admin': service.admin, - 'roles': [r.name for r in service.roles], - 'url': service.url, - 'prefix': service.server.base_url if service.server else '', - 'command': service.command, - 'pid': service.proc.pid if service.proc else 0, - 'info': service.info, - 'display': service.display, - } - - class ServiceListAPIHandler(APIHandler): - @needs_scope('read:services') + @needs_scope('read:services', 'read:services:name', 'read:services:roles') def get(self): scope_filter = self.get_scope_filter('read:services') data = { - name: service_model(service) + name: self.service_model(service) for name, service in self.services.items() if scope_filter(service, kind='service') } @@ -41,10 +23,10 @@ class ServiceListAPIHandler(APIHandler): class ServiceAPIHandler(APIHandler): - @needs_scope('read:services') + @needs_scope('read:services', 'read:services:name', 'read:services:roles') def get(self, service_name): service = self.services[service_name] - self.write(json.dumps(service_model(service))) + self.write(json.dumps(self.service_model(service))) default_handlers = [ diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 9bd66be9..336fcad1 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -1606,6 +1606,7 @@ async def test_get_services(app, mockservice_url): services = r.json() assert services == { mockservice.name: { + 'kind': 'service', 'name': mockservice.name, 'admin': True, 'roles': ['admin'], @@ -1631,6 +1632,7 @@ async def test_get_service(app, mockservice_url): service = r.json() assert service == { + 'kind': 'service', 'name': mockservice.name, 'admin': True, 'roles': ['admin'], diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 46dabc70..7b06738b 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -763,13 +763,39 @@ async def test_resolve_token_permissions( assert token_retained_scopes == intersection_scopes +@mark.parametrize( + "scopes, model_keys", + [ + ( + {'read:services'}, + { + 'command', + 'name', + 'kind', + 'info', + 'display', + 'pid', + 'admin', + 'prefix', + 'url', + 'roles', + }, + ), + ({'read:services:roles', 'read:users:names'}, {'name', 'kind', 'roles'}), + ({'read:services:name'}, {'name', 'kind'}), + ], +) +async def test_service_model_filtering( + app, scopes, model_keys, create_user_with_scopes, create_service_with_scopes +): + user = create_user_with_scopes(*scopes, 'teddy') + service = create_service_with_scopes() + r = await api_request( + app, 'services', service.name, headers=auth_header(app.db, user.name) + ) + assert r.status_code == 200 + assert model_keys == r.json().keys() + + async def test_roles_access(app, create_user_with_scopes): pass - - -async def test_service_model_filtering(app, create_user_with_scopes): - pass - - -async def test_group_model_filtering(app, create_user_with_scopes): - pass diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index ac10661e..51e69c4e 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -298,7 +298,8 @@ async def test_hubauth_service_token(app, mockservice_url): ) r.raise_for_status() reply = r.json() - assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} + service_model = {'kind': 'service', 'name': name, 'admin': False, 'roles': []} + assert service_model.items() <= reply.items() assert not r.cookies # token in ?token parameter @@ -307,7 +308,7 @@ async def test_hubauth_service_token(app, mockservice_url): ) r.raise_for_status() reply = r.json() - assert reply == {'kind': 'service', 'name': name, 'admin': False, 'roles': []} + assert service_model.items() <= reply.items() r = await async_requests.get( public_url(app, mockservice_url) + '/whoami/?token=no-such-token', From 0233faf19d029696469116ee43253ad5f82a6e43 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 8 Jun 2021 15:26:06 +0200 Subject: [PATCH 227/270] Added tests --- jupyterhub/tests/test_scopes.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 7b06738b..8a6b6438 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -797,5 +797,12 @@ async def test_service_model_filtering( assert model_keys == r.json().keys() -async def test_roles_access(app, create_user_with_scopes): - pass +async def test_roles_access(app, create_service_with_scopes, create_user_with_scopes): + user = add_user(app.db, name='miranda') + read_user = create_user_with_scopes('read:users:roles') + r = await api_request( + app, 'users', user.name, headers=auth_header(app.db, read_user.name) + ) + assert r.status_code == 200 + model_keys = {'kind', 'name', 'roles'} + assert model_keys == r.json().keys() From bb577fca04431b780d52d8297d0657596efd9eba Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 8 Jun 2021 15:55:49 +0200 Subject: [PATCH 228/270] Resolved merge conflicts and updated tests --- jupyterhub/scopes.py | 11 ++++------- jupyterhub/tests/test_scopes.py | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index bdf0c4bb..255c4a24 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -22,7 +22,6 @@ from tornado.log import app_log from . import orm from . import roles - scope_definitions = { '(no_scope)': {'description': 'Allows for only identifying the owning entity.'}, 'self': { @@ -48,13 +47,13 @@ scope_definitions = { 'read:users:name', 'read:users:groups', 'read:users:activity', + 'read:users:roles', ], - # TODO: add read:users:roles as subscopes here once implemented }, 'read:users:name': {'description': 'Read-only access to users’ names.'}, 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, 'read:users:activity': {'description': 'Read-only access to users’ last activity.'}, - # TODO: add read:users:roles once implemented + 'read:users:roles': {'description': 'Read-only access to users’ roles.'}, 'users:activity': { 'description': 'Grants access to read and post users’ last activity only.', 'subscopes': ['read:users:activity'], @@ -90,12 +89,10 @@ scope_definitions = { 'read:groups': {'description': 'Read-only access to groups’ models.'}, 'read:services': { 'description': 'Read-only access to service models.', - 'subscopes': ['read:services:name'], - # TODO: add read:services:roles as subscopes here once implemented + 'subscopes': ['read:services:name', 'read:services:roles'], }, 'read:services:name': {'description': 'Read-only access to service names.'}, - # TODO: add read:services:roles once implemented - #'read:services:roles': {'description': 'Read-only access to service role names.'}, + 'read:services:roles': {'description': 'Read-only access to service role names.'}, 'read:hub': { 'description': 'Read-only access to detailed information about the Hub.' }, diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 0e51ad55..660470c7 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -706,14 +706,14 @@ async def test_resolve_token_permissions( 'roles', }, ), - ({'read:services:roles', 'read:users:names'}, {'name', 'kind', 'roles'}), + ({'read:services:roles', 'read:users:name'}, {'name', 'kind', 'roles'}), ({'read:services:name'}, {'name', 'kind'}), ], ) async def test_service_model_filtering( app, scopes, model_keys, create_user_with_scopes, create_service_with_scopes ): - user = create_user_with_scopes(*scopes, 'teddy') + user = create_user_with_scopes(*scopes, name='teddy') service = create_service_with_scopes() r = await api_request( app, 'services', service.name, headers=auth_header(app.db, user.name) From c121a1731042e6da341f790f78a794f966181ec8 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 9 Jun 2021 09:10:51 +0200 Subject: [PATCH 229/270] Removed default service roles from upgrade and docs --- docs/source/rbac/roles.md | 7 +++++-- jupyterhub/roles.py | 2 +- jupyterhub/tests/test_roles.py | 18 ++++-------------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 49aeaeda..a8bb35a9 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -25,8 +25,11 @@ Roles can be assigned to the following entities: An entity can have zero, one, or multiple roles, and there are no restrictions on which roles can be assigned to which entity. Roles can be added to or removed from entities at any time. -**Users and services** \ -When a new user or service gets created, they are assigned their default role ( `user` or `admin`) if no custom role is requested, currently based on their admin status. +**Users** \ +When a new user gets created, they are assigned their default role ( `user` or `admin`) if no custom role is requested, currently based on their admin status. + +**Services** \ +Services do not have a default role. Services without roles have no access to the guarded API end-points, so most services will require assignment of a role in order to function. **Groups** \ A group does not require any role, and has no roles by default. If a user is a member of a group, they automatically inherit any of the group's permissions (see {ref}`resolving-roles-scopes-target` for more details). This is useful for assigning a set of common permissions to several users. diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 6417a3e6..1f8bcc12 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -488,7 +488,7 @@ def check_for_default_roles(db, bearer): Groups can be without a role """ Class = orm.get_class(bearer) - if Class == orm.Group: + if Class in {orm.Group, orm.Service}: pass else: for obj in ( diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 72a68476..aa7f9f8d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -521,20 +521,10 @@ async def test_load_roles_services(tmpdir, request): # test if predefined roles loaded and assigned culler_role = orm.Role.find(db, name='idle-culler') culler_service = orm.Service.find(db, name='idle-culler') - assert culler_role in culler_service.roles - - # test if every service has a role (and no duplicates) - for service in db.query(orm.Service): - assert len(service.roles) > 0 - assert len(service.roles) == len(set(service.roles)) - - # test default role assignment - if service.admin: - assert admin_role in service.roles - assert user_role not in service.roles - elif culler_role not in service.roles: - assert user_role in service.roles - assert admin_role not in service.roles + assert culler_service.roles == [culler_role] + user_service = orm.Service.find(db, name='user_service') + assert not user_service.roles + assert admin_service.roles == [admin_role] # delete the test services for service in db.query(orm.Service): From 1d93d6e99b55dbb1a385ea34926a607794095f05 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 May 2021 15:12:53 +0200 Subject: [PATCH 230/270] fix allowed_role assignment from service config Service.oauth_roles is list of names, OAuthClient.allowed_roles is list of orm.Roles --- jupyterhub/app.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 7fb3a775..1e5eb048 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2264,7 +2264,11 @@ class JupyterHub(Application): client_id=service.oauth_client_id, client_secret=service.api_token, redirect_uri=service.oauth_redirect_uri, - allowed_roles=service.oauth_roles, + allowed_roles=list( + self.db.query(orm.Role).filter( + orm.Role.name.in_(service.oauth_roles) + ) + ), description="JupyterHub service %s" % service.name, ) service.orm.oauth_client_id = service.oauth_client_id From deb03d40062bf2a8803a0761e8f105f639c16101 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 May 2021 15:13:38 +0200 Subject: [PATCH 231/270] Fix user role list adding `read:` to everything isn't right because not everything has a `read:` counterpart and not every `read:` has a write counterpart --- jupyterhub/roles.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 1f8bcc12..329e82f9 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -81,16 +81,17 @@ def expand_self_scope(name): """ scope_list = [ 'users', - 'users:name', - 'users:groups', + 'read:users', + 'read:users:name', + 'read:users:groups', 'users:activity', + 'read:users:activity', 'users:servers', + 'read:users:servers', 'users:tokens', + 'read:users:tokens', + 'access:users:servers', ] - read_scope_list = ['read:' + scope for scope in scope_list] - # access doesn't want the 'read:' prefix - scope_list.append('access:users:servers') - scope_list.extend(read_scope_list) return {"{}!user={}".format(scope, name) for scope in scope_list} @@ -164,24 +165,22 @@ def expand_roles_to_scopes(orm_object): return expanded_scopes -def _get_subscopes(*args, owner=None): +def _get_subscopes(*roles, owner=None): """Returns a set of all available subscopes for a specified role or list of roles Arguments: - role (obj): orm.Role - or - roles (list): list of orm.Roles + roles (obj): orm.Roles owner (obj, optional): orm.User or orm.Service as owner of orm.APIToken Returns: expanded scopes (set): set of all expanded scopes for the role(s) """ - scope_list = [] + scopes = set() - for role in args: - scope_list.extend(role.scopes) + for role in roles: + scopes.update(role.scopes) - expanded_scopes = set(chain.from_iterable(list(map(_expand_scope, scope_list)))) + expanded_scopes = set(chain.from_iterable(list(map(_expand_scope, scopes)))) # transform !user filter to !user=ownername for scope in expanded_scopes: From b97b05343c037f507b322ffc0b70e74679ab7a62 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 May 2021 15:15:37 +0200 Subject: [PATCH 232/270] WIP: show permissions on authorize page incomplete because the current text isn't formatted appropriately for the "will be able to do..." framing of an authorization page --- examples/service-whoami/jupyterhub_config.py | 1 + jupyterhub/apihandlers/auth.py | 105 +++++++++++++------ jupyterhub/scopes.py | 68 ++++++++++++ share/jupyterhub/templates/oauth.html | 33 +++--- 4 files changed, 160 insertions(+), 47 deletions(-) diff --git a/examples/service-whoami/jupyterhub_config.py b/examples/service-whoami/jupyterhub_config.py index c1363e62..bc480adf 100644 --- a/examples/service-whoami/jupyterhub_config.py +++ b/examples/service-whoami/jupyterhub_config.py @@ -10,6 +10,7 @@ c.JupyterHub.services = [ 'name': 'whoami-oauth', 'url': 'http://127.0.0.1:10102', 'command': [sys.executable, './whoami-oauth.py'], + 'oauth_roles': ['user'], }, ] diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index 7506dd40..f36cfcf0 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -1,6 +1,7 @@ """Authorization handlers""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import itertools import json from datetime import datetime from urllib.parse import parse_qsl @@ -13,6 +14,7 @@ from oauthlib import oauth2 from tornado import web from .. import orm +from .. import roles from .. import scopes from ..utils import token_authenticated from .base import APIHandler @@ -174,12 +176,16 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): raise self.send_oauth_response(headers, body, status) - def needs_oauth_confirm(self, user, oauth_client): + def needs_oauth_confirm(self, user, oauth_client, roles): """Return whether the given oauth client needs to prompt for access for the given user Checks list for oauth clients that don't need confirmation - (i.e. the user's own server) + Sources: + + - the user's own servers + - Clients which already have authorization for the same roles + - Explicit oauth_no_confirm_list configuration (e.g. admin-operated services) .. versionadded: 1.1 """ @@ -195,6 +201,30 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): in self.settings.get('oauth_no_confirm_list', set()) ): return False + + # Check existing authorization + existing_tokens = self.db.query(orm.APIToken).filter_by( + user_id=user.id, + client_id=oauth_client.identifier, + ) + authorized_roles = set() + for token in existing_tokens: + authorized_roles.update({role.name for role in token.roles}) + + if authorized_roles: + if set(roles).issubset(authorized_roles): + self.log.debug( + f"User {user.name} has already authorized {oauth_client.identifier} for roles {roles}" + ) + # FIXME: uncomment after debugging + # it's easier to run manual tests + # if we always show the confirmation page + # return False + else: + self.log.debug( + f"User {user.name} has authorized {oauth_client.identifier}" + f" for roles {authorized_roles}, confirming additonal roles {roles}" + ) # default: require confirmation return True @@ -211,53 +241,66 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): uri, http_method, body, headers = self.extract_oauth_params() try: - scopes, credentials = self.oauth_provider.validate_authorization_request( + ( + role_names, + credentials, + ) = self.oauth_provider.validate_authorization_request( uri, http_method, body, headers ) credentials = self.add_credentials(credentials) client = self.oauth_provider.fetch_by_client_id(credentials['client_id']) - allowed = False - - # check for access to target resource - if client.spawner: - scope_filter = self.get_scope_filter("access:users:servers") - allowed = scope_filter(client.spawner, kind='server') - elif client.service: - scope_filter = self.get_scope_filter("access:services") - allowed = scope_filter(client.service, kind='service') - else: - # client is not associated with a service or spawner. - # This shouldn't happen, but it might if this is a stale or forged request - # from a service or spawner that's since been deleted - self.log.error( - f"OAuth client {client} has no service or spawner, cannot resolve scopes." - ) - raise web.HTTPError(500, "OAuth configuration error") - - if not allowed: - self.log.error( - f"User {self.current_user} not allowed to access {client.description}" - ) - raise web.HTTPError( - 403, f"You do not have permission to access {client.description}" - ) - if not self.needs_oauth_confirm(self.current_user, client): + if not self.needs_oauth_confirm(self.current_user, client, role_names): self.log.debug( "Skipping oauth confirmation for %s accessing %s", self.current_user, client.description, ) # this is the pre-1.0 behavior for all oauth - self._complete_login(uri, headers, scopes, credentials) + self._complete_login(uri, headers, role_names, credentials) return + # resolve roles to scopes for authorization page + role_objects = ( + self.db.query(orm.Role).filter(orm.Role.name.in_(role_names)).all() + ) + raw_scopes = set(itertools.chain(*(role.scopes for role in role_objects))) + if not raw_scopes: + scope_descriptions = [ + { + "scope": None, + "description": scopes.scope_definitions['(no_scope)'][ + 'description' + ], + "filter": "", + } + ] + elif 'all' in raw_scopes: + raw_scopes = ['all'] + expanded_scopes = ['all'] + scope_descriptions = [ + { + "scope": "all", + "description": scopes.scope_definitions['all']['description'], + "filter": "", + } + ] + else: + # expanded_scopes = roles._get_subscopes(*role_objects, owner=self.current_user.orm_user) + # print("expanded scopes", expanded_scopes, self.current_user) + # parsed_scopes = scopes.parse_scopes(expanded_scopes) + scope_descriptions = scopes.describe_raw_scopes( + raw_scopes, + username=self.current_user.name, + ) + print("scope definitions", raw_scopes, scope_descriptions) # Render oauth 'Authorize application...' page auth_state = await self.current_user.get_auth_state() self.write( await self.render_template( "oauth.html", auth_state=auth_state, - scopes=scopes, + role_names=role_names, + scope_descriptions=scope_descriptions, oauth_client=client, ) ) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 32276a20..f6123d0a 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -540,3 +540,71 @@ def check_scope_filter(sub_scope, orm_resource, kind): if user_in_group: return True return False + + +def describe_parsed_scopes(parsed_scopes, username=None): + """Return list of descriptions of parsed scopes + + Highly detailed, often redundant descriptions + """ + descriptions = [] + for scope, filters in parsed_scopes.items(): + base_text = scope_definitions[scope]["description"] + if filters == Scope.ALL: + # no filter + filter_text = "" + else: + filter_chunks = [] + for kind, names in filters.items(): + if kind == 'user' and names == {username}: + filter_chunks.append("only you") + else: + kind_text = kind + if kind == 'group': + kind_text = "users in group" + if len(names) == 1: + filter_chunks.append(f"{kind}: {list(names)[0]}") + else: + filter_chunks.append(f"{kind}s: {', '.join(names)}") + filter_text = "; or ".join(filter_chunks) + descriptions.append( + { + "scope": scope, + "description": scope_definitions[scope]["description"], + "filter": filter_text, + } + ) + return descriptions + + +def describe_raw_scopes(raw_scopes, username=None): + """Return list of descriptions of raw scopes + + A much shorter list than describe_parsed_scopes + """ + descriptions = [] + for raw_scope in raw_scopes: + scope, _, filter_ = raw_scope.partition("!") + base_text = scope_definitions[scope]["description"] + if not filter_: + # no filter + filter_text = "" + elif filter_ == "user": + filter_text = "only you" + else: + kind, _, name = filter_.partition("=") + if kind == "user" and name == username: + filter_text = "only you" + else: + kind_text = kind + if kind == 'group': + kind_text = "users in group" + filter_text = f"{kind_text} {name}" + descriptions.append( + { + "scope": scope, + "description": scope_definitions[scope]["description"], + "filter": filter_text, + } + ) + return descriptions diff --git a/share/jupyterhub/templates/oauth.html b/share/jupyterhub/templates/oauth.html index bb297001..8a3044c3 100644 --- a/share/jupyterhub/templates/oauth.html +++ b/share/jupyterhub/templates/oauth.html @@ -15,37 +15,38 @@

    {{ oauth_client.description }} (oauth URL: {{ oauth_client.redirect_uri }}) would like permission to identify you. - {% if scopes == ["identify"] %} - It will not be able to take actions on your behalf. + {% if not role_names %} + It will not be able to take actions on + your behalf. {% endif %}

    The application will be able to:

    - {% for scope in scopes %} + {# these are the 'real' inputs to the form -#} + {% for role_name in role_names %} + + {% endfor %} + + {% for scope_info in scope_descriptions %}
    {% endfor %} - +
    - {% endblock %} From 981ad5b05af94f209aaa72321c58c1a1e581d867 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 9 Jun 2021 16:29:11 +0200 Subject: [PATCH 233/270] Implemented suggestions and adjusted tests --- jupyterhub/apihandlers/base.py | 73 ++++++++++++++++---------- jupyterhub/apihandlers/groups.py | 4 +- jupyterhub/apihandlers/services.py | 11 ++-- jupyterhub/roles.py | 6 +-- jupyterhub/scopes.py | 53 +++++++++---------- jupyterhub/tests/test_roles.py | 15 ++++-- jupyterhub/tests/test_scopes.py | 14 ++--- jupyterhub/tests/test_services_auth.py | 5 +- 8 files changed, 101 insertions(+), 80 deletions(-) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 4023b61a..d5d4407e 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -173,6 +173,21 @@ class APIHandler(BaseHandler): } return model + def _filter_model(self, model, access_map, entity, kind, keys=None): + """ + Filter the model based on the available scopes and the entity requested for. + If keys is a dictionary, update it with the allowed keys for the model. + """ + allowed_keys = set() + for scope in access_map: + scope_filter = self.get_scope_filter(scope) + if scope_filter(entity, kind=kind): + allowed_keys |= access_map[scope] + model = {key: model[key] for key in allowed_keys if key in model} + if isinstance(keys, set): + keys.update(allowed_keys) + return model + def user_model(self, user): """Get the JSON model for a User object""" if isinstance(user, orm.User): @@ -201,11 +216,11 @@ class APIHandler(BaseHandler): 'created', 'last_activity', }, - 'read:users:name': {'kind', 'name'}, + 'read:users:name': {'kind', 'name', 'admin'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, 'read:users:servers': {'kind', 'name', 'servers'}, - 'read:users:roles': {'kind', 'name', 'roles'}, + 'read:users:roles': {'kind', 'name', 'roles', 'admin'}, 'admin:users:auth_state': {'kind', 'name', 'auth_state'}, } self.log.debug( @@ -214,11 +229,9 @@ class APIHandler(BaseHandler): ", ".join(self.expanded_scopes), ) allowed_keys = set() - for scope in access_map: - scope_filter = self.get_scope_filter(scope) - if scope_filter(user, kind='user'): - allowed_keys |= access_map[scope] - model = {key: model[key] for key in allowed_keys if key in model} + model = self._filter_model( + model, access_map, user, kind='user', keys=allowed_keys + ) if model: if '' in user.spawners and 'pending' in allowed_keys: model['pending'] = user.spawners[''].pending @@ -236,15 +249,18 @@ class APIHandler(BaseHandler): def group_model(self, group): """Get the JSON model for a Group object""" - model = {} - scope_filter = self.get_scope_filter('read:groups') - if scope_filter(group, kind='group'): - model = { - 'kind': 'group', - 'name': group.name, - 'roles': [r.name for r in group.roles], - 'users': [u.name for u in group.users], - } + model = { + 'kind': 'group', + 'name': group.name, + 'roles': [r.name for r in group.roles], + 'users': [u.name for u in group.users], + } + access_map = { + 'read:groups': {'kind', 'name', 'users'}, + 'read:groups:name': {'kind', 'name'}, + 'read:groups:roles': {'kind', 'name', 'roles'}, + } + model = self._filter_model(model, access_map, group, 'group') return model def service_model(self, service): @@ -261,19 +277,22 @@ class APIHandler(BaseHandler): 'info': getattr(service, 'info', ''), 'display': getattr(service, 'display', ''), } - # todo: remove admin key now we have roles? - # todo: More default keys present? access_map = { - 'read:services': set(model.keys()), - 'read:services:name': {'kind', 'name'}, - 'read:services:roles': {'kind', 'name', 'roles'}, + 'read:services': { + 'kind', + 'name', + 'admin', + 'url', + 'prefix', + 'command', + 'pid', + 'info', + 'display', + }, + 'read:services:name': {'kind', 'name', 'admin'}, + 'read:services:roles': {'kind', 'name', 'roles', 'admin'}, } - allowed_keys = set() - for scope in access_map: - scope_filter = self.get_scope_filter(scope) - if scope_filter(service, kind='service'): - allowed_keys |= access_map[scope] - model = {key: model[key] for key in allowed_keys} + model = self._filter_model(model, access_map, service, 'service') return model _user_model_types = { diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index f49bbbd3..85190941 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -34,7 +34,7 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @needs_scope('read:groups') + @needs_scope('read:groups', 'read:groups:names', 'read:groups:roles') def get(self): """List groups""" query = self.db.query(orm.Group) @@ -77,7 +77,7 @@ class GroupListAPIHandler(_GroupAPIHandler): class GroupAPIHandler(_GroupAPIHandler): """View and modify groups by name""" - @needs_scope('read:groups') + @needs_scope('read:groups', 'read:groups:names', 'read:groups:roles') def get(self, group_name): group = self.find_group(group_name) self.write(json.dumps(self.group_model(group))) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 7db84ccc..e2106801 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -13,12 +13,11 @@ from .base import APIHandler class ServiceListAPIHandler(APIHandler): @needs_scope('read:services', 'read:services:name', 'read:services:roles') def get(self): - scope_filter = self.get_scope_filter('read:services') - data = { - name: self.service_model(service) - for name, service in self.services.items() - if scope_filter(service, kind='service') - } + data = {} + for name, service in self.services.items(): + model = self.service_model(service) + if model: + data[name] = model self.write(json.dumps(data)) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 11f2c650..fa84aa3c 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -30,7 +30,7 @@ def get_default_roles(): }, { 'name': 'admin', - 'description': 'Admin privileges (can do everything)', + 'description': 'Elevated privileges (can do anything)', 'scopes': [ 'admin:users', 'admin:users:servers', @@ -42,6 +42,7 @@ def get_default_roles(): 'shutdown', 'access:services', 'access:users:servers', + 'read:services:roles', ], }, { @@ -54,7 +55,7 @@ def get_default_roles(): }, { 'name': 'token', - 'description': 'Token with same rights as token owner', + 'description': 'Token with same permissions as its owner', 'scopes': ['all'], }, ] @@ -86,7 +87,6 @@ def expand_self_scope(name): 'users:activity', 'users:servers', 'users:tokens', - 'users:roles', ] read_scope_list = ['read:' + scope for scope in scope_list] # access doesn't want the 'read:' prefix diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 255c4a24..5940d8f3 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -28,45 +28,43 @@ scope_definitions = { 'description': 'Metascope, grants access to user’s own resources only; resolves to (no_scope) for services.' }, 'all': { - 'description': 'Metascope, valid for tokens only. Grants access to everything that the token’s owning entity can access.' + 'description': 'Metascope, valid for tokens only. Grants access to everything that the token-owning entity can access.' }, 'admin:users': { - 'description': 'Grants read, write, create and delete access to users and their authentication state but not their servers or tokens.', - 'subscopes': ['admin:users:auth_state', 'users'], + 'description': 'Grants read, write, create and delete access to users and their authentication state, not including their servers or tokens.', + 'subscopes': ['admin:users:auth_state', 'users', 'read:users:roles'], }, 'admin:users:auth_state': { - 'description': 'Grants access to users’ authentication state only.' + 'description': 'Grants access to user authentication state.' }, 'users': { - 'description': 'Grants read and write permissions to users’ models apart from servers, tokens and authentication state.', + 'description': 'Grants read and write permissions to user models, not including servers, tokens and authentication state.', 'subscopes': ['read:users', 'users:activity'], }, 'read:users': { - 'description': 'Read-only access to users’ models apart from servers, tokens and authentication state.', + 'description': 'Read-only access to user models, not including servers, tokens and authentication state.', 'subscopes': [ 'read:users:name', 'read:users:groups', 'read:users:activity', - 'read:users:roles', ], }, 'read:users:name': {'description': 'Read-only access to users’ names.'}, 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, 'read:users:activity': {'description': 'Read-only access to users’ last activity.'}, - 'read:users:roles': {'description': 'Read-only access to users’ roles.'}, + # todo: describe that it only specifies timestamp of activity + 'read:users:roles': {'description': 'Read-only access to user roles.'}, 'users:activity': { - 'description': 'Grants access to read and post users’ last activity only.', + 'description': 'Grants access to read and update user activity.', 'subscopes': ['read:users:activity'], }, 'admin:users:servers': { - 'description': 'Grants read, start/stop, create and delete permissions to users’ servers and their state.', + 'description': 'Grants read, start/stop, create and delete permissions to user servers and their state.', 'subscopes': ['admin:users:server_state', 'users:servers'], }, - 'admin:users:server_state': { - 'description': 'Grants access to servers’ state only.' - }, + 'admin:users:server_state': {'description': 'Grants access to server state only.'}, 'users:servers': { - 'description': 'Allows for starting/stopping users’ servers in addition to read access to their models. Does not include the server state.', + 'description': 'Allows for starting/stopping user servers. Does not include the server state.', 'subscopes': ['read:users:servers'], }, 'read:users:servers': { @@ -74,22 +72,27 @@ scope_definitions = { 'subscopes': ['read:users:name'], }, 'users:tokens': { - 'description': 'Grants read, write, create and delete permissions to users’ tokens.', + 'description': 'Grants read, write, create and delete permissions for user tokens.', 'subscopes': ['read:users:tokens'], }, - 'read:users:tokens': {'description': 'Read-only access to users’ tokens.'}, + 'read:users:tokens': {'description': 'Read-only access to user tokens.'}, 'admin:groups': { 'description': 'Grants read, write, create and delete access to groups.', - 'subscopes': ['groups'], + 'subscopes': ['groups', 'read:groups:roles'], }, 'groups': { 'description': 'Grants read and write permissions to groups, including adding/removing users to/from groups.', 'subscopes': ['read:groups'], }, - 'read:groups': {'description': 'Read-only access to groups’ models.'}, + 'read:groups': { + 'description': 'Read-only access to group models.', + 'subscopes': ['read:groups:name'], + }, + 'read:groups:name': {'description': 'Read-only access to group names.'}, + 'read:groups:roles': {'description': 'Read-only access to group role names.'}, 'read:services': { 'description': 'Read-only access to service models.', - 'subscopes': ['read:services:name', 'read:services:roles'], + 'subscopes': ['read:services:name'], }, 'read:services:name': {'description': 'Read-only access to service names.'}, 'read:services:roles': {'description': 'Read-only access to service role names.'}, @@ -491,17 +494,9 @@ def identify_scopes(obj): identify 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", "roles", "groups"} - } + return {f"read:users:{field}!user={obj.name}" for field in {"name", "groups"}} elif isinstance(obj, orm.Service): - # FIXME: need sub-scopes for services - # until then, we have just one service scope: - return {f"read:services!service={obj.name}"} - return { - f"read:services:{field}!service={obj.name}" for field in {"name", "roles"} - } + return {f"read:services:{field}!service={obj.name}" for field in {"name"}} else: raise TypeError(f"Expected orm.User or orm.Service, got {obj!r}") diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 1c6e9208..2e0680e7 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -199,7 +199,6 @@ def test_orm_roles_delete_cascade(db): 'users:activity', 'read:users:name', 'read:users:groups', - 'read:users:roles', 'read:users:activity', }, ), @@ -209,18 +208,28 @@ def test_orm_roles_delete_cascade(db): 'read:users', 'read:users:name', 'read:users:groups', - 'read:users:roles', 'read:users:activity', }, ), (['read:users:servers'], {'read:users:servers', 'read:users:name'}), - (['admin:groups'], {'admin:groups', 'groups', 'read:groups'}), + ( + ['admin:groups'], + { + 'admin:groups', + 'groups', + 'read:groups', + 'read:groups:roles', + 'read:groups:name', + }, + ), ( ['admin:groups', 'read:users:servers'], { 'admin:groups', 'groups', 'read:groups', + 'read:groups:roles', + 'read:groups:name', 'read:users:servers', 'read:users:name', }, diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index 660470c7..e6c82aa8 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -415,7 +415,7 @@ async def test_vertical_filter(app, create_user_with_scopes): user = create_user_with_scopes('read:users:name') r = await api_request(app, 'users', headers=auth_header(app.db, user.name)) assert r.status_code == 200 - allowed_keys = {'name', 'kind'} + allowed_keys = {'name', 'kind', 'admin'} assert set([key for user in r.json() for key in user.keys()]) == allowed_keys @@ -647,7 +647,6 @@ async def test_server_state_access( 'read:users!user=y', 'read:users:name!user=y', 'read:users:groups!user=y', - 'read:users:roles!user=y', 'read:users:activity!user=y', }, ), @@ -659,7 +658,6 @@ async def test_server_state_access( 'read:users!user=y', 'read:users:name!user=y', 'read:users:groups!user=y', - 'read:users:roles!user=y', 'read:users:activity!user=y', }, ), @@ -703,11 +701,13 @@ async def test_resolve_token_permissions( 'admin', 'prefix', 'url', - 'roles', }, ), - ({'read:services:roles', 'read:users:name'}, {'name', 'kind', 'roles'}), - ({'read:services:name'}, {'name', 'kind'}), + ( + {'read:services:roles', 'read:users:name'}, + {'name', 'kind', 'roles', 'admin'}, + ), + ({'read:services:name'}, {'name', 'kind', 'admin'}), ], ) async def test_service_model_filtering( @@ -729,7 +729,7 @@ async def test_roles_access(app, create_service_with_scopes, create_user_with_sc app, 'users', user.name, headers=auth_header(app.db, read_user.name) ) assert r.status_code == 200 - model_keys = {'kind', 'name', 'roles'} + model_keys = {'kind', 'name', 'roles', 'admin'} assert model_keys == r.json().keys() diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 840ac26d..ab9cd9c3 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -83,7 +83,7 @@ async def test_hubauth_token(app, mockservice_url, create_user_with_scopes): r.raise_for_status() reply = r.json() sub_reply = {key: reply.get(key, 'missing') for key in ['name', 'admin']} - assert sub_reply == {'name': u.name, 'admin': 'missing'} + assert sub_reply == {'name': u.name, 'admin': False} # token in ?token parameter r = await async_requests.get( @@ -92,7 +92,7 @@ async def test_hubauth_token(app, mockservice_url, create_user_with_scopes): r.raise_for_status() reply = r.json() sub_reply = {key: reply.get(key, 'missing') for key in ['name', 'admin']} - assert sub_reply == {'name': u.name, 'admin': 'missing'} + assert sub_reply == {'name': u.name, 'admin': False} r = await async_requests.get( public_url(app, mockservice_url) + '/whoami/?token=no-such-token', @@ -168,7 +168,6 @@ async def test_hubauth_service_token(request, app, mockservice_url, scopes, allo 'kind': 'service', 'name': name, 'admin': False, - 'roles': [role_name], 'scopes': scopes, } if allowed: From 1023653aafb9c24f5646725a0b22f2fb53566e0d Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 10 Jun 2021 17:45:25 +0200 Subject: [PATCH 234/270] Fixed scopes and added tests --- jupyterhub/apihandlers/groups.py | 4 ++-- jupyterhub/tests/test_scopes.py | 39 +++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 85190941..df6e197d 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -34,7 +34,7 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @needs_scope('read:groups', 'read:groups:names', 'read:groups:roles') + @needs_scope('read:groups', 'read:groups:name', 'read:groups:roles') def get(self): """List groups""" query = self.db.query(orm.Group) @@ -77,7 +77,7 @@ class GroupListAPIHandler(_GroupAPIHandler): class GroupAPIHandler(_GroupAPIHandler): """View and modify groups by name""" - @needs_scope('read:groups', 'read:groups:names', 'read:groups:roles') + @needs_scope('read:groups', 'read:groups:name', 'read:groups:roles') def get(self, group_name): group = self.find_group(group_name) self.write(json.dumps(self.group_model(group))) diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index e6c82aa8..e5687caa 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -704,7 +704,7 @@ async def test_resolve_token_permissions( }, ), ( - {'read:services:roles', 'read:users:name'}, + {'read:services:roles', 'read:services:name'}, {'name', 'kind', 'roles', 'admin'}, ), ({'read:services:name'}, {'name', 'kind', 'admin'}), @@ -722,6 +722,43 @@ async def test_service_model_filtering( assert model_keys == r.json().keys() +@mark.parametrize( + "scopes, model_keys", + [ + ( + {'read:groups'}, + { + 'name', + 'kind', + 'users', + }, + ), + ( + {'read:groups:roles', 'read:groups:name'}, + {'name', 'kind', 'roles'}, + ), + ({'read:groups:name'}, {'name', 'kind'}), + ], +) +async def test_group_model_filtering( + app, scopes, model_keys, create_user_with_scopes, create_service_with_scopes +): + user = create_user_with_scopes(*scopes, name='teddy') + group_name = 'baker_street' + group = orm.Group.find(app.db, name=group_name) + if not group: + group = orm.Group(name=group_name) + app.db.add(group) + app.db.commit() + r = await api_request( + app, 'groups', group_name, headers=auth_header(app.db, user.name) + ) + assert r.status_code == 200 + assert model_keys == r.json().keys() + app.db.delete(group) + app.db.commit() + + async def test_roles_access(app, create_service_with_scopes, create_user_with_scopes): user = add_user(app.db, name='miranda') read_user = create_user_with_scopes('read:users:roles') From d169359d5126836c886ca8ca2b0c38f9b9d34339 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 11 Jun 2021 11:44:10 +0200 Subject: [PATCH 235/270] Refactored scope description to be usable for both docs and authorization page --- docs/source/rbac/generate-scope-table.py | 5 +- jupyterhub/scopes.py | 65 +++++++++++------------- share/jupyterhub/templates/oauth.html | 4 +- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index b282e642..902550c3 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -61,6 +61,9 @@ class ScopeTableGenerator: def _add_subscopes(table_rows, scopename, depth=0): description = self.scopes[scopename]['description'] + meta_description = self.scopes[scopename].get('metadescription', '') + if meta_description: + description = description.rstrip('.') + f" ({meta_description})." table_row = [f"{md_indent*depth}`{scopename}`", description] table_rows.append(table_row) for subscope in scope_pairs[scopename]: @@ -76,7 +79,7 @@ class ScopeTableGenerator: """Generates the scope table in markdown format and writes it into scope-table.md file""" filename = f"{HERE}/scope-table.md" table_name = "" - headers = ["Scope", "Description"] + headers = ["Scope", "Grants permission to:"] values = self._parse_scopes() writer = self.create_writer(table_name, headers, values) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 1fb4a120..36b39b58 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -23,82 +23,79 @@ from . import orm from . import roles scope_definitions = { - '(no_scope)': {'description': 'Allows for only identifying the owning entity.'}, + '(no_scope)': {'description': 'Identify the owner of this entity.'}, 'self': { - 'description': 'Metascope, grants access to user’s own resources only; resolves to (no_scope) for services.' + 'description': 'The user’s own resources.', + 'metadescription': 'metascope for users, resolves to (no_scope) for services', }, 'all': { - 'description': 'Metascope, valid for tokens only. Grants access to everything that the token-owning entity can access.' + 'description': 'Everything that the token-owning entity can access.', + 'metadescription': 'metascope for tokens', }, 'admin:users': { - 'description': 'Grants read, write, create and delete access to users and their authentication state, not including their servers or tokens.', + 'description': 'Read, write, create and delete users and their authentication state, not including their servers or tokens.', 'subscopes': ['admin:users:auth_state', 'users', 'read:users:roles'], }, - 'admin:users:auth_state': { - 'description': 'Grants access to user authentication state.' - }, + 'admin:users:auth_state': {'description': 'Read a user’s authentication state.'}, 'users': { - 'description': 'Grants read and write permissions to user models, not including servers, tokens and authentication state.', + 'description': 'Read and write permissions to user models, e servers, tokens and authentication state.', 'subscopes': ['read:users', 'users:activity'], }, 'read:users': { - 'description': 'Read-only access to user models, not including servers, tokens and authentication state.', + 'description': 'Read user models, (exluding including servers, tokens and authentication state).', 'subscopes': [ 'read:users:name', 'read:users:groups', 'read:users:activity', ], }, - 'read:users:name': {'description': 'Read-only access to users’ names.'}, - 'read:users:groups': {'description': 'Read-only access to users’ group names.'}, - 'read:users:activity': {'description': 'Read-only access to users’ last activity.'}, - # todo: describe that it only specifies timestamp of activity - 'read:users:roles': {'description': 'Read-only access to user roles.'}, + 'read:users:name': {'description': 'Read names of users.'}, + 'read:users:groups': {'description': 'Read names of users’ groups.'}, + 'read:users:activity': {'description': 'Read time of last user activity'}, + 'read:users:roles': {'description': 'Read names of users’ roles.'}, 'users:activity': { - 'description': 'Grants access to read and update user activity.', + 'description': 'Update time of last user activity.', 'subscopes': ['read:users:activity'], }, 'admin:users:servers': { - 'description': 'Grants read, start/stop, create and delete permissions to user servers and their state.', + 'description': 'Read, start, stop, create and delete user servers and their state.', 'subscopes': ['admin:users:server_state', 'users:servers'], }, - 'admin:users:server_state': {'description': 'Grants access to server state only.'}, + 'admin:users:server_state': {'description': 'Read and write users’ server state.'}, 'users:servers': { - 'description': 'Allows for starting/stopping user servers. Does not include the server state.', + 'description': 'Start and stop user servers.', 'subscopes': ['read:users:servers'], }, 'read:users:servers': { - 'description': 'Read-only access to users’ names and their server models. Does not include the server state.', + 'description': 'Read users’ names and their server models. Does not include the server state.', 'subscopes': ['read:users:name'], }, 'users:tokens': { - 'description': 'Grants read, write, create and delete permissions for user tokens.', + 'description': 'Read, write, create and delete user tokens.', 'subscopes': ['read:users:tokens'], }, - 'read:users:tokens': {'description': 'Read-only access to user tokens.'}, + 'read:users:tokens': {'description': 'Read user tokens.'}, 'admin:groups': { - 'description': 'Grants read, write, create and delete access to groups.', + 'description': 'Read and write group information, create and delete groups.', 'subscopes': ['groups', 'read:groups:roles'], }, 'groups': { - 'description': 'Grants read and write permissions to groups, including adding/removing users to/from groups.', + 'description': 'Read and write group information, including adding/removing users to/from groups.', 'subscopes': ['read:groups'], }, 'read:groups': { - 'description': 'Read-only access to group models.', + 'description': 'Read group models.', 'subscopes': ['read:groups:name'], }, - 'read:groups:name': {'description': 'Read-only access to group names.'}, - 'read:groups:roles': {'description': 'Read-only access to group role names.'}, + 'read:groups:name': {'description': 'Read group names.'}, + 'read:groups:roles': {'description': 'Read group role names.'}, 'read:services': { - 'description': 'Read-only access to service models.', + 'description': 'Read service models.', 'subscopes': ['read:services:name'], }, - 'read:services:name': {'description': 'Read-only access to service names.'}, - 'read:services:roles': {'description': 'Read-only access to service role names.'}, - 'read:hub': { - 'description': 'Read-only access to detailed information about the Hub.' - }, + 'read:services:name': {'description': 'Read service names.'}, + 'read:services:roles': {'description': 'Read service role names.'}, + 'read:hub': {'description': 'Read detailed information about the Hub.'}, 'access:users:servers': { 'description': 'Access user servers via API or browser.', }, @@ -106,9 +103,9 @@ scope_definitions = { 'description': 'Access services via API or browser.', }, 'proxy': { - 'description': 'Allows for obtaining information about the proxy’s routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy.' + 'description': 'Read information about the proxy’s routing table, sync the Hub with the proxy and notify the Hub about a new proxy.' }, - 'shutdown': {'description': 'Grants access to shutdown the hub.'}, + 'shutdown': {'description': 'Shutdown the hub.'}, } diff --git a/share/jupyterhub/templates/oauth.html b/share/jupyterhub/templates/oauth.html index 8a3044c3..b1d56bd0 100644 --- a/share/jupyterhub/templates/oauth.html +++ b/share/jupyterhub/templates/oauth.html @@ -21,7 +21,7 @@ {% endif %}

    -

    The application will be able to:

    +

    This will grant the application permission to:

    {# these are the 'real' inputs to the form -#} @@ -38,7 +38,7 @@ {{ scope_info['description'] }} {% if scope_info['filter'] %} - For {{ scope_info['filter'] }}. + Applies to {{ scope_info['filter'] }}. {% endif %} From 73a6b3477a679ff916ae40a57912d523bf116760 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 11 Jun 2021 11:59:18 +0200 Subject: [PATCH 236/270] Fixed typos and formatting --- docs/source/rbac/generate-scope-table.py | 2 +- jupyterhub/scopes.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index 902550c3..0e2b93f8 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -63,7 +63,7 @@ class ScopeTableGenerator: description = self.scopes[scopename]['description'] meta_description = self.scopes[scopename].get('metadescription', '') if meta_description: - description = description.rstrip('.') + f" ({meta_description})." + description = description.rstrip('.') + f" __({meta_description})__." table_row = [f"{md_indent*depth}`{scopename}`", description] table_rows.append(table_row) for subscope in scope_pairs[scopename]: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 36b39b58..c7c37577 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -38,11 +38,11 @@ scope_definitions = { }, 'admin:users:auth_state': {'description': 'Read a user’s authentication state.'}, 'users': { - 'description': 'Read and write permissions to user models, e servers, tokens and authentication state.', + 'description': 'Read and write permissions to user models (excluding servers, tokens and authentication state).', 'subscopes': ['read:users', 'users:activity'], }, 'read:users': { - 'description': 'Read user models, (exluding including servers, tokens and authentication state).', + 'description': 'Read user models (excluding including servers, tokens and authentication state).', 'subscopes': [ 'read:users:name', 'read:users:groups', @@ -51,7 +51,7 @@ scope_definitions = { }, 'read:users:name': {'description': 'Read names of users.'}, 'read:users:groups': {'description': 'Read names of users’ groups.'}, - 'read:users:activity': {'description': 'Read time of last user activity'}, + 'read:users:activity': {'description': 'Read time of last user activity.'}, 'read:users:roles': {'description': 'Read names of users’ roles.'}, 'users:activity': { 'description': 'Update time of last user activity.', @@ -67,7 +67,7 @@ scope_definitions = { 'subscopes': ['read:users:servers'], }, 'read:users:servers': { - 'description': 'Read users’ names and their server models. Does not include the server state.', + 'description': 'Read users’ names and their server models (excluding the server state).', 'subscopes': ['read:users:name'], }, 'users:tokens': { From 5e3201cfe3ce1ee6b9f685e850bc650dba9d086b Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 11 Jun 2021 12:27:40 +0200 Subject: [PATCH 237/270] Minor formatting change --- docs/source/rbac/generate-scope-table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index 0e2b93f8..7a4d3a4a 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -63,7 +63,7 @@ class ScopeTableGenerator: description = self.scopes[scopename]['description'] meta_description = self.scopes[scopename].get('metadescription', '') if meta_description: - description = description.rstrip('.') + f" __({meta_description})__." + description = description.rstrip('.') + f" _({meta_description})_." table_row = [f"{md_indent*depth}`{scopename}`", description] table_rows.append(table_row) for subscope in scope_pairs[scopename]: From 03e2e7f3b0dbf6a7621a9ae34a8e32ca07ed4963 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 11 Jun 2021 13:23:23 +0200 Subject: [PATCH 238/270] Fix auth page logic --- jupyterhub/apihandlers/auth.py | 35 +++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index f36cfcf0..73e2e489 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -216,10 +216,7 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): self.log.debug( f"User {user.name} has already authorized {oauth_client.identifier} for roles {roles}" ) - # FIXME: uncomment after debugging - # it's easier to run manual tests - # if we always show the confirmation page - # return False + return False else: self.log.debug( f"User {user.name} has authorized {oauth_client.identifier}" @@ -249,6 +246,31 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): ) credentials = self.add_credentials(credentials) client = self.oauth_provider.fetch_by_client_id(credentials['client_id']) + allowed = False + + # check for access to target resource + if client.spawner: + scope_filter = self.get_scope_filter("access:users:servers") + allowed = scope_filter(client.spawner, kind='server') + elif client.service: + scope_filter = self.get_scope_filter("access:services") + allowed = scope_filter(client.service, kind='service') + else: + # client is not associated with a service or spawner. + # This shouldn't happen, but it might if this is a stale or forged request + # from a service or spawner that's since been deleted + self.log.error( + f"OAuth client {client} has no service or spawner, cannot resolve scopes." + ) + raise web.HTTPError(500, "OAuth configuration error") + + if not allowed: + self.log.error( + f"User {self.current_user} not allowed to access {client.description}" + ) + raise web.HTTPError( + 403, f"You do not have permission to access {client.description}" + ) if not self.needs_oauth_confirm(self.current_user, client, role_names): self.log.debug( "Skipping oauth confirmation for %s accessing %s", @@ -276,7 +298,6 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): ] elif 'all' in raw_scopes: raw_scopes = ['all'] - expanded_scopes = ['all'] scope_descriptions = [ { "scope": "all", @@ -285,14 +306,10 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): } ] else: - # expanded_scopes = roles._get_subscopes(*role_objects, owner=self.current_user.orm_user) - # print("expanded scopes", expanded_scopes, self.current_user) - # parsed_scopes = scopes.parse_scopes(expanded_scopes) scope_descriptions = scopes.describe_raw_scopes( raw_scopes, username=self.current_user.name, ) - print("scope definitions", raw_scopes, scope_descriptions) # Render oauth 'Authorize application...' page auth_state = await self.current_user.get_auth_state() self.write( From 8864780bfb363a7eda3a6a2738ce2d4ca10b1fa2 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 11 Jun 2021 13:32:20 +0200 Subject: [PATCH 239/270] Adjusted documentation for auth pages --- docs/source/rbac/generate-scope-table.py | 6 +++--- jupyterhub/scopes.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index 7a4d3a4a..99b1ddbb 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -61,9 +61,9 @@ class ScopeTableGenerator: def _add_subscopes(table_rows, scopename, depth=0): description = self.scopes[scopename]['description'] - meta_description = self.scopes[scopename].get('metadescription', '') - if meta_description: - description = description.rstrip('.') + f" _({meta_description})_." + doc_description = self.scopes[scopename].get('doc_description', '') + if doc_description: + description = doc_description table_row = [f"{md_indent*depth}`{scopename}`", description] table_rows.append(table_row) for subscope in scope_pairs[scopename]: diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index c7c37577..e47786a6 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -25,12 +25,12 @@ from . import roles scope_definitions = { '(no_scope)': {'description': 'Identify the owner of this entity.'}, 'self': { - 'description': 'The user’s own resources.', - 'metadescription': 'metascope for users, resolves to (no_scope) for services', + 'description': 'Your own resources', + 'doc_description': 'The user’s own resources _(metascope for users, resolves to (no_scope) for services)_', }, 'all': { - 'description': 'Everything that the token-owning entity can access.', - 'metadescription': 'metascope for tokens', + 'description': 'Anything you have access to', + 'doc_description': 'Everything that the token-owning entity can access _(metascope for tokens)_', }, 'admin:users': { 'description': 'Read, write, create and delete users and their authentication state, not including their servers or tokens.', @@ -50,9 +50,9 @@ scope_definitions = { ], }, 'read:users:name': {'description': 'Read names of users.'}, - 'read:users:groups': {'description': 'Read names of users’ groups.'}, + 'read:users:groups': {'description': 'Read users’ group membership.'}, 'read:users:activity': {'description': 'Read time of last user activity.'}, - 'read:users:roles': {'description': 'Read names of users’ roles.'}, + 'read:users:roles': {'description': 'Read users’ role assignments.'}, 'users:activity': { 'description': 'Update time of last user activity.', 'subscopes': ['read:users:activity'], @@ -88,13 +88,13 @@ scope_definitions = { 'subscopes': ['read:groups:name'], }, 'read:groups:name': {'description': 'Read group names.'}, - 'read:groups:roles': {'description': 'Read group role names.'}, + 'read:groups:roles': {'description': 'Read group role assignments.'}, 'read:services': { 'description': 'Read service models.', 'subscopes': ['read:services:name'], }, 'read:services:name': {'description': 'Read service names.'}, - 'read:services:roles': {'description': 'Read service role names.'}, + 'read:services:roles': {'description': 'Read service role assignments.'}, 'read:hub': {'description': 'Read detailed information about the Hub.'}, 'access:users:servers': { 'description': 'Access user servers via API or browser.', From 1ecce476eac13b11b0962606249518f8b1a6ff82 Mon Sep 17 00:00:00 2001 From: 0mar Date: Fri, 11 Jun 2021 14:41:46 +0200 Subject: [PATCH 240/270] Outlined tests and updated oauth page --- jupyterhub/scopes.py | 2 +- jupyterhub/tests/test_pages.py | 7 +++ jupyterhub/tests/test_services_auth.py | 24 ++++++++++ share/jupyterhub/templates/oauth.html | 65 +++++++++++++------------- 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index e47786a6..85bbb616 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -23,7 +23,7 @@ from . import orm from . import roles scope_definitions = { - '(no_scope)': {'description': 'Identify the owner of this entity.'}, + '(no_scope)': {'description': 'Identify the owner of the requesting entity.'}, 'self': { 'description': 'Your own resources', 'doc_description': 'The user’s own resources _(metascope for users, resolves to (no_scope) for services)_', diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index 4fe1dfb9..a48dc2d5 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -946,6 +946,13 @@ async def test_bad_oauth_get(app, params): assert r.status_code == 400 +async def test_oauth_page_scope_appearance(app): + # Test scopes presence + # test subscopes presence + # test filter presence + pass + + async def test_token_page(app): name = "cake" cookies = await app.login_user(name) diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index ab9cd9c3..6ed15d32 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -372,6 +372,30 @@ async def test_oauth_access_scopes( assert r.status_code == 403 +async def test_oauth_page_memory(app): + pass + # add service + # Login + # go to service oauth page + # hit auth page + # go to service oauth page again + # don't hit auth page + # clear authorization + # go to service oauth page + # hit auth page + + +async def test_oauth_page_role_expansion(app): + pass + # add service + # login + # go to service oauth page + # hit auth page + # expand service roles + # go to service oauth page + # hit auth page again + + async def test_oauth_cookie_collision(app, mockservice_url, create_user_with_scopes): service = mockservice_url url = url_path_join(public_url(app, mockservice_url), 'owhoami/') diff --git a/share/jupyterhub/templates/oauth.html b/share/jupyterhub/templates/oauth.html index b1d56bd0..c726388b 100644 --- a/share/jupyterhub/templates/oauth.html +++ b/share/jupyterhub/templates/oauth.html @@ -5,48 +5,47 @@ {% block main %}
    -

    Authorize access

    +

    Authorize access

    -

    - A service is attempting to authorize with your - JupyterHub account -

    +

    + An application is requesting authorization to access data associated with your JupyterHub account +

    -

    - {{ oauth_client.description }} (oauth URL: {{ oauth_client.redirect_uri }}) - would like permission to identify you. - {% if not role_names %} - It will not be able to take actions on - your behalf. - {% endif %} -

    +

    + {{ oauth_client.description }} (oauth URL: {{ oauth_client.redirect_uri }}) + would like permission to identify you. + {% if not role_names %} + It will not be able to take actions on + your behalf. + {% endif %} +

    -

    This will grant the application permission to:

    -
    - - {# these are the 'real' inputs to the form -#} - {% for role_name in role_names %} - - {% endfor %} +

    This will grant the application permission to:

    +
    + + {# these are the 'real' inputs to the form -#} + {% for role_name in role_names %} + + {% endfor %} - {% for scope_info in scope_descriptions %} -
    -
    + +
    + {% endfor %} + + +
    {% endblock %} From e6810b7ec5d047b1539f88ce548a375518e7dec0 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 May 2021 15:12:53 +0200 Subject: [PATCH 241/270] fix allowed_role assignment from service config Service.oauth_roles is list of names, OAuthClient.allowed_roles is list of orm.Roles --- jupyterhub/app.py | 10 +++++++--- jupyterhub/tests/test_services.py | 8 +++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 7fb3a775..f4aab838 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2260,14 +2260,18 @@ class JupyterHub(Application): service.orm.server = None if service.oauth_available: - self.oauth_provider.add_client( + oauth_client = self.oauth_provider.add_client( client_id=service.oauth_client_id, client_secret=service.api_token, redirect_uri=service.oauth_redirect_uri, - allowed_roles=service.oauth_roles, + allowed_roles=list( + self.db.query(orm.Role).filter( + orm.Role.name.in_(service.oauth_roles) + ) + ), description="JupyterHub service %s" % service.name, ) - service.orm.oauth_client_id = service.oauth_client_id + service.orm.oauth_client = oauth_client else: if service.oauth_client: self.db.delete(service.oauth_client) diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index fd922273..75ff2874 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -3,12 +3,11 @@ import asyncio import os import sys from binascii import hexlify -from contextlib import contextmanager from subprocess import Popen from async_generator import asynccontextmanager -from tornado.ioloop import IOLoop +from .. import orm from ..roles import update_roles from ..utils import maybe_future from ..utils import random_port @@ -86,15 +85,18 @@ async def test_external_service(app): 'admin': True, 'url': env['JUPYTERHUB_SERVICE_URL'], 'api_token': env['JUPYTERHUB_API_TOKEN'], + 'oauth_roles': ['user'], } ] await maybe_future(app.init_services()) - await maybe_future(app.init_role_creation()) await app.init_api_tokens() await app.proxy.add_all_services(app._service_map) await app.init_role_assignment() service = app._service_map[name] + assert service.oauth_available + assert service.oauth_client is not None + assert service.oauth_client.allowed_roles == [orm.Role.find(app.db, "user")] api_token = service.orm.api_tokens[0] update_roles(app.db, api_token, roles=['token']) url = public_url(app, service) + '/api/users' From be61bbc530b8d38882e637a0e0ccdb4dfded9206 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 27 May 2021 15:13:38 +0200 Subject: [PATCH 242/270] Fix self scope list adding `read:` to everything isn't right because not everything has a `read:` counterpart and not every `read:` has a write counterpart includes a test verifying that every scope has a definition --- jupyterhub/roles.py | 13 +++++++------ jupyterhub/tests/test_roles.py | 8 ++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index fa84aa3c..1d77522d 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -82,16 +82,17 @@ def expand_self_scope(name): """ scope_list = [ 'users', - 'users:name', - 'users:groups', + 'read:users', + 'read:users:name', + 'read:users:groups', 'users:activity', + 'read:users:activity', 'users:servers', + 'read:users:servers', 'users:tokens', + 'read:users:tokens', + 'access:users:servers', ] - read_scope_list = ['read:' + scope for scope in scope_list] - # access doesn't want the 'read:' prefix - scope_list.append('access:users:servers') - scope_list.extend(read_scope_list) return {"{}!user={}".format(scope, name) for scope in scope_list} diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 2e0680e7..e33e936a 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -3,16 +3,15 @@ # Distributed under the terms of the Modified BSD License. import json import os -from itertools import chain import pytest from pytest import mark from tornado.log import app_log -from traitlets.config import Config from .. import orm from .. import roles from ..scopes import get_scopes_for +from ..scopes import scope_definitions from ..utils import utcnow from .mocking import MockHub from .utils import add_user @@ -731,6 +730,11 @@ async def test_self_expansion(app, kind, has_user_scopes): # test expansion of user/service scopes scopes = roles.expand_roles_to_scopes(orm_obj) assert bool(scopes) == has_user_scopes + if kind == 'users': + for scope in scopes: + assert scope.endswith(f"!user={orm_obj.name}") + base_scope = scope.split("!", 1)[0] + assert base_scope in scope_definitions # test expansion of token scopes orm_obj.new_api_token() From 244624579fc64cc2d78faef11d36d2dacaadda89 Mon Sep 17 00:00:00 2001 From: 0mar Date: Mon, 14 Jun 2021 14:54:27 +0200 Subject: [PATCH 243/270] Added tests for auth page --- jupyterhub/tests/test_pages.py | 44 ++++++++++++++++-- jupyterhub/tests/test_services_auth.py | 64 ++++++++++++++++++-------- 2 files changed, 84 insertions(+), 24 deletions(-) diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index a48dc2d5..cf441198 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -12,8 +12,10 @@ from tornado.escape import url_escape from tornado.httputil import url_concat from .. import orm +from .. import scopes from ..auth import Authenticator from ..handlers import BaseHandler +from ..utils import url_path_join from ..utils import url_path_join as ujoin from .mocking import FalsyCallableFormSpawner from .mocking import FormSpawner @@ -21,6 +23,7 @@ from .test_api import next_event from .utils import add_user from .utils import api_request from .utils import async_requests +from .utils import AsyncSession from .utils import get_page from .utils import public_host from .utils import public_url @@ -946,11 +949,42 @@ async def test_bad_oauth_get(app, params): assert r.status_code == 400 -async def test_oauth_page_scope_appearance(app): - # Test scopes presence - # test subscopes presence - # test filter presence - pass +async def test_oauth_page_scope_appearance( + app, mockservice_url, create_user_with_scopes, create_temp_role +): + service_role = create_temp_role( + [ + 'self', + 'read:users!user=gawain', + 'read:users:tokens', + 'read:groups!group=mythos', + ] + ) + service = mockservice_url + user = create_user_with_scopes("access:services") + oauth_client = ( + app.db.query(orm.OAuthClient) + .filter_by(identifier=service.oauth_client_id) + .one() + ) + oauth_client.allowed_roles = [service_role] + app.db.commit() + + s = AsyncSession() + s.cookies = await app.login_user(user.name) + url = url_path_join(public_url(app, service) + 'owhoami/?arg=x') + r = await s.get(url) + r.raise_for_status() + soup = BeautifulSoup(r.text, "html.parser") + scopes_block = soup.find('form') + for scope in service_role.scopes: + base_scope, _, filter_ = scope.partition('!') + scope_def = scopes.scope_definitions[base_scope] + assert scope_def['description'] in scopes_block.text + if filter_: + kind, _, name = filter_.partition('=') + assert kind in scopes_block.text + assert name in scopes_block.text async def test_token_page(app): diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index 6ed15d32..b3b2838f 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -372,28 +372,54 @@ async def test_oauth_access_scopes( assert r.status_code == 403 -async def test_oauth_page_memory(app): - pass - # add service - # Login - # go to service oauth page - # hit auth page - # go to service oauth page again - # don't hit auth page - # clear authorization - # go to service oauth page - # hit auth page +@pytest.mark.parametrize( + "token_roles, hits_page", + [([], True), (['writer'], True), (['writer', 'reader'], False)], +) +async def test_oauth_page_hit( + app, + mockservice_url, + create_user_with_scopes, + create_temp_role, + token_roles, + hits_page, +): + test_roles = { + 'reader': create_temp_role(['read:users'], role_name='reader'), + 'writer': create_temp_role(['users:activity'], role_name='writer'), + } + service = mockservice_url + user = create_user_with_scopes("access:services", "self") + user.new_api_token() + token = user.api_tokens[0] + token.roles = [test_roles[t] for t in token_roles] + + oauth_client = ( + app.db.query(orm.OAuthClient) + .filter_by(identifier=service.oauth_client_id) + .one() + ) + oauth_client.allowed_roles = list(test_roles.values()) + token.client_id = service.oauth_client_id + app.db.commit() + s = AsyncSession() + s.cookies = await app.login_user(user.name) + url = url_path_join(public_url(app, service) + 'owhoami/?arg=x') + r = await s.get(url) + r.raise_for_status() + if hits_page: + # hit auth page to confirm permissions + assert urlparse(r.url).path == app.base_url + 'hub/api/oauth2/authorize' + else: + # skip auth page, permissions are granted + assert r.status_code == 200 + assert r.url == url -async def test_oauth_page_role_expansion(app): +async def test_scope_expansion_revokes_tokens(app): + # todo: test when new scopes are added to roles, all api_tokens for services with those roles are deleted + # and auth will be hit again pass - # add service - # login - # go to service oauth page - # hit auth page - # expand service roles - # go to service oauth page - # hit auth page again async def test_oauth_cookie_collision(app, mockservice_url, create_user_with_scopes): From 7a3b237bb335fbb4787f83eea104da981ab209d2 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 15 Jun 2021 12:07:07 +0200 Subject: [PATCH 244/270] Refactored scope names and updated docs to reflect this --- docs/rest-api.yml | 76 +++++++++++++++----------- docs/source/rbac/index.md | 2 +- docs/source/rbac/roles.md | 2 +- docs/source/rbac/scopes.md | 8 +-- docs/source/rbac/use-cases.md | 12 ++-- docs/source/reference/services.md | 2 +- examples/service-fastapi/README.md | 2 +- examples/service-whoami/README.md | 10 ++-- jupyterhub/apihandlers/auth.py | 2 +- jupyterhub/apihandlers/base.py | 14 ++--- jupyterhub/apihandlers/groups.py | 4 +- jupyterhub/apihandlers/services.py | 4 +- jupyterhub/apihandlers/users.py | 24 ++++---- jupyterhub/handlers/pages.py | 2 +- jupyterhub/roles.py | 27 ++++----- jupyterhub/scopes.py | 42 +++++++------- jupyterhub/services/auth.py | 4 +- jupyterhub/spawner.py | 4 +- jupyterhub/tests/test_pages.py | 2 +- jupyterhub/tests/test_roles.py | 24 ++++---- jupyterhub/tests/test_scopes.py | 48 ++++++++-------- jupyterhub/tests/test_services_auth.py | 2 +- jupyterhub/tests/test_singleuser.py | 24 ++++---- 23 files changed, 180 insertions(+), 161 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 9e94ed1a..790e24b2 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -17,35 +17,37 @@ securityDefinitions: flow: accessCode authorizationUrl: "/hub/api/oauth2/authorize" # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? tokenUrl: "/hub/api/oauth2/token" - scopes: + scopes: # Todo: Generate based on scope table + (noscope): Allows only to identify the requesting entity self: Metascope, grants access to user's own resources; resolves to (no scope) for services. - all: Metascope, valid for tokens only. Grants access to everything that the token's owning entity can do. + all: Metascope, valid for tokens only. Grants access to all resources of the token-owning entity. admin:users: Grants read, write, create and delete access to users and their authentication state but not their servers or tokens. - admin:users:auth_state: Grants access to users' authentication state only. + admin:auth_state: Grants access to users' authentication state only. users: Grants read and write permissions to users' models apart from servers, tokens and authentication state. users:activity: Grants access to read and post users' activity only. users:activity!user=username: Update a single user's activity (example horizontal filter). read:users: Read-only access to users' models apart from servers, tokens and authentication state. read:users!user=username: As above limited to a specific user (example horizontal filter). - read:users:name: Read-only access to users' names. - read:users:roles: Read-only access to a list of users' roles names. + read:users:name: Read-only access to user names. + read:roles:users: Read-only access to user role assignments. read:users:groups: Read-only access to a list of users' group names. read:users:activity: Read-only access to users' activity. read:users:activity!group=groupname: Read-only access to specific group's users' activity (example horizontal filter). - admin:users:servers: Grants read, start/stop, create and delete permissions to users' servers and their state. - admin:users:server_state: Grants access to servers' state only. - users:servers: Allows for starting/stopping users' servers in addition to read access to their models. Does not include the server state. - users:servers!server=servername: Limits the above to a specific server (example horizontal filter). - read:users:servers: Read-only access to users' server models. Does not include the server state. - users:tokens: Grants read, write, create and delete permissions to users' tokens. - read:users:tokens: Read-only access to users' tokens. + admin:servers: Grants read, start/stop, create and delete permissions to users' servers and their state. + admin:server_state: Grants access to servers' state only. + servers: Allows for starting/stopping users' servers in addition to read access to their models. Does not include the server state. + servers!server=servername: Limits the above to a specific server (example horizontal filter). + read:servers: Read-only access to users' server models. Does not include the server state. + tokens: Grants read, write, create and delete permissions to users' tokens. + read:tokens: Read-only access to users' tokens. admin:groups: Grants read, write, create and delete access to groups. groups: Grants read and write permissions to groups, including adding/removing users to/from groups. + read:roles:groups: Read-only access to group roles assignments groups!group=groupname: As above limited to a specific group only (example horizontal filter) read:groups: Read-only access to groups. read:services: Read-only access to service models. read:services:name: Read-only access to service names. - read:services:roles: Read-only access to a list of service roles names. + read:roles:services: Read-only access to a list of service roles names. read:hub: Read-only access to detailed information about JupyterHub. proxy: Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. shutdown: Grants access to shutdown the Hub. @@ -126,8 +128,10 @@ paths: - read:users:name - read:users:groups - read:users:activity - - read:users:servers - #TODO: add admin:users:auth_state/server_state? + - read:servers + - read:roles:users + - admin:auth_state + - admin:server_state parameters: - name: state in: query @@ -203,9 +207,10 @@ paths: - read:users:name - read:users:groups - read:users:activity - - read:users:servers - - admin:users:auth_state - - admin:users:server_state + - read:servers + - read:roles:users + - admin:auth_state + - admin:server_state parameters: - name: name description: username @@ -340,7 +345,7 @@ paths: summary: Start a user's single-user notebook server security: - oauth2: - - users:servers + - servers parameters: - name: name description: username @@ -369,7 +374,7 @@ paths: summary: Stop a user's server security: - oauth2: - - users:servers + - servers parameters: - name: name description: username @@ -386,7 +391,7 @@ paths: summary: Start a user's single-user named-server notebook server security: - oauth2: - - users:servers + - servers parameters: - name: name description: username @@ -420,7 +425,7 @@ paths: summary: Stop a user's named-server security: - oauth2: - - users:servers + - servers parameters: - name: name description: username @@ -460,7 +465,7 @@ paths: summary: List tokens for the user security: - oauth2: - - read:users:tokens + - read:tokens responses: "200": description: The list of tokens @@ -476,7 +481,7 @@ paths: summary: Create a new token for the user security: - oauth2: - - users:tokens + - tokens parameters: - name: token_params in: body @@ -519,7 +524,7 @@ paths: summary: Get the model for a token by id security: - oauth2: - - read:users:tokens + - read:tokens responses: "200": description: The info for the new token @@ -529,7 +534,7 @@ paths: summary: Delete (revoke) a token by id security: - oauth2: - - users:tokens + - tokens responses: "204": description: The token has been deleted @@ -542,9 +547,10 @@ paths: - read:users:name - read:users:groups - read:users:activity - - read:users:servers - - admin:users:auth_state - - admin:users:server_state + - read:servers + - read:roles:users + - admin:auth_state + - admin:server_state responses: "200": description: The authenticated user's model is returned. @@ -556,6 +562,8 @@ paths: security: - oauth2: - read:groups + - read:groups:name + - read:roles:groups parameters: - name: offset in: query @@ -586,6 +594,8 @@ paths: security: - oauth2: - read:groups + - read:groups:name + - read:roles:groups parameters: - name: name description: group name @@ -688,6 +698,8 @@ paths: security: - oauth2: - read:services + - read:services:name + - read:roles:services responses: "200": description: The service list @@ -701,6 +713,8 @@ paths: security: - oauth2: - read:services + - read:services:name + - read:roles:services parameters: - name: name description: service name @@ -790,7 +804,7 @@ paths: accepts passwords (e.g. not OAuth). security: - oauth2: - - users:tokens # minrk: this is a deprecated alias to POST /users/{name}/tokens, either remove it or use the same scope + - tokens parameters: - name: credentials in: body @@ -817,7 +831,7 @@ paths: summary: Identify a user or service from an API token security: - oauth2: - - read:users:tokens # minrk: is it really necessary to have a scope for this, or use self handler for token whoami? + - (noscope) parameters: - name: token in: path diff --git a/docs/source/rbac/index.md b/docs/source/rbac/index.md index 3f9ed98f..6fb102f9 100644 --- a/docs/source/rbac/index.md +++ b/docs/source/rbac/index.md @@ -17,7 +17,7 @@ To remedy situations like this, JupyterHub is transitioning to an RBAC system. B ## Definitions -**Scopes** are specific permissions used to evaluate API requests. For example: the API endpoint `users/servers`, which enables starting or stopping user servers, is guarded by the scope `users:servers`. +**Scopes** are specific permissions used to evaluate API requests. For example: the API endpoint `users/servers`, which enables starting or stopping user servers, is guarded by the scope `servers`. Scopes are not directly assigned to requesters. Rather, when a client performs an API call, their access will be evaluated based on their assigned roles. diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index a8bb35a9..afff5f55 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -55,7 +55,7 @@ c.JupyterHub.load_roles = [  {    'name': 'server-rights',    'description': 'Allows parties to start and stop user servers', -   'scopes': ['users:servers'], +   'scopes': ['servers'],    'users': ['alice', 'bob'],    'services': ['idle-culler'],    'groups': ['admin-group'], diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index e97aefe8..f4ed13e1 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -7,7 +7,7 @@ A scope has a syntax-based design that reveals which resources it provides acces ## Scope conventions - `` \ - The `` scopes, such as `users` or `groups`, grant read and write permissions to the resource itself and all its sub-resources. E.g., the scope `users:servers` is included within the scope `users`. + The top-level `` scopes, such as `users` or `groups`, grant read and write permissions to the resource itself as well as its sub-resources. For example, the scope `users:activity` is included in the scope `users`. +++ - `read:` \ @@ -19,7 +19,7 @@ A scope has a syntax-based design that reveals which resources it provides acces +++ - `:` \ - The {ref}`vertically filtered ` scopes provide access to a subset of the information granted by the `` scope. E.g., the scope `users:servers` allows for accessing user servers only. + The {ref}`vertically filtered ` scopes provide access to a subset of the information granted by the `` scope. E.g., the scope `users:activity` only provides permission to post user activity. +++ - `!=` \ @@ -42,8 +42,8 @@ Metascopes do not follow the general scope syntax. Instead, a metascope resolves Access to the user's own resources and subresources is covered by metascope `self`. This metascope includes the user's model, activity, servers and tokens. For example, `self` for a user named "gerard" includes: - `users!user=gerard` where the `users` scope provides access to the full user model and activity. The filter restricts this access to the user's own resources. -- `users:servers!user=gerard` which grants the user access to their own servers without being able to create/delete any. -- `users:tokens!user=gerard` which allows the user to access, request and delete their own tokens. +- `servers!user=gerard` which grants the user access to their own servers without being able to create/delete any. +- `tokens!user=gerard` which allows the user to access, request and delete their own tokens. The `self` scope is only valid for user entities. In other cases (e.g., for services) it resolves to an empty set of scopes. diff --git a/docs/source/rbac/use-cases.md b/docs/source/rbac/use-cases.md index 4b31ba63..d0858ae3 100644 --- a/docs/source/rbac/use-cases.md +++ b/docs/source/rbac/use-cases.md @@ -38,7 +38,7 @@ Below follows a short tutorial on how to add a cull-idle service in the RBAC sys { "name": "idle-culler", "description": "Culls idle servers", - "scopes": ["read:users:name", "read:users:activity", "users:servers"], + "scopes": ["read:users:name", "read:users:activity", "servers"], "services": ["idle-culler"], } ] @@ -48,7 +48,7 @@ Below follows a short tutorial on how to add a cull-idle service in the RBAC sys Note that in the RBAC system the `admin` field in the `idle-culler` service definition is omitted. Instead, the `idle-culler` role provides the service with only the permissions it needs. If the optional actions of deleting the idle servers and/or removing inactive users are desired, **change the following scopes** in the `idle-culler` role definition: - - `users:servers` to `admin:users:servers` for deleting servers + - `servers` to `admin:servers` for deleting servers - `read:users:name`, `read:users:activity` to `admin:users` for deleting users. ``` @@ -65,8 +65,8 @@ A service capable of creating/removing users and launching multiple servers shou The scopes required to access the API enpoints: 1. `admin:users` -2. `users:servers` -3. `admin:users:servers` +2. `servers` +3. `admin:servers` From the above, the role definition is: @@ -77,7 +77,7 @@ c.JupyterHub.load_roles = [ { "name": "api-launcher", "description": "Manages servers", - "scopes": ["admin:users", "admin:users:servers"], + "scopes": ["admin:users", "admin:servers"], "services": [] } ] @@ -117,7 +117,7 @@ c.JupyterHub.load_roles = [ {    'name': 'teacher',    'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', -   'scopes': [ 'read:users!group=class-B', 'users:servers!group=class-B'], +   'scopes': [ 'read:users!group=class-B', 'servers!group=class-B'],    'users': ['johan'] } ] diff --git a/docs/source/reference/services.md b/docs/source/reference/services.md index a78e8707..7de3a7ea 100644 --- a/docs/source/reference/services.md +++ b/docs/source/reference/services.md @@ -91,7 +91,7 @@ c.JupyterHub.load_roles = [ "name": "idle-culler", "scopes": [ "read:users:activity", # read user last_activity - "users:servers", # start and stop servers + "servers", # start and stop servers # 'admin:users' # needed if culling idle users as well ] } diff --git a/examples/service-fastapi/README.md b/examples/service-fastapi/README.md index 26fb6a7b..b26a586b 100644 --- a/examples/service-fastapi/README.md +++ b/examples/service-fastapi/README.md @@ -45,7 +45,7 @@ $ curl -X GET http://127.0.0.1:8000/services/fastapi/me \ "servers": null, "scopes": [ "access:services", - "access:users:servers!user=test-user", + "access:servers!user=test-user", "...", ] } diff --git a/examples/service-whoami/README.md b/examples/service-whoami/README.md index 2fb59f02..072ff526 100644 --- a/examples/service-whoami/README.md +++ b/examples/service-whoami/README.md @@ -43,19 +43,19 @@ $ curl -H "Authorization: token 8630bbd8ef064c48b22c7f122f0cd8ad" http://127.0.0 ], "scopes": [ "access:services", - "access:users:servers!user=test", + "access:servers!user=test", "read:users!user=test", "read:users:activity!user=test", "read:users:groups!user=test", "read:users:name!user=test", - "read:users:servers!user=test", - "read:users:tokens!user=test", + "read:servers!user=test", + "read:tokens!user=test", "users!user=test", "users:activity!user=test", "users:groups!user=test", "users:name!user=test", - "users:servers!user=test", - "users:tokens!user=test" + "servers!user=test", + "tokens!user=test" ], "server": null } diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index d25d06c7..c88753ac 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -258,7 +258,7 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): # check for access to target resource if client.spawner: - scope_filter = self.get_scope_filter("access:users:servers") + scope_filter = self.get_scope_filter("access:servers") allowed = scope_filter(client.spawner, kind='server') elif client.service: scope_filter = self.get_scope_filter("access:services") diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index d5d4407e..d792d542 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -143,7 +143,7 @@ class APIHandler(BaseHandler): 'user_options': spawner.user_options, 'progress_url': spawner._progress_url, } - scope_filter = self.get_scope_filter('admin:users:server_state') + scope_filter = self.get_scope_filter('admin:server_state') if scope_filter(spawner, kind='server'): model['state'] = spawner.get_state() return model @@ -219,9 +219,9 @@ class APIHandler(BaseHandler): 'read:users:name': {'kind', 'name', 'admin'}, 'read:users:groups': {'kind', 'name', 'groups'}, 'read:users:activity': {'kind', 'name', 'last_activity'}, - 'read:users:servers': {'kind', 'name', 'servers'}, - 'read:users:roles': {'kind', 'name', 'roles', 'admin'}, - 'admin:users:auth_state': {'kind', 'name', 'auth_state'}, + 'read:servers': {'kind', 'name', 'servers'}, + 'read:roles:users': {'kind', 'name', 'roles', 'admin'}, + 'admin:auth_state': {'kind', 'name', 'auth_state'}, } self.log.debug( "Asking for user model of %s with scopes [%s]", @@ -237,7 +237,7 @@ class APIHandler(BaseHandler): model['pending'] = user.spawners[''].pending servers = model['servers'] = {} - scope_filter = self.get_scope_filter('read:users:servers') + scope_filter = self.get_scope_filter('read:servers') for name, spawner in user.spawners.items(): # include 'active' servers, not just ready # (this includes pending events) @@ -258,7 +258,7 @@ class APIHandler(BaseHandler): access_map = { 'read:groups': {'kind', 'name', 'users'}, 'read:groups:name': {'kind', 'name'}, - 'read:groups:roles': {'kind', 'name', 'roles'}, + 'read:roles:groups': {'kind', 'name', 'roles'}, } model = self._filter_model(model, access_map, group, 'group') return model @@ -290,7 +290,7 @@ class APIHandler(BaseHandler): 'display', }, 'read:services:name': {'kind', 'name', 'admin'}, - 'read:services:roles': {'kind', 'name', 'roles', 'admin'}, + 'read:roles:services': {'kind', 'name', 'roles', 'admin'}, } model = self._filter_model(model, access_map, service, 'service') return model diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index df6e197d..84f97a6b 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -34,7 +34,7 @@ class _GroupAPIHandler(APIHandler): class GroupListAPIHandler(_GroupAPIHandler): - @needs_scope('read:groups', 'read:groups:name', 'read:groups:roles') + @needs_scope('read:groups', 'read:groups:name', 'read:roles:groups') def get(self): """List groups""" query = self.db.query(orm.Group) @@ -77,7 +77,7 @@ class GroupListAPIHandler(_GroupAPIHandler): class GroupAPIHandler(_GroupAPIHandler): """View and modify groups by name""" - @needs_scope('read:groups', 'read:groups:name', 'read:groups:roles') + @needs_scope('read:groups', 'read:groups:name', 'read:roles:groups') def get(self, group_name): group = self.find_group(group_name) self.write(json.dumps(self.group_model(group))) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index e2106801..dc751a16 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -11,7 +11,7 @@ from .base import APIHandler class ServiceListAPIHandler(APIHandler): - @needs_scope('read:services', 'read:services:name', 'read:services:roles') + @needs_scope('read:services', 'read:services:name', 'read:roles:services') def get(self): data = {} for name, service in self.services.items(): @@ -22,7 +22,7 @@ class ServiceListAPIHandler(APIHandler): class ServiceAPIHandler(APIHandler): - @needs_scope('read:services', 'read:services:name', 'read:services:roles') + @needs_scope('read:services', 'read:services:name', 'read:roles:services') def get(self, service_name): service = self.services[service_name] self.write(json.dumps(self.service_model(service))) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index 98a23490..7bca6b02 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -75,10 +75,10 @@ class UserListAPIHandler(APIHandler): @needs_scope( 'read:users', 'read:users:name', - 'read:users:servers', + 'read:servers', 'read:users:groups', 'read:users:activity', - 'read:users:roles', + 'read:roles:users', ) def get(self): state_filter = self.get_argument("state", None) @@ -195,10 +195,10 @@ class UserAPIHandler(APIHandler): @needs_scope( 'read:users', 'read:users:name', - 'read:users:servers', + 'read:servers', 'read:users:groups', 'read:users:activity', - 'read:users:roles', + 'read:roles:users', ) async def get(self, user_name): user = self.find_user(user_name) @@ -297,7 +297,7 @@ class UserAPIHandler(APIHandler): class UserTokenListAPIHandler(APIHandler): """API endpoint for listing/creating tokens""" - @needs_scope('read:users:tokens') + @needs_scope('read:tokens') def get(self, user_name): """Get tokens for a given user""" user = self.find_user(user_name) @@ -352,7 +352,7 @@ class UserTokenListAPIHandler(APIHandler): self._resolve_roles_and_scopes() user = self.find_user(user_name) kind = 'user' if isinstance(requester, User) else 'service' - scope_filter = self.get_scope_filter('users:tokens') + scope_filter = self.get_scope_filter('tokens') if user is None or not scope_filter(user, kind): raise web.HTTPError( 403, @@ -417,7 +417,7 @@ class UserTokenAPIHandler(APIHandler): raise web.HTTPError(404, "Token not found %s", orm_token) return orm_token - @needs_scope('read:users:tokens') + @needs_scope('read:tokens') def get(self, user_name, token_id): """""" user = self.find_user(user_name) @@ -426,7 +426,7 @@ class UserTokenAPIHandler(APIHandler): token = self.find_token_by_id(user, token_id) self.write(json.dumps(self.token_model(token))) - @needs_scope('users:tokens') + @needs_scope('tokens') def delete(self, user_name, token_id): """Delete a token""" user = self.find_user(user_name) @@ -451,7 +451,7 @@ class UserTokenAPIHandler(APIHandler): class UserServerAPIHandler(APIHandler): """Start and stop single-user servers""" - @needs_scope('users:servers') + @needs_scope('servers') async def post(self, user_name, server_name=''): user = self.find_user(user_name) if server_name: @@ -496,7 +496,7 @@ class UserServerAPIHandler(APIHandler): self.set_header('Content-Type', 'text/plain') self.set_status(status) - @needs_scope('users:servers') + @needs_scope('servers') async def delete(self, user_name, server_name=''): user = self.find_user(user_name) options = self.get_json_body() @@ -569,7 +569,7 @@ class UserAdminAccessAPIHandler(APIHandler): This handler sets the necessary cookie for an admin to login to a single-user server. """ - @needs_scope('users:servers') + @needs_scope('servers') def post(self, user_name): self.log.warning( "Deprecated in JupyterHub 0.8." @@ -625,7 +625,7 @@ class SpawnProgressAPIHandler(APIHandler): await asyncio.wait([self._finish_future], timeout=self.keepalive_interval) - @needs_scope('read:users:servers') + @needs_scope('read:servers') async def get(self, user_name, server_name=''): self.set_header('Cache-Control', 'no-cache') if server_name is None: diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index 77e6b4a3..fd32905e 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -456,7 +456,7 @@ class AdminHandler(BaseHandler): @web.authenticated @needs_scope('users') @needs_scope('admin:users') - @needs_scope('admin:users:servers') + @needs_scope('admin:servers') async def get(self): auth_state = await self.current_user.get_auth_state() html = await self.render_template( diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index fda19fb4..23f220e4 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -33,16 +33,16 @@ def get_default_roles(): 'description': 'Elevated privileges (can do anything)', 'scopes': [ 'admin:users', - 'admin:users:servers', - 'users:tokens', + 'admin:servers', + 'tokens', 'admin:groups', 'read:services', 'read:hub', 'proxy', 'shutdown', 'access:services', - 'access:users:servers', - 'read:services:roles', + 'access:servers', + 'read:roles', ], }, { @@ -50,7 +50,7 @@ def get_default_roles(): 'description': 'Post activity only', 'scopes': [ 'users:activity!user', - 'access:users:servers!user', + 'access:servers!user', ], }, { @@ -70,9 +70,10 @@ def expand_self_scope(name): users:name users:groups users:activity - users:servers - users:tokens - access:users:servers + tokens + servers + access:servers + Arguments: name (str): user name @@ -87,11 +88,11 @@ def expand_self_scope(name): 'read:users:groups', 'users:activity', 'read:users:activity', - 'users:servers', - 'read:users:servers', - 'users:tokens', - 'read:users:tokens', - 'access:users:servers', + 'servers', + 'read:servers', + 'tokens', + 'read:tokens', + 'access:servers', ] return {"{}!user={}".format(scope, name) for scope in scope_list} diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 85bbb616..f9ffb035 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -34,9 +34,9 @@ scope_definitions = { }, 'admin:users': { 'description': 'Read, write, create and delete users and their authentication state, not including their servers or tokens.', - 'subscopes': ['admin:users:auth_state', 'users', 'read:users:roles'], + 'subscopes': ['admin:auth_state', 'users', 'read:roles:users'], }, - 'admin:users:auth_state': {'description': 'Read a user’s authentication state.'}, + 'admin:auth_state': {'description': 'Read a user’s authentication state.'}, 'users': { 'description': 'Read and write permissions to user models (excluding servers, tokens and authentication state).', 'subscopes': ['read:users', 'users:activity'], @@ -52,32 +52,38 @@ scope_definitions = { 'read:users:name': {'description': 'Read names of users.'}, 'read:users:groups': {'description': 'Read users’ group membership.'}, 'read:users:activity': {'description': 'Read time of last user activity.'}, - 'read:users:roles': {'description': 'Read users’ role assignments.'}, + 'read:roles': { + 'description': 'Read role assignments.', + 'subscopes': ['read:roles:users', 'read:roles:services', 'read:roles:groups'], + }, + 'read:roles:users': {'description': 'Read user role assignments.'}, + 'read:roles:services': {'description': 'Read service role assignments.'}, + 'read:roles:groups': {'description': 'Read group role assignments.'}, 'users:activity': { 'description': 'Update time of last user activity.', 'subscopes': ['read:users:activity'], }, - 'admin:users:servers': { + 'admin:servers': { 'description': 'Read, start, stop, create and delete user servers and their state.', - 'subscopes': ['admin:users:server_state', 'users:servers'], + 'subscopes': ['admin:server_state', 'servers'], }, - 'admin:users:server_state': {'description': 'Read and write users’ server state.'}, - 'users:servers': { + 'admin:server_state': {'description': 'Read and write users’ server state.'}, + 'servers': { 'description': 'Start and stop user servers.', - 'subscopes': ['read:users:servers'], + 'subscopes': ['read:servers'], }, - 'read:users:servers': { + 'read:servers': { 'description': 'Read users’ names and their server models (excluding the server state).', 'subscopes': ['read:users:name'], }, - 'users:tokens': { + 'tokens': { 'description': 'Read, write, create and delete user tokens.', - 'subscopes': ['read:users:tokens'], + 'subscopes': ['read:tokens'], }, - 'read:users:tokens': {'description': 'Read user tokens.'}, + 'read:tokens': {'description': 'Read user tokens.'}, 'admin:groups': { 'description': 'Read and write group information, create and delete groups.', - 'subscopes': ['groups', 'read:groups:roles'], + 'subscopes': ['groups', 'read:roles:groups'], }, 'groups': { 'description': 'Read and write group information, including adding/removing users to/from groups.', @@ -88,15 +94,13 @@ scope_definitions = { 'subscopes': ['read:groups:name'], }, 'read:groups:name': {'description': 'Read group names.'}, - 'read:groups:roles': {'description': 'Read group role assignments.'}, 'read:services': { 'description': 'Read service models.', 'subscopes': ['read:services:name'], }, 'read:services:name': {'description': 'Read service names.'}, - 'read:services:roles': {'description': 'Read service role assignments.'}, 'read:hub': {'description': 'Read detailed information about the Hub.'}, - 'access:users:servers': { + 'access:servers': { 'description': 'Access user servers via API or browser.', }, 'access:services': { @@ -279,7 +283,7 @@ def get_scopes_for(orm_object): spawner = orm_object.oauth_client.spawner if spawner: token_scopes.add( - f"access:users:servers!server={spawner.user.name}/{spawner.name}" + f"access:servers!server={spawner.user.name}/{spawner.name}" ) else: service = orm_object.oauth_client.service @@ -388,7 +392,7 @@ def parse_scopes(scope_list): """ Parses scopes and filters in something akin to JSON style - For instance, scope list ["users", "groups!group=foo", "users:servers!server=user/bar", "users:servers!server=user/baz"] + For instance, scope list ["users", "groups!group=foo", "servers!server=user/bar", "servers!server=user/baz"] would lead to scope model { "users":scope.ALL, @@ -397,7 +401,7 @@ def parse_scopes(scope_list): "alice" ] }, - "users:servers":{ + "servers":{ "server":[ "user/bar", "user/baz" diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index 64080723..d95775c1 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -835,8 +835,8 @@ class HubAuthenticated: which in turn is set by $JUPYTERHUB_OAUTH_SCOPES Default values include: - 'access:services', 'access:services!service={service_name}' for services - - 'access:users:servers', 'access:users:servers!user={user}', - 'access:users:servers!server={user}/{server_name}' + - 'access:servers', 'access:servers!user={user}', + 'access:servers!server={user}/{server_name}' for single-user servers If hub_scopes is not used (e.g. JupyterHub 1.x), diff --git a/jupyterhub/spawner.py b/jupyterhub/spawner.py index 22fbe451..74f9240d 100644 --- a/jupyterhub/spawner.py +++ b/jupyterhub/spawner.py @@ -222,8 +222,8 @@ class Spawner(LoggingConfigurable): @default("oauth_scopes") def _default_oauth_scopes(self): return [ - f"access:users:servers!server={self.user.name}/{self.name}", - f"access:users:servers!user={self.user.name}", + f"access:servers!server={self.user.name}/{self.name}", + f"access:servers!user={self.user.name}", ] handler = Any() diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index cf441198..922c00e6 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -956,7 +956,7 @@ async def test_oauth_page_scope_appearance( [ 'self', 'read:users!user=gawain', - 'read:users:tokens', + 'read:tokens', 'read:groups!group=mythos', ] ) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index e33e936a..26740ec6 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -180,13 +180,13 @@ def test_orm_roles_delete_cascade(db): ['admin:users'], { 'admin:users', - 'admin:users:auth_state', + 'admin:auth_state', 'users', 'read:users', 'users:activity', 'read:users:name', 'read:users:groups', - 'read:users:roles', + 'read:roles:users', 'read:users:activity', }, ), @@ -210,32 +210,32 @@ def test_orm_roles_delete_cascade(db): 'read:users:activity', }, ), - (['read:users:servers'], {'read:users:servers', 'read:users:name'}), + (['read:servers'], {'read:servers', 'read:users:name'}), ( ['admin:groups'], { 'admin:groups', 'groups', 'read:groups', - 'read:groups:roles', + 'read:roles:groups', 'read:groups:name', }, ), ( - ['admin:groups', 'read:users:servers'], + ['admin:groups', 'read:servers'], { 'admin:groups', 'groups', 'read:groups', - 'read:groups:roles', + 'read:roles:groups', 'read:groups:name', - 'read:users:servers', + 'read:servers', 'read:users:name', }, ), ( - ['users:tokens!group=hobbits'], - {'users:tokens!group=hobbits', 'read:users:tokens!group=hobbits'}, + ['tokens!group=hobbits'], + {'tokens!group=hobbits', 'read:tokens!group=hobbits'}, ), ], ) @@ -398,7 +398,7 @@ async def test_delete_roles(db, role_type, rolename, response_type, response): 'users', 'users!user=charlie', 'admin:groups', - 'read:users:tokens', + 'read:tokens', ], }, 'existing', @@ -501,8 +501,8 @@ async def test_load_roles_services(tmpdir, request): 'scopes': [ 'read:users:name', 'read:users:activity', - 'read:users:servers', - 'users:servers', + 'read:servers', + 'servers', ], 'services': ['idle-culler'], }, diff --git a/jupyterhub/tests/test_scopes.py b/jupyterhub/tests/test_scopes.py index e5687caa..1bc4d0a2 100644 --- a/jupyterhub/tests/test_scopes.py +++ b/jupyterhub/tests/test_scopes.py @@ -79,9 +79,9 @@ def test_scope_multiple_filters(): def test_scope_parse_server_name(): handler = get_handler_with_scopes( - ['users:servers!server=maeby/server1', 'read:users!user=maeby'] + ['servers!server=maeby/server1', 'read:users!user=maeby'] ) - assert _check_scope_access(handler, 'users:servers', user='maeby', server='server1') + assert _check_scope_access(handler, 'servers', user='maeby', server='server1') class MockAPIHandler: @@ -99,7 +99,7 @@ class MockAPIHandler: def user_thing(self, user_name): return True - @needs_scope('users:servers') + @needs_scope('servers') def server_thing(self, user_name, server_name): return True @@ -140,18 +140,18 @@ def mock_handler(): (['users!user=george'], 'user_thing', ('fake_user',), False), (['users!user=george'], 'user_thing', ('oscar',), False), (['users!user=george', 'users!user=oscar'], 'user_thing', ('oscar',), True), - (['users:servers'], 'server_thing', ('user1', 'server_1'), True), - (['users:servers'], 'server_thing', ('user1', ''), True), - (['users:servers'], 'server_thing', ('user1', None), True), + (['servers'], 'server_thing', ('user1', 'server_1'), True), + (['servers'], 'server_thing', ('user1', ''), True), + (['servers'], 'server_thing', ('user1', None), True), ( - ['users:servers!server=maeby/bluth'], + ['servers!server=maeby/bluth'], 'server_thing', ('maeby', 'bluth'), True, ), - (['users:servers!server=maeby/bluth'], 'server_thing', ('gob', 'bluth'), False), + (['servers!server=maeby/bluth'], 'server_thing', ('gob', 'bluth'), False), ( - ['users:servers!server=maeby/bluth'], + ['servers!server=maeby/bluth'], 'server_thing', ('maybe', 'bluth2'), False, @@ -488,17 +488,17 @@ async def test_metascope_all_expansion(app, create_user_with_scopes): @mark.parametrize( "scopes, can_stop ,num_servers, keys_in, keys_out", [ - (['read:users:servers!user=almond'], False, 2, {'name'}, {'state'}), + (['read:servers!user=almond'], False, 2, {'name'}, {'state'}), (['admin:users', 'read:users'], False, 0, set(), set()), ( - ['read:users:servers!group=nuts', 'users:servers'], + ['read:servers!group=nuts', 'servers'], True, 2, {'name'}, {'state'}, ), ( - ['admin:users:server_state', 'read:users:servers'], + ['admin:server_state', 'read:servers'], False, 2, {'name', 'state'}, @@ -506,8 +506,8 @@ async def test_metascope_all_expansion(app, create_user_with_scopes): ), ( [ - 'read:users:servers!server=almond/bianca', - 'admin:users:server_state!server=almond/bianca', + 'read:servers!server=almond/bianca', + 'admin:server_state!server=almond/bianca', ], False, 1, @@ -634,8 +634,8 @@ async def test_server_state_access( ), ( 'no_intersection_user_server', - ['users:servers!user=y'], - ['users:servers!server=x'], + ['servers!user=y'], + ['servers!server=x'], set(), ), ( @@ -704,7 +704,7 @@ async def test_resolve_token_permissions( }, ), ( - {'read:services:roles', 'read:services:name'}, + {'read:roles:services', 'read:services:name'}, {'name', 'kind', 'roles', 'admin'}, ), ({'read:services:name'}, {'name', 'kind', 'admin'}), @@ -734,7 +734,7 @@ async def test_service_model_filtering( }, ), ( - {'read:groups:roles', 'read:groups:name'}, + {'read:roles:groups', 'read:groups:name'}, {'name', 'kind', 'roles'}, ), ({'read:groups:name'}, {'name', 'kind'}), @@ -761,7 +761,7 @@ async def test_group_model_filtering( async def test_roles_access(app, create_service_with_scopes, create_user_with_scopes): user = add_user(app.db, name='miranda') - read_user = create_user_with_scopes('read:users:roles') + read_user = create_user_with_scopes('read:roles:users') r = await api_request( app, 'users', user.name, headers=auth_header(app.db, read_user.name) ) @@ -822,15 +822,15 @@ async def test_roles_access(app, create_service_with_scopes, create_user_with_sc ), # resolves server under user, without warning ( - set(["read:users:servers!user=abc"]), - set(["read:users:servers!server=abc/xyz"]), - set(["read:users:servers!server=abc/xyz"]), + set(["read:servers!user=abc"]), + set(["read:servers!server=abc/xyz"]), + set(["read:servers!server=abc/xyz"]), False, ), # user->server, no match ( - set(["read:users:servers!user=abc"]), - set(["read:users:servers!server=abcd/xyz"]), + set(["read:servers!user=abc"]), + set(["read:servers!server=abcd/xyz"]), set([]), False, ), diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index b3b2838f..c402c6be 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -128,7 +128,7 @@ async def test_hubauth_token(app, mockservice_url, create_user_with_scopes): ), ( [ - "access:users:servers!user=$service", + "access:servers!user=$service", ], False, ), diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index bf3b0905..7d6c860c 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -17,18 +17,18 @@ from .utils import AsyncSession @pytest.mark.parametrize( "access_scopes, server_name, expect_success", [ - (["access:users:servers!group=$group"], "", True), - (["access:users:servers!group=other-group"], "", False), - (["access:users:servers"], "", True), - (["access:users:servers"], "named", True), - (["access:users:servers!user=$user"], "", True), - (["access:users:servers!user=$user"], "named", True), - (["access:users:servers!server=$server"], "", True), - (["access:users:servers!server=$server"], "named-server", True), - (["access:users:servers!server=$user/other"], "", False), - (["access:users:servers!server=$user/other"], "some-name", False), - (["access:users:servers!user=$other"], "", False), - (["access:users:servers!user=$other"], "named", False), + (["access:servers!group=$group"], "", True), + (["access:servers!group=other-group"], "", False), + (["access:servers"], "", True), + (["access:servers"], "named", True), + (["access:servers!user=$user"], "", True), + (["access:servers!user=$user"], "named", True), + (["access:servers!server=$server"], "", True), + (["access:servers!server=$server"], "named-server", True), + (["access:servers!server=$user/other"], "", False), + (["access:servers!server=$user/other"], "some-name", False), + (["access:servers!user=$other"], "", False), + (["access:servers!user=$other"], "named", False), (["access:services"], "", False), (["self"], "named", False), ([], "", False), From ceed989e77b876cf3b1d77a0967b9a53d11c6401 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 15 Jun 2021 13:49:24 +0200 Subject: [PATCH 245/270] Generate REST API scope descriptions from source code --- docs/rest-api.yml | 180 +++++++++++++++-------- docs/source/rbac/generate-scope-table.py | 27 +++- jupyterhub/scopes.py | 2 + 3 files changed, 145 insertions(+), 64 deletions(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 790e24b2..34e8abf0 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -17,40 +17,53 @@ securityDefinitions: flow: accessCode authorizationUrl: "/hub/api/oauth2/authorize" # what are the absolute URIs here? is oauth2 correct here or shall we use just authorizations? tokenUrl: "/hub/api/oauth2/token" - scopes: # Todo: Generate based on scope table - (noscope): Allows only to identify the requesting entity - self: Metascope, grants access to user's own resources; resolves to (no scope) for services. - all: Metascope, valid for tokens only. Grants access to all resources of the token-owning entity. - admin:users: Grants read, write, create and delete access to users and their authentication state but not their servers or tokens. - admin:auth_state: Grants access to users' authentication state only. - users: Grants read and write permissions to users' models apart from servers, tokens and authentication state. - users:activity: Grants access to read and post users' activity only. - users:activity!user=username: Update a single user's activity (example horizontal filter). - read:users: Read-only access to users' models apart from servers, tokens and authentication state. - read:users!user=username: As above limited to a specific user (example horizontal filter). - read:users:name: Read-only access to user names. - read:roles:users: Read-only access to user role assignments. - read:users:groups: Read-only access to a list of users' group names. - read:users:activity: Read-only access to users' activity. - read:users:activity!group=groupname: Read-only access to specific group's users' activity (example horizontal filter). - admin:servers: Grants read, start/stop, create and delete permissions to users' servers and their state. - admin:server_state: Grants access to servers' state only. - servers: Allows for starting/stopping users' servers in addition to read access to their models. Does not include the server state. - servers!server=servername: Limits the above to a specific server (example horizontal filter). - read:servers: Read-only access to users' server models. Does not include the server state. - tokens: Grants read, write, create and delete permissions to users' tokens. - read:tokens: Read-only access to users' tokens. - admin:groups: Grants read, write, create and delete access to groups. - groups: Grants read and write permissions to groups, including adding/removing users to/from groups. - read:roles:groups: Read-only access to group roles assignments - groups!group=groupname: As above limited to a specific group only (example horizontal filter) - read:groups: Read-only access to groups. - read:services: Read-only access to service models. - read:services:name: Read-only access to service names. - read:roles:services: Read-only access to a list of service roles names. - read:hub: Read-only access to detailed information about JupyterHub. - proxy: Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. - shutdown: Grants access to shutdown the Hub. + scopes: # Generated based on scope table in jupyterhub/scopes.py + (no_scope): Identify the owner of the requesting entity. + self: + The user’s own resources _(metascope for users, resolves to (no_scope) + for services)_ + all: Everything that the token-owning entity can access _(metascope for tokens)_ + admin:users: + Read, write, create and delete users and their authentication state, + not including their servers or tokens. + admin:auth_state: Read a user’s authentication state. + users: + Read and write permissions to user models (excluding servers, tokens + and authentication state). + read:users: + Read user models (excluding including servers, tokens and authentication + state). + read:users:name: Read names of users. + read:users:groups: Read users’ group membership. + read:users:activity: Read time of last user activity. + read:roles: Read role assignments. + read:roles:users: Read user role assignments. + read:roles:services: Read service role assignments. + read:roles:groups: Read group role assignments. + users:activity: Update time of last user activity. + admin:servers: Read, start, stop, create and delete user servers and their state. + admin:server_state: Read and write users’ server state. + servers: Start and stop user servers. + read:servers: + Read users’ names and their server models (excluding the server + state). + tokens: Read, write, create and delete user tokens. + read:tokens: Read user tokens. + admin:groups: Read and write group information, create and delete groups. + groups: + Read and write group information, including adding/removing users to/from + groups. + read:groups: Read group models. + read:groups:name: Read group names. + read:services: Read service models. + read:services:name: Read service names. + read:hub: Read detailed information about the Hub. + access:servers: Access user servers via API or browser. + access:services: Access services via API or browser. + proxy: + Read information about the proxy’s routing table, sync the Hub with the + proxy and notify the Hub about a new proxy. + shutdown: Shutdown the hub. security: # global security, do we want to keep only the apiKey (token: []), change to only oauth2 (with scope self) or have both (either can be used)? - token: [] - oauth2: @@ -106,7 +119,9 @@ paths: properties: class: type: string - description: The Python class currently active for JupyterHub Authentication + description: + The Python class currently active for JupyterHub + Authentication version: type: string description: The version of the currently active Authenticator @@ -115,7 +130,9 @@ paths: properties: class: type: string - description: The Python class currently active for spawning single-user notebook servers + description: + The Python class currently active for spawning single-user + notebook servers version: type: string description: The version of the currently active Spawner @@ -253,16 +270,22 @@ paths: - name: body in: body required: true - description: Updated user info. At least one key to be updated (name or admin) is required. + description: + Updated user info. At least one key to be updated (name or admin) + is required. schema: type: object properties: name: type: string - description: the new name (optional, if another key is updated i.e. admin) + description: + the new name (optional, if another key is updated i.e. + admin) admin: type: boolean - description: update admin (optional, if another key is updated i.e. name) + description: + update admin (optional, if another key is updated i.e. + name) responses: "200": description: The updated user info @@ -285,9 +308,9 @@ paths: /users/{name}/activity: post: summary: Notify Hub of activity for a given user. - description: Notify the Hub of activity by the user, - e.g. accessing a service or (more likely) - actively using a server. + description: + Notify the Hub of activity by the user, e.g. accessing a service + or (more likely) actively using a server. security: - oauth2: - users:activity @@ -369,7 +392,9 @@ paths: "201": description: The user's notebook server has started "202": - description: The user's notebook server has not yet started, but has been requested + description: + The user's notebook server has not yet started, but has been + requested delete: summary: Stop a user's server security: @@ -385,7 +410,9 @@ paths: "204": description: The user's notebook server has stopped "202": - description: The user's notebook server has not yet stopped as it is taking a while to stop + description: + The user's notebook server has not yet stopped as it is taking + a while to stop /users/{name}/servers/{server_name}: post: summary: Start a user's single-user named-server notebook server @@ -420,7 +447,9 @@ paths: "201": description: The user's notebook named-server has started "202": - description: The user's notebook named-server has not yet started, but has been requested + description: + The user's notebook named-server has not yet started, but has + been requested delete: summary: Stop a user's named-server security: @@ -453,7 +482,9 @@ paths: "204": description: The user's notebook named-server has stopped "202": - description: The user's notebook named-server has not yet stopped as it is taking a while to stop + description: + The user's notebook named-server has not yet stopped as it + is taking a while to stop /users/{name}/tokens: parameters: - name: name @@ -491,7 +522,9 @@ paths: properties: expires_in: type: number - description: lifetime (in seconds) after which the requested token will expire. + description: + lifetime (in seconds) after which the requested token will + expire. note: type: string description: A note attached to the token for future bookkeeping @@ -712,9 +745,7 @@ paths: summary: Get a service by name security: - oauth2: - - read:services - - read:services:name - - read:roles:services + - read:services - read:services:name - read:roles:services parameters: - name: name description: service name @@ -729,7 +760,9 @@ paths: /proxy: get: summary: Get the proxy's routing table - description: A convenience alias for getting the routing table directly from the proxy + description: + A convenience alias for getting the routing table directly from + the proxy security: - oauth2: - proxy @@ -755,7 +788,9 @@ paths: description: Routing table schema: type: object - description: configurable-http-proxy routing table (see configurable-http-proxy docs for details) + description: + configurable-http-proxy routing table (see configurable-http-proxy + docs for details) post: summary: Force the Hub to sync with the proxy security: @@ -774,7 +809,9 @@ paths: - name: body in: body required: true - description: Any values that have changed for the new proxy. All keys are optional. + description: + Any values that have changed for the new proxy. All keys are + optional. schema: type: object properties: @@ -845,7 +882,9 @@ paths: /authorizations/cookie/{cookie_name}/{cookie_value}: get: summary: Identify a user from a cookie - description: Used by single-user notebook servers to hand off cookie authentication to the Hub + description: + Used by single-user notebook servers to hand off cookie authentication + to the Hub parameters: - name: cookie_name in: path @@ -955,10 +994,14 @@ paths: properties: proxy: type: boolean - description: Whether the proxy should be shutdown as well (default from Hub config) + description: + Whether the proxy should be shutdown as well (default from + Hub config) servers: type: boolean - description: Whether users' notebook servers should be shutdown as well (default from Hub config) + description: + Whether users' notebook servers should be shutdown as well + (default from Hub config) responses: "202": description: Shutdown successful @@ -1009,13 +1052,17 @@ definitions: auth_state: type: string #TODO: will there be predefined states? Should it rather be object instead of string? - description: Authentication state of the user. Only available with admin:users:auth_state scope. None otherwise. + description: + Authentication state of the user. Only available with admin:users:auth_state + scope. None otherwise. Server: type: object properties: name: type: string - description: The server's name. The user's default server has an empty name ('') + description: + The server's name. The user's default server has an empty name + ('') ready: type: boolean description: | @@ -1046,10 +1093,15 @@ definitions: description: UTC timestamp last-seen activity on this server. state: type: object - description: Arbitrary internal state from this server's spawner. Only available on the hub's users list or get-user-by-name method, and only with admin:users:server_state scope. None otherwise. + description: + Arbitrary internal state from this server's spawner. Only available + on the hub's users list or get-user-by-name method, and only with admin:users:server_state + scope. None otherwise. user_options: type: object - description: User specified options for the user's spawned instance of a single-user server. + description: + User specified options for the user's spawned instance of a single-user + server. Group: type: object properties: @@ -1104,7 +1156,9 @@ definitions: properties: token: type: string - description: The token itself. Only present in responses to requests for a new token. + description: + The token itself. Only present in responses to requests for a + new token. id: type: string description: The id of the API token. Used for modifying or deleting the token. @@ -1121,7 +1175,9 @@ definitions: type: string note: type: string - description: A note about the token, typically describing what it was created for. + description: + A note about the token, typically describing what it was created + for. created: type: string format: date-time diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index 99b1ddbb..bcfe78c0 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -1,11 +1,14 @@ import os from collections import defaultdict +from pathlib import Path from pytablewriter import MarkdownTableWriter +from ruamel.yaml import YAML from jupyterhub.scopes import scope_definitions HERE = os.path.abspath(os.path.dirname(__file__)) +PARENT = Path(HERE).parent.parent.absolute() class ScopeTableGenerator: @@ -64,7 +67,7 @@ class ScopeTableGenerator: doc_description = self.scopes[scopename].get('doc_description', '') if doc_description: description = doc_description - table_row = [f"{md_indent*depth}`{scopename}`", description] + table_row = [f"{md_indent * depth}`{scopename}`", description] table_rows.append(table_row) for subscope in scope_pairs[scopename]: if subscope: @@ -76,7 +79,7 @@ class ScopeTableGenerator: return table_rows def write_table(self): - """Generates the scope table in markdown format and writes it into scope-table.md file""" + """Generates the scope table in markdown format and writes it into `scope-table.md`""" filename = f"{HERE}/scope-table.md" table_name = "" headers = ["Scope", "Grants permission to:"] @@ -92,10 +95,30 @@ class ScopeTableGenerator: "Run 'make clean' before 'make html' to ensure the built scopes.html contains latest scope table changes." ) + def write_api(self): + """Generates the API description in markdown format and writes it into `rest-api.yml`""" + filename = f"{PARENT}/rest-api.yml" + yaml = YAML(typ='rt') + yaml.preserve_quotes = True + scope_dict = {} + with open(filename, 'r+') as f: + content = yaml.load(f.read()) + f.seek(0) + for scope in self.scopes: + description = self.scopes[scope]['description'] + doc_description = self.scopes[scope].get('doc_description', '') + if doc_description: + description = doc_description + scope_dict[scope] = description + content['securityDefinitions']['oauth2']['scopes'] = scope_dict + yaml.dump(content, f) + f.truncate() + def main(): table_generator = ScopeTableGenerator() table_generator.write_table() + table_generator.write_api() if __name__ == "__main__": diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index f9ffb035..bb4342af 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -22,6 +22,8 @@ from tornado.log import app_log from . import orm from . import roles +"""when modifying the scope definitions, make sure that `docs/source/rbac/generate-scope-table.py` is run + so that changes are reflected in the documentation and REST API description.""" scope_definitions = { '(no_scope)': {'description': 'Identify the owner of the requesting entity.'}, 'self': { From ac7625306b05e857441d060fdfa6510718d0e068 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 15 Jun 2021 15:34:43 +0200 Subject: [PATCH 246/270] Revoke tokens for oauth if their roles expand permissions --- jupyterhub/apihandlers/auth.py | 12 ++++--- jupyterhub/app.py | 45 ++++++++++++++++++++++---- jupyterhub/tests/test_roles.py | 28 +++++++++++++++- jupyterhub/tests/test_services_auth.py | 6 ---- 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/jupyterhub/apihandlers/auth.py b/jupyterhub/apihandlers/auth.py index c88753ac..ee0a5343 100644 --- a/jupyterhub/apihandlers/auth.py +++ b/jupyterhub/apihandlers/auth.py @@ -290,10 +290,14 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler): return # resolve roles to scopes for authorization page - role_objects = ( - self.db.query(orm.Role).filter(orm.Role.name.in_(role_names)).all() - ) - raw_scopes = set(itertools.chain(*(role.scopes for role in role_objects))) + raw_scopes = set() + if role_names: + role_objects = ( + self.db.query(orm.Role).filter(orm.Role.name.in_(role_names)).all() + ) + raw_scopes = set( + itertools.chain(*(role.scopes for role in role_objects)) + ) if not raw_scopes: scope_descriptions = [ { diff --git a/jupyterhub/app.py b/jupyterhub/app.py index f4aab838..30f6b824 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1985,13 +1985,41 @@ class JupyterHub(Application): config_role_names = [r['name'] for r in self.load_roles] init_roles = default_roles - for role_name in config_role_names: + roles_with_new_permissions = [] + for role_spec in self.load_roles: + role_name = role_spec['name'] + # Check for duplicates if config_role_names.count(role_name) > 1: raise ValueError( f"Role {role_name} multiply defined. Please check the `load_roles` configuration" ) - for role_spec in self.load_roles: init_roles.append(role_spec) + # Check if some roles have obtained new permissions (to avoid 'scope creep') + old_role = orm.Role.find(self.db, name=role_name) + if old_role: + if not set(role_spec['scopes']).issubset(old_role.scopes): + app_log.warning( + "Role %s has obtained extra permissions" % role_name + ) + roles_with_new_permissions.append(role_name) + if roles_with_new_permissions: + unauthorized_oauth_tokens = ( + self.db.query(orm.APIToken) + .filter( + orm.APIToken.roles.any( + orm.Role.name.in_(roles_with_new_permissions) + ) + ) + .filter(orm.APIToken.client_id != 'jupyterhub') + ) + for token in unauthorized_oauth_tokens: + app_log.warning( + "Deleting OAuth token %s; one of its roles obtained new permissions that were not authorized by user" + % token + ) + self.db.delete(token) + self.db.commit() + init_role_names = [r['name'] for r in init_roles] if not orm.Role.find(self.db, name='admin'): self._rbac_upgrade = True @@ -2069,11 +2097,12 @@ class JupyterHub(Application): orm_obj.admin = True setattr(predef_role_obj, bearer, orm_role_bearers) db.commit() - allowed_users = db.query(orm.User).filter( - orm.User.name.in_(self.authenticator.allowed_users) - ) - for user in allowed_users: - roles.grant_role(db, user, 'user') + if self.authenticator.allowed_users: + allowed_users = db.query(orm.User).filter( + orm.User.name.in_(self.authenticator.allowed_users) + ) + for user in allowed_users: + roles.grant_role(db, user, 'user') admin_role = orm.Role.find(db, 'admin') for bearer in admin_role_objects: Class = orm.get_class(bearer) @@ -2174,6 +2203,8 @@ class JupyterHub(Application): # purge expired tokens hourly # we don't need to be prompt about this # because expired tokens cannot be used anyway + + # purge all OAuth tokens that gained extra permissions due to role definition changes pc = PeriodicCallback( self.purge_expired_tokens, 1e3 * self.purge_expired_tokens_interval ) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 26740ec6..a1ba9b02 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1030,6 +1030,33 @@ async def test_config_role_users(): assert role not in user.roles +async def test_scope_expansion_revokes_tokens(app, mockservice_url): + role_name = 'morpheus' + roles_to_load = [ + { + 'name': role_name, + 'description': 'wears sunglasses', + 'scopes': ['users', 'groups'], + }, + ] + app.load_roles = roles_to_load + await app.init_role_creation() + user = add_user(app.db, name='laurence') + for _ in range(2): + user.new_api_token() + red_token, blue_token = user.api_tokens + roles.grant_role(app.db, red_token, role_name) + service = mockservice_url + red_token.client_id = service.oauth_client_id + app.db.commit() + # Restart hub and see if token is revoked + app.load_roles[0]['scopes'].append('proxy') + await app.init_role_creation() + user = orm.User.find(app.db, name='laurence') + assert red_token not in user.api_tokens + assert blue_token in user.api_tokens + + async def test_duplicate_role_users(): role_name = 'painter' user_name = 'benny' @@ -1249,7 +1276,6 @@ async def test_token_keep_roles_on_restart(): 'scopes': ['read:users'], } ] - hub = MockHub(load_roles=role_spec) hub.init_db() hub.authenticator.admin_users = ['ben'] diff --git a/jupyterhub/tests/test_services_auth.py b/jupyterhub/tests/test_services_auth.py index c402c6be..c55746fb 100644 --- a/jupyterhub/tests/test_services_auth.py +++ b/jupyterhub/tests/test_services_auth.py @@ -416,12 +416,6 @@ async def test_oauth_page_hit( assert r.url == url -async def test_scope_expansion_revokes_tokens(app): - # todo: test when new scopes are added to roles, all api_tokens for services with those roles are deleted - # and auth will be hit again - pass - - async def test_oauth_cookie_collision(app, mockservice_url, create_user_with_scopes): service = mockservice_url url = url_path_join(public_url(app, mockservice_url), 'owhoami/') From f75df1264817016fb17f01d702e83a0dff598529 Mon Sep 17 00:00:00 2001 From: 0mar Date: Tue, 15 Jun 2021 15:48:03 +0200 Subject: [PATCH 247/270] Small db fix --- jupyterhub/app.py | 1 - jupyterhub/tests/test_roles.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 30f6b824..5b3190bd 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2204,7 +2204,6 @@ class JupyterHub(Application): # we don't need to be prompt about this # because expired tokens cannot be used anyway - # purge all OAuth tokens that gained extra permissions due to role definition changes pc = PeriodicCallback( self.purge_expired_tokens, 1e3 * self.purge_expired_tokens_interval ) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index a1ba9b02..64d3d664 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -848,6 +848,7 @@ async def test_server_role_api_calls( app, token_role, api_method, api_endpoint, for_user, response ): user = add_user(app.db, app, name='test_user') + roles.grant_role(app.db, user, 'user') if token_role == 'no_role': api_token = user.new_api_token(roles=[]) else: From 684cac4dc9231c54e333dddb69c6535f8566b4fa Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 09:15:27 +0200 Subject: [PATCH 248/270] Fixed newlines --- docs/rest-api.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/rest-api.yml b/docs/rest-api.yml index 34e8abf0..3178752b 100644 --- a/docs/rest-api.yml +++ b/docs/rest-api.yml @@ -745,7 +745,9 @@ paths: summary: Get a service by name security: - oauth2: - - read:services - read:services:name - read:roles:services + - read:services + - read:services:name + - read:roles:services parameters: - name: name description: service name From 0a231fe8ba277e55c9dc47da2889fa1211180635 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 15 Jun 2021 15:19:52 +0200 Subject: [PATCH 249/270] ensure managed services work with internal ssl - ensure create_certs is called for managed services - wait for services with http, which checks ssl connections (without http, only tcp was checked, which doesn't verify it works!) --- jupyterhub/app.py | 9 ++------- jupyterhub/services/service.py | 8 ++++++-- jupyterhub/tests/conftest.py | 5 +++-- jupyterhub/tests/test_services.py | 11 ++++++----- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index f4aab838..df65530b 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2290,7 +2290,7 @@ class JupyterHub(Application): if not service.url: continue try: - await Server.from_orm(service.orm.server).wait_up(timeout=1) + await Server.from_orm(service.orm.server).wait_up(timeout=1, http=True) except TimeoutError: self.log.warning( "Cannot connect to %s service %s at %s", @@ -2983,7 +2983,7 @@ class JupyterHub(Application): if service.managed: self.log.info("Starting managed service %s", msg) try: - service.start() + await service.start() except Exception as e: self.log.critical( "Failed to start service %s", service_name, exc_info=True @@ -2996,11 +2996,6 @@ class JupyterHub(Application): tries = 10 if service.managed else 1 for i in range(tries): try: - ssl_context = make_ssl_context( - self.internal_ssl_key, - self.internal_ssl_cert, - cafile=self.internal_ssl_ca, - ) await Server.from_orm(service.orm.server).wait_up( http=True, timeout=1, ssl_context=ssl_context ) diff --git a/jupyterhub/services/service.py b/jupyterhub/services/service.py index 24d19592..db761c7e 100644 --- a/jupyterhub/services/service.py +++ b/jupyterhub/services/service.py @@ -38,6 +38,7 @@ A hub-managed service with no URL:: } """ +import asyncio import copy import os import pipes @@ -369,7 +370,7 @@ class Service(LoggingConfigurable): managed=' managed' if self.managed else '', ) - def start(self): + async def start(self): """Start a managed service""" if not self.managed: raise RuntimeError("Cannot start unmanaged service %s" % self) @@ -407,6 +408,8 @@ class Service(LoggingConfigurable): internal_certs_location=self.app.internal_certs_location, internal_trust_bundles=self.app.internal_trust_bundles, ) + if self.spawner.internal_ssl: + self.spawner.cert_paths = await self.spawner.create_certs() self.spawner.start() self.proc = self.spawner.proc self.spawner.add_poll_callback(self._proc_stopped) @@ -417,7 +420,8 @@ class Service(LoggingConfigurable): self.log.error( "Service %s exited with status %i", self.name, self.proc.returncode ) - self.start() + # schedule start + asyncio.ensure_future(self.start()) async def stop(self): """Stop a managed service""" diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index a51bf858..18239a28 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -29,6 +29,7 @@ import asyncio import inspect import os import sys +from functools import partial from getpass import getuser from subprocess import TimeoutExpired from unittest import mock @@ -263,7 +264,7 @@ def _mockservice(request, app, url=False): async def start(): # wait for proxy to be updated before starting the service await app.proxy.add_all_services(app._service_map) - service.start() + await service.start() io_loop.run_sync(start) @@ -277,7 +278,7 @@ def _mockservice(request, app, url=False): with raises(TimeoutExpired): service.proc.wait(1) if url: - io_loop.run_sync(service.server.wait_up) + io_loop.run_sync(partial(service.server.wait_up, http=True)) return service diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 75ff2874..8c2d1d4b 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -9,6 +9,7 @@ from async_generator import asynccontextmanager from .. import orm from ..roles import update_roles +from ..utils import exponential_backoff from ..utils import maybe_future from ..utils import random_port from ..utils import url_path_join @@ -51,11 +52,11 @@ async def test_managed_service(mockservice): assert proc.poll() is not None # ensure Hub notices service is down and brings it back up: - for i in range(20): - if service.proc is not proc: - break - else: - await asyncio.sleep(0.2) + await exponential_backoff( + lambda: service.proc is not proc, + "Process was never replaced", + timeout=20, + ) assert service.proc.pid != first_pid assert service.proc.poll() is None From 4359b6dc3cef6cd35debfb049cbfae23af71ea7e Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 11:36:49 +0200 Subject: [PATCH 250/270] Added test for service role defaults --- jupyterhub/tests/test_roles.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 64d3d664..7829719d 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -1219,7 +1219,17 @@ async def test_empty_admin_spec(): assert not admin_role.users -# Todo: Test that services don't get default roles on any startup +async def test_no_default_service_role(): + services = [ + { + 'name': 'minesweeper', + 'api_token': 'some-token', + } + ] + hub = MockHub(services=services) + await hub.initialize() + service = orm.Service.find(hub.db, 'minesweeper') + assert not service.roles async def test_hub_upgrade_detection(tmpdir): From 528ab288712695e9b34d8dde74acfe0f6f54e4db Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 11:37:23 +0200 Subject: [PATCH 251/270] Raise error when hub has no roles defined --- jupyterhub/app.py | 5 +++-- jupyterhub/orm.py | 14 ++------------ jupyterhub/tests/conftest.py | 4 ++++ jupyterhub/tests/test_orm.py | 3 --- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index c2a4de40..89d7feba 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -214,11 +214,12 @@ class NewToken(Application): hub.load_config_file(hub.config_file) hub.init_db() - def init_users(): + def init_roles_and_users(): loop = asyncio.new_event_loop() + loop.run_until_complete(hub.init_role_creation()) loop.run_until_complete(hub.init_users()) - ThreadPoolExecutor(1).submit(init_users).result() + ThreadPoolExecutor(1).submit(init_roles_and_users).result() user = orm.User.find(hub.db, self.name) if user is None: print("No such user: %s" % self.name, file=sys.stderr) diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index c38feff7..7dcf5a00 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -716,18 +716,8 @@ class APIToken(Hashed, Base): orm_token.expires_at = cls.now() + timedelta(seconds=expires_in) db.add(orm_token) - token_role = Role.find(db, 'token') - if not token_role: - # FIXME: remove this. - # Creating a token before the db has roles defined should raise an error. - # PR #3460 should let us fix it by ensuring default roles are defined - - warnings.warn( - "Token created before default roles!", RuntimeWarning, stacklevel=2 - ) - default_roles = get_default_roles() - for role in default_roles: - create_role(db, role) + if not Role.find(db, 'token'): + raise AttributeError("Default token role has not been created") try: if roles is not None: update_roles(db, entity=orm_token, roles=roles) diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 18239a28..a7b6c2fe 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -44,6 +44,8 @@ import jupyterhub.services.service from . import mocking from .. import crypto from .. import orm +from ..roles import create_role +from ..roles import get_default_roles from ..roles import mock_roles from ..roles import update_roles from ..utils import random_port @@ -129,6 +131,8 @@ def db(): app = MockHub(db_url='sqlite:///:memory:') app.init_db() _db = app.db + for role in get_default_roles(): + create_role(_db, role) user = orm.User(name=getuser()) _db.add(user) _db.commit() diff --git a/jupyterhub/tests/test_orm.py b/jupyterhub/tests/test_orm.py index 6c1be117..c9ed8c51 100644 --- a/jupyterhub/tests/test_orm.py +++ b/jupyterhub/tests/test_orm.py @@ -221,9 +221,6 @@ async def test_spawn_fails(db): orm_user = orm.User(name='aeofel') db.add(orm_user) db.commit() - - # TODO: default roles should be assigned to users anytime a user is added to database (in orm?) - # the user added here has no role while the server token gets the default server role def_roles = roles.get_default_roles() for role in def_roles: roles.create_role(db, role) From 5094baf797da3ebfda4c543585739e4d1c3a211a Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 11:45:02 +0200 Subject: [PATCH 252/270] Added scope checker --- jupyterhub/scopes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index bb4342af..e7fcd39c 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -444,6 +444,10 @@ def unparse_scopes(parsed_scopes): def needs_scope(*scopes): """Decorator to restrict access to users or services with the required scope""" + for scope in scopes: + if scope not in scope_definitions: + raise ValueError(f"Scope {scope} is not a valid scope") + def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): From 1bfe4be634063c4037b61268fb140d87c5c6dd2d Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 11:59:48 +0200 Subject: [PATCH 253/270] Added test for admin pages scope guard --- jupyterhub/handlers/pages.py | 2 +- jupyterhub/tests/test_pages.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/jupyterhub/handlers/pages.py b/jupyterhub/handlers/pages.py index fd32905e..e3be65bf 100644 --- a/jupyterhub/handlers/pages.py +++ b/jupyterhub/handlers/pages.py @@ -454,7 +454,7 @@ class AdminHandler(BaseHandler): """Render the admin page.""" @web.authenticated - @needs_scope('users') + @needs_scope('users') # stacked decorators: all scopes must be present @needs_scope('admin:users') @needs_scope('admin:servers') async def get(self): diff --git a/jupyterhub/tests/test_pages.py b/jupyterhub/tests/test_pages.py index 922c00e6..10b8cfbc 100644 --- a/jupyterhub/tests/test_pages.py +++ b/jupyterhub/tests/test_pages.py @@ -949,6 +949,24 @@ async def test_bad_oauth_get(app, params): assert r.status_code == 400 +@pytest.mark.parametrize( + "scopes, has_access", + [ + (["users"], False), + (["admin:users"], False), + (["users", "admin:users", "admin:servers"], True), + ], +) +async def test_admin_page_access(app, scopes, has_access, create_user_with_scopes): + user = create_user_with_scopes(*scopes) + cookies = await app.login_user(user.name) + r = await get_page("/admin", app, cookies=cookies) + if has_access: + assert r.status_code == 200 + else: + assert r.status_code == 403 + + async def test_oauth_page_scope_appearance( app, mockservice_url, create_user_with_scopes, create_temp_role ): From a6a048c546af0d5aa84901d3c91054b80f389721 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 12:28:36 +0200 Subject: [PATCH 254/270] WIP: dealing with users only in load_roles --- jupyterhub/app.py | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 89d7feba..ffd350dc 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2037,7 +2037,7 @@ class JupyterHub(Application): async def init_role_assignment(self): # tokens are added separately - role_bearers = ['users', 'services', 'groups'] + kinds = ['users', 'services', 'groups'] admin_role_objects = ['users', 'services'] config_admin_users = set(self.authenticator.admin_users) db = self.db @@ -2059,21 +2059,21 @@ class JupyterHub(Application): for predef_role in self.load_roles: predef_role_obj = orm.Role.find(db, name=predef_role['name']) if predef_role['name'] == 'admin': - for bearer in admin_role_objects: - has_admin_role_spec[bearer] = bearer in predef_role - if has_admin_role_spec[bearer]: - app_log.info(f"Admin role specifies static {bearer} list") + for kind in admin_role_objects: + has_admin_role_spec[kind] = kind in predef_role + if has_admin_role_spec[kind]: + app_log.info(f"Admin role specifies static {kind} list") else: app_log.info( - f"Admin role does not specify {bearer}, preserving admin membership in database" + f"Admin role does not specify {kind}, preserving admin membership in database" ) # add users, services, and/or groups, # tokens need to be checked for permissions - for bearer in role_bearers: + for kind in kinds: orm_role_bearers = [] - if bearer in predef_role.keys(): - for bname in predef_role[bearer]: - if bearer == 'users': + if kind in predef_role.keys(): + for bname in predef_role[kind]: + if kind == 'users': bname = self.authenticator.normalize_username(bname) if not ( await maybe_future( @@ -2084,19 +2084,23 @@ class JupyterHub(Application): "Username %r is not in Authenticator.allowed_users" % bname ) - Class = orm.get_class(bearer) + Class = orm.get_class(kind) orm_obj = Class.find(db, bname) if orm_obj: orm_role_bearers.append(orm_obj) else: - app_log.warning( - f"User {bname} not added, only found in role definition" + app_log.info( + f"Found unexisting {kind} {bname} in role definition {predef_role['name']}" ) - # Todo: Add users to allowed_users + if kind == 'users': + # todo: check allowed or add to list+db? + app_log.info(f"Adding user {bname} to allowed users") + else: + app_log.warning(f"{kind} {bname} not created") # Ensure all with admin role have admin flag if predef_role['name'] == 'admin': orm_obj.admin = True - setattr(predef_role_obj, bearer, orm_role_bearers) + setattr(predef_role_obj, kind, orm_role_bearers) db.commit() if self.authenticator.allowed_users: allowed_users = db.query(orm.User).filter( @@ -2105,10 +2109,10 @@ class JupyterHub(Application): for user in allowed_users: roles.grant_role(db, user, 'user') admin_role = orm.Role.find(db, 'admin') - for bearer in admin_role_objects: - Class = orm.get_class(bearer) + for kind in admin_role_objects: + Class = orm.get_class(kind) for admin_obj in db.query(Class).filter_by(admin=True): - if has_admin_role_spec[bearer]: + if has_admin_role_spec[kind]: admin_obj.admin = admin_role in admin_obj.roles else: roles.grant_role(db, admin_obj, 'admin') @@ -2118,8 +2122,8 @@ class JupyterHub(Application): app_log.warning( "No admin role found; assuming hub upgrade. Initializing default roles for all entities" ) - for bearer in role_bearers: - roles.check_for_default_roles(db, bearer) + for kind in kinds: + roles.check_for_default_roles(db, kind) # check tokens for default roles roles.check_for_default_roles(db, bearer='tokens') From 0381b5164884dc4b38ea2169c88849752d9b4d08 Mon Sep 17 00:00:00 2001 From: 0mar Date: Wed, 16 Jun 2021 14:32:31 +0200 Subject: [PATCH 255/270] Raise error if role_spec bearers are invalid --- jupyterhub/app.py | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index ffd350dc..d05b8923 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1951,6 +1951,22 @@ class JupyterHub(Application): TOTAL_USERS.set(total_users) + async def _get_or_create_user(self, username): + """Create user if username is found in config but user does not exist""" + if not (await maybe_future(self.authenticator.check_allowed(username, None))): + raise ValueError( + "Username %r is not in Authenticator.allowed_users" % username + ) + user = orm.User.find(self.db, name=username) + if user is None: + if not self.authenticator.validate_username(username): + raise ValueError("Group username %r is not valid" % username) + self.log.info(f"Creating user {username}") + user = orm.User(name=username) + self.db.add(user) + self.db.commit() + return user + async def init_groups(self): """Load predefined groups into the database""" db = self.db @@ -1962,19 +1978,7 @@ class JupyterHub(Application): db.add(group) for username in usernames: username = self.authenticator.normalize_username(username) - if not ( - await maybe_future(self.authenticator.check_allowed(username, None)) - ): - raise ValueError( - "Username %r is not in Authenticator.allowed_users" % username - ) - user = orm.User.find(db, name=username) - if user is None: - if not self.authenticator.validate_username(username): - raise ValueError("Group username %r is not valid" % username) - self.log.info(f"Creating user {username} for group {name}") - user = orm.User(name=username) - db.add(user) + user = await self._get_or_create_user(username) self.log.debug(f"Adding user {username} to group {name}") group.users.append(user) db.commit() @@ -2093,10 +2097,12 @@ class JupyterHub(Application): f"Found unexisting {kind} {bname} in role definition {predef_role['name']}" ) if kind == 'users': - # todo: check allowed or add to list+db? - app_log.info(f"Adding user {bname} to allowed users") + orm_obj = await self._get_or_create_user(bname) + orm_role_bearers.append(orm_obj) else: - app_log.warning(f"{kind} {bname} not created") + raise ValueError( + f"{kind} {bname} defined in config role definition {predef_role['name']} but not present in database" + ) # Ensure all with admin role have admin flag if predef_role['name'] == 'admin': orm_obj.admin = True From 2f8f7ad0b0f4f7cb29e7bb970db22bdda9768f80 Mon Sep 17 00:00:00 2001 From: 0mar Date: Thu, 17 Jun 2021 12:45:54 +0200 Subject: [PATCH 256/270] Resolves sql warnings on 3.6 and fixes for scope expansion bug --- jupyterhub/app.py | 15 +++++++++------ jupyterhub/orm.py | 2 +- jupyterhub/roles.py | 9 ++++----- jupyterhub/tests/test_named_servers.py | 2 +- jupyterhub/tests/test_roles.py | 15 +++++++++++++++ 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index d05b8923..fc624621 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -1960,7 +1960,7 @@ class JupyterHub(Application): user = orm.User.find(self.db, name=username) if user is None: if not self.authenticator.validate_username(username): - raise ValueError("Group username %r is not valid" % username) + raise ValueError("Username %r is not valid" % username) self.log.info(f"Creating user {username}") user = orm.User(name=username) self.db.add(user) @@ -2301,15 +2301,18 @@ class JupyterHub(Application): service.orm.server = None if service.oauth_available: + allowed_roles = [] + if service.oauth_roles: + allowed_roles = list( + self.db.query(orm.Role).filter( + orm.Role.name.in_(service.oauth_roles) + ) + ) oauth_client = self.oauth_provider.add_client( client_id=service.oauth_client_id, client_secret=service.api_token, redirect_uri=service.oauth_redirect_uri, - allowed_roles=list( - self.db.query(orm.Role).filter( - orm.Role.name.in_(service.oauth_roles) - ) - ), + allowed_roles=allowed_roles, description="JupyterHub service %s" % service.name, ) service.orm.oauth_client = oauth_client diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 7dcf5a00..e9b94e80 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -717,7 +717,7 @@ class APIToken(Hashed, Base): db.add(orm_token) if not Role.find(db, 'token'): - raise AttributeError("Default token role has not been created") + raise RuntimeError("Default token role has not been created") try: if roles is not None: update_roles(db, entity=orm_token, roles=roles) diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 23f220e4..32c92f15 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -183,9 +183,8 @@ def _get_subscopes(*roles, owner=None): scopes.update(role.scopes) expanded_scopes = set(chain.from_iterable(list(map(_expand_scope, scopes)))) - # transform !user filter to !user=ownername - for scope in expanded_scopes: + for scope in expanded_scopes.copy(): base_scope, _, filter = scope.partition('!') if filter == 'user': expanded_scopes.remove(scope) @@ -198,7 +197,6 @@ def _get_subscopes(*roles, owner=None): name = owner.name trans_scope = f'{base_scope}!user={name}' expanded_scopes.add(trans_scope) - if 'self' in expanded_scopes: expanded_scopes.remove('self') if owner and isinstance(owner, orm.User): @@ -232,7 +230,7 @@ def _check_scopes(*args, rolename=None): raise NameError(f"Scope '{scope}' {log_role} does not exist") if filter_: full_filter = f"!{filter_}" - if not any(full_filter in scope for full_filter in allowed_filters): + if not any(f in scope for f in allowed_filters): raise NameError( f"Scope filter '{full_filter}' in scope '{scope}' {log_role} does not exist" ) @@ -454,7 +452,8 @@ def assign_default_roles(db, entity): db.commit() # users and services can have 'user' or 'admin' roles as default else: - app_log.debug('Assigning default roles to %s', type(entity).__name__) + kind = type(entity).__name__ + app_log.debug(f'Assigning default roles to {kind} {entity.name}') _switch_default_role(db, entity, entity.admin) diff --git a/jupyterhub/tests/test_named_servers.py b/jupyterhub/tests/test_named_servers.py index e07f405f..8b9c4c04 100644 --- a/jupyterhub/tests/test_named_servers.py +++ b/jupyterhub/tests/test_named_servers.py @@ -143,7 +143,7 @@ async def test_delete_named_server(app, named_servers): username = 'donaar' user = add_user(app.db, app, name=username) assert user.allow_named_servers - cookies = app.login_user(username) + cookies = await app.login_user(username) servername = 'splugoth' r = await api_request(app, 'users', username, 'servers', servername, method='post') r.raise_for_status() diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 7829719d..1ad5793c 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -788,6 +788,19 @@ async def test_user_filter_expansion(app, scope_list, kind, test_for_token): app.db.delete(test_role) +async def test_large_filter_expansion(app, create_temp_role, create_user_with_scopes): + scope_list = roles.expand_self_scope('==') + # Mimic the role 'self' based on '!user' filter for tokens + scope_list = [scope.rstrip("=") for scope in scope_list] + filtered_role = create_temp_role(scope_list) + user = create_user_with_scopes('self') + user.new_api_token(roles=[filtered_role.name]) + user.new_api_token(roles=['token']) + manual_scope_set = get_scopes_for(user.api_tokens[0]) + auto_scope_set = get_scopes_for(user.api_tokens[1]) + assert manual_scope_set == auto_scope_set + + @mark.role @mark.parametrize( "name, valid", @@ -849,6 +862,8 @@ async def test_server_role_api_calls( ): user = add_user(app.db, app, name='test_user') roles.grant_role(app.db, user, 'user') + app_log.debug(user.roles) + app_log.debug(roles.expand_roles_to_scopes(user.orm_user)) if token_role == 'no_role': api_token = user.new_api_token(roles=[]) else: From 5a4314ea8c8621df7f3ed75c3f29f43b7fd2cc55 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Thu, 17 Jun 2021 15:56:13 +0200 Subject: [PATCH 257/270] Refactor scope relationships creation This version reduces the number of access to dictionaries data. --- docs/source/rbac/generate-scope-table.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/source/rbac/generate-scope-table.py b/docs/source/rbac/generate-scope-table.py index bcfe78c0..370d88ba 100644 --- a/docs/source/rbac/generate-scope-table.py +++ b/docs/source/rbac/generate-scope-table.py @@ -32,9 +32,10 @@ class ScopeTableGenerator: used for creating hierarchical scope table in _parse_scopes() """ pairs = [] - for scope in self.scopes.keys(): - if self.scopes[scope].get('subscopes'): - for subscope in self.scopes[scope]['subscopes']: + for scope, data in self.scopes.items(): + subscopes = data.get('subscopes') + if subscopes is not None: + for subscope in subscopes: pairs.append((scope, subscope)) else: pairs.append((scope, None)) From 12ffc421146ab0cde33f5b254b55e7264a978cd4 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 18 Jun 2021 11:07:33 +0200 Subject: [PATCH 258/270] Fix docstring indentation and reference to flask example in docs example using flask for Implementing your own Auth with JupyterHub was not displayed --- docs/source/reference/services.md | 2 +- jupyterhub/services/auth.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/reference/services.md b/docs/source/reference/services.md index 7de3a7ea..5fed9896 100644 --- a/docs/source/reference/services.md +++ b/docs/source/reference/services.md @@ -297,7 +297,7 @@ You will only get to this stage if the user has the required `access:services!se To retrieve the user model for the token, make a request to `GET /hub/api/user` with the token in the Authorization header. For example, using flask: -```{literal-include} ../../../examples/service-whoami-flask/whoami-flask.py +```{literalinclude} ../../../examples/service-whoami-flask/whoami-flask.py :language: python ``` diff --git a/jupyterhub/services/auth.py b/jupyterhub/services/auth.py index d95775c1..ebe47edd 100644 --- a/jupyterhub/services/auth.py +++ b/jupyterhub/services/auth.py @@ -836,8 +836,8 @@ class HubAuthenticated: Default values include: - 'access:services', 'access:services!service={service_name}' for services - 'access:servers', 'access:servers!user={user}', - 'access:servers!server={user}/{server_name}' - for single-user servers + 'access:servers!server={user}/{server_name}' + for single-user servers If hub_scopes is not used (e.g. JupyterHub 1.x), these additional properties can be used: From a137134d3a798909bb323e7ba9b5839ef066d5f1 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 18 Jun 2021 12:28:30 +0200 Subject: [PATCH 259/270] Update roles.md for rbac docs with role creation/deletion and assignment changes --- docs/source/rbac/roles.md | 31 +++++++++++-------------- docs/source/rbac/tech-implementation.md | 2 ++ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index afff5f55..a30de815 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -4,9 +4,9 @@ JupyterHub provides four roles that are available by default: ```{admonition} **Default roles** - `user` role provides a {ref}`default user scope ` `self` that grants access to the user's own resources. -- `admin` role contains all available scopes and grants full rights to all actions similarly to the current admin status. This role **cannot be edited**. -- `token` role provides a {ref}`default token scope ` `all` that resolves to the same permissions as the token's owner has. -- `server` role allows for posting activity of "itself" only. The scope is currently under development. +- `admin` role contains all available scopes and grants full rights to all actions. This role **cannot be edited**. +- `token` role provides a {ref}`default token scope ` `all` that resolves to the same permissions as the owner of the token has. +- `server` role allows for posting activity of "itself" only. **These roles cannot be deleted.** ``` @@ -26,7 +26,7 @@ Roles can be assigned to the following entities: An entity can have zero, one, or multiple roles, and there are no restrictions on which roles can be assigned to which entity. Roles can be added to or removed from entities at any time. **Users** \ -When a new user gets created, they are assigned their default role ( `user` or `admin`) if no custom role is requested, currently based on their admin status. +When a new user gets created, they are assigned their default role (`user` or `admin`) based on their admin status. If existing user's admin status changes via API or `jupyterhub_config.py`, their default role will be updated accordingly (after next startup for the latter). **Services** \ Services do not have a default role. Services without roles have no access to the guarded API end-points, so most services will require assignment of a role in order to function. @@ -43,10 +43,8 @@ A token’s permissions are evaluated based on their owning entity. Since a toke Roles can be defined or modified in the configuration file as a list of dictionaries. An example: -% TODO: think about loading users/tokens into roles if membership has been changed via API. +% TODO: think about loading users into roles if membership has been changed via API. % What should be the result? -% What happens if a user is _removed_ from this list? -% Do they lose their role assignment or keep it? ```python # in jupyterhub_config.py @@ -59,7 +57,6 @@ c.JupyterHub.load_roles = [    'users': ['alice', 'bob'],    'services': ['idle-culler'],    'groups': ['admin-group'], -   'tokens': ['foo-6f6e65','bar-74776f']  } ] ``` @@ -68,11 +65,10 @@ The role `server-rights` now allows the starting and stopping of servers by any - users `alice` and `bob` - the service `idle-culler` -- any member of the `admin-group` -- requests using the tokens `foo-6f6e65` or `bar-74776f`. +- any member of the `admin-group`. ```{attention} -The `foo-6f6e65` and `bar-74776f` tokens will be assigned the `server-rights` role only if their owner has the corresponding permissions, otherwise JupyterHub throws an error. See {ref}`resolving-roles-scopes-target` for more details on how this is assessed. +Tokens cannot be assigned roles through role definition but may be assigned specific roles when requested via API (see {ref}`requesting-api-token-target`). ``` Another example: @@ -102,13 +98,14 @@ In a role definition, the `name` field is required, while all other fields are o - start with a letter - end with letter or number. -If no scopes are defined for new role, JupyterHub will raise a warning. Providing non-existing scopes will result in an error. -Moreover, `users`, `services`, `groups`, and `tokens` only accept objects that already exist or are defined previously in the file. +`users`, `services`, and `groups` only accept objects that already exist in the database or are defined previously in the file. It is not possible to implicitly add a new user to the database by defining a new role. ``` -In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the `admin` role, which cannot be overwritten; an error will be raised if trying to do so. -Any previously defined role bearers for this role will remain the role bearers but their permissions will change if the role's permissions are overwritten. The newly defined bearers (in this case `maria` and `joe` and `external`) will be added to the existing ones. +If no scopes are defined for _new role_, JupyterHub will raise a warning. Providing non-existing scopes will result in an error. -Once a role is loaded, it remains in the database until explicitly deleting it through `delete_role()` function in `roles.py`. Default roles cannot be deleted. -Omitting the `c.JupyterHub.load_roles` or specifying different roles in the `jupyterhub_config.py` file on the next startup will not erase previously defined roles, nor their bearers. +In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the `admin` role, which cannot be overwritten; an error will be raised if trying to do so. All the role bearers permissions present in the definition will change accordingly. + +Only the entities present in the role definition in the `jupyterhub_config.py` remain the role bearers. If a user, service or group is removed from the role definition, they will lose the role on the next startup. + +Once a role is loaded, it remains in the database until removing it from the `jupyterhub_config.py` and restarting the Hub. All previously defined role bearers will lose the role and associated permissions. Default roles, even if previously redefined through the config file and removed, will not be deleted from the database. diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index 7df666a2..f1545425 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -14,6 +14,8 @@ Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. Roles and scopes are resolved on several occasions, for example when requesting an API token with specific roles or making an API request. The following sections provide more details. +(requesting-api-token-target)= + ### Requesting API token with specific roles API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific existing roles. To date, it is only possible to add roles to a token in two ways: From f767a082f81e80f73b47e8626dd92f1245265ad7 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Fri, 18 Jun 2021 13:10:02 +0200 Subject: [PATCH 260/270] Fix user/admin default role assignment in roles.md --- docs/source/rbac/roles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index a30de815..6d39eeb4 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -26,7 +26,7 @@ Roles can be assigned to the following entities: An entity can have zero, one, or multiple roles, and there are no restrictions on which roles can be assigned to which entity. Roles can be added to or removed from entities at any time. **Users** \ -When a new user gets created, they are assigned their default role (`user` or `admin`) based on their admin status. If existing user's admin status changes via API or `jupyterhub_config.py`, their default role will be updated accordingly (after next startup for the latter). +When a new user gets created, they are assigned their default role `user`. Additionaly, if the user is created with admin privileges (via `c.Authenticator.admin_users` in `jupyterhub_config.py` or `admin: true` via API), they will be also granted `admin` role. If existing user's admin status changes via API or `jupyterhub_config.py`, their default role will be updated accordingly (after next startup for the latter). **Services** \ Services do not have a default role. Services without roles have no access to the guarded API end-points, so most services will require assignment of a role in order to function. From 7c9a80b4f0ff1314486ee7c684a76cfb18e997bf Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 22 Jun 2021 15:27:07 +0200 Subject: [PATCH 261/270] Remove pre-commit from GHA we are trying out pre-commit.ci, which means these steps in GHA are redundant --- .github/workflows/test.yml | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a84ac0d..726e8511 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,30 +27,6 @@ env: LANG: C.UTF-8 jobs: - # Run "pre-commit run --all-files" - pre-commit: - runs-on: ubuntu-20.04 - timeout-minutes: 2 - - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - # ref: https://github.com/pre-commit/action - - uses: pre-commit/action@v2.0.0 - - name: Help message if pre-commit fail - if: ${{ failure() }} - run: | - echo "You can install pre-commit hooks to automatically run formatting" - echo "on each commit with:" - echo " pre-commit install" - echo "or you can run by hand on staged files with" - echo " pre-commit run" - echo "or after-the-fact on already committed files with" - echo " pre-commit run --all-files" - # Run "pytest jupyterhub/tests" in various configurations pytest: runs-on: ubuntu-20.04 From e5345514ab197f2dfd280cd825788f1d08f10f3f Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 22 Jun 2021 15:27:43 +0200 Subject: [PATCH 262/270] remove unused defaults.run this is leftover and has no effect --- .github/workflows/test.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 726e8511..2c0e2919 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,17 +11,6 @@ on: push: workflow_dispatch: -defaults: - run: - # Declare bash be used by default in this workflow's "run" steps. - # - # NOTE: bash will by default run with: - # --noprofile: Ignore ~/.profile etc. - # --norc: Ignore ~/.bashrc etc. - # -e: Exit directly on errors - # -o pipefail: Don't mask errors from a command piped into another command - shell: bash - env: # UTF-8 content may be interpreted as ascii and causes errors without this. LANG: C.UTF-8 From eb0f995886e34a6774468d1953c5f2c348e1dbfe Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 22 Jun 2021 16:22:51 +0200 Subject: [PATCH 263/270] Add scope hierarchy duplicates explanation --- docs/source/rbac/scopes.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index f4ed13e1..81e631de 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -4,23 +4,24 @@ A scope has a syntax-based design that reveals which resources it provides acces `` in the RBAC scope design refers to the resource name in the [JupyterHub's API](../reference/rest-api.rst) endpoints in most cases. For instance, `` equal to `users` corresponds to JupyterHub's API endpoints beginning with _/users_. +(scope-conventions-target)= + ## Scope conventions - `` \ The top-level `` scopes, such as `users` or `groups`, grant read and write permissions to the resource itself as well as its sub-resources. For example, the scope `users:activity` is included in the scope `users`. - +++ - `read:` \ Limits permissions to read-only operations on the resource. - +++ - `admin:` \ Grants additional permissions such as create/delete on the corresponding resource in addition to read and write permissions. - +++ + +- `access:` \ + Grants access permissions to the `` via API or browser. - `:` \ The {ref}`vertically filtered ` scopes provide access to a subset of the information granted by the `` scope. E.g., the scope `users:activity` only provides permission to post user activity. - +++ - `!=` \ {ref}`horizontal-filtering-target` is implemented by the `!=`scope structure. A resource (or sub-resource) can be filtered based on `user`, `server`, `group` or `service` name. For instance, `!user=charlie` limits access to only return resources of user `charlie`. \ @@ -44,6 +45,7 @@ Access to the user's own resources and subresources is covered by metascope `sel - `users!user=gerard` where the `users` scope provides access to the full user model and activity. The filter restricts this access to the user's own resources. - `servers!user=gerard` which grants the user access to their own servers without being able to create/delete any. - `tokens!user=gerard` which allows the user to access, request and delete their own tokens. +- `access:servers!user=gerard` which allows the user to access their own servers via API or browser. The `self` scope is only valid for user entities. In other cases (e.g., for services) it resolves to an empty set of scopes. @@ -82,13 +84,27 @@ The payload of an API call can be filtered both horizontally and vertically simu Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them. +There are four exceptions to the general {ref}`scope conventions `: + +- `read:users:name` is a subscope of both `read:users` and `read:servers`. \ + The `read:servers` scope requires access to the user name (server owner) due to named servers distinguished internally in the form `!server=username/servername`. + +- `read:users:activity` is a subscope of both `read:users` and `users:activity`. \ + Posting activity via the `users:activity`, which is not included in `users` scope, needs to check the last valid activity of the user. + +- `read:roles:users` is a subscope of both `read:roles` and `admin:users`. \ + Admin privileges to the _users_ resource include the information about user roles. + +- `read:roles:groups` is a subscope of both `read:roles` and `admin:groups`. \ + Similar to the `read:roles:users` above. + ```{include} scope-table.md ``` ```{Caution} Note that only the {ref}`horizontal filtering ` can be added to scopes to customize them. \ -Metascopes `self` and `all`, ``, `:`, `read:` and `admin:` scopes are predefined and cannot be changed otherwise. +Metascopes `self` and `all`, ``, `:`, `read:`, `admin:`, and `access:` scopes are predefined and cannot be changed otherwise. ``` ### Scopes and APIs From 024e8fca30ed5ce05cbe55ab9f5b3f2adc185996 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Tue, 22 Jun 2021 17:16:06 +0200 Subject: [PATCH 264/270] Add !user filter explanation --- docs/source/rbac/scopes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/rbac/scopes.md b/docs/source/rbac/scopes.md index 81e631de..b2a70644 100644 --- a/docs/source/rbac/scopes.md +++ b/docs/source/rbac/scopes.md @@ -68,6 +68,14 @@ Requested resources are filtered based on the filter of the corresponding scope. In case a user resource is being accessed, any scopes with _group_ filters will be expanded to filters for each _user_ in those groups. +### `!user` filter + +The `!user` filter is a special horizontal filter that strictly refers to the **"owner only"** scopes, where _owner_ is a user entity. The filter resolves internally into `!user=` ensuring that only the owner's resources may be accessed through the associated scopes. + +For example, the `server` role assigned by default to server tokens contains `access:servers!user` and `users:activity!user` scopes. This allows the token to access and post activity of only the servers owned by the token owner. + +The filter can be applied to any scope. + (vertical-filtering-target)= ## Vertical filtering From 8764f6493b6c960491b5063275deca9dbef26997 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 23 Jun 2021 11:33:48 +0200 Subject: [PATCH 265/270] Add scope variable nomenclature and update tech implementation --- docs/source/rbac/roles.md | 4 +-- docs/source/rbac/tech-implementation.md | 35 +++++++++++++++---------- docs/source/rbac/upgrade.md | 2 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 6d39eeb4..388ba115 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -15,7 +15,7 @@ The `user`, `admin`, and `token` roles by default all preserve the permissions p Only the `server` role is changed from pre-2.0, to reduce its permissions to activity-only instead of the default of a full access token. -Additional custom roles can also be defined (see {ref}`define_role_target`). +Additional custom roles can also be defined (see {ref}`define-role-target`). Roles can be assigned to the following entities: - Users @@ -37,7 +37,7 @@ A group does not require any role, and has no roles by default. If a user is a m **Tokens** \ A token’s permissions are evaluated based on their owning entity. Since a token is always issued for a user or service, it can never have more permissions than its owner. If no specific role is requested for a new token, the token is assigned the `token` role. -(define_role_target)= +(define-role-target)= ## Defining Roles diff --git a/docs/source/rbac/tech-implementation.md b/docs/source/rbac/tech-implementation.md index f1545425..c396e220 100644 --- a/docs/source/rbac/tech-implementation.md +++ b/docs/source/rbac/tech-implementation.md @@ -1,8 +1,22 @@ # Technical Implementation -Roles are stored in the database, where they are associated with users, services, etc., and can be added or modified as explained in {ref}`define_role_target` section. Users, services, groups, and tokens can gain, change, and lose roles. -For example, one can change a token's role, and thereby its permissions, without the need to issue a new token (currently through `update_roles()` and `strip_role()` functions in `roles.py`, this will be eventually available through APIs). -Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. +Roles are stored in the database, where they are associated with users, services, etc., and can be added or modified as explained in {ref}`define-role-target` section. Users, services, groups, and tokens can gain, change, and lose roles. This is currently achieved via `jupyterhub_config.py` (see {ref}`define-role-target`) and will be made available via API in future. The latter will allow for changing a token's role, and thereby its permissions, without the need to issue a new token. + +Roles and scopes utilities can be found in `roles.py` and `scopes.py` modules. Scope variables take on five different formats which is reflected throughout the utilities via specific nomenclature: + +```{admonition} **Scope variable nomenclature** +:class: tip +- _scopes_ \ + List of scopes with abbreviations (used in role definitions). E.g., `["users:activity!user"]`. +- _expanded scopes_ \ + Set of expanded scopes without abbreviations (i.e., resolved metascopes, filters and subscopes). E.g., `{"users:activity!user=charlie", "read:users:activity!user=charlie"}`. +- _parsed scopes_ \ + Dictionary JSON like format of expanded scopes. E.g., `{"users:activity": {"user": ["charlie"]}, "read:users:activity": {"users": ["charlie"]}}`. +- _intersection_ \ + Set of expanded scopes as intersection of 2 expanded scope sets. +- _identify scopes_ \ + Set of expanded scopes needed for identify (whoami) endpoints. +``` (resolving-roles-scopes-target)= @@ -10,7 +24,7 @@ Roles' and scopes' utilities can be found in `roles.py` and `scopes.py` modules. **Resolving roles** refers to determining which roles a user, service, token, or group has, extracting the list of scopes from each role and combining them into a single set of scopes. -**Resolving scopes** involves expanding scopes into all their possible subscopes and, if applicable, comparing two sets of scopes. Both procedures take into account the scope hierarchy, {ref}`vertical ` and {ref}`horizontal filtering ` limiting or elevated permissions (`read:` or `admin:`, respectively), and metascopes. +**Resolving scopes** involves expanding scopes into all their possible subscopes (_expanded scopes_), parsing them into format used for access evaluation (_parsed scopes_) and, if applicable, comparing two sets of scopes (_intersection_). All procedures take into account the scope hierarchy, {ref}`vertical ` and {ref}`horizontal filtering `, limiting or elevated permissions (`read:` or `admin:`, respectively), and metascopes. Roles and scopes are resolved on several occasions, for example when requesting an API token with specific roles or making an API request. The following sections provide more details. @@ -18,10 +32,7 @@ Roles and scopes are resolved on several occasions, for example when requesting ### Requesting API token with specific roles -API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific existing roles. To date, it is only possible to add roles to a token in two ways: - -1. through the `jupyterhub_config.py` file as described in the {ref}`define_role_target` section -2. through the _POST /users/:name/tokens_ API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). +API tokens grant access to JupyterHub's APIs. The RBAC framework allows for requesting tokens with specific existing roles. To date, it is only possible to add roles to a token through the _POST /users/:name/tokens_ API where the roles can be specified in the token parameters body (see [](../reference/rest-api.rst)). RBAC adds several steps into the token issue flow. @@ -29,7 +40,7 @@ If no roles are requested, the token is issued with the default `token` role (pr If the token is requested with any roles, the permissions of requesting entity are checked against the requested permissions to ensure the token would not grant its owner additional privileges. -If, due to modifications of roles or entities, at API request time a token has any scopes that its owner does not, those scopes are removed. The API request is resolved without additional errors, but the Hub logs a warning (see {ref}`Figure 2 `). +If, due to modifications of roles or entities, at API request time a token has any scopes that its owner does not, those scopes are removed. The API request is resolved without additional errors using the scopes _intersection_, but the Hub logs a warning (see {ref}`Figure 2 `). Resolving a token's roles (yellow box in {ref}`Figure 1 `) corresponds to resolving all the token's owner roles (including the roles associated with their groups) and the token's requested roles into a set of scopes. The two sets are compared (Resolve the scopes box in orange in {ref}`Figure 1 `), taking into account the scope hierarchy but, solely for role assignment, omitting any {ref}`horizontal filter ` comparison. If the token's scopes are a subset of the token owner's scopes, the token is issued with the requested roles; if not, JupyterHub will raise an error. @@ -42,16 +53,12 @@ Resolving a token's roles (yellow box in {ref}`Figure 1 `) Figure 1. Resolving roles and scopes during API token request ``` -```{note} -The above check is also performed when roles are requested for existing tokens, e.g., when adding tokens to {ref}`role definitions ` through the `jupyterhub_config.py`. -``` - ### Making an API request With the RBAC framework each authenticated JupyterHub API request is guarded by a scope decorator that specifies which scopes are required to gain the access to the API. When an API request is performed, the requesting API token's roles are again resolved (yellow box in {ref}`Figure 2 `) to ensure the token does not grant more permissions than its owner has at the request time (e.g., due to changing/losing roles). -If the owner's roles do not include some scopes of the token's scopes, only the intersection of the token's and owner's scopes will be used. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will results in only the `read:users:name` scope being passed on. In the case of no intersection, an empty set of scopes will be used. +If the owner's roles do not include some scopes of the token's scopes, only the _intersection_ of the token's and owner's scopes will be used. For example, using a token with scope `users` whose owner's role scope is `read:users:name` will result in only the `read:users:name` scope being passed on. In the case of no _intersection_, an empty set of scopes will be used. The passed scopes are compared to the scopes required to access the API as follows: diff --git a/docs/source/rbac/upgrade.md b/docs/source/rbac/upgrade.md index 8fb7b708..96d64e8f 100644 --- a/docs/source/rbac/upgrade.md +++ b/docs/source/rbac/upgrade.md @@ -21,7 +21,7 @@ When the JupyterHub is restarted for the first time after the upgrade, all users ## Changing the permissions after the upgrade -Once all the {ref}`upgrade steps ` above are completed, the RBAC framework will be available for utilization. You can define new roles, modify default roles (apart from `admin`) and assign them to entities as described in the {ref}`define_role_target` section. +Once all the {ref}`upgrade steps ` above are completed, the RBAC framework will be available for utilization. You can define new roles, modify default roles (apart from `admin`) and assign them to entities as described in the {ref}`define-role-target` section. We recommended the following procedure to start with RBAC: From a6471670c2727743232a3f8a031cf3cddfaba0a2 Mon Sep 17 00:00:00 2001 From: IvanaH8 Date: Wed, 23 Jun 2021 11:44:40 +0200 Subject: [PATCH 266/270] Update upgrade section --- docs/source/rbac/roles.md | 4 ++++ docs/source/rbac/upgrade.md | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/source/rbac/roles.md b/docs/source/rbac/roles.md index 388ba115..ec0a8cb0 100644 --- a/docs/source/rbac/roles.md +++ b/docs/source/rbac/roles.md @@ -106,6 +106,10 @@ If no scopes are defined for _new role_, JupyterHub will raise a warning. Provid In case the role with a certain name already exists in the database, its definition and scopes will be overwritten. This holds true for all roles except the `admin` role, which cannot be overwritten; an error will be raised if trying to do so. All the role bearers permissions present in the definition will change accordingly. +(removing-roles-target)= + +## Removing roles + Only the entities present in the role definition in the `jupyterhub_config.py` remain the role bearers. If a user, service or group is removed from the role definition, they will lose the role on the next startup. Once a role is loaded, it remains in the database until removing it from the `jupyterhub_config.py` and restarting the Hub. All previously defined role bearers will lose the role and associated permissions. Default roles, even if previously redefined through the config file and removed, will not be deleted from the database. diff --git a/docs/source/rbac/upgrade.md b/docs/source/rbac/upgrade.md index 96d64e8f..56a81adf 100644 --- a/docs/source/rbac/upgrade.md +++ b/docs/source/rbac/upgrade.md @@ -25,10 +25,10 @@ Once all the {ref}`upgrade steps ` above are complete We recommended the following procedure to start with RBAC: -1. Identify which admin users and services you would like to grant only the permissions they need through the new roles +1. Identify which admin users and services you would like to grant only the permissions they need through the new roles. 2. Strip these users and services of their admin status via API or UI. This will change their roles from `admin` to `user`. ```{note} - Stripping entities of their roles is currently under development and will be available only via API/UI. + Stripping entities of their roles is currently available only via `jupyterhub_config.py` (see {ref}`removing-roles-target`). ``` 3. Define new roles that you would like to start using with appropriate scopes and assign them to these entities in `jupyterhub_config.py`. 4. Restart the JupyterHub for the new roles to take effect. From 63315feb56bf2c4b86abc1b74471823ad6a1f155 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 17:44:07 +0000 Subject: [PATCH 267/270] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v1.9.0 → v2.5.0](https://github.com/asottile/reorder_python_imports/compare/v1.9.0...v2.5.0) - [github.com/psf/black: 20.8b1 → 21.6b0](https://github.com/psf/black/compare/20.8b1...21.6b0) - [github.com/pre-commit/mirrors-prettier: v2.2.1 → v2.3.2](https://github.com/pre-commit/mirrors-prettier/compare/v2.2.1...v2.3.2) - https://gitlab.com/pycqa/flake8 → https://github.com/PyCQA/flake8 - [github.com/PyCQA/flake8: 3.8.4 → 3.9.2](https://github.com/PyCQA/flake8/compare/3.8.4...3.9.2) - [github.com/pre-commit/pre-commit-hooks: v3.4.0 → v4.0.1](https://github.com/pre-commit/pre-commit-hooks/compare/v3.4.0...v4.0.1) --- .pre-commit-config.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index baf7dd62..145f75b5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,22 +1,22 @@ repos: - repo: https://github.com/asottile/reorder_python_imports - rev: v1.9.0 + rev: v2.5.0 hooks: - id: reorder-python-imports - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 21.6b0 hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.2.1 + rev: v2.3.2 hooks: - id: prettier - - repo: https://gitlab.com/pycqa/flake8 - rev: "3.8.4" + - repo: https://github.com/PyCQA/flake8 + rev: "3.9.2" hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.0.1 hooks: - id: end-of-file-fixer - id: check-case-conflict From 18c5b6a17af1aeb6191142119237e9c8300aa078 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 17:44:34 +0000 Subject: [PATCH 268/270] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/bootstrap-script/jupyterhub_config.py | 4 ++-- jsx/src/util/withAPI.js | 7 +++---- jupyterhub/apihandlers/groups.py | 2 +- jupyterhub/orm.py | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/bootstrap-script/jupyterhub_config.py b/examples/bootstrap-script/jupyterhub_config.py index 4fbdc179..61eae47a 100644 --- a/examples/bootstrap-script/jupyterhub_config.py +++ b/examples/bootstrap-script/jupyterhub_config.py @@ -10,7 +10,7 @@ from jupyter_client.localinterfaces import public_ips def create_dir_hook(spawner): - """ Create directory """ + """Create directory""" username = spawner.user.name # get the username volume_path = os.path.join('/volumes/jupyterhub', username) if not os.path.exists(volume_path): @@ -20,7 +20,7 @@ def create_dir_hook(spawner): def clean_dir_hook(spawner): - """ Delete directory """ + """Delete directory""" username = spawner.user.name # get the username temp_path = os.path.join('/volumes/jupyterhub', username, 'temp') if os.path.exists(temp_path) and os.path.isdir(temp_path): diff --git a/jsx/src/util/withAPI.js b/jsx/src/util/withAPI.js index f1c111ea..37506004 100644 --- a/jsx/src/util/withAPI.js +++ b/jsx/src/util/withAPI.js @@ -7,10 +7,9 @@ const withAPI = withProps(() => ({ data.json() ), updateGroups: (offset, limit) => - jhapiRequest( - `/groups?offset=${offset}&limit=${limit}`, - "GET" - ).then((data) => data.json()), + jhapiRequest(`/groups?offset=${offset}&limit=${limit}`, "GET").then( + (data) => data.json() + ), shutdownHub: () => jhapiRequest("/shutdown", "POST"), startServer: (name) => jhapiRequest("/users/" + name + "/server", "POST"), stopServer: (name) => jhapiRequest("/users/" + name + "/server", "DELETE"), diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 84f97a6b..7d578fbb 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -46,7 +46,7 @@ class GroupListAPIHandler(_GroupAPIHandler): @needs_scope('admin:groups') async def post(self): - """POST creates Multiple groups """ + """POST creates Multiple groups""" model = self.get_json_body() if not model or not isinstance(model, dict) or not model.get('groups'): raise web.HTTPError(400, "Must specify at least one group to create") diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index e9b94e80..aa24c499 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -314,7 +314,7 @@ class User(Base): class Spawner(Base): - """"State about a Spawner""" + """ "State about a Spawner""" __tablename__ = 'spawners' From d86612c8e50ee9dd3fdba72b74a5de79afdad608 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Tue, 29 Jun 2021 22:57:40 +0200 Subject: [PATCH 269/270] Add test to reproduce regression, external services requires api_token --- jupyterhub/tests/test_services.py | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/jupyterhub/tests/test_services.py b/jupyterhub/tests/test_services.py index 8c2d1d4b..fb88d891 100644 --- a/jupyterhub/tests/test_services.py +++ b/jupyterhub/tests/test_services.py @@ -110,3 +110,51 @@ async def test_external_service(app): assert len(resp) >= 1 assert isinstance(resp[0], dict) assert 'name' in resp[0] + + +async def test_external_services_without_api_token_set(app): + """ + This test was made to reproduce an error like this: + + ValueError: Tokens must be at least 8 characters, got '' + + The error had the following stack trace in 1.4.1: + + jupyterhub/app.py:2213: in init_api_tokens + await self._add_tokens(self.service_tokens, kind='service') + jupyterhub/app.py:2182: in _add_tokens + obj.new_api_token( + jupyterhub/orm.py:424: in new_api_token + return APIToken.new(token=token, service=self, **kwargs) + jupyterhub/orm.py:699: in new + cls.check_token(db, token) + + This test also make _add_tokens receive a token_dict that is buggy: + + {"": "external_2"} + + It turned out that whatever passes token_dict to _add_tokens failed to + ignore service's api_tokens that were None, and instead passes them as blank + strings. + + It turned out that init_api_tokens was passing self.service_tokens, and that + self.service_tokens had been populated with blank string tokens for external + services registered with JupyterHub. + """ + name_1 = 'external_1' + name_2 = 'external_2' + async with external_service(app, name=name_1) as env_1, external_service( + app, name=name_2 + ) as env_2: + app.services = [ + { + 'name': name_1, + 'url': "http://irrelevant", + }, + { + 'name': name_2, + 'url': "http://irrelevant", + }, + ] + await maybe_future(app.init_services()) + await app.init_api_tokens() From b8023cbd839be02de6cf1befb73496454c4a5357 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Tue, 29 Jun 2021 22:57:58 +0200 Subject: [PATCH 270/270] Fix regression where external services require api_token --- jupyterhub/app.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index fc624621..8ceaf34d 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2267,18 +2267,14 @@ class JupyterHub(Application): raise AttributeError("No such service field: %s" % key) setattr(service, key, value) - if service.managed: - if not service.api_token: - # generate new token - # TODO: revoke old tokens? - service.api_token = service.orm.new_api_token( - note="generated at startup" - ) - else: - # ensure provided token is registered - self.service_tokens[service.api_token] = service.name - else: + if service.api_token: self.service_tokens[service.api_token] = service.name + elif service.managed: + # generate new token + # TODO: revoke old tokens? + service.api_token = service.orm.new_api_token( + note="generated at startup" + ) if service.url: parsed = urlparse(service.url)

Iyy0@FfU@4#9=&+R*Wv*Dy9 z1-($Wr-V8>BDtBm7-fC0NG?F*V-K!dCGrs}SM+18h=><71x5*CccdgmtjD0_?#I1T zrJ1Dd$;=nOA)ki~41#neYgw=x_`>pW5U;6#7B+8_<`Yni5|FbF?QE|=v4H`67x!l& za?RMTee^Ox0zcpGf*gotueLi`B^t|Qkz!fgQh|-?1(jb$u%HyUCb0XgjYF_YReioY z)GHsa#^&LOsYnE!>YgW@4Vehg7TX8`jktg1NJuD5AfGM1jUJ3E-s0xlg&SRVH=Ur8 zr_j^2+7!o%cQ=Dp+JO`Xt^h$fkVOQW>=kLyvH1efKlQLD=SteILTk)~9oV2ypRx{H zu^MbLKsZ4w+joZ6$xsUj44f~ZGXSbIT^&o@6ADZ)Y_wFXYGues)Tt|1fDF$O_djHTKt0WEE<4%POq-#-kkBesw`H!bbg9EGs3-?W1*n36OKaZ|eJX{xn&9#(-Ra zM4-BImT)>uv`zyewXAwChZieGI<4Bo3#-~QiSP4VXbsDE!*)SRtoAyw@l%Ooh2CD* z1KMj?WBZWC1(~pszU6hGAO8r67ZR)Ex*dWQospYG&BDKdANl%k{uGopz(TrJ^PT!Z zogO~;(`E*F&_ihDIZebi2$xQAV&9)lQ4##>|D;xLk^2U!d1H%aU2ATsIR8Mq5BC%X z@Nb|WYTIxI%66VW&Ne$<8bOH*jZ4YJf`#-yRI-I)c7a+kx+>(I^qmfze=6`eAJ@}H zN%jgND4VG-4I!Ao7Dwc5UU>V>1VrT9k^Ex_3xMk5Wc~#|N@c<2TR~47K;%GViR9t( z=l)IhDB5H>>5-}zBi}rP@S{=_djC*>EV2#749w2%OBSXZ*3H)@M3Z!Ms&`NQ#=?&h zlvi{Dpi}{p@(d)!19TizFeNO@wAW#mE z?!+HR@-es}&eor9#v#t-UMA!4wgjwj z9WNnEZ3xHzvWBGdmYQ8b11wQ1@?21}%⊒`03b~P~E${FDM^`>XIhlRG$Yu>SD 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%0DKY_qkUG${3#2A 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 z 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∨un8rnf*WCOoUFb`|CWen@oakFz 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 diff --git a/docs/source/images/rbac-api-token-request-chart.png b/docs/source/images/rbac-api-token-request-chart.png deleted file mode 100644 index 5a37b225e355d144913c78adfd0e67ea9e2078c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214426 zcmeFYbyU^ezb;A&(nurS-7O&?-7TGqF6jlf}_^4j!r$wT@jiJGq>y2t`~=b>{K?q?oIE<|qWsi{(GzE8+{UMA>R=bgy; zE{fc>U(+tkjEZlsZl$cU49B9wgi#zE-Q^}%v?ynhl15dL)?OSd zm5S)mwK}L!P8{s4itVk6vA2?5#v-4(>nK@$Z_nxead6XrvBY*bvmLU1br5#9+L3_S zmeiz#Vk|{UY9Nks0F{65g?DpTbW;6>qUx69z$QFLje<-ha`I%MbUs%5>U<7e`{%lD zR67-Q@&!tNU{x2>(xSiD{3dCPzuwpahQIsfB|*;Nna5oFJzv&n$L7c1-+mtKdNBmo z`pExwj=11eBnlQ>tith&>PTDKyXW#NFHonYHyrhOA~MNKDm`@cm38Uv=%!ssgun#p zMO-{aHCr{|-l9Fn*E6Qkv@U1%Dpg0X zE2Z1pW3kQBwKgrbiwu)5IO@SD;%SqN7Vk0qg?H$dp#1M|FQq)A&DfUMv}k_h92uCH zJ*eoG7kFS1^Ru7aLqDq*W_cOj=x)v?93NP6nd*BK8)CGG)i3KOfLBgl%qAT;%FiT8 zpc)mjHkIprLVR*DAJ^lJKTLtik4sn{>VEei1(+Ui&rgr^r>kkec^hH^2i;%g>mOVeZIxHoDt3=b1Y`5!% zkDeFBXG$XeA~yG&HoweeX=fWg9%+0YmGkJ5(fl^>S~@!_gX5(r!uoERaM5z2!1}J$ z^6TM16?19}Pe>F>@t(Nwz3%?~z(YvA^*%{#{)@71!Bvt=G*MidT=KH5159JMQ$TP=Z1*nnyGS^aLJzSJUgduMp zM7-VoZ;<&9P{YOuojoFri@7yx#3e#XNO)~tOitk@1$K$_J%QJlcxM;fbc6N8S90ro zax}&&Si$GX*w4HKD2KOOlk=R+alL(boPnGJ<`o|D^7v&J!lXO3%EM{P4Tn)*?~nMM88x8u$?wJXx4SCYg}V`h%e@Eg=^P5Z(}INYpFaPFzu4dYrM*oE6RSFn#c z4WFD!91u*NjZ($Zqo-t};`ZA|z7LVef)#i!_=COSy&^1SBzNtTim6+JNVtw75?=$V zWiC~|tdO~*c{q>i%6FOms`LA#F5)r6X_CB-7vYpW+%SQN|0?d;lL_O$ZkM+*y2@#AO8l_PJYhQBzZVhfn2HXNVh zc8%#~LI3np85fcn9{)VCypcvejt|9@YEF88BVrl-Yvjo#QKwWuhAwI3n=z4h8$zY^ z^)qG2zKLb-NX580$}CTh#eR$s5?JTY1S_M2ebdO>>$V zloT7nkMMCLnbXWqQ|5{n$ir9i@EN^f1u4Z81r|n$@K80CUR&jI507RcZPN|}!f3wm z(4Y5hYJL!ye=$1^pY?q|SEZ4#-afFf;o!^8en6hPK4HoXvh2jU;0}FU0vB|C0On?= zhag=vT;TDRI${$iRL%RX?iUmt3MfxARX+qvLaRn)`>!r67$zInJ8!YsVtG;6CC((O zJg*_l>f)eccnT9jXj@=siEGI{-Hf}w9pJu<_=?d_9bLNhI{$#Yj% zKOwdYElPu4r##$mWZ`5Fx(b%HpQU!Lwa7w=Lg5h4X;?GTCCzO=YA-=@3Gr30aKx}K zd`pa{;`-p9s7krfy?8(1vr$AE$P5WMCPXQSg^v??ek@w~MWP|NYwfD&bwF}Gxjzbb z&5UH2e4>uFxbpR4=_^8)u9Occ@8m=s2v3ML1y-E%@yoW+jPUsQuGcBxTHg>rsMh-P zy6DMltzOzbX}$Nu)r7X=#WK|HL#v5$#EASJpNJ&#gZb&XOJ@tSCY3Tz(27K&z2)ak zA3ohXL+2C{n=9E0mJ~uwhwzPwV#Y5or(R<+9i}w2qNBj-*KId8P9cBL48}d#vWbOH z*D1-zgBFl5&pjs?^(c+0QyNvfpd3T7AOCI$6CkL#Yy`i7NBYJpa2Bn1%pwyexLK}| zw%~paVVGQX={-+$Ek{^WzIUE+yqEnaBe^egthiG{Cr_()&h5;r^9~U>6 z9>pljI4?}#Xdx+_ZEa4aY!tPvD@A&y6|LQ4e4SA>;VC8enuI_-bp=kYQKEd};8`tV zy*b6_YSzy3S?qHwD+&cm-O%vhp95Dk#!jVZ6X+V~Cccg91aZWeuY7odE=$F2hb4s2 zR2AbArA-cWU%(y{Bp8d?x`-S*1)?f5My0vSnu#H^?yWuDo&Nf6U|QLoUw&^@Qqtar zneHvFxYEdXp=E|2Z(oj>@X5V`+EOF`cG^s#iY8C2Y*Cc-S58NG`Qf5QniJNP1(O@y zQZX3j1x8X|KaW$KozkijGN?HaeiM{wlx0fMyQ)D})2iHXo}!cT}2Q7{Op-^dIMlwTOR>M_)6O~vpX$82`PqQfCT zeOhPxqSD0Z!o395ch)@}!<(I5T-QM~nT4Z6!r2M)@uqA%JOLikKr@A&k`MSRX6@=U*_)>S=XEs}@SdXGU zM~)auzu0Elv7Y; zxGpxBPxB5n3CtYF;n{UIl)6^YcO9jc?nPhUW9h%c``X}8)R+Etp)NJ(OOUts!N}qe z$&tVed@Q>2qEp7sja<_~6{?=R?cJ$Dr2Z%QBth6}8lg!JSpvu%m*7~)nyR^-vV-Yt zAMpbH!H1eOJPBkbUGXmH7UC64{OpMIIfkx9jWOi?B50weV486pPcoZw4CxQj_(Lsz zR*sj439UCx^Gx(l5uK`);O{*a5qaCxT3fjf_b+Lmt=;B<()zGl=m zp&T^EtvNrMM15g2fZ9_L@Jc)Kmx~@xO@P-Z^u)UfZisQM+%ik(Tv7O#2;HS@T@hdC za6gHUX7A;4@BSxBEcbVB3$M!7hqR?9iJ?BGrW#bZYv)hFFl;#KL zHJ&kmf)JoyWIKrIRW3k=Wxhf<@J@1$nF=MJh*>zq@Ph@WbDg*$b# zP(7?LVf9a#2<>s63+%;kFcq~?^#!eTKlw~6HE3!o%`M@L7X}Cq z92Hq6-C`lFMx=P+lD8gACTK9?x$ZXaku93H;WY$_6rKhms~LnwTxdrQA*07V*S0tM z;<9iPvw>oHatO7v#VOvw`Vn)+H+}l4Rcj`ez000DJ=+H24$mOgLGukPCn^G4i6*Ag zgy(=j>)3d{kmPuBmE19nSb!xR0}5K1qk4d$`M0U}wah<~k;ITk5+n<;hMZFmf09xzH8;T4sM0I0WAXGD6*X{CjXRi_c{?XWOZ%i0QWo&L&Ko-xAp<%* z;wQY+r4ABWKFwjVE{`ZaQsTFX7@k7)4X+fex1ESBh!cA4=lYS?(bu0Gw=%yk*d5UF znr5zA&k4yT1mvl!P~%Gv?~@ImcEr|Lw3$q@MbJU7XuZYVsS(G$BzZPX6-J1CQA6^< z+nkVxgDsp-_ANJkK~G2uuCTD=wNKR4FmnZrzGRkyl*k=gLAc zgToR(CETE4db>B!;p2)8!ANvh980JKLa9(6&vdwL?|G|alK13A*M`KO4~{XuhNO~) zzB+1j3VQi8F)0E4QiMMO7bz~_dw19Iag<8oN|oHu>|2Ts#KwTo$(0r1@A|hSo8NqG zL@Zj1E3N5cncT{a2Q*`cex7AJ9FPlPsTvkRR#!&GFB|p4g>_&gl}gBz&GrnznN{8ePtxS^XYyMD%Oe*J}C@G zs7ge_h;&3sPA>VSa!i2R5C4uLtX~TJ@z4R2{F?SJprxT|lHSZuq(`^eL~Xsl*b%qXNSGyoBHHg%?QOFE3>IQ>fK^%*|jL9VgnGnPyWt)b~OO z2vGIP&tcM$oJwXeir?@DI)C)Z!|5<%+QxRlMx+05qZRqVn*5XH$;X%1bgs-)t>Zl^ z#Z| zMb-8EycEYfFZxb~(P7bZ59fKzF#fJBTe%oVfl)G7UG`Wwy{y$q552NAadmwbFNaz*F-iO|9J!VnHBS}yf?+zhmKrI8yruIZqh}W*w=4U z&sikYoE|)aJYT3jfBoY5VU>a;IY<)ej-fr~Teqo2N& z!Ztq-D@B6lIt=^#Y6Y%}&KFoSR!)3ZB$e`c*xKy!dG4DvoA?>DqlSoY$JExxwwMAVnl@<_lkXk zvB#AUS(IO-ShVV+Geg#-Jx&qj$DUL-Vue?->PJr&UKda6epYYh(RNPLfwu3f>o<*j z^A5pJv>vyX`R75hTL`N(3)O0!v68!uP&`IV%EweJ3al8}n|Cqe+eb+ANcp@dd=>q* zb(NzY3{Re9Cuz&c(2mu+K5I6_tSc-#O0neaGY8sP-l5}L>SiV$XzGsro#}N@Vuxr4@dU7w# zpOQzm*lzd8PRDj|SD;Mu+1nmicXr`42Cj#VPYrJDFGsiK88QWlmqjL%Ml-|R3~32D zo*h_YkySoB(p5rut*O(WYO^I85QRr;OtG#$1Y3M411F0#Qr2hFideV${<_z{SK;lL zIf`rTSNF(wS-mR~bKA@uu}sMnK{_OB)6=b*?i+6!e-o^qW~8ikDv1;$_+K)Z6hKy_ zb=dbg@Zix#84GWjv>x%C+ZE6BjBRouU$2%epzdsJSQaf^R}Lpy@j~y7r!1ji>YN{4LdyeiSvx4-jN*ju$QO3}>Y`H&Qa5+!|R7U}&6L%dk8qUX=-_+x{SDi$<;pw?mNN5jLSWroAm?na7;*Yr>#^4ZOh zACO=o5v0ga%4}3>66na2?=>O{RbsW(qfT_f!n)$Lz`Mh+$|%{x$}10D5Hyp!q{h=N zm&&1MQ6!Ejd8t>1X4Rjk5!$|}6Km(nA?e1(#4Iux=M3#on-o#}=~2rd_e-hyID7%2 zbWNNVTg8vg=INdJfia6a?b8qe$h^}>I;6t)lR<`Z=yW2XUPb4nudLavFAkU0#uYYc z+^mXlibBT)FLVMMqu0txeNQo*;Y7aqGQjQ)DbtBcOODnXrSiWpWt#M5dQv`aimTsm z#Iluw3|FB<{#<{~kLrpOe;&o}Z&l)7y(!4e&GM zLl*|^+2wQ%9A~_?w1H9z_Z|*aQA>}7x+rC#`Vf7I2*=!s2LJfjyIgQSCDcBuTidCJU?mrY9Cs7Egng-*z!OnPBf6j^1U3dDZT z3K|S3x4+yZV;J&XgdNO%^QJ~8TI*>YVnP!WdT|I&BZZZnJB4J)Y@(Mu88r1rsRYI` zYt&U&*y6L>53aJ_IUa-d8i&&8MKsJ_-J`#o!m4(xW-TS(+bEWbFVOQaTmD4t!@fm{ z2p@b|O?>A7U9T|u;I((Kx{0BtB*_w6$)a-fcl& zW1aeiOavB*OUEUy5P_C3nv>79@g-TA9UgQOci$)Dj|;1Fi?{Ka$6gQU3>Wc9KY{hk zp=gd2^7?dqRWWwI(880s@BmFUI3AdDE#3+R1s!Z9F0L#iF8;4p4QSA0`o0&E?s-Yn zXQ)<0frIlRoX@OO5%-k@ksMB>QC=;Mjw@T!DRMd&6+KJLTbr(~*uL_h$j_B%m2b%| zp;tCG3b!bz?^)?8cTeqGaP9C=(xD@QPcXPtI~b9k%6v^ zbJhmk%4;zgneaFjaRQvz;bZ0RO(-O8*wG)tSC!)BXtW5Th>%OgLe?(39+ur3%#FPU z6_CCJ?BmVdoGx71(1AP9Xs+L<(cuJycgo_71J9#^Y^Z(UB6mZ>w6G#+0E%m!4=fQ8%&Nqo!G(vrl7+)Vw$<4M z?9&4$Uz8#7T_`B@Oe@ejd#xZZVCrDUVr=GM0%7s6a|Eq5C@4V@4@YBD8;A>;3Bn`bVI(p^Co^*a z)mM^#PXS&DQCPaTI0~?`y1ToxxO1{NI9af=^YinwvT?9-a4>@r%+8+nF2)|r_Rf@# zQ~Wi@D~PkHla-^3m4iLmpPEW|fH(hM;PLgJ>78B7SY^Nq zE^r<&fR%%djgOg)gPDV$^`Fm!PZbpY?P+`GzpV)D$?9S3$jZ*b#%gExAD(b_k#PI> z_5RZ*oYg@GlT{Vs?BMET3XyPw*t<~vb5TcISLc7O>FNx5eCyA?ZOzPC!KVJK{Lg2k zWE7PD?U_e2T3FdR{(0hY^gl^2e?MuN+KW9~YH*B}DPKUjZ`*Q!6upKfiLbne(!n znVK^5^7EN8b3sfX%>1U@#?0(o#^9<F5IQ}t}jJ>mqvArqeaVju5ixrrMhu_$Q zmxGU+*_?xoA56i)$IK7z8N4(%<>cfrHihtU|6>XzCo2#M#DlxXhW2xp?`Rx!L%P&5g~?_#o`;f2Ml82LVxK86gS|7PfzXN7>fc#oWQk z4uqGLy_ti%^S^(jZe<5ib1{B28#@m>CpS1R7Y`RZ4;$A%X4Hf@IRiI;oRyu8h2yW2 zo0$qof;o+WyII*8TR>PH?JfSy`*<+|;5fjv#*fhfX8!X&IE{d~6U5lX!Aaf0!B&Xk zakpfTQ~n7mGQq#YML^!c^v{ET21CpqBku2*6En78{qs_g^}ibYzs#g&>ELev|81Us zANp^zh&s8rJ2=@WIVqV~Lrh)%>v{gO!T&asD#&)uE>4~@|A#~Uzs3pv<*?G=SqCT2 zf2^+tdGpt+zfzK|)gM!lk^M;n0>-9)ncvyi4Py4^3V|q*@-v%&-~cbVcuh>rdDtL)JpXZaX9sf^cVj1rs0Hu= zaL*vP{@gPe-QWI4{~yP@TS6Y4i;aW*F$uEss%SGuzrEx!kp3_J z{Ox`J7gqpN|IZ@-E&KkDx&Fso|1Asrw+8=@cm0pK{#zFKZw>w*@B07ETuA>;xgqud z_qhW?UBgh*1<3eQM`>+mC@2=n$A8csMIvtCO#~Mi1qp<87)%Umg7DB(Jt!zLD4AEH z>K?PZ3l<*g>*qX&77b}KVN`HW;ppE}&?!W~z(lBTKf_$3V>k{&lx2-rr<*85lvWuF zc77E>F+v&f40B2uwzrd_ub7hxBU6;&(A$Lt)H_k zn7eA2o;(T#P*4rRm<@mZ1_h1&*Dn}{|C=}d(+_gFLXA_4Wn!=7ZW`Pd+1`TD;oL>C3h6(ZQ(#h?n=U3J@f*7;tpPA$^f>jOR!7xM*D5%4*T){7- z8O8L7Z|NfZ`VUDD{0y6C`Q?;C!GM4O1Slwf>`AV>_~+DZHlekuNWSM=i2r)j;*haX zzxv+X|JWK{fZD}W&9yhxj8|~@0!&znVoJ6GN)aUVu28!EhT&QJS8kuKBFMj)J z*MwW(KUs>E3XJRL*PoFq7QLMYPcJ9atl~mJ%}01V<3w5Q4nf`=&FOIb^|rj6B({I^ zHJQQ&hkX>fzDkkJqQnqoRwgKSK{Q zzQ~__N=Kh1;A-6;L%ig3GScpQ!=m3@Xhm2g>}3qzH~I7PHYf-d1_qpzLGvR%At50S z4h}XpHZCqM21aK=N?UF}zM4iIFgPpg!SVXg=C>^8mW8IKCZH>Uy|U2J@%i0eju%KN zOcq9Dk|CxShXe=L+WxH3Z*d#R;H}bc;mHa{3Qa`u+#4s^lT~~Jw)uEf0US7cyV~Da z;UVVc`-^SfbM%av zf&=J03JJ3Q=PMbNJ6Bg%H|KjdSDQKhm%qZMrl#alSeo=$zPwgZQ86+ya&&YYN@gbY z+REdxn|&oIsXDys8H)$Stx#a`xD^nJxlxl`3ds;r4Ef1ZuQuI!+n=9|#Z^_~XLgF# zaGyPUhK)UyFA+(jkj`a4f4S&=kOWDy;1_AGoJ+_S>Kj+`i14KT;5l61^v!`RyK*O< z$|^lMJ3Bk`&rf!?-|i3gNiK15ab#pwYcqRR_Jis&DI*Uc~w_eW2fELul>xZy38xj66!eG zyh@;!TKw5DXuGF+skPnaqCYw~DB!r<87p$%=zXytgn%xPrKq6+3kwTuJlEoWfJQ6; zVksN{?i(yHz++B;Acf?#wzlFhYWf_1rQP1%j;G?!Qk>)>^*tT;ySo;;TnNUi`#Kc6%P_pk)A0A1p6b77xO0(gxq+q$obrrw@({gg?67I6*$17`*uh) zo7P)FpCjRG)PBq4Kbh8b@ICvk6>7ZIY*1y;*4WqxqAi)#u$^fEiGj_a)#FW1D5}j& zro5$z!(0jir496XAU5?jRm^50gBwW`iS>SIA-FjYnNzB6chrzLZffF70 z_AQ&;^h-Lo4c)`(*0||%XJCa+ok^efCY1~W6B7y=8q4#Gz=v_J5wHLVI=8Fib@j#F zxrPHd);4S`EJ~Spp^dU~Sp>3K=)Z2@_N*)Pz~J*{awHyW`^BR7Pzoz66O&ogg6oWa z0);;zNiMsC#WqUGsDZCvkG$IQ>0+Mq?iZyPaG(UeCF;Z185>~q zgBZCHv6>!RY;pc>Zuhx5-kvPM!^W15$0i{WwweAYMdBH3?LI}Ah-;l3eFG+c%y5o2 zn*y>N231;w_#bv5oEF6pzi7Wb9^$r{KGkiPZaI7XlR@{0*yTK%y%l!k>SS}t z?`99AbovNYb@kKB)mWt*VIeB2-gXG)Ht?0lEU;W<7E6tQMug8}`{NxJElN+RO2L=j zcUT|>R3Zcns%F-mRE~df?qAw$e}Ir}sSaaFyic|{KIfczDS_Qb>Ua5Tgm+2MX)V0G zoSmKBq5aAnWL>#);zyJGaTs|OmGR*;PON9oe1u6&Z69y(OH|%`_l_&Jkw;WsRdNv$ z$pN8tZ2Kwnp7^M%zW>ABMTt^QrByl^qLScI?}w^(kevsWdqLE`?1Y87bUv)fSW3vJ z+t}Rf@9%#c9%@``Gqb;*VhBn^%bR{#_l@B+0#0+E>+OS3yB*? zK{%1WcP0{1Y!$_>oeVDu0=09wD~OYW15Om5-)SwC-SqVvXUzFh8}p6zp_EwS7t`A= zl9G}v2Ca=U2{aM;hb^1Dq9kCR%7k!TC@4pTsV52SG&1q|bZ^Og?yok1f4uO$uI>5d zu~X3yicb0s|HP|J+I=Qr|CP$_QpZC)wH(M-BO`k=RfZ-e6pSnhsu9KX*p2#N$_``( zkeX(`ND(UYX*W9lI^CXh)#pVq{nZ^J`c-We37hvF>s73?E0%cD2ib1afh)O;+GOKCs)@;n&=Dio7`b1m?P+fN*0&rU`~R}bje zN=i!53AyMvITP4%Nl8VFyWzgz*O^zNKkntv4Q3?ldj#5lji**CmLGR*^E&%|(DC30 z>ZnK4JND4og|pncl*IYc@vRVKylk)EWp_6h$Zy%Kr+_0#K7AX|O$=}XYNvxFG*o5a zL>5Gw)c^Jx` z`pBniKl%0|5|=r@3As`0(Ml<&*E?0KEKpE-lMy(K2A=CURWoxSnf3Pee)_~lcqS>w zt9>La^pTJTL?(PM|Q@&($l$7bY|7n!tif>^!)~!MMFbV@352|8&%=}XUGyshWdAGM!WRO zIr`+JLbN?SJ&9kq4G$07&Nm)?iGE%-Lb?8e`<$^T7D?7q>Z3Za!;U903ncrZ|cx?rU_oS z=$CBVH){DSH=9RkRO)#SCelMgLj$np_bUVse7Fm8kQx4yJIszOxW9s}QL?!}uYcy= z?#CzNz6hMRWW9ZTLMOwVk8xAYaTqJ-9+8juHrGn0!G0kWjhI1Zq5-6wUty#ZPTIdU z8HPAewK|Ex0qLGT8u(tM9d(#3YJPqmRAd8CYARdyuU8^j0TkQzoaDlh=xVzT;>d<* z3w8?~^%S!LNGPRQ5&5H$6u>k&_m|*q^-pG}vzj8ZR)NgWH zXV55rB_-A0+YA1mTvf~x7|9V4;pLrKOb?O5CL!GZppIYI-`a%epB>73h&RhRcfjuZ z-Ouy9Kl5&{@-nKtoSvTEg*vJ_jnl$ydxBa>DC>Uf%D4-R{%cZ;o^pdhJH(BFGyT1o9@TL zw0mCgEWs*WeSMN^Z!Aw7SdLi4&&SWNy>bUTn6785SuyXuTjF>eln$Bfj>NWSxur_| zuOx9%jNP8=EnDn3kmrddkqPM`M{;!$1fil~M{sg@oemNP28%zcO=l|gs3syJBAG?sT6=m@Nrae$#9+|+WrPxTt!2$yrlFI~Q4!}2d2{m( zU?~7sobPY1K-NSf5xksp=(zj+p~_6VJ`77c*>ie=Yoxs@>KW!bwM;xXKwC%~_Lm^6 z5IR4el1VEO^rhF*RX7npIdQ02Zs1dkw_OBS0l2w3hNxgew3Df6Yy+5TP?h3D z+!ieSKA#RPENDN}7+*bcb#>WOR25qyT|#v0bK5CdPjL7#8B+=BfE?|(k9#3vB2C>Bp88*oZcCPa^3 z-C8LfD~E2IUfkE$2S^#9jE;+~p4ezAU4NJ7#wS%X8F6vTM;jn)>-3VVPWCnHCRp3F!&!0C%k{p4jD`=R>^ehs-vQ!01Pt&blLlSmq6IZ!`9Xo6f8VegWZ!W7yZpW)ff^XLQ+!y ziv@T0-&0mQ(-k0-?vLg5fTX{T1c=tRw4!-yom+mh0SpyvUc1@Eq@=!~c;LFr2oEn| zpl%1*qR@pe$#{7i023Y+zG2FF=gwVg7=t$tC;G|3d=;5YDNCTvay%bYRCIhcGB&oj zY(dZCwNJ)9s%mQ73JDNTzyKdBXz)|4P!s~Ox~kRw*pAZ)Igm4*1hR^)Vn{{qr^?ho zlCL$6#Yw?cn4EIWQk3(a%Tz4sUmfRCP)R&JJq3^k5U-)l6Zj`j>}P8qPl81wA08W9 z!T`|8O0CtTi@uh|S&E@w8oTL}J$xpu%FN20h<&z~!lS#KHIS<2MzozlMp{SU+1=$7xoy6z<*0YE0e1G9Nz#ATiMj9Gd zEAq`fwe7Wux)pS?fY9JF>m+7px0`*92XiGEtAfAh?o9fV^;by4^Dp-rmXO|#0nRlx zrcCl(_Gz%-!nmx2{tU3cL6K|{$gb*uC4en}$_P$&vzDL)ip@lwjh4bB)6nsi&(o(* zfByUl;KVfmjf!BwwSo7dK~F}~IBEI$(|-FgYJTK%S{qpVnxLkt%E7@Q3`(~h@Snxj zGzNX2E~+9?O~L%E`UzmLi2NnA*Ubt*If<%Fg$3g@WDnP=I@cccc6uv2NdLdv5z}R#AuD3ze5Wc@$jj9Ing9Ph~N`II-#NDYbU;>dFe047g{k2>{LhR0D318fmz>zt?;OB>6|iYlA(H zMYE9OC)}cWH6##bg-JaYEx_PQ6tk{Dh&+LZr;ngO6f-wBcXB!gL<_hWZG?PRR~Jw% zZ073sE|&Zq(l-F7xj0x_0^0&5Ff1(WdFVI@ZXlVcSzt#b);>gEJ5GF8y^5)C0F^f> zsSeQ8Up-+LyFWSU=myxLKx%oj`egy&dmxYqt=G1;3VunQ+naV>_~qCNd>qhqAheVy zy=sai8GELdGg?y4uq1AYFA1PXw(q(2U=L6(tbW!MO>P%brvpZzsHg~RTLMlmCML$E zurpaQ3W}qI#j<-84y#4mtnY^5@9ByRh&C|j3-|qA!$+L?NMQ_*7E@baTHt@VKHEX< zDFqe=d4PUK-#MKhb)jBKHdVy`9xyV%t+KMS?`LhQ0B&^!WtoMAg^Vm9hnbdkvojDD z;IDF(f+x}6BHz6$({DN77|C#Uasr8d!TtisBI!JKza9DLD%ijLo~c@@wNhIY3PD#l z>Qh7Ajg)YGBnv{Wzo!5**}4Th3t;#PwUTfC_a`|3O#u$81+t&jWU-;&6$H5TY`tBJ zQPBJ(vTKD|p8^emX>HbSBy0O8 zrVkdQ*;C;)r!~(Q?eV_y_Pu#aR$5L-L?q~Oxa@zsN?O%=JO~65t8dV4gWE1Z#yInG z)i3Ew7R&^mCy5b!`}pG%*3;GUuC)BOQ&V?$Hy!;rhvMR|1X}7@dMWBx5-LbYNI(h& zw<(b{MXr{-?!5U;<*Pl2+@qr-0IE9x4+f4%>bdq9%2|S*@or=ML}<meq?x02A0~@UU!#-!9q4c% ztoG&_S{CdVUnRztEiWkpkT-{${t>FvE^GyknnEYIjBXG_7;tpfq2q#BVe44CA~V4V zmRhV>3S912d6uuBkB|CEl>j)9m$#iN9rwLh0FLTPXB@>0xERP2ToRoJ`ry0_T9vlx z=6_*%#%vm(0hjV4jqt}oer}!|jsH%D0N?_Yv8Z@j{Y8Kf1l)F|^;Ip6sUCKlE5kxU z+Q9LF)bavQSv*6ZYLKm1J8o;7)(5NF&Iw0$0ROBli#4H&o&_={HXcN~IL*7*Y63@9 z3U?N1fOffhh592{0(kP)c)`@ikZ)h{tPM_DXb`(8V+Da2==6K4EXV)82{=DC#}#e2 z4^W+~Tj7GDCNMgfMN-Rf7OywtQ!^6V?76&|PEX^wB>Mnt``}jfvhZ^d?fQw65|YD zmjL|HP*Vf>k&%*eb-u~@6k4AJ&#tY2O8%i}O>%USds5eEH9a;9Au*A$eF%irMUBuUyB1oAJyA7MS!HZv^kZxeB5@b?Pl0G0SdxslI{ zZxbWsC+9o-JM!tyc4kU;Mbp;O31Ve+)$8*|oLbc-J`gEP`YZ<`JVC+#1XRYtLaIUX z?|>45oB;Nk%%mNklcR*w1h_>d2y>8X)Uc@;7|JCgaRCv|67oI=l7xf`Sl|I1Wx>9| z7@rGW2oxzn!COG9uYk9?>a#L1$jZyl*FcaBJGBcWqgxKzALUnohdX?(YRb!na~yz1 z0rIEeC!@gfa=>`O@1&gO@`{RRzL`Kw1{@Oz9$$KUm6y2`KIi5J%=`o<_ZY<~A6H={ zl+`??P8rfrRyNYs97*S%tF`(J(hVqLo^1vi8Xb4%b4iR^Kz=p&y~f^hdVu$t8LLRa z7m$`(uo)e^8kn{ojr~ry6ko3Z1V)iGBB71&4iW?XE3qXtgStyeLpa$U6O&|$^ zK7sdcb^lfnT?B}lW5B+792R}RB{o+gARwG*l&M3l+3|2IIP(#4tqZcTDPsiZ=H}Ao z_)M%j2>}fU>^3?&8t6hxpe6u|w;EK@Mbt2<#T7dn>ezI>K;RHh$GOX&bBWS=gS!HOXAK{clDqZTgAP!zlA^0>ho zsH^v8R?aeox0G8Nse{B=-5~zrJ05yT5m1|Zo$f$ywrBz6;1<2_UN^K4g3=Ft0 z`MTd;9)aT`BOwt2oB^c>z$utXr?H!7V80GnOm*s6m2i zR!S@a4zd`SRS^jT&=;r?7xV`&fP`*raO z3t;p5knc=Tju|VzqH!7B_GXjVlhe})F)>B&gAb?zlkQ#UY_uU8J_wg~QVvEN+TT&c=? zNnJnF&s$o^Z6=5vJja@Kh`bXY@0XF4C1f+|986*)^*I#1$CT~(?n49D@txaxYK)7S zoIDR?^;>~G=gp%TaOL*8rOVKrd-!{)6;rE@e1J&O3^@UD0VJqV_pKvsyQ0i;vxTqO zEFO+Eqnx>us&^6Dzu;fq%pLhc&Rt$1vu@)@IC9Yjte`6B>sFUB zY{7hpZcreJI>}Y`wtoo?7HCpX_+LQtp!+ecgN6lwUb3OV89!3r^HLf|J@%_oM>h)~ zndcNZ5FVL$k1!b|9YLaF`{Y|B&!QM9ChH^_R4rMhl2e1Jtq_(C^D>a0f&2nu3;bC2 zXIZ6#((llEBnfc82XsREN4-(s4R#JLu0-}P-aS7UbLf_!L9s^bIDiY7OKgj91(bb| zq&4nL>f`C>6u9kbfG55pwGMTZmnXVio;rKq#C3MQBurIo3deDGR>AHwfG)UnA9?2p zsPSTAL?AEk0{a(GZHfWf1Fb0lXw!=c2nlBa$^{A9b#L~2J8HbJ;`YUe0eLMGBL@f2 z6#!8A3CsVe>O!I52tqZEz>-uv8y*?Kk*EfRhWc}_LX_t@MG_gJx?6!N$wR!aDarR~ zb&aBWModghps?rpI*{N%c{YtY^vrQruR#mw;Y*vVUY_-Z!MZM?IL4 z@#SANnLxdFb%)&QLf_b!{3a;n>Ign!m`74+l8ey(TMs_-cwxXRWcqC{OBfQ39&CwU z?_;e41eeEQWkZV)1cm#)ZM&#;w|;AM6)Gi^ftP6yj<4+Z(>O;BE829dEG-RZoqBck zuU-nTb2TL;CA{ds=;&q^!$WxICxFR8!W&Ly55h^QaM8zm6chn;0Q$otPyL|DEFjPf zLKZ-J00A6;Vhj{A049~z%YYjyOm2M3ngfLZ(E5|S-#)&SRS4N4{=z`3pMk9!U_$|h zqfG;d0ARFu&~n9U2|Z4=FvJ+@A!)<>jv}{oX0fC?0GnNGQ^3WCQ9ZAPITdbl85E_q@V~0Zz!# zUXNTFRK$iitCEX2p*UJ?vXYueDk2ZJ&Y=4TR0&W17(*1LPd;NX%=d*dUO)ny_DS}^ ziS0eVIJ@$phW+eYR_Ghv@^jE51&A7_a@Z#cM*1A}uS*34)5(3ot``eSz8=rO%DS`b|1|9j@ zJ|KN|0kZ+UJOg~g0JL1w(waaS1C$c)OvC z0Ny|k1$<>@^~hs)M6j%^xaXI$Mv^K)2zw73K=+sa4;TIbG6A@(#Wep@1hI`$g8rHk zXKRb{#0m-Ypc;ys4J|D#MMa@;x-Lz%NkRPY!#~X{o7;N=i7tsB5f`M}EOk?p4)D5=b0#8Uc-$hB<{Dsw!=0 zZ=i|+#7P~o0w6k2PJlc@P@Z=OZVHGSp!u<{@4mnd$RQv#s%!<%D1^{ZQHwS*K{^BD z`$3)Avfpa9$N$oCe^v#60nl^Ks{2VEy$^t*Qu(gD1wL1zZdjYl5aNPGoB5yb!v`hxs? zeA7pG`aBv(tHGX6P`NE~+Pb)?sHm{8)_!4j-D$!5pba#B!PiNmD|Zx25}sizbb`(Z zenG9wriunPFK-G<)hU~J3j)0?`y8C3!sKIH_WtgsN~f+Iq`#VvpgH%utR#E3@eQS+ zlZ?#p>JeRp6M#}c;NoUru%2&xGu6Y%%IeS?j`>KI17Q)=HSPeG2gkhI$Z)v!5pEX- zq_?oJ5Fk$gXlGZC%pj1q^I4n6Mz+g#JSb$up+56h2YoX>grRS?#>kshz;RcQHMeVd ztKsRunIDCJ=Fl)y2^G-tr$rQ#l|?eN^BCEW(dxnTJbrzAcd?Yhs8tCT05k|RT>zj5 zycNhH*bkTH{2T_~rZus2mU`KY`AnG`^^n}ZI2 zkhDNQ6kF{It@HVf;?djRz>q+^0)_xhrmFvkvi}a`a{vFpVHNFAQ7EhI6d|%BBeGXW zWRFC{CQ8!DrVtg`D`aIBk&t93$qLz7k?r@mob&nKf86))kJ}%o(>ZU~`x>v;b3DfL zTG)s9S9HCuh>YY$X@5>&1e?Z|bl16GSl`{{UXu2wZfUlFE2;@*?0s|nGQd@E@z#1e zs6K(r0j(~y?=^%bWo1G%y93~*>f;*gOtyl~R|dti2UW%P)6js0NlVoEB+sw>*mnR* zBy}oHO-<+DKZFrU7bd$jpGDw2iw&|YV_XTIyx>{~(v^(r^Rqc7)w^2-@F`jb29-x> zTl@)Z@a~pvK+*SAy{sGnvYnfoOGLYogy8L)KY%E3XX4I3M5k573jpbRu6aHBxK{J& zKo21?-+NOZxUxvPI#RW-@u6t;)4Ak;B}Y5~D8nA5}? z0Le)9rEEj7#wVWxSxqU*FBlGN3OgvYa=B0VNzaQfPXKPm4>n2J&ta!hQ&Uqwj$dEt zwL%&5HS=<7(asY6`dn}_?bM^1x)IvCy1Jlmsi~9F)3JvgV;m&Yc1J&ZcCo>9gznqE zcG=MZHJ25v{khp$8Fde6y|NcxR2$i2A!lx|?|`=QT!i_;v_nZ)E|2H{&iCKM;KMAuGf&BmK_;MRdIL*Wt3C>eun9v<#E@ht}=JHGVK zWS0;p=O{YSwn8Y{f@`WQJFoB$sQV@=(gkb0av^7!bWN~wMnZzr0m__b^4wQCys+xA z7{w$e;_4AX;sGH z$e8pQ5(PZ39c5XI?o;fO%lyiDpqqe_CtEL!G;iD1@L&1q`8ZT}Mq1u28O#>sGGcHzPhTSEOQ^0wIZ~s~ymfVOl1>umQ z6m@`x=3B1$#hwVD>i;Y!fXqq8w#3szko)T*h9>}kv$yEx00_|+v9a0XC5^*~8pwj( z2+V7%j_8NuuOnsqkCrT&?DH&V`_X~VRX5B0= zZ9XO(V#9$8xvv5H0MM9Qam4ET`3Hj=eM~Y${N|jmxl!SBm z0jzkX7PobM0R$DH;ox29N~brnym0X-3K@=_l^{MkGB3+>j&F~4QZs82IEl&$dk0q> zA5!Jqpw58)XabC(s^r>}hzL2JM1ks>k?>n<0?t9yLQMUP4}0PPy`1;m3moMWI`6r; zIWj4tKtg<5UYN|_Pz0!lGHbqBo)Ltsx?19y_*0SffI>(zAciwA_R>y8Ay~u)3|C)ExyV*!X*Y`z|yqDBv8?8NX zE>v))0rL}`kEaL@fJAcZo6{r}lTkC@v_(Xa*PM~da3(7#RP2iUlMz{lf;=XU80}JM zoZjZrdQnHLtUtP2bjf;C&+KtF=FS$D`JBYLxgv8f=Z96sj3>`UO5LW)T1TPKP;v;rzA=0BUgiFqv6t$r~~!*d0~>=&)LMMHrp@fzV69w?qs326WLx;LB@=Z|g)-H>?c-*8znJGfzSB&$ z_C!1ZOC+#&0Mfpa{NdCE~w;G&OxH8<; z=<<~-s%e#Bn&hM3CH@G8hl|3atbdHkBd3`@$os6kJudmtP-7r!8ofz7zvp`o77?$W z^>+&twOOVr^u6zE4}?%R`05x$+k(uBS4@4 z^I7VB1z^{fV=8aawe-HKRBmf>8G&kzspaG z`*wAc`XhK4;3UZ5*?M`&XmK4#?2m2rB30}t8{N|&psK8_tv!!$m7$$+sQ0VOwrwMb zmv%cA=lMx0HsnWDsH#yis6-1Wbj*W^Cy07MUq}}2DBnm}-|3+vYQMPD2>J`8sIPGV zEx&IIeP(~61#gk*|4sz#HWU{oLRL*LA2PVrj?ZTy&UEIQzbd-6vtYgEZOPIG)1zb6 zf;MXeO9INWmp1@s8%%TBJEEG)&m{IQjzr@5TIL{0-=zg{mw?l;jge7NopI-PWOrPn z`H0V=Y@D2N0kyRFzQ|hWaJOM>Ba{GXUtWlUF-mDAusAT;yj?FPzh^$|Lg}e?V10^| zW{8;@JQDGS|~f3`_tYZgce)J%NJb5Jh;FBl#T;^`PP?c|M}T)ux) z{B^LNW%cpdy;V;|9LKO@X-$#jP}Fgoejd6tQ#Dbwd9{Qd^e?UOEi(|>=6Z$*3}CKZ zR|lTWxLo#fqQ74zMI}pj^1?;qllAe5@*6~B0)*m3{VkNrDay}$^$0b7`5t0189=%v z5z7M(l$8}iQR6D#K*%Tsloi6b>wh}3$IOH%D9Rrs8!h)VWe1eUrW(WTXJTeH2pH4g z)L}a|LYL>=E3gd*V%n*a!VmNl&|g3f*`7mX>&xT0+^s!g!8NAP-YCR#91Ap{i21G5 z>TvexA9p$BRtwNcH-E}})J3O(MZzenPAXMlD2f}_`*-6cU{ewUidF$A(;F>+iC;FNoCwA|iDDSN_ZI z>y%|YUQSLhBh2^Fi~Ip!dNn{+Ufv5_ zG+2`4cn(HI9BMOo2t7=;Zo7h5$!0zaougN^d1i%GHkl9(R2mH zrjU>`gg{UPBpA~e8yh1;XCN2-hPk9-U)5F`lDpUXMuWcJBXTBkFbYG*>*$4@ z@{AEW`O9~1RPh2@Hz~>T2hd`oqVffr90JOjcav2o z)aNKhQ8zdGS-$I*7&wR(KcpCA|JE?OeuxmFl)26wI%RO-Zz2Q^Fax9-6!QgECcK|n zyoeYrc4S z7p&UNvwi3z;=a%qcz!i(*T&80kPu!dyx~US^ot)~M#*)?xYDPhq9XUL;^W}Zmq*|c zLgk#S?2bNcUlk?k`%wo8Fkirhe$9*6WV$}%CQMsI8M!FBT};wruSoB$k2Ljlb*@uy z{~kDa5Vw)L{@%TNAhy4wLH;zj7RSeCf0WBFK5HDE#dG)tPyuq+gI*?L97s(lSM_dc z9$GnB&83WU-jt=g{}M(Q3J?ww?5TM-dUAOw2r#zplQ7iW&zx}tCISQ_(maY!l@K5y7H1nt!d-Qn%7wW;rc{wleEn|us&Dg8g%yP? z;pTg%!cN^^Xl`!zgoOjV`L}m>O0A;Gw>m2`_`8k;9ym zveJgkiKdH@BZP;`5Z4AWil3h!e7X4-Z@Bjd#RkUu)x2r( zw_Q!Jj(!6q1_~z^B$F_f(URYg!{kap=L9)d|Lw^|23d=1uOF4O;5&&ztMI_ew4J*v z%7`l+Xvp6p+2V17QTiTm7(EXNY}{HQhzE}ylctiDxbSjNTG4&)fcuhN-?58XWCfAm zT|z^4ltXudUxO?`74in*$y|PA&DMOFp7POs6%WUN<~$%9+VOXB2hY-eeDfw&dg$f2 z$b+NqLxCT?R<7FEKE$m7vNUdbRwjuw@eg)TLx_oWGEjpLOeKh zNS^)-_Gbs0e~BCKZyPwEeM7^M65-ZeKX!ONiu%vg+*BIzJJ3G4@OfWK2onfuEo9$a%9EG^_rK%)%ac?iRJhpPg$Fb5p< zj54&?VJua=0?N0G4e*;M_4BRJ@gg~-U&{XSINdrr*?KwYZ24eaunf9_f6qSc&|!Hs@&=_`dLEro{m<_Yl)9ElP_8w#nFf2NfG2Z zN;;HaTw1B;cI@$1TfRYPZZ;2otw}&RjKzI4VBz)9(2%*g`OqNo13(!15J5>vNm0?u z+S>(GvilUp+wgB-@QK`As%*RlIGpk$Cik#z}iku3~Gyx6;}o)e&zNx ze*IH#xGaG!HYrG)U}ZP`!R5J^8W*{5#gwk*9zF59vT`nlX{SVNu%G)M)=!S;9YYc% zq883Xc^nlMME$tgZ&ffpkk1ZNZ_4G4`RyV$P-8UnU?HrJTJvZ;;dwbps;q;9O? zn?Kkun?L_w|Kb1jfBf&0|NE2Ja{s>%@xM>}@6Z4DPyYXRh;?%A`U9l*PA6N_nZmqb z+iM%pH5Csuj+qECGXlOfUwLt3V$w*FNfbBR(xo4 z-IganfiyfkEP9kYy^YhaQuC;+#3z?9mQ1}oxemu4r%_Mj%6~iwzsQmJ_;{!oFGF$) z`bPlp3=~Zf<~n6E$VRsj7twnGsm)4H-#j{pDXDE0@oRglTwsqT>_AsKWYq~l5KM%h zKkua=ek5=H^f9LKW^$PP?g;slH`CQ{Wax99_gSOS1N*QjpzMU1DcRb>($dnxg3IsL zXiJi5O^|vcwK^3*T!$<2CD`8_kJX@d=MdG>z7E<3D)eBF1;c1;stABfj!?PL_%bUT z_)UXD)860BfPWg(_*V5>b-g)hs-#ZkCPzv7{l0v{eg>H5u>bTU9ynl|5tS5)m(i0> zx4*wn?%aB^?TLA3F1N&b(CGyr{=2t+wZmO}qPJ+t0O#&Y?MPo^xO(A%1L%CPaS09< z3VIQ(Qm5;lymoZ|pKoSX2(yk3V{!cbLl572hrOOJN%W&GP6PpsZ>~o*tf#Flii6hJ2fCnsC~0F6BP^z=iL-yqkaxvPs@Gi{$I6A;&m&cc} zlU-fK1LL?)00ej-vBQMqRq^uFvE#>i42mfC?sxncg)p=sRju^YGp{$d=H`Ctk!+GxZxzsYM`CLn9{*mDVN3&TGI2dB z|9r6Voy~RoU~}D)o-Au48iDlYD@8Y$Ap~S+Pl2JpbBE>}^$!6oEWYg#JD;1PBPp|snLy72(|BdtGOUh?oUU&5PN7zv}ZWRENVQ@{JdHtc~ zpu zvW~9mM(MjXn6koIm%oB#{tR50mfU*4%UGM{8gjr!@n2W5mUI7 zpf-fe)z=u@+xW)%)CQ2I8hN(G%q5`f|2`ysHQURuhJt8?{*!4Z3J*FM3h?czWd7!Q zsQiLN^*<_vm!KwqlkFO+{y(dLjg4IT$s+5kFL}oQ^M3*7z^AKdnmiCRVHUB|(>Zsp z0umI|!mdyW?q|!cZl-W``|O@dhWyyU*eh|4jlZpMU** z%9EMM@Kh|F{_KsbXo(53gJ~xWs<2R?#UrPn*m!H7o<0UXUFgoTgA^r;f=y4^63&ir zl}b@^jD{QJSWopl(r3g`i9oWLcd3iJJ~u_QhpQE^j{x-Y(0QX&Q@O?oM+Gko<#5~_ z@nzmwx$gtK3K(@k4AZzZqzF#{$0rc8r{U#z`jkfG?oZY$B;tMA68boy{~g{S3WE#G zXWm2z#00@$W(xonr&mINU+^k8LnG-GWl(d%$D4_TmG$k$`U>m_Z#n$(PuoL!uGKlP z)cUUSaTX;`mdLynv4j_9R)eN}oa0VZa@3P20Peuqc)uvtWnfI>D0lvy2v3`QVI5nfFzO8^7-=61OS8m zd1MazaI+!No||Bd2$JE$&Lx6CQTVq@Czl&&Uh=57#aZsHx>4GV&hN?_TU1KkOaf4^ zAg~anF?Hiy3Yl2Rg?FQ0#^+H0IY1FW^rx)(Kq!=A#4w@7`=QYKDD0>PpHwfLxOkd| z2*|`me63;+?m7}>aI;ijTDlU54Z3h~237c=(A_Z{K3wD3wIykA`LpDX^6fnu4^A)4 zcNjH3Jv~sqvBs0sy6Yg@hnkwX;9q}TN7<%N$ank?Fu5FH#K6Dz{yK+We0n-z|CLo= zMTZLkB=oV0JOGUc5jWCWs*QdZmd&Y_diLCYU_T93$?yp=S_D7~oF-JVY1$cI|Ji>W zOj|m~?)il>{gA5V|EAd7z05;oM!kq+>q|$sLMc3h4%lm<(=xx?uHx<%xIFO82D0Dk zQ!XF;YI(pg6qa!+*%bjYbt*tYRsBUSGe0p%2L?UZ6H#uV=YvJMx6JkSM@R(`Im&rF z56(@nO5jEj4`Z=(uAa9fi~l3XbW!(ju+flC1b=cvXg&&*5NzzZny!u;%P$5Sjgsnk zKK9(M_9QuZUisq1XUM}~D>2EYs-GD0f$KrFIB!0XW{o>z#sqLe=>9ACDP$!GpJ^OXLp|%oh8% z&16NbQ-$}6tRGc1TPsGd7V66oDGX$DMB5YacdCV@i{({&I(|3b}k!p|hTd(ApS z>3@aZ-yG+I{V(`kIZOh~&CEVWpBV?2NKN{Fe4ZFQ0D{%P)|PwapitYIFh|0#U%w!@ z6J=(;cbd)51R#!l&{0CGuG}i4KG^(Z$5oNNRTKEw8$}rIM%mXnp$+e_Kqi#|lO<*fcN$**@TAICEw|za_t{-`FDk zf2z@J3c&^QD9EfJ9=HtPLwiib`L`I#M+jYVf3CR*@Ky*YW7dn5sor;Y3!i*BdBf}UJO9tQudp}1M4!n>O|9*} z0dwM2BpM3wKa{~DNyG7%#Rp~#IWMhPA+LcRKve1mu3ta&sj-m}AR2sUXrcp^<@f&& zTFL$k7QG=xd<9T9>MJ>j1%z)wvoA1NA#wD1x^|hx(A*N0Y+SgXd9q8=cnQ<01_ELSeY-75BJFhg4@oT5+ujg}OyLV(LxynJk1y0BC z_0{)aPL$a+(ZH>(uHxi4S1oIaBA0{-&#~_c;RHtxeIaotI(e$>?OP}qp1*jJrmRjS z>vwnH7{jI2r)7UVifY5tSMLaaOATq+LqTCw=8{uq21qC!OBT`))LYY!h*u30hh*A_ z6FHLPB3dM&@%lZ$N9ptDVfmH0Z;4>BckkX;&;kBfljNB-$~hV)?>CoG#@}DV!=lP; zSw$1BC@abqyi%Xtf#9-d-@a}@yu|nmS2wril@%1Ip}X%qe|auv_Y+wu@8XK5t;A(e z;<-*A+ArH|SC|(T>P+*g<}*4EQxg+g!DpSec5SJl<>iu{((A#M0Wpe{q+cBqUvix7 zx2NKreZI|icqDaHp!};|rcUcY0{!FS8bg3?%Nqllg!X)5VxsTk=u2MaIpUjk67Y}L zW06Fsq7d@}efR))@n&A2O-UMQ9pkWgW59{Z$ER%`wL{60VNR}92V6{VJvHly*ckgV z+tIK1LO+v@k*fG}{g*F-GlppEDnYzn@c97!;Tu~$iFB(&`7F)~ui@pX2j$lVeFt2D zFv4k2`T&-MQP#dQ_km8Z%`-J3qLGlIDJa|Z*3dpj*A6uxEZlCcuH8j9t85DJFE7sC ztnBK#9L930DYWJ4J~^_ijdYRP#n4xLWKz6zfe?t!{rU3)6dcgraK#~%<^aA$(Nl2~<5tU+w*0gTBXDJ`Vb>0EY(X zj5aUc0Z#qz$}wWaaH1{ga)+T9eCtLCS&)Tx?%I`R_!jw3C`t*kx1fN4ALtZ8$cu}K zji~2KK0k0uHKTszKpW>+pGoEJ#|^?ms;sM)&Ld!zK`V(OfuL{3yt)}vh3Hwko!NVY zyyo7m38U9I$iNU267sU$Mppf(fR);f8?T=|J5tWE@o1=jcfLs_<7aUqtdUV`A+V7h z63I(BcqgO%(@&Y&%wj$6Ln>^T4S+{t?%`3^ZI=zINlEE5N(kKAXXTl9^S34Do-%r8 zTc8g~07Rd6-Wu}w#T#a4Yo)b3;nW0N?}-5bpLX>XR#33VRcFR&ZOPNm)LL(`5;)}l z;Py_J+#rT81!p~t@&gr<;)mmmr61R!FA@f=(BdPV^*6wvdsp#oH)*>)2x_Fm(*88efv8g<*aj-QD8M%*>pebu~39m<7ndzISqS3dYSJC2X zUz{0$t+f!m5C|6V8_W_CF}%2B#_ody@QZ zbFEfFDG?dj0beAHjwS{AXeK-{!2tb2$o7L~nodjJIvK1{Qeg>Ti?-iqK6Z?##q;mg znf(+$e5>A^B?59p2oK)EH2XmMCKSG>J`)V+Yalvk3_N`Cf3%reGO35sd6Z zxM2!(p4u^N^ZM{y3hcVwz>?spX>x@h@*g6k?TgdKkh9<$8G-dcDQRTX3vLg(luVrr zjWm?rr8p0?htIKS0gQssf_NYC_jsDOI_R=2ilCTSqmMtkLT zO`=>cMLmT5$p8Tz&I9p(1Lp~t(Db5`>sRS_6%7$>;rc+Gz$t>O#4gcGX+^M&heH7& zKv`M&Oq7yV<{3Kd+OXDzo_nmE#7?`1^<;loF+ZVMwD@o>q68jIiESrefj*o7OGr_# z5aTd`gk`&nLEz-6xw)q&o+YDIoSmLt#JCV5gusb_3{}_F)z#ho7MvIoHaJV%j<>8@YvXQ^aZb8y#l*m-^)}t;9(#XW}_7f-ZG;dI%8vS z@klw@82t74aVyp~CSAUBn$(YG7NFT%CMhuU&mp4M-i%D|&&%?bcB|YcDja;W1CIr` z?u3&&&^h1`kOZp+{`14^g5>wfh1JZ}+P6xJG0^_wB8X>3klrrSFSE1l6%{{076XF0 zaaSKCJvOM%LyyU(I%{RLM{sH;qw2yE31bn5pccCoT51PJM~o$Kz|!mf@x!Jg>n%p0 zVRVK@tR+StW@KE$LE3Bz+HFqi1vCo`FFS9zn2~a9geDs z3UYu4@ofilp*e=q_IGOvg*M$%=1{^l*2pOb5qfuvmOx_bph*G%j^OvE(-!?2AqEB* zVeiRw&7G({{|nYt-imQ*XmypI@*3khP?YJUX>HrS_bdkOq0}8^jB!m6p)TO&qS{UV zuKw^y!M8g;V-^mVsbnoJhcUDcvs!+46=tKjKukW5fveQa4Ho?Ezc1Vj)lQa6h)Z>N zp(1bp_;(_+2%n6Csw%RsnNWPQ73>1e%tF3FF?zLUs8~lYLRO~x^JtH)MszT>*n#KXpW`3fHyL8e*fIjO(VcnNI_v7{5W9|Gz#=-Z)Zgrd@dWI) z*@uXG-&tC6Fk0ss-cozQ-l>#u%z&(4LX!wwv^~8YF$U$T5z3^6_Q89nbsX#!C_>B- zI#4%**j|U~$NFKr&6&wO76s^`ZQy7?5#qHnDdff@;KSDFfpLvv`T}%t`@n*YeM^Ks zoEgFlT>khghFrY65PD3@ALVdcQElD>a<>4MV?0dk-7|~FBz34{4R3r+-Tk1_B&R8X zqmap~Acu)xvHwMXZ%I)RMC(G(z)mzLJZ!KKb^F5+ZUYG%y#&K5^HKuSjwMTi9lT4h z;e}*rd(ykkrc!CplNWdGeqe$dg6n+r&p&EuTG$wubIs}q2`1nIuHB(!%=_lZJ{w-4@Z9NV67@Pl zGSa6^dhm4>UCNf%KY%{RNZe6OmrK&PvocwT!Ve8c1w-Hl2dI48@b zx68+i%8<3>-3+Dtzl(Q~ZshFe9@K4Xb}eqUVww94obu0jhdmM%9;3($JGAT&;Vr@) zH|Zo=olv)}RG6lZ{+wubyAAH|^N5IFlU-U*8J&syw>JBP_`nP!#g3$ziL^=is z8-tLGT}5Sj?t0dg?dbh8X@@A-bJ^7s*|UT?@S_cIU`nCB*SzN%GQQ&;inBp=BdOM!SCEg-{I2 zvc-*qLgwdf=k&#!2iZnxUFWAxN)^a|_X?ClT#v=FuKDEh-aG@?Ysc2~0tU=;#!WJ8^{*O+G57q{2?zA>8ts z>S|UNmXJn8G;WaJ%l%Z&XrC23qAhRD8~pXF8DDWxQHVpEl>oM1ISMdvJMWf$9nrr{ zK@ki&QB&->kcMAxuSdy?HV&P2%|OncUszz^y?PGY5+pE+Dn5|h_%JFeLg+~rQ+6<1 zfMEywF(DLV6+8UKFx=xkWEB!SQ}+c|HVqp8_>rEX#sTCJ{WprEeMuU`ux#L%2tFk; zj}H8JSQj1AKutfUWlxbS$xJO37>)7|zSBIpggO*Q%F2#TPIibf$SycT1ac+&F+6uv zV|K7}MMhq7b900D1*HMpKY-cgW%I_f4p9 zF}+F**aS*(VlYRE<25LEP-&;Fh08P2`$b5x*T){ zyum1Bc6s*!#vC5TBxhc?f9lN8lh{sPIK$`~JKQ@jcQ(0E>T-+B(NVyWiBL46b|8k7 ztZQn~pP+R+&dp>U5HQ@l|Q{U~*AG~)~BP_Jxkv@eP!Al zdG~Z4InuF;yf$nfbubh9jtqk_1*D{;1jCNf01dST)&+t(JF}2wu(&Ld4T(hWa#*dw zuR08{4I&IEJ}f+UOzV@P6cZPxV3ZI8U>zpXcDE+|5tllPtuAwj+^62MQc1Bsu5gye zXH8T>3buv`9@k6i7=Q3XPwEp($T(}5mrX(R1IF;vOLs!IC+7&H-@N&e{<@M=Wd6Qu z%zk{s@yGt=wv-*~_~i4$hT(_>22%|V%KU9o4EyELHC{Iry#k4HyrlThVzbh5;be_R zjg5^{sHo7LBr)wo*j$*Mr9+y)p0{Ro4Q=isRu|Dc%^ob~9iZfQwR)zJ2K$0724JHp zMU#ddh_&?^lkKqSKQ%TRbv>*T4>U7Awo1S4(yZ{g;{2<6tb^OxZ&YinCl7{&_dfYC z5<4)F`hmTpki1f3eQbh#={tSIHT5O9lnt`p^=w&T)NOM}c_KfUcPKNi*F*)yu z;h~-~@xY$C6P{BQ^na?>o+3{AJb1v$%9_@0bNFy1%0FWMc)r2WC+tRY43kx3_x=u_ z<&-q2<+=T|!D8$%lRCR3+w{E$ZlvD?55?a8w=}x`qG)Gs*c0hECR2*Xbq**Putm`t zSr_PMw2w_qO-)X&!Sr_58vY$d5Kq(Q^RvVv!I~h zv164$?j{!?)!VUsJJ=}H`K{Jj7%4lxa;j<#Bc z#ZUG!k?HxJdwiD3`A`xC^A}*RG9GCa&06(!M*CF1KbZ z_@cgDdKBbm&^RndvdsIe!Gf-pbq{L^2b(=@#q8GUes6nDl8P0VuazRoDXn^$U(x(w zC=up~IU~u#Ux67C;K(4bWZiQ93~hS;g)o_*ATm?V!L)7h9AVLGRomQtFGaB^Ai@$Q zH@p@{-fX1AHCuhtd-6N(_Zj35$Qh@nr@@1vh0vw+K~{(7YYxu9hA&@|%eSV9I#H7K z-8ri=>*c|48Xe#Dmc&O7AJ(9=9pns6?1b%N4Xgkd<4-0zBMu@WI!zpWw5zi}cp?t} zdn;94z8b};+4jDB`!C+uZY2N-BB5P}JhBz)ACYTu^^LRq3`rUaIQapY=MFFA5<+9E z-Wr>}yGji5DY9)ve_jh3_Y35b1)&H-6rXf^TKFSJ>#r2oU^$wXGZUfM}JSn;x{CKr; zOP#R3oQ|7^;YG^|RGE?}Bh}PG>dX{XRb#;gq8Wu$OJ*y@#oaxOM?dp(E+#^og2M*| z1xY}mR%J24pyU^{zDLc1jZw1Gm8^cxCgeGI1jNiU;oHd%AIh7Uz;}RB3a)j6ih>_Z zMWn{2AZ(jNq>j%I|5jW8meU___i{ORiL292E1|imlVN)%?fUbk1M2-j zk|%9r6pY;@o&>%A) zI7USFU+L~UzKcw<n zUO^qmA`2)*97BhQwiu{AOs&7!b^qSlFm`ex#;1vii2<9R!zzTP@S~N$E!_wXKNJwV zLBU{a0JMj`<2LH;j$h`~&!@@_)Q6|{|8)6_?inSpZBJP-F|j4w2Dt~Tf8V}+;Vh5F zUH&28=5<^vG?{{VX`8h`G$`h?!opDKf?c`@)N^22l3rlMdq2H2P8@!GoCn4-C&4_; zDB>^z5<2*we`v6!ke-JatxKGIIW9~ugvj%Kl5`}p#dO@5NVuYTUMFUSHe>Ok@C4gR zv)30^UKTdClG4&HTS0ZIjeFq-$xj?6?FT%D2M(b&AI)A_KdPLrNo+s{d=sivlv?u` zv`FZS(1JoBwAv2j^OepC*|+5`Gso~cqO)fg@d2*zG0Yesie*t}J7n({a~O7khjSfq z78Tg1FJDkZ{Y6ns=)|aAMs!HZ1FD8mizw$X!XdBo=;naPJR}=^?n5H>Y|gv27Ai_5 zB~rDxN>tuY{upH8R?vVN0ybY1iw?_wtl#w|HCs7|yy&z|zF!4x7-nT*=avG=#CKr~ z@WN!Sz7Dx>LP8K(a2!#>C5@#X#HwRewqe7k!0C~>ch8SXw&Y@tBzB}T2{Rsf;6 zUf2Z#>I%k41kj5{EdO&h<8SO63D{VA2>xLJr3A*fLIke`^9^|3R|dtoz#X74#3lZQ z3miU0Ah0H;rl8x=fF*I>2^MMFggpG0dj|7z))&safN38w*}0_$=3Xq%&}#CEV#4GRxF-xM%ByafX| zi){v}6o!!|r=$#1NUny&#Hd6*9639I0;b^FD>0WNYIjd|_zCxHTNQ3H-3KoXnG*O! zR2}FTKwH=p04UxKia|4lT(vcHE6edIuf79d1f?iJgaSZoE52>{#zPDN0m3W>YHFAo zju+@(7ogj*kIpQw6XlH4&?o9kmo9yg!*~Hu8t7nYum~|eZX}}(m`iZf#WfygjaCeA1~jFK-S`&gH*TSgAkJ3dEv8 zK(Yd7{s0&r+OGACrF|qzkGvOPp$^qU&y!-t;P&*p-bj zG6!yuV^bzrQV0P+!_xFK(OWFw)&as%gT&UAFFR!X@NDDrH721skfmTFTkDR#h(cQc z4bLk`4Opc2Zol7dL*&P2&xqF&aO4Lz$l`()VD^X39%dEoRJAy`=`i*7Bu)un0%EF_ zF-F||8XE%-t6gY!g@-2_Pa6{(H7H5_>JF@@@msWwaxs#F7FtHY!isLgpx7jhVytE? zPfU=EP>~^ViR9LOefQM4oyBC9iuE4zV}PI(lX3xSV*P@2!eGe6-j-eYfWF@n&`(>U z@+UP)QbZuWDBLPSYJ}aD%X9h>;87Uq@0stg-^L{~7YvDRrVi#X(OD{b&2D9l00HgX z49EqrKKOr314h2IMDoOLLG(`1v?+=BtZBAUQSXA5D5Vv2D<~W^zOAD!V;@nME3xgK z__Zh2rl1680Sy2psZCkpp1JM!-`ffv*}ENkf&I2EQxsk*6cb~J&L6`eWn^WWKYSsc z#_w*-a#WX;EXSDBurJf=_o%thjj*aMPc+A#4@*Qvj@F)-RA;M#N$TOy|7$!9(T zn+dA~je^v2xoSC*3!B7n-${D=y5HKAq~Id?qA(6TIyCfN_&oq#9xhnP7O-amr~#6q zib*@<`;fm*M$&6iW}!Oe+P5T)ru+gqAyH9Fpi+;? z`l)H2*d;7d_n3tfZvgAOpRy{XW5hDR5s0On`YN`hPiscX z+~2+r(F-%7L~KSA9}NdV_S)`TQ&eZ6cK={ zh*!e_<)sV6i-<7A8AXB}hKE^Q*XE+$MZ7&u$hw7vnb{ay7v6m6ytyNY78Su0mh!~e zHi$bAScr?zuK;L=NOK5}7Vlf@51x-R(hTtu(=C|Yx5Vyu@ffo4b*xYahkWTc4k-6P zIpO*Nry7Ige8;|_v~~K6#AlD82glEiQoetwl8a4@dWT6~R9dP!hl? zhe86Z$MdMD(Vssdju@PrY#_Jypli6VL{e6tXS}pOcx+YRj(p(tqy8x!c)i~p@Hr5L za39)Jtk=X`h!aQUV*sxnq6c`WR`|X_jX`i;TU||dVsFI`4^Oh2d!bx>xqeQ9pKY6+ z#vQzdLKhnaHT0-i63Q90rAX{t&bx13y(@N1^_2AP&!2mcOre5;=n{RiYP;A0F2yA1 z&L3mxisH>phS|=}&WwC!7m%nGX0S)E!q$Skhan-!Nifg+Kwd@JgDXS68p6LpWf9J) z>AQXDiQ*9WH^ScNYQ zmzD(0N-owY*?s$X?0)&shjW0cMI2Ir+->!9+1z4(txo+Njfj1>iqZeQimT$(D6i1f`1Fq1)^LF7Tj7{gKmgWudL2%9`rVUR%MS>hW8FS z&izszyR>)bPQn%N^f041v^=RGTF&R(0nqiOG@nvt@C!teM zV);Br##CxE2RbL6kSVPX{t?8e84O7Q;4Thw6@*G(AArCeq8yg%mv79F4v9_+#q8Tt zJi3!S^2p*ba{Hk+(we=$e>@Ys(Pt5@+sVc&#t38N5w4g ztO0;H(1!K(bv$2}s!^4Dp-v9JtCe+Lv8GPceLtSKw_kcn?K;rdfoPfvd71c^)6;Pt%KgeoRWKaGM| z3i{O(%R=nz@+qxS9b0ya5#V6$4r})Etj}XXs(K@3A8ZOxZk*D6eHHDBBGh9V5JDKE z@q-d%|E<7@2OZ(_yDOHbqiEY-=w7VNem@+3o19+nRyNhczFSMe$JnQu!)}=vZh89t z@io(hSW4L$7#q-2t>f*BqYW6}WD1oA-1ny=6*_Al%1_bQ*;IR3PRAHj)@Ju0bSYq3N|4iboIlH?$myDvzvO zn46)xS9*EL?9%$Fe_O;2G&-f-hVe3wun5u5Yet8MF|PfZU`V3;O|S0DFT#FaikluUiw>j?3aP0L5w>^MJ|n*&t@ZQ$D5B0Ml4P^m6kp8kKvt~W>7Ga`pPTU*!U&(RbbkN zW(b-8hGXhcj3Rf3zqOB2p21i2Q`1m+jkd^by_ZA6n`+qy)6!{t{ z=kAR5=!l3n2wqU2JXK-?ob5b^f*YbYB}Z35a-dL~3aLRQ|pVKmH>}ql>=TKK8h| zn3K;&ZXb1KvdhZuiR#|mn8X6WMjHUgkWLk^WP_=XI(yRuiD*uTZtl{J&3o!@+1Is) zWcqzYu8;l}GN~pj0c^5IetsaKG||OC1}iNs4JiR;wbT!B@8}BmcydrHErD6R6`mVbm{cSo3h!jV7kF35x?|J+S8DXIN-M6jEQOxC`^A}>@T&hJ?E zv$D>xJ5ora9DXd;m@vmX$XBr9&Gpo{cfff*mLi5&>WBL$1 z7+y?>jvJ@}YLtd-yBysj`$JWzDL35LKym@R>Dt&-v_&VQ1&!T z)d<(%;F*NY1fLa;$vV+3v7TKr3KKsnui}2O#hc5*_C^i;qeKd8{&c=j4ijd1)oTKD zqk@s7oF}~X85IU{Zf>m;bG24kY&`MO_N9EbbWDg-sW>NR8mcVlbRKuLzm{NWzTg-7 zLZ#R{MI+5>Q4J__Q0Px;Qe(nmhDIKu8-&&4KU%$DuK6Fj$ixc_Azx@w zYymKUAQufh0FPwoT7mE2i)Sx{dw5P{SIzpKkeqc=)8Wp~;1(P-KaD9xd{Hh24Yq=h zLlSy5q#CdChLHCU-gFZ+J68FN)>M5HCza2i&%I zDWc_Y>Nd?ZEkm@xz!d=$DJm-$=yGFph_KtA5l9rQUs&(>CK=*jYiNpT=l}64j9gzs z{rW^*F9Zy@-SO~%XRQb0GtlQl5T%M~97erQo=`cF)@85tf1=U$^f4&BSsW#C#wPdG zPd24f-lOwwhlGzxsYC=nX_1Q$`oPSo;Chga-R^clU`*`T^Vz3T-vi#HToR($t5uV* zJEiQecJ1|vL`GL3E2a?VM=VJOwi#Mn=wjVE(0FKbg+s1_a+7XS4x>B(bip$e78dqx zL^e$eG`ojwb7H$7T_E0@INF&<4C-_cxq_ODfC*xkkbF2 z>7GYh7)TPn$}ia~3|k3AL!?vv@grVYNW8@WZXi3lg6P*72SchMrl=<@ctex{0o0tQK{02F}(rVK+--Q;yL!pkf%rUSt56^xcI?qmzE-%ZUW z!}Y|eui#^x*N}7tU|6`@@V+1*7Qlvc04gJFd`;7QD8b(LRPkE9O~jzU<^XmHhc?}< zBoz<6tAq>h`zNdlhR+iNY=LG$(!gz4cJ}1SlgEw`?iGxCzz|fnE(IwI8BPj?+qI-# zc@dOmQd0i3UEmMo9xxezZ;3pif&;JJJ&8;d5}K`C=se)kV_VMYp6p2HbB}W@OF25 zD-b(O__?S$4}=qjF1*WxVAzbjd$@;Gn|=^d1HhL7atY9t5wIobf2=LEscN?e06oEU z=z`smq+!h$1vp?1Jo@wJM-5LuT!m;7rC1i3o)nJRb6YH-QGvb!FA@pB zqf}9e;WJmnucAk}aM0W!_@@cEC`WGh#*vuk?uP*cp+)2HL!Ay;jvJ(E2<~8o?m&Eo zMhtb!Jjy8O)3CbHCum~C7T&-HVZ46km)csG2kzIIp)GC3S^@+t4vrFCF(jCejiS5w z6z<)4#Ymk1fCA_sA+1Hri#LPfyC9Hsz`8?I2ZX-O)deU7!c#C_(F;5rY8)Z^9*huN zL^B8YhfHdEZmtVP7=QnZ&}m?kK)SFF0vNfgJ@c{<&}uMgh|WEDbqKfxB-m#_e^0yt zjD${32}6s~oP)L@hPb2A!wY0N4qy3yi24qAs{il*YhNQS$;!A!Mai!0dF?%uA|WG* zjO>wQWmERvL|Ms-%8X=(tg`pW2;qOOKHuNJ$LHbG6z?5ZE(EC#P>`5)b~z1?YcJ#Soqc5Cwn& zVsM#5phqC%23%B-+ybZ9L7JrFFy;7}TrB*`^IY%iT3x>edFLKS623rOKH6hcDq1Q`8v7ALk1AZTaa zd21>I`{el@!E;21*edmm4F4z82_ zk`9fbbUB!8MV1g8gPVjzzN2B&?aGy~tAmoHLIB_bm0Vt^zB6M#t4$3x6_9-e1$|f) z$lC~J_Zq%2kzgi(g|%8f#oN+bGOG1WMe3&ssBGq--x09Ya{`At>vN00f5 zt-Ct&-=u%ti?f`n4RR7XV;BNbL3klGC^pFwRnv-y}Kl$t~y z@=9>s9Qhu9JAwEujzbxYfZa&>EC5Fx^UwaCs}cPDb&iEGys4Me0@-mjZlJbM?=tjk zahvD@8lWj3Gz8q5Rn67ehXV{;z@(vRe5VGJ6W|6sHuQ&ycu+NSs2TcPO`tGBaY7JM z;cXW$#K1LPF#-uH1qH(Ajov_+1B@9!5qN~4Wta6pK`*QlD2<31M@vHF?>av`~c*iLLUz9+|UyA#(audUp}Yomr)I$``bOG;+i ze&=c17H)!v1Q66PklEp(-t*l|kVpdC2Lz~uKj?H-jjS2RE&R>vdAbj={+@Tzeb0qSB zp@C?*^mqc`!!JA^s!lI08NuR$bp!3JSVV;(Hx|NinhOJd3Lh5|x9YCX-_15qY?hRi z)LXJ>)84ljKR+dDD1*XUQ7~G23%%2T^gO9+0K6F64ir3WpaQW|Y@T)e>UgYp1}n~b zT0lpHp!HP})^>T3*QkVqJM1bC&m+idz(2a2Sc7Q|SLK~MSo)^G==sZ1ch2R!(s&SJ zaYpXVaGv^k>%PIJmh2Sj-9XN2QSE30#G8 z;UnlO;JPxr31_r!+y~+U_+F5!f)H9c2K-^L;?yK9U`xQgQ!iSCOfc46?#aY!AaOSb zgr~_`sLu%`DW`$n3wZ~CeGEP{{<@i~Yc09wf`h1%l%@m$o? zRzcJ4Y{+la)g6NMg{BgH{rzyj8ll52fG@y3?fAW5Jr#b)u{cr?6f2+o)pD8!1C&*$ z?1pL-1w}dNq zbUmSMOfNWRm-VaxWg5_f%14cSTj*{JMZ54zSk0QHr_}PjgM)*eoiEhXAvrPxz6fL? zL8854WaZbdnAFs9a3UcT=qU$c1EjGZz?0zXOhB0+IXM~XegG|on^i_5ZF?6h?hd}c z*0>`$Vc?&Ef+gTp8RNUZe`lxZzyl!zO+g9z5zmMqnA-$G(eK~pEVM@MLF9%+uIdMn z83B2B4sPxhNK5F&0q0;8`q$3f7X9nJFETqF{bwEKb&BQj7O=}FP0zvBMFjxi7L1r) zOb(oqzW|0vfvg&MUeK&!Wob#pF=9z$rMN@TXC?<;r2#A!IKPmP7=yr8=7mln&^p`! zNrOf&&^?C-DGR&TvO8rFbl>D$S)j)l1vcMf37VHLyyDTXGhEiJiV4FQK|;xk3)my!|6 zLCmKb$GM4ZISpe67l8!|%wfVW8@yKX&IDZIoct#E3NS3-!Yo5GI32k1fm{k48Z5yd z1QoH_aCj$JQDLfa_yQoQz`#MDB$5Q0$)Zq@-E#+@3|O#`f|VHxO@yNWcM4>hfbAA@ z*)wim1BZ}1voJGG#cSrQdG!zAxMN#b!9E8+q+oCf77JRHg!*%Cgb*P7{DWjOvBgsr zmf>h*50|gwnUnZ^fEE8-GKDPAn{_ZS5Us$`%k&rr{01_B(7NC~BX|+#Ch>3ehLE^! zF~o__-Db9GGq|wD>EM$w{>T@sA$(RsLZSnw<>!d?n*w2l+#(4(yA&ycmCU=}^U!M|N$DNkq9klJs29LZS%rsobhze)JMM3$>0I1m9cxLI#pq zoaMI2`Db3kerR5Xh=fTvR-?#%(g&{FnO-U=5C*OjWZSmPe%;2Zr<`Iu zH)O`24cK!j$ADD<>p0()sQcQGUz-}@ODGgS1deC>k&zo+q&bz6O2_;cPOp^nVv9F( z{1>YA^x-ZMO$J=U?uVv$AYvi+Y$$Rp&Gjcs26Syc5I!XG&+%XBa;jY0my`L5@ zRNXrZ#ve6;aR6&Wc!mKJkqtNh0i0)Gl^48Le5uS@O-|g8^}VL5ObLO+d+a-WIo7G+ zR?wY#H-6~R18xqulh#59r++}fH{s&Q!d>@zVF?w?lXiQ@Y#XJ}$yCp-M>Fx>TGzITeizqBbN{kKV#IFLvddO(r=^M?;#cUYAFScM81IA%6L#*e!F)S{-{J0Au|!kqB&6h!w@FwteBmlF-B4CPRU z%-@-Ra@H+oTsk?}*42vP3>SRgKfBv_$GW4jVQa#49aR&8T)sf1v}GuDeU~GoDPzE~2V#Zf+_np*n@!+F8x8 z@`pRiZ4*~hBd%$OLdK$V$s@?MEAh?$R{t7$}%cGtcx=FsLtP-;g zjyYU15HvH81wvSYgGUHepimj8Y~saU(5s!cW{l3@ks6)q#IO^FQa*BOA@@AG}}w;puUI`BzU$>AiRRiDg^3NJ%2m&Wq!Ii1;QFZ zZP#g@FHLu0MrDvTab(1hT;zhxubsEQ!>gmy_vo@Jcq*8g6H4X=w<*Pn7nl+jlZEF%fs;52L|1fOtalgy8kvmBto2vpru%?Gheo3a~jxrW@Yz=?s$aDaQvpjf}e0B*<0&dy>$8X1Xh z`VlZ+F(j&jq**pFlHqs(&!@y-d2NlEkrB&wsHbo?yijy_&h#F(8Vr{LyR65S7d{g^ zdgXJ5Qge6jVIeKp2f!558%u_QQYdGLjn(~V!pQtN`^)*Nd}#cEQB;g|EQUK(TG|h; z-;H!i%1Vh4iJI6m%MS)N|Nn&e{E8Ae9+kcx^!gpROMpB5fjcsWqo%g@V1GZHQKUR$ z$s|Zf9Pnbeje2@|p!qJOseoGq)f|we@DCT7UEGjOGnHU`IZj6?Fr4R^BK*IGi%^pfnYe?=PH}aPy?tB zau2|Zn$<{#k^Ywg_A=Faz68RyAY%b8d+f+VFf0JpkrNYh8P^J_Z)@8{u@4Z)M9sG} z*e_{-cH`|Q`cSY4wvg~MfQ?wU5*l+u>{R^&3U=0@s1<7GN`12?u^PeuvdmtlQ7f6O zLI=>;5wI^9IiM@iub_tr{E4+{>o_-lxX8`+=0>^KEDPisVAlbLXiyBkM-deC0G9H5 z*W^R`D0pE1J<#t2_XYhccQD$3bwX(LeB>d((XSgDPr$C9k}9UwugjpQNeHB7Brwd1 zkE(w_D8oca8J&{yuwq2=U?Cfdhe01(#pF$_mAsZ4S`v%wqc{TE$&X2IvKoqw{UO?3KqddqM+lO0v|qx1ENsn80$yssDM4K@v_YjkQGV( z3SI7?{2O2%z-}R@1m!jmS7F8bp-e{kn#7lKD0H^?uyxnzRN-UeJ5~k~F;U7EqsjnM zJrCc(nE)aiK<(kq;~?t*89~4=2qx5WbsEx*f?HRi1{Wp?^l~$?$_c<e%T2mZhIVouMfKeDq(n${yK%g zN&#aqwCKD(fB37k7rYoiH5%MDKRv1jUZ4mEM-Eh>c{EIXq}FRMxfhxRbl!|*n6>}% z&Ory~b^`ASLIvdI2#$X6lYyXn@~edu2q|-OG|++=sL*B9UT=nhDGsmaukHd9eX{Ihdc$WEn#&>N>UsVtk`7elet`>-cCly!;+ffk%9WTOMvpfE|wY^>a{ z$A>?5Uj)C{kVmE8LE$ry*25~p=fNz1BnKJcX9(KCs{|g4Hu5@*6y>&lj_wH&!mp9O zoH-G+MPLGer`=`w8|397Ma2S0Mpu_wYzJo2VQWaSrU2OHGre1vJ}54ZDCKZblVtZQ zJ$3o(Nb(#MZrFu{D#6GQQ7~5;asvlSMM=pJust|lnQQP}r)36+2(3diAa#K&^$z9} zux%*P2Xq*GbZk|q-iPcdoJWT_wJcSN$0A}hRE{efAm#;>AVY4)GvM}rfk+5W3^o+v zzU7E5n*06+TPG`HV_<@Ts-}lWEhH*|UknEb z0=|Mdg@z>VC7=+EKbr5_K4Drqp_bRq)zP-o;-QA=VgZ#`hcude0 z&cYXLQC3>ZVr~4>0|WMvR&y7~z;Saw1SE!|3A#frK&l)Fxf5wCYRA9!3O3R|&cg18 zublbBO4Z_-_P`)tnsELP7sh&`b%aK0r(hx-4v=SuJKTk{7W3A%9R< zpk$Y|_4icluB|@_ZZ*`er%BJ31BHMN7j~H zgJPyoN657R{tEao03Z-!10!e^Y8hayhPR~}@Zze$yOw{^0%|}Y)#v5qC2XHca4DY) zS#w|RL2vV2Y?bambLn@o^CRM_K1N$8Q4OpzUz0|x#13OIoO+foxlv}sYxwz3k5jIJ7c`MJ43mV*92fic*^ z44D51L$5pDagsd$1=li+9%6sCK>#S$L5v^{fgFlBa1N6O#i3#9e0Wj^41`h$URQ;a;qXE^eN+8lj--)w|C*}Ng>gi$q zWyA(grsxmbpxKAlf55c7;xYDsqX)M?fM`Hc0YGzm+d28G0dQ7eG|(agb8P7DFOr9K zxBl5$C{UbqKiMltO^#7~Iz153F%-`Mp-(8(?L4*a=(Vh~AJyJCxBt0WV^Pe!(9dRSU{1&P+t-dk9r>`@Tbqfz4?+ePC~)u15k2 z0DuDsH))~RgB52tM##4$>`!9y z!4IooOdW?;t7B7UXdR)EsRd3P7a5dJxq3L+FK=M8zV{}1cd zHF<^)KA1%~%NVpl+9HMnOn331%5%vWFYG5cO$*AvbZYUz(g~Rcv;W>EC}8|iJgIoM#?&eQ;NSCbl*DR(YJGfG2@n4_3NNMhw$=8l z{jAhD0x$`uQ9EMerwzc}@*jx}v5EbEvolGoKkCQjwT>?kBZ`h4^<&N`|-x$~O+ zC{L%*@T?={H)|mhe-L!)E%+bUi*U=2iURc*&~AVb0r))+yeNpJWKeJ!4L$(s0<@s2 zG8*lIBtfPYfU%>kkE(%muN+fAh)vP}1jL{U|6af9&ZMifqy1PDZmsM*4rOpTkFS6^ z{l1K?6BkG<=m8-$r8%ybD#>31IkA(MA?=Ude)aiKfS48GL|*Vmfl8y@u3itjoE*w# zBYEGK7ZsOUD}StV|Hf!rlwiN_zwL+15IeoZxTEhl2vR*)UaG)w!ec$I!Em8yC|vnF zaZQC6q?YFlG_k*Px|(jZGwNmR@|R{93bc$P^cb(1oKA!d9?uA9RXvyeIPC@V3!|?) z_4@wpVN#{HkM|?G1R>lrHa0#vTKBD})GZ!#p2l`01D+AE2Li^{)E{hdbmSWp7uv+; zFrCr|zzoCOxDx4aSig>#Nr5N}f^#Uq0T%<3KCm>(qfp5XCkHSkAR=f3zC(-u^hoc| z2xws9qS+~io-O^~#;IrL1WJ#d5A@2wVyXae6C{3}gMWd7TYmnfNx32JxBwm`KCz5IWdQ@ICW8Bs{QvQV?sfm)p|= z0()jLQyY5*|2TZC76uc_#}HX}B^46Zd+YYqKR_@Ml4?D`rh$3CLQTR@4Kjt2P@Mp? z2Yga??CisXq0G((WNBbqK)UFHvJSNCU7Kh)1ePO|&47tL&nfJKk6oEbL9oXkO_vK3G7AQRb{c`hzfUt0|#E!?2=E=6^?Gl5cfaBgsA7^kRzu$5CYB%iu0u0@$ zE&$8lk1XOK{K^%bXW6T#!j(I*?i`Y*qtYO?ZCP59eWrlgQ(RNLbdv zZv};MIx1XeHsEK&Z_06*1Nm=?3JR~Qc043r3eZxrZB3kwuG)P+9dWzHF}I2)PmM5d zUhQ#4)f4d7p$N+zgo963z8$Yr`yN&|Zs+oP!$5jp-NcT%@!zPws|me+T`BK>HE$#tv@ifZic z<-*|b#Nnr+GRYDG{oI|cZ_zoU8f2Iu8w+tNP!NwBkCz)YxP)-ft;6ZRRJB?Puz;qVw*(TiJ<3qD`rOb}v5BruN!9R2x6i+0#Gbx}-Wc>(gTu!!lPqv0`0|3R) z_f8+aMW{(vh07%lZ5H~gsAy{<|Nbk4G=}Y0iYmon!{lKDDbM>U`1sM-yyOjNED3nU z`A6@unpHNh?BORD-aIL9J)eMp&VL|nU+{O3QIBaHN(ZL6Tjz^+%i}^bB@ob-+HGO^H zqj5S6Q}9z%BeM-StI9XRbcg8_owB|MzH5*&=_wYXz#> zcS(Mbk9K5~rNE2l;-u-oqLuo*JBLu}6zEUta@Hi-?UP7SkpKU`XbgQ&qHL>wAfmqf zQXhZzJ^g+EfCYBUgl_P2q7K8+DS+6R$lsbpOr@yaz;MjodCKL9-Sq!^zO^3_qATU% zW{MMkYozaAEcvwo(nyrOBA3|o^>fEPM$P{J^Rf@FeWi>})a}>;IvchnE>y<}>{;AW zz}T3>Xt{DFOy!_+B|Kz^48wNKKr-Zc0R=KPCZ9S z+fKp@|C@7<#sr4Oop|fKt}9$k$sUc^F`e$r9m!bB4V@Av>=nQFsES-OKlh4l_MIyqdAR#c9|pLNE>_PN_z{2qR#-0`w0TII=X$kl@2m28 z5MxoI{xtnvf+$trwo({&iTD-R80hGvn~REq3!qs|3H71Pi^A+e?oRP<{UIul{bf%r z^|<`sz-Z~sM^~Se7?83W+Uh;Fr5?12U+nY!~9-bJE5Hj zQdT8{_cRjbN zxtb9&er}WevUlk~@3Ipbw+R}Z9zf$($<$niajx7vm1n0y;y@vgrj=mgN&Tq1#1uut zkSi%f*+K{TrCYYEz>}5|5a@e&owC;`nR%|^yTqlXc5fbBX$Tg(>CL~Cj{$57TI58! zedqFeN~IPu271NiaZDkJBK0&Su(k63KO;S1ZqH$xd4oE22%Rgv_Tui}Ur@Cs?sCjg zlF=_?>k?4!gX2(pDb?jDfCjtf7iw>Vi!<&zc?NNGB~!umzv-1f8k;;aH%c5?x67Xh zQ*d2U@;ut@_US&C5EEmfDZ5j8=hC6eM&&iwzsM(qmBgn9`QHHk`|GLc!EXD1X6xU7 zJ+%g>f5jRV>}mP$>O1`_Y~g{!kl+B6j(5H@M^@orD~6-BV5cokr!Dx$qq?i(O0(-3 zHyQLW3G|fxxsE_-1kOYMFRX>ZZVA>2PmFUns~Oxmu3cl13-x?15!r!IMU^c9v65Q}#j<;!)k|J5BE;U95sVXapQY7xrd=3HWSYMI7gGmX_KOfHY%Z!eg7-;3iRm#m*-$}ThUG#zEHfNc;cnUp;;KP z!04Em2oP+dz%*d-Tq&cQ1|ana2z$`2j|GvikG*~uvR+iyfH`!tDg0#nrr|nBPtj#p zT@UCvd6blQHX0KB_M?@=2wCKiktGeKxf;puO8S?gLpgiL5_@A6P-weQ5~LHPVnr3_ zK}2T`bSVmiO;87Pi%zM%2y7fB_927=T>5znJnEZp!4c`yHd99L`9NX|tI1(Y@^+(7!(LiqNmZe_RTx*NPPW+T?kaTEMc#wpAlOh}-{{W3-JnFr(%^PDY?vGf zrrk@g=EWUkeEBUN(A3pkL;dNNZ3vjC!o+}nj~#HKgy(gH=wy`&ukEmb&4+Ef!&5N? zeVIxd^OP_;Iq{$Bg#@t7Id-#Ar!4HF5X;{NaGHP%QB;NImgbvQ;_G3Cylc1h^ z5*_J%G#%)#9Ndlu!rqU&Ng9~e1n90qX2L*$E&^ND4Y6WW} z!1tVR((zwkF0Cs~zgQ}zg`FZeMc#5VJUAo!AI5?($$gU<_$^+vK^J7w+r%$7VVgLNS%}DT6t39UfpvYDlN(nw@ z^u9~_>+h_v6G(-R7{>FQ>XF(D$WKcgP1RPc*z0OCsYmEZ?zUE9a$LDqj->?tAdeVT z4hRB--0x8%aIBb+cU)I@kkm!N(zb8vo<5`NQ~mYxu9O7no>@H|`*te>xiCdOncPCM z5p2ByelcdHqX{9kBPC&n0xbmJ5eq$Pn-t}TZuTS85V6}#w7Tk)cy6ZYxLR_T5(ftt zjiQ!Dq3n2?@JeOIrHFfHT*-werC%@?XG@N@GzA1860a@#2cv_B8|X;TemH0ZUW2>) z!1NmlY(F$>H!bNrb(Wfya@7ttL;zjoee!vvDUu+gzc68hjv7H@nYdM0g1uG>eZmxb zj$|`@+JPXs`1v_XM~X3@TT?WzF$*7u#zN*vV#8L^mCJXDzf5g34Sp|O^Px>(eZrC# zPRQLfERl-9N8@7Nnh9o*wdWL{)xi%&;NmMW%oS!6;xI-L#D(G@vNA9$d&vYIzukh( zqKNC9Jje>#Zb)W5g(*|;`#$N+jzT)jSaaKSG7eFCEuN7sX-Dy2wMXZ4ye#vm(!=iC zyjHh{M>n)ZI}b>KoRA7>A8D zI%^ZO`r2`K>iS<#_byrACFXkWU`>oqmMM>zYCrb7WnDI|s9`2?TssZHSBNR_8W)+f zgr4PJb!u0{=W%S~$CVDF#JOcC?M$b}MSw6!mS&>Q|Mi>iU-lbqDz60>>j;%T$K4Q~%nKzd9bJ+C97tg}TsWXD zD&<|vKw^kvfk4vH8;hQ!?7Pj-Z{&hf_uRA$UO2e+o%nN*{T&uL1jal}kOp&pb%QSx z!AFVEGSU#=Pjoi@VQbFi^3d46ig@5-^cR`&1uoAne3^~!uKkg#?7wF0mb+fY8!Ic_ zd{a9riigYQ*tAjn&am-P7 z{_~4?B-^wl>}w3?B04G%^cY{-R627?g7P^X$AzLk z0dW;B@W$RmuIa43$5TO@8gYGBW%HA68V{*E_J}e+sWUWp83 zQ@&%w;FIjN`5vs#r@K)(OXU|ztrcBiKHd4pTWUVzca*7{wln?5Luk?%4sBlh6K2F) zP#{wu-vo92Y2I{P-1P=0a@`9AmP*CeLbc0JBs z%nU>&yTjjnp7@?IYZ$YayNwL*^g_!}g>m{J22$e`5N7yPJ=5ozug1)CvP#y^(kr$) zRVq<7BOV+wE>R*dQ6+Zt#49*x$4b*YpCnbOYYa z2tzz}I%!tSt7E(1l-B$z?+FY1Q6ygQjV>f-fIp8B!t87dpG+`+AXRy5Wy8nrq#K%( zHA@Q-0gt)GXxw{x4pb$DbT6w0N0(S2&B+LO~EUgKB5a3s|qpEs9v`c*F?XpmBi?2LLwhl*Y>cW|eXRjQfMLOfSW zphO7g8uxDMkyD<@L_Ettpr|t5btSXlH1Xj$a?nsyW8U#FAaIFRdvL=pe)G4;o;qH% zij=;Vw|>WknlhuRlqbsN;zdh~aD@t?75-p6eA9~*2o5sY=qz-sb)*qfmFD9_lY!ww z&IvWS+^ z-K08ICI&yDLr1j}MQNh(*txCk#v4bGQ6*?TeH$C7DeldT%3cUIBhyE<)=PYtlyi8V zXQZv@iVlmy$22p9=`RZ7mllC=lpogtqLGY3y9NmZH@*&Sfi7_AqW%e42L{ z6i(LeN}P@dy|6*<*yW=dF-%u^7=qMFIY4$6;}~M7ANcHXvyxwQZ3`tGf{g@0CxgFu zVM+8!B%Aj89|>H7;eKicPo?I5%!fzzl`x)R^Ox~Me9R&UYcd(-{$RId_Es_>`kK48 z0#mGkVzQNeiF`;mve|IvmA7kB1d{F}2F<~WkD`Lxlqt8Dh~qP(cMCm^!>AqwZpO4J z*6)nC6`Zj3h~LSmnBJT^0QpPq^+=Zkh8HElN<~NB5aD*hMMsAdprt#Emt!q*;o|+Y zuoUxwqze1dN3saAX8#lwHal&xzS&TO@HkCn?bw zwumq`R5URrs>Pp=ZSjXOQ`L)0?7_n3DNYy;1e>2soy+M^W+O-iA!61|xWv}Q&4xC> zMERMUl6TW#rkYxvNjVVC73e1~bl4dO<~1Ut*VOL1Hl9PrqDV-YHMDQW>FNIYE=hQQ z>)q7MmBj`+nv||Fq(hIb&+?lYzsa(_3S)min-^?|7ic!tT%qfW7t}TGvhFQg=GGvn zmZavBPx6Qwn8h7xrK2`o&LaJTjt;k;Hm=XC3(WeYm0P$z_yDO}q0qOy;o|DSYk`K2&p&lkqD?H@m`8@*1o@DkdMJp zS-*=Lp_I!iQ%M#`z?ailmTn*Tc&nD9fg=2v07Za$f0&3nke)@0kiJfaK=qR3JfMDv z&bg$iNs4G_+m?(#NOPiGxN)T=Ffr)yvi5VK+K?^HfyVi4im!#H@>Dq@!$EvTvc*20y6vlv@aLkM-oBSk@_`gF zjq}oiYqn?R(cyNZ46XvgkDiqc6Lb7P{z^mpzLtsR7q8Flu^)fTNPUeX{}wkh;>LMG zGA^k?a$DDuNhCv8=@TNxq{$*^u0)~{fxsY4rBOLiwVk+BXDAtHg$4ZSBBr9*8)RMy z=SBcZN!NnXM&LE$AdHtr@z9~mL2O6W$y3ouEvnIhh?jwDo|eCT|8_TqS-Gfm60yZb z1*eob9Jg4dIQQC+MplX)05ROxJ2`gfplhF zf(1pUH3$Jo1@jJB{r!k5gkHf&8e&#V_o`s_q5a{IRJ!l4tg2$3Zvw&h#m+hpIV$?` zjY_|goh_*XAdZBU&K55eY@tS#Eg4zv>fzBV`{)bN3_1bE~jWQzwlu?k7B6z zdk8wIeM-HHOgX>nw^4GBVn@3}u(sRpHHnk9NuTNL8^#qri!oWRhwtedJQG4?zb$Dm zcQ}`g68)rhxf`m`6xapMUs*t-*^)lJOPUUUEloon-DGCLhNKq97Z5=@D7GgAqqvZv z(aujVuu78Hy0AY-Qe_K&Q4gKvv?Gx3f1yku{4)A`b%jowfz(}aQ-wK{&;e*aO7etK zRw@*}jEEZtT_PoZ-D8dF&+O8DOyX-S{SrOv6b;YK?f-~8e>E0<&txxw+D0o$Yw7Fv z9S`}%b#+q1gCmZ#uqP7-%QA#hK18K^9E&&OJ8U`&GpQXK6EN%cnxB7+hsrm6@8CEh zE~`H9KqdGc_FAsLp+VqS;O1=?kst1@20reKv{WWvsLzu!+aqY7!8EZ}S~be4aSo(9 zr>?N&|HQ=!D`4+gGJemzTiX%4H#MWLU0ZS6CXgi3D>CgVfe0N#Wabw_FM~Z?0O)0? zZC3?vo7Ar!o;V&hNF_>d2J>`6enPUj3Bkd(qacINick2M$I5b@{Z?DR)0WZKTl|EN zuNN0dV@#2hzr~3Vm3c$f4k#4Af!7MckM+U(Y=)>;%j z8NU`0-d$gx<|+>5h+m%h$_=0GY%$+m^t_AEjL1Q|ytY*| zGUmn-E57BsA%UQJ?av+`zTM15==Yjtp>g~=bm}fs%6pv?)hCO&PcL{DGEWbk#XHYe z8G(Ad8CQAAv&xI3@+K6$hYNLLV?BImI@}n6I5zmKj3`mx%u?_2&CQveScJ!gNRRJ> z&bwwtI8rV>nh*r^(2MU}7n4?KLdxPt3E2mlCWImI4A*#NR(5DA7Dbb91@_M~)t^WHd~5Wf`a0>w__5rUwpabp7d;1TN-RU_Ahf;&#Fjuf2`?3Ki8svHk~=* zsAnlWCD4EU{vuI@QGYcw0}^}E+?-@l7H3*^IU8rH=bpK7Hve_XW%-6y);1%jdXZte z(A1)&g<+X($>4;`Z1l@DmD*ut+L#0aR)>YsvjDpT3_ygN7eX6#EHpZUiJ%N7in#wp zJJEm9vI;*e?vvPpym-5?NN7lqNJfVZ?_J+dYdehtabg~uw4n$E3u@W5tM{qZY)h5M zeIKbDJRW}jIJWO92h2wl1NMl`ja%uFGDP6*{Zm(MvWra%|ae)V+ zi{DkkHt&4Pb|jkM9!vJj&QCk@5`}ES*@6y|4%?J-=G3Ncrj@!P84BL$xamYlY^U5lQImv-l_m44sLN;YsU+2pUx!$Z0g%9WmFlkX@h=cCD@r7WVCA)_R| z%JBWy#qWf!&ZE!5vj#Ua2fHhb9QH9}aoR0x77uQPw-tqPc7_&>)0kfovg>-BAsKo# z-D<_S#2|aB1kt>JFPQusB}Zn;dFDXd{#&vFAl$Grha&Z=Vv7`Gk&kMN{|HkxuN9s1 zf5c2FS+6zsl|7d0_NM?p^F57FKj{>zcvq_*h(3Sim68bYu(ts^vTbVz@e^ixiDSPs zKgBwE4FAYR;``x`*@i#Lz{I{#rpUjE=1XMF{Qh3ovB;FSHo#{fDCqBUo-re^XO22L z9!)%tD?l7Z4txmLQH-LC3NuvVWYd53BO;m}g~>t?M%*Xsk`7bo33gl0yneKAoPF}= z&o>sIpCSTtWAZPCQmcMdCf@oSz>xL%p=L+5RNa0=8}r1EG4Ij8`|&)YPCMm-fkh9D zK07OoB0bCAuNU4OKbo1oeb>`&sJ*?YqWicx^kr(f?)e9mvWr((&N#}L-;vlXp7-52 z67yM)O*i!V6egM_c#%zfZ|Pm*{;{!Ds`tT}E8Pjm+%PrYhn?@%CAXWL-ZZ?T4L_$E zZ|uDk)6)Mr%?)bc|8W7%)3jbyP*u`;B1^z?){4b*cTwtZ>uO!0<(((%vFATHe9gU? z;vPslW*@pPwcXyJ`EYoGQOfSPzF5Q9`73>=&m3Dl^((!26B{B*az>l* zW-L5<^J^lnvQmNqVTeGIokg?s-t@Q8#4SfWUeC?FA8^Ex;TKeMk5ESEqOebPh*(mL z+Ve}awgM^#B_WiQIJwDvXLZ#=$r>(+&nUku++W9^;P`6sG=9 zPhGVl?+^16AD`PlR%Dqx9wSY^?fUtaQ~qK3S&_pvZ>ggp-Sf#+U7kK3 z{X-46O_o>2HW#mSum92LoML{}c=XfNw-$skofF4@jGe63t&dc=A6h-Czt^rvNFBi0 z#X93I`TNgE%T)Uulc$Ce-MMuJzSUa5Pn7RmwkyrJvU-Om;q6aRC@Hg%u;`d z==igg*V#@>@?WR~oDMV2^TQ?;e_uOkN{+nD41avsJaL%jW4V?Udt6uCEn;*0+Va-w zsMO|HmI?R6BdG)c)+!Y9P8>UT^Gzna1}|8>somN-yS&rO*eMT+y@kCSm zr|Eggy4hK$Z=&XD9U*Rt^yxmEvn@_E+zFCxTKj#wsgdG4U0W61AC9+v2NJy&u5kZ- zWpaNaRcd@=xSpPtjBX1R@;dtt?kJ+u^4nqL$@IGKQQag{0fpDfl5M`r<;mzn-<>XA z6OY;Hc<+Vs-`%PFLgf{M$A@C;CqLOEucnFAKiE$MpYkek?_7(j`Re?2@eg*tE7FZz zKX09#f3bIU(#vMAd2g-Zq^m!^q;clcv|?bu<|1wNaeu1Raql;l^Cm7IO+SY}9;|$P z_$N&;GX2QjckdNJh1KfDZ1wuzpA8feHCtV|F9?Z(9ujgR{As>ui3rw2`D>GYzMMPZ zog}Z@P*M;YLXgNWeZz`9NBmXTSm!t|S7#O_ADN=_0Xaf<#IN#VtWLSg%*5p{+w^K- z1I3OG*1UOl2{)Q9t?V}BT~t~8b~|q+d$ALVZeOO-rXtB5;|oePW%A@D%&%{MCb#)H ziM4s+d)$21jg*D~?syfZdtsbN++Q!c9JntWkhS}5;yf#}i@z#vJCZNC`!l(;rv4rQ zLC=h4W4X6#U6tAD8Ns>qfy>24lESO+r+I7E4oVJp8{a#9KYo&UgRs?T_0=1{w-Q5% z`~uSeFnb+S9OvJvh_tUdn%LYe7Te>NbpILjrpD3d9+Bc+%1oEb6<+aqf70t8Hhz8R zwJb^x<(k&56XogDH0JaD-N|eBLrg_4qp(3-v~0hM$tvxMQEG6nIh zHB(n1gnc^-X-kX`+kYolud=)tD(eWivmq@VSQhw>_1DGL{C&VsaF$yyw)$4hw!Gk} z-3WY1n`Y$1KJ7Vo{_k+rcOFsq%~sm$>u2<*f`?4g*4OkX>_!fz71RE1?A%Ck|AotJ zpB-5$`DZ5Y>&{t?_YYTVqo?QI(&eo*x8&b-*a>fRbN}uZtL(^TTf+4Eob8+XmAJ)c zRYzi0PV>L+tJ)FT;Sg3{lzSD2jC;tN^|{0OrRYR%oQLZoS(=9}llRKnjLJxsyiOq# zbqt-kLSV5eu@*YFj7ApP^_b6UM@f?**jnZ8u>F~%P{^WVN1!MLZ*y1@B4o=0x@7RR z$tY!3BCXZ9)Q``%Nd@Z=|Ixdo#U^InS&m^Rw=<3CYNeB7cNsFP!VTh>v zhWa1ht9ca5dlHQ08;DC)@+q^4&2u<}@pp#CrH)zhC^bIe(|R-f@#i*YVmSXN{{SRM z6Pc{FVSw%}t0uibQj{Ulo0p=FpKXu}oCZu0)5&Y}&qg zZ_<8?E4fbgT@Gn+<{4U7T@HG)JsT zom8Bh|CAs|$@u~&rPH{gL84jYVc$=oHx2R9|tN0tMYa1bWLv%M(wo8b7G|ryQ*GL!iY`tUSbnijJeBH&Q z9}1m!*T#1Cd3{Cp`r1QZ@v<9b9cV4?t?|&R^FAmOH2nA}vBGNZ`Lvb==964vqRZdM z*{eE!vIUN8cyyE)Hfj3?@6nXkKT~y<#`6T-mh3|KLxVBzFr3uce>lTt2ri1=zol>e zn!lBeGNWB=woFeJDwjy$J#*d{>XRoc=zOZ{rKp{qmyp8sDx`xLfj*tbY$)vTpYGe zecGNVIDNRMuBIkD&)`n!ZHltx`ZE+3J=)i=an#cPZH2+M3fFFQYwMSMez(-m_jIGk zQtk$Vi;Dw}7}V<`QP%5iL|UR>iLFZPgHp;--t?o^2_nr1_aW090fQE4$sy*Qa|5>Y zNbr1-DWaJpI5s`w@{JjjY1%&Gp6KA5mz=E3M8N zznnWzrzvK!RI+o`1AVns4nIJTs68e+*pv(%LvS7W3GoXdAV6&%CWFr{OHJq%^nH`n zZ0|WeRgM28z;q@N|Ju$_yHW{xe$a#|lZKtQtKMB(qD0;u#a`UFKPxLj)r)6Xn51;I3oqbem zGv390JuE;aYyQ(L0qe`NRVYqeVn>BmR-EiTswOHuethcI1(Ghpd-fvC<_f~$@TvD;Uq0d^w@ZXMDO&)Q(&D=}ebdLrMRr(q0{xru*?)*qk zv5zh?xG;1}3_Z*+E)j({fA95{*8BRf=CY#qmJjjo?S{Y3;OvS{EUBpKs(c=e6yBY# z?I5m~Q@6n~`WTrW=mbULv{>-}Kbp>ht*tIvw+U{AUYLmO^jURsd-LQyxEEDRl)sl(K ze?G;7gSTKTa!-)1(57^j&;<$hG@%6C#-Lm-PWhCl=s6WCp&5t+rJ-6u?P$o*30uH| z#`-#6DT$Kk$6gEuq1}7?$X|2N+V{ zd1T6YSF({KWME*;?b#)6%W=Ef6v6gg6tVa7$?y!gZoe6;RDjr zcUbRY-(jS{Q#m*fETC0dByiSA2L|S~Rt;UN;K z4{+j0%H?VB?hQL(`273E)qb542`u8_tfHO;qDZQ;O9^uz0kD%~!SriY!ZN|sjVskk z?eM$Ue&*+$k>;&gdUQga7=I$VfLO4{dc&gE0#}nLvOXV$L@-O~pKu}g=7-argk8Yl z3y7=13TcEGzA?duC2B)Wn42U)FDqI|9~#5e)jX@p;7%=EBc*@>FoDGl*-g~D(H7!g z4e3}Qyi2%N67svuS10%1E~^r}J0W%OGG>7#oNZ(-Z?^6P$rvxcB$BQe8DDs|zvhtp zKd03AJ|>Xr(|&k>nHO{Z{dv2&kAK}xJMh@QHI!sKBO`TcvV8XrL)=0SW>!vrd$wEc ze!B=)^w}vDdQDDw>Gg}ZU%D9ea#bQEaZFnKB9GfOTed=KEZqZ!%(^t2^kyO(uiRWT zjk_wt&X<-1eF@6+a<6~+Qgy=5%_7gk;p_exX-(spA{^MS*DqKvId6O9yq#^`S{Ny7 zUn&*2KQf@H6aK;&T4O&8{S>f=YxUV9kB%6aY|)gUL$ydGVDCBA>P|5Kcr zIxh0{^1^M<(R7X2xv5WYFo&DZ<&b}rJm5h)UZfKnIdk+PsUKZFB;fkxTxgzTlY{dC ze5oaG+;u#`_T2w=Ju^|v;6SGEzOYsjr@S72lt)90Q5`-Nh!O!}6yr%7zWy}I3B>7h zYb`v}$d2=X@wAFCwwY8fhK`eeSp)boE)oE>>h^590s+`z>o?&7y;tf4#=mZE_RtBi zcs^vgz^M*>*bj_+P^#4XoTn{kY8msn8FIS%cHVXK2HO(QT+D3f2oH0Lm$}@I8Rv?E z>%jnsml>=&F|W{qC6gQp%_Ixw%RFMbkQQQh!^Gh5LQp6$z@2=!-bKCYt(~jq&(qgz zjxP`Cb_A2@HdEh&%F87QV=PR9jlypJ9AQWnlA0B4K11JJRzA~Jb=o$f#PbZge$!>a zqU@-4`uX}5(_vbr;bg91E!g5OV2ZWk)a=Rsc@{P=*tpl{t=5NKV8Eji70Wiw%alY^ zsu9)60^)y3`7(eFlw51{xta^?Ef_0Vce!8OT7v+FPZ5;T9h+bSUTf8|3Y8zLT$+Se^%GiY$}dS_-{EhtZExqyj* z@lc;kq)iYo(xKZda`h8n;IrN+fuN%)O=#w|^4p6bC*Ta$yEqr|bC9>Bm!qc&`J-If z<tn-mg#vBK{|NY_7YWHvy*dfqjO=Trk6MEo6kvNmd$y%RJw{8Q^P#@SD@cv1-&_UVO`XiV%2GGX1Ow z#K$hO$g!a#1BZj82M1sGbGrPdVd;^db`+@pu-tWVBP{5$iGdJMa|K<)#Q~v>17{vG zS20z$nybzfU=BP`;oBqII-{#^WI-1k2xUNAlQIRI#&Me`R<;5Im`@10j*B6J>>&sG zNl<=}=BZq8EzQW7iJvzG4)kh3w1kmE+>wQlzA8yGInPKfNq}?54sOknpwWA)2y=Z(Iqrn*r7Kfh4n+}!@mY4BTnefX4i3$ao0s~ z$x)`1YmI=@a&-SUJBz(345EK8#ETo3Lp#b2-hY#|jf5Qk4b}Ifv+94H_w+Q?D=9%@K#bs&DLx)n9h3p@;z+zKvpda5uWT+?>I(q12@xnVl*m9b z8lkiCTbU90k6KEMv7Q*&o}mL;S)+>I#p{3V85udNluEwzw*5}cGsT#YLXc+1&;kGv z(y&)zG`LChs^!=Hw4+~Gi|pKsVSpj(`xB_N5TP{27hW(3LFz^X&5xZg98Xl zph|Rqocd*>o1!@$h0;SIRdvCU`_u7Mj1tcTAWMv>sv-)Y!iFcL1w=;%no<`A<6sbS zn1!Mh;Ew^1Z^39hovCA5luf1pyZm@-`rKb5nCh5Psz?;T;6RGGiY>Aza3Ua&BA5`B zI!2G!uuS5^l$b}@b)Exhmd`-q^`s%?bVj{oXnnb@myx-yZkUbx>&@+=)?!sPaA4u# zm$X?WzsHQqX~4tWpuQxj&0-H$BP~+-2p|Zgy~pjsYv?`vG1UMroTUDpMM(Z(%*RTm zQOoR)Ew+Y!clF;`4agFrBc%>@Ia4&NFcc#%`wk`E_FbD>KBa?5^d*Wv3JCi+Uj%gR zaTyHkz~Oj!ogDY&n9*u+52mWf~U5ws) zI>ywGD+vOvq@!sVySQ0jC`Ktxmeb17K92QUKCwrS+u7&N6S>f9+C*YR){Ojwo|>A7 zm~gYo*r1pl5}RN*STdU#X#h-_b)lo2dJ!0D053^y(p|0a30Rp5{DD3ykv_UmR&ER7I|WK21qTSg@xHhm z4((&dUrcCb=k;G89t%X^#3|+9%R;&4pSJt8r-}CSxyPJ_`v5y!eXZ(11F2{}%#ZJs zB$ue)MP+dYi9U(RJD z#^N%+_0pK%NfU`<9%`UQB_v1UOZ~1&rWgIyQ*NCEg5v_vf6;d)VfN;UhJ(IOM$6ldz~IIe%V*wjyqW-of)0__#%qiCtat9TyNaC`%)yilC+^ z!Di-(@fd~7~^ezsfE~ zW0mr&T!8WL@xjUCin6iy-qdnPESy%2uE%kDBkyFE#CI9e;X-*=XZs{s>wW$kcM>7@ zE15}uNNvNp{QbJqkOBb_T~P>>^;7$OqeKato90gJx0JIMi&0UT{BK~fdHU$Loz0iS zcXo^G9VY{+Mr)mK55p}I$ z-R7m|ck_15)w;8&q6P?8w4A*JXthI`awFPDvE2_V+D+>oCD#|b%Ep8T)&7SC_ctCi zI)|UWetCY>_8{f+?f716yPV(dxKZo>H@KAN2lZY>955EQmXJ{P0E=Ff0ssWTan{j0e>S0FrQoRlGKCQ>#!ipYQ!2dGU!tLI<^HZE=@FC0R?C2cI*S+ z?a}K_DjgICIIEi!X6{w}NEO(>al3nmP*r37uzyb$aJq!8EQ;@WJkw_<;^_^2D4JaN z@ClZakCVek!WM-OzGp;8hCjfg21o`e)~>U4UQTdL2R8g43jhhIuUQzQqNMeDy*OM{ zHhSKEfoyhNh10josUj>adX=X|o}c?ZjqG*%?LX$(4%VzeYQ)kU7aCmdxt=zBPx=Xn zaYS>qMkmOH-8@aVb;gB{@57grtHakZy?W`B3Ym$jyaJD(i68 zC|_;8+@S7vP9 z=SX}Ciamg65+z#NPyO&>adP7xFmxec%V#@IOCYt;}cQQdjQk@VU2h zTANyKHTx6JH&duLix-KJJ)%uacuYX_ru)D<2NSKEXBX;gYoA= zK1XK}=bJ9qmK9WVfBSjwyDsL`<$bJRE|2`tB$`5D1R$nxjg|oHvqsk}Mqg7!-bM(z zFCKl~v($R|`?p>G&Tu+j^1mylWXq5s>a_ahy0T#l#pWxeh?X-}B=mgvAh>hW!em5k#? z*Db8Xi6gbyH=Go5|94Oq^|8V-Ilre`jj;lbSUpy)NG~p*xrV=BQ;@g*`qk%5r<2x0 zs?1s2GJUe!Uo=&a%=KDK9h|lDIS!!Stx}6yvO*AiUmZzbSDntNl(* zH)y#lj$iW{t$gk3IfA7+Pr|GjrU$8sDXZS#V?F^T0^retmL$e5^Q7t@0s#by8kiJN@{ znCp^#*kH_%?CY#J&TGs(nbQs6Y&sc$Q$e_XxDW-N2qjLHs~My$xNK zzjor2m7mb(dW(h+oxa;A{f!mccd71NbHOcJ-z1|{bXu%868;Ph zEUxisoSIk3NKcT%Jnl}uudW=b17FU4WESnacdFaZTz+s_5Claz8T;7r7zuiO@!h$a zSIy;fHYIBGbk^l@fKQ$E)-H^;tXd{4;1lpT+=iLcg}bkV+6it~Z$9ZSHMLaW@&r5* zPm%}r%i!Khpj6(D zIm}(VUFRDA>8j^c9!XFkeg7~eZ)5kYYV&!&fQ~IwxAuZ(h@>zL^*7~Q)E&9V%Ix~( zMV!OB#oai=xxAfI2LpS@bHShts}k(ex{Kh7t+hbl7#AGW2V?$yC+g$XOXw}Pn()Ok zc*rrOFCsAr0fC_)J`-$NfDpSXd!HU68sqK&M?D-|uNJ!%dVf_g>!O?9sGA%JPMkt( zEQY#Da#fUi4lSO08$Qe+go23{KnftlMnRYgMF|#nqtE>*D;q_7XS#$dfF;&PE%(F2 zhBZtUh^@+SWS-FB3xofb0>=;1JF8?UHQ}K1cop@WmCl z755gJ>L&uwej)zR6+L;9{h0o*be=E|A zf7rVNoGGFbf90X8p!^YnA9N8B5D>7l#zYRMVC1C8gM(Gl`2=^TA`dICh#~M0dxLHd z&%59=%y&t}?rP~Ol(u4b!ZjZ5({3y+zF*#c8|Bw4OSK%D`1-mj8AHSOMj0u&q`1^* z5z`k}g_^sa>V-A$TO+BZd4pmb!{)WqV}DSU_`hvFpKCnG!S%|d!AB4xr|y&KXkm;W zH||e6`R>UKz-A$Si;BeWnMva8Ly>$F)SuMnipL|QK?u1POY$)oqVzzbDK6{=wZ*&o z?}f=2($s-7iIBx4RMgVrTZOvhB0A77lVgJ~*y83iH~wY#!4xc2h*jePa6lWWkS0#} zpz5OCMmH+leDN6sdNCc@{!8-)u?4Mdgd-wE4U>*Z#K=lZl&WMh8l38k7dQ%|<|k7; zS|k9TEvkz3az6kCBvFBZ!OewSN`>n~PQvIA%cdeqgeNNVd&t+pP6*QHgLijGht?`*yX)2t*)fygxz zR@G5?uAP?saGu9)#gG@R3Z6>zFh2pn6rMJsa9P3E&qx#2z`a$a@!6TWY#wCoxIM8T z-CZDF^!I@JxsGrccP2tjWQl4@C-NnV48%1kTh@>fJ!M#YeerX#9*Z_}?SvXmdHDiq#WjP>rZjzKV+N zkbam8kDZv_OGBgl>|E||b7#`+iWJPsqzN<&{IIN`?sATv8d}lFWEcMa_V(_~>-u7Z zMjrV|em5FUGO^s+p1VFeIIeyoLl&Hcq)E9D;!vCb;s@8fBSazk=grTEc$v4AmZng7 zCqSsS9m2#1*V*Kn>ocll80vSPMMRYKI9lRyjM7|f@Gp!-AE}Wwb;q((i-Q#A`P-`h zJ^wAbOox;o>Px@PH_|W{k>B3V<;30TF7!2NUrg$KfAZ+wnAdry8c*nVpH#7-YwkV) zYZnr4F#QKW5))hzyI5L>fbGl4ypUn{Z9>+j|6v%HHk~oQ(A9QSf*Q?hpAclT!Tjt* zM`GFt%V~CB0{i>VUlb^N^cVnYYM30k^s{InoVcC7A~M1h23nv40D(0U0Xq<+!v$~_ zZF9Usi6#=A`)Gx2nIx(NP{E_XLkQ0ODVl^C9twb?LidL0(fdWkfzwQu0Hh=n3K|Q0 zT^XfZ;ZvivfP?-Wr)QYsVRedk>=w5BVXKhu!ZP|R8so?1lw6P*S`1l`EEo^&3*{yn zlN5EAktA#b0jc`@7B%r;$@a(MaU}yw#$dMBey5pL*F&1}q`Wpu3f`? zaPmBKr~mqAM`Yu6pZNN$MMyQ7+iv$@q{wqVnppT{h>GJ&vPu-*M1KOBR09)$=Ucw> zHF8_P?W+%2$Nh!`-2|C{$7^2{S5226Oii_nRcSN;-s4129iJOlV#GXp2Tc#p_`Sym zB*)ReBTH)fq5e^iPmuPI%XYlp!e@i8?PR~|2d+8+tMXdApIul8cwM$3^rjQC_E@*- z_|fJ)kReve89_J!w8s#d8HQgEmQ>RPa6}HY^`K!3(c(!VbXlht_N_bs^ziZ=#^&Im zq*pLC|m8 zt$bZt)HJ5(d~>R+4cXEZ1y!f_Ncn1sjU!XQ;9A>hlYsG?dEEa5I^6~s|D!%iI8ITZVc{v+Ij{=;3zB^Q1~THc^rqpm6DcEvN)O{mrnj8GX2`o z<8^qz4mw@6LM9*Y-NL0hvQn1c_M?y;68XUqW9q7e%71l%7)oStU|?w9qS~Lp-G7Y3 zAEEe;4BPra}O~i$NOEE=3=>mR~zE}n|AebalC=w#9IwYs~`8)MQ;*9y0u4D=jK~@hDznX?* z`*uqcE+5br2u8u^i564Y(krL>btk@hxeL4HJtC&(H``plVR7MNgQHQvI0=!F2&PWl z?}d@2yvXEKO$~MY{^Yw8JFdB!yiH#+x#RP8YLu@Rx!j%{s>d>=3WzrhDndTe?uSpE z`i^B64Pp1wcBy26Cb2qPCo11AgHGR$34}XsU)SnJQ%PFYth^Ssrpjia8HBb!@pmN( zC#?=I>n^*_s;l`}qiG4p2<=-(y=L;|Mm_=MyZ(VDqATV z7x_H*p_a!&@U)Sy^#U3e66SGor120we&rByUB^+8~i8-u1TgCig*^?e= zWLC#R^#s=>gOC-exB7x-SqJABCh_3Za)%ngW)dhtOSn)4aqLJW4I%<1bn6{#be6Ec z8lTmHc2!9UV3pi0$~d#hysb#NQ?a_kw^@u zH~SI9XZl49s77i1s>^8hpKGXF0Z6oZmzbo=W5OA?$ z=;Ojuyq4@m)Xlw+*|DM@_3=G?Cn-}n0h#A%kE_qUF`he3b*8Q5rq5Xk-9$DK*~w{a z5)E>m=$EiU(N=D@p!D^5L5QdIW)LqHxnP(5a(%Q`l(T{kr|taOU-ZEZpR2)1MS?t_ z2KwLKF!X>|SRUoE{w5AK)^7x{FDhs#Y5bu8YBDd{LdAm4M%RBxDPyNT-iu66%0?~p zZPV-bSHtR?es^iviMov@N`>r`t~gacDV(%=tFpQ5{>&7KEI+LbDG1$)ik-E5RqT%# z47livs+$h~s93@J(azZCWHsPrF~HBu-azt$P5Jl0&IJKBG*yAfTDHKT$ZGjBQ8cxQ z_-w(K$=CUFzqc?$^=(T7q;xhz5*sDs(?eFf-&-y2>=GdCDhJaaTX1>r6nfQ{Q>Z5+ ztZuQ!$vm$HMf_h*`bWP)C5v1qhZ~eXJ^gS=tki9rtBu6cJEmq#VBbBQ;cuX{6TUx* zS2k|@^f!0FgSP10@99$HpU9hu{YfUw3@zgQy!m|D9dLYbIIKX;z$@`}|DcYQ_}$&z zp3TZDeWT6w-&<0(yeS4t7W!b=t~@i}x?5RXO=32)<|NpVTUGT`ak!X-J-S$jGXp_& zVIZi_t}xElFi8T3nlyuXcj9Lz#=x{2cC_tz%;`_HqOUx+ab1UM+FEC1c6jD;Uo{-L zKhQGlC8Vj?G9G2J-kJ+F&l|k70}h;;avv7(^h(Io z*ww%KHma4~j|m*-VoTxB#d2%%zyZ#MY%&DNGvo7Hh?0`pXVoV0)dgglrq_8XM>N{L z0SbT7S5g%k&a2u@>I;$$j>{D(A*hB%>M?9Lb--HJ<7^nG52ZZhXp(r}7qHF=gk>ae znB%66^_eKXpnrh3Kg)2png2(A7I55XHn?Bi+1uhfUirGJUE^;$+4c6Q+|3B5XGiL0 z9D47l!!%73f)@(Z)?bP)!V%+&lo2E{_XmqN6Vy24ey*7jS?P0riWry?g%nsY> z+a1%Bx*-K3v*+qca)y(EUT~6MCuDOdnwulCx+SmM`+g;Z>PO(Dt2q)o+H?boZI26Hs?SKg@KXWg z?(}gyUYK)jzR_=X-|5r+40*tL6m4kWkkNk9PQ24bZE2;S^-3HooqbYcrNabz;z*Ms z@!NsEOisZ4y7GEc|Nh@_xxtAHrI%IAqL0Bim4PsI!MUn0}4Yl`%rMuYmq$kdF#~Ac%!*l!ttXMvhDb2$Ol#2$UDHOJ zb!`sut?Vj_?A0gfnB^M7Hs`^Vcbfr+$pN>q-@vqd)r^MjXX^JGJbcZWSIM{f3mx7^ zC**$TX+(3ZXwly`g3sG+)-N*8WI0;yGRt6XIes)`tya@oN^zcQi))na&+5vP%hInW z`Z6BmzW3W>H_y5ukQ#$JvzJ)S)lYtxzqQGH{w-uQpLEzLTF<#BTXqNv3k!SOY%lDM zhS=c<;I4AvsvAG;7eE{h+FjPeVfy69gi&=YA>YlQKQfS0zjuHIX1%M61^q=D(k@k| z<%!W--?rH^0ngn%c&kl8pD&)JkkvK|tQx&JCw}K@2e*rnG2ZUCn{nc1ZokX9Y=VF7 zBi)xy$D%$haRBJ3$Z`B4wmLV5myc_BE|D;^^pJ6KNW)@@nJhC5! zy^{wIht0~J&KFB*=w=Px?T|{NHiz5#);rXmLN41YPCIu{KFG zg~^a-1kCA7q3vevzPK`9L&pDnXIHZ()Xv%5o=@R>61Qskj^*L7i#I-tjDyFB&&hLe zANGlaDupVV`n{}P{fxZE5>q0{Zyx+ z6D{-J9EhDf-{f`oTEkZy-P6~qVZEL3z8i1e;PYDn))+PT4yJ4BL+>>C$FKBK7Ai7R zufrK<5Gt0(#u9sj^m!}&%+6n{uJ^0bg^cmt-o~5VS#+LvkDoR>oyn36Tb&m=j~CZD zAYx?~L`bGqe%K9E=4NAa8tZP+eE1xQt_=+KZW(^G~=bS z(}|2vXdB2|t?T-Bgm3rHJ0ILU(6&Xj80lweFl&uYB;qzY4j zH?-e)OmIK=iSl;?(v$!7H(0u9?7b1c_p^&Yow?^-r+lh|ap&()4Go`aSUV;Fwx$VE z4g3!Ce5*(?97&|ocKz%7VKq>EGzL0^K`#DJH?2|f1v#x&@`GEVliOkEMs05LO&tBzLVV5&up7SlJo<=vGqG^r5vIAJ=~JwCMQ4VQ9V1#>*a4w9k=U- zK342nU-y1LB$Eq4zHFb=O`fiClxU2&IyHX5IE|?NzxNFdW~Q?9dIU!jq6U0{#(f(1 zruq{$=}Lh(z)ph)hvm^9a3N?M9l6s{ZCHy#k+saz?DJ$r=7C7i`(u6x@guF7R5_71 z3eH%!=k>~DwSGTExp`2?t(aGhuFozr`Ehlh;Ns-#F6n62Xsm1rr(kA3SQb~ ze(V>PK!qJ>4-pPjfWs^bkP5*7`8odCpR`|s%Y?0(Y^ca>axeMK)~qc8F1sT62~h%KvKz|!rYaRw zP&Q0opT9mO`UnZQUgQpXSH^Y~v~gz1wO;4ayZ(07t(hL=8kQe81jLJ!`dM`v&~ST3 zD-cg6%S~x6wTxJWFH!t%7m?UZg5KBlXyA3iqWhIWEx0Qo!m^RdBTjKE&eB0$8yfx8 zjO@^lj3zbQPCZG*F1$-B@HQ3#;mlQC*=59IM}K)ik7yc8E7(E!iOa;A6TKG7@N@b` z11$R+>eTu-N61ZIXgtZ8r0;uReJ=r^{8WDm*1`lzF|cCi5@@6c!3V)j#lqc@2>NgT zUMe|X^1fHh5MaDquF&pkht97%og1@*9M*kD-!W;6Jk8DS{Fq&r@C(W_dVsl1$wa(7 z%zgj->qnnSn<$)r)^TPs#Ze}@T_3WPKeb#} z@5y_s($^e|XF}AXSmjTL`tNzFjIOp`$kT8&Ge>j$U&8#_jYZsd@-v)tSiO{3f7!0} z>#(AwO1yXbdh(o*%#<2%oAU+HLioI@Qx~nRY6bLz9%G@^d?dG%-x3O+=GhlIFlQ#vW`1<*9al`X$J{5}LQPuLL zH(C1b?ym%7tz|cx^jC%&;Mfq8Xxxp zyo0ZFwfV1ZH5lOR!j|MG;)1vl<2q+?FlyQVb(9VyxV9=E<2wxNq*`G9M4^}cY=;tf z(z_U2tEQ8azOX>=a6E2_CsU^tR#CBrr9Gm1Dwi5Ng=npy?I1ZXw~yu#rWt)5J_C>( zixH3FIB->@+-+O}p_!L82yhnqsk)^)aAo~8jy}F+xTM5^wO2k;)<%N90mVhbsOd>u z#^+AaENS=BZ^vlstV+HGyD-~GVlwg-6qKp3>tW<~&TfHdGSZ^+BVz%Anxdc-dTan_ zP`9c^T+Mv;RysfpQwdyO*xO2b2)fFbPZbTMCbT>LF{`T4ls65MrBT2^yxiZ&w;2Up91e%!YtJ>Z`EqoVe#^=g}0lo z_FxEP)2K!wx{^+-PqA*M(DtRfZ(>;$Mm1+!?Py?_@l~knQ5!5%lOH&`!@$m zdl^m}YH=qTT6nC-=ZF7>NcB_hAp>4j`KO8%DQ78Y1O&I2ipV%wpplE55<+zQ3>E z{K@lp-@ktm-^huvB)jY7*#h z%uBs~{1aQUAgo2}rCQa81Lt*+NbQ7Y(85>#?~^2BT~VSL?|LRMENVLT6IGRpN(laY zz@-f(eW@rYxlV@yNhQX}wYv4M-TPQ&S4LlZs)`s_OgI4Omx9)J03a=B3LU-?FtY?nECEr9LKaO9FYI>__-ke;1!W`+!dB&lxkAEx@_d?k8yZQU zPjyoJrwG1iTQ06W7X{|`^s2PuBsi!+AiXS5X`qo!Ri8X%dSXv669|@#te)T~%W@W- zclME9Rgd8-t9JTG5hHp%1&F;KOA(Dx96r3$lOa$gv2+B(2m==tS}KY$=QpB3=un6P z?3JuzVpr2cZL^$}rY&3H-rYbfQmjn;G|ElO>Q2O4Kph9y7EVy)OKVuf81Wl*@N=Rd zkWJLVYZ3N9lQ^fL;$tINik9f8u!l+)czoIY4IB21%%fS&;=w!f;JGuC6MCPo4PTa} z^><3Za6U5rfUl>D$F^!DLS7zXn>|w}d60OLuZ8IN}-`$5-em445n%C8v zSIAXevgfkxrxiCpm3cOtR?*neqQ+Kj{%=o6hI|zg-0CRX3g>3-dTEFJq-!^cIUM9P zcAlMKu2^Ajk9((hp5;1j3%R#H{3+71bqK-izM>1@FKK{WhkvZlX3NI4!^|t0ODMUW z!%yb>oRJo{gXfo*gw?+m_u5sO*tZa7St_Z`YS6{U>3#1YI0f&*j=*~DS8O+2=>_{U z%3(ed>LfJ?7Uu+7G2D^G8UOV5xtfOsd^iG%G0R&q+~)oocmY!j2x(_qL#}g#ot^J< zo)xtrZw|x@8}-&3SG}zGzQZe1Ln8t>))Ce)vD`jENYgjV3@nbChb`Reu0Lq(I66`= z>Y=g9UCk0pG*r%x)PNPNcMPsY){yo&Z>353+36_}4dO?@j*|PFZY5dRI1ys?`?sJa z1^C=g6)%#IQ(LKg=zz1PaU5N{7Qj#u%Rvj-7{JB`M1X?Xf+-7B2YGO?!7g6dneh&V zjo4z;FzW%>=a5-jg?hApVGo220w!R0IFE8_-~~#n8k|+4g|5uup}A=Z!hDD(C3uW> z@DbdjRUc1$6L?_b?_?-{A`-P;AcO67kxB+oKOVdAPaqB zaD*OQp{VLvq+!CEiEAQN7{v#$8AU0Z+)hLtf&ZKhjkF$;MUg95Sn-)OTH*pAeqVSp z1^Y;+_ zeHy>GgJuDbx?CkXB30<`WCwc?PLYJOnE096aD|3|O5`V*Qs(dTNFc5p{F4s0 zNZA6+uA%F>6w^sc4xR7E!DG6bT+A2tjaqDilis zARs6~7l02J>57CJlm-L=gZA3Oz~#&U={hSJ(ck%iAb4y5CxG6}z$9AXuZu=5ka|}S z*v#4&90p>z!w8H-3;e8(jYjd6l78+tY^Ycihyelw!CBAH2YzVy4WzK$3sa?%u#Q?u z>5fK0Luo_<6pYl9d{;=S1@L}L zU=*8i08X&hIbC5MATJJH6u<^Jk+R$AgAWo%2%-oM%!QK|HD51(2*pN+jV|}M#Dc6M z;7Wg)F!?0nqXh;7nDc+VBST@Kzzb^@NC5N%0YcLP0jdZTP!xF_1W_C?W)SG7kgW*- zDHiU7if^rSt4gl47%Q4qDS)OW7(@-geLog#@(bz9dq)_6?I8Rd%&hwZDrL_to+}Qn za3KfNBp^cR{0M6W27+e{YDX1#N@7e(>ah3cmC`${&&n?Agz-PZVcgwO_er4dclg{X zG^}wDJ(vIe>ynLz$Ppb{g(K>LQHoE2O>~JTVGd8f$Sk&l3vq0PtTs79lItzi&a4X+ zRSeXo(!$5A04JS`CWZr13uv8@6ebDsk_!drR1b9eyzQ%wLavT(=Lu9!v6%uFXNTk( zcYb$4Pl^8&P{U#%YbpXjI>WD;P&vL_3$0)hus9k+h(uP2S2nxuk3y;JFX<5q-1-G0 z>C6Rqk-54S=I{iEPJaIiu*USYFohezTlT#)l4wMp@rO5oYTbWq0^r{4>99ogR%Bkgi;q1|kIxw;#a?v_ z&U2y{>0TaOk^ej$o-Wx!y*rVfeHLxAUV(nm5BIN;fTMp!yCP*=)vz5@NCmmUIDVh= z3&pdb)g|(W-fq{_tDLTXlkRk{>tsG}fY%;2G{mHiP1-k^6({#|WQ-?6!6+1fe5uIqBgy8q-M&XR zhrZLX?saj`{6;j^_I{cq+mL&b0ool(2O#81R!i@yn%quU@ z-?JUC($IXZ)X3fsLdPZ-2jng-NvonXbu@zDAvBkj6En#T=U-g2!aB-J{oV6F$mj)) z&VcZwzZz8xst%_w5eR>mnUMIapaxd!B@k2BGEayz<3x{uvg)*M^W+HK_3adB)6v?F zOYxveQANuc`2r~WDzo)9!fT!RRX>yH6j{07y_-A}@_+7YDq=bwvzgv4n&4Ke1Osn2wx*PC$&0(@}OO+Gi2Z@28$>10&I&iS=!U266u|W8KwT`n@ z3-oF8Y2rb{kM?@L)STtLu#-sWe{;)z9c+6DjM4h29oj#|k^(BM9;MMOE7j zPSd-chmVmrpDu}!w3;>|211j);?}lRw`)1fG8t7Epv8u(awx`NES!DA0IWErf9i|BuEV1b{a{3MuW7; zYOf=?rrYBng00IX;D`VKQH|4MbtM)m%_{tO<0|qp z{QsDG??5X1H-7x!;Fukv4k3G1W>#d+WK-EfR>&UNdvDo$3uPv=C@WbRMJSX_WhLQv zou1F{`~CXs={#rL_w~NU>-D;>`~7xAeF+VD^4@;B+O$rHAihSwLSo%L=ECpFKSie| zZegCEKIhF(#$41WIf^b6YgLv*Whom`gvfI$ znvLoaV5B8@uvJ_2cw{HxgX>iS&j|P7m9J~%mD_8zo$gQ9eRn?bp#ONyz&68 zCB6IL>J87eKfS?=AR6FarBe!@JSDnKIY&$^fW!AgMifna=dJ8{42`IX1hsylDZLzh z+22szsJqNU^`3pfTcvFaSvPhT6kPq@(2_CZ{c+#^+*QC=_I|#g*Nk&4-F$qESa$B2 z-%4_V=aBJpv-uml^klNqWYTR@@7pfs(ICO;k8;~QGuynrwNpPu$OMmf4oe*NPGCyPRvTsxUT|n3F(7uNXzc`=FE$(l#%fITMtAlyyfxS zsuk_nkFw60?|kmpW)V7|si~tw&)6%N^Fd=ch5Gt!3lrH4S_|#TGzS;MtxrAwNm}9NZ`yS(Sn^;b=5mW)i;H4GPT>{Q9Y?hCSTG0j}`#} zJ`=%ux9`*#b}W4unaQ81dfZ0dp|RtY!@ru&QBM~p!~Xjd+LE&m`LWbFCFR=DSoJ5@ zDJPy!Ef#m4KFI87bHBDZT4<#hPMUm|!epYjZ$RwREvdgF5!pBGb67N-7McUnw{s11 z8SM_lo$r|#QykK%UwVKE$7krlntC5W%!j}&k!HdV#6eo{>6)X@S-P&ptxdbyoHb|; zJZ}}hW%dMjL>e>E!YFu&t*W~~;X(0d6Uh>yR~ey8TtvCEjn0cig>gL65kV|-Ir85V zhUw3T`(Mb?y{%U)ujsA!cA$^mb=G}aG^kgT<9^+GRrJH@jp?6z^SN!UwIl>GA?yeINgfr*uKr3q8e$y7}F&{YZT2 zh1FR<>tYU5nDx>!GdXwd!wnM{Q zF@Xsci=(x2vsq{}e8ISVV} zg`ZRy0U2WvzdyI!C3!b0S&1hTGTp9Yp)z`3P?f2~+A3j*-zvDJ)+`2{b9C!_Q&v?< zd#d;W5sRTxBOv=H+c}uMC zJVXWttM*PbBWU>u3V+H`t+Fj|XGum4k@EerS9Jkn(J?$qq7FC5gp1+wp&}zGabibj zaNJ5MWw}B#lEv?3Rx%diWmXCJ3taG|Q^L(?xrm3i8bQ=I=08YLfL5zm8cb8%&=vTO zLTHXtXmhhkn5PnvhNCpM%IW$j#3Q+w@WTtAA$yIIs<;z^qIg0otJKa(5QbP<6%S=l zVM^?}bxV2N)q+@Lj)Ua;BdyHLC`}%$Ze(l(skh49#tmlYXR@!V8a#b$q;4Sv$2A5m zi58A2hW6rce5bi;{3tbnrht(q^m?V21dEUXCm%bJxdLu*hUu2B-UB=zcI7GEH<#XO z7UZjmaT=Mct={5F87QGbyQ-D($k#Kos9Di&(XzNj7OJx@V%9TOA{mtn2F5e!Ge|>d zYWJEh2djJWQ@C7~2se+%d<^-Q4o!`eD*W$ZP_cPZGy<5%oz z(h?a<7150J941?rmP8BgcTzBh%4^b6i8GEehOdSsQ-<*qNHZy~`E*_mbcsbsvrwce z2I2Bg;FfHJ5*X_Sng!B(k@h@)Wq}Dd&tRc}(-9*gv=S&ok$jA?IC#M`%Eab$QIw>i z-JIsiF*I&67(`sKxQD8piE5NDu}slKvmQGlxa6`eGLVlGp}DpD4HqGUqEbXKsv^*X zCHTeia&rO{uMnz8JjEhP6s1f7*#&I^&EN@K95!M!BMxf;GLV zDy2-xr6BP@vl1L3Mdc{PB4nx}3a22}K9q=>77-O+QlZaBEK?xQH{q$nOjf2MLWLZq zM0}8xuzgd4V2Py=Vl+c4hn`%D5ct2hg^`yCRlLbn3fZF=pHUgXrNv!S!e^jNWh+xU zs$ec_rTJwgC~QwR@W`l2nI%?!+)2A2spRKsn6dAD)>b$5n z35ptlDWnJ`S5Q_L`ZYYs-P5Q!hRZ3=&rPf1O@s_$eOMwbUC9=x#*wdrkfxBX`9Y!= zDVw5%?tEkv%D<|NxGIaTP=Ml`B{7qUp?FrWP=AgTwZ!u&iuC8W zSa4#Wgu7x*{~usdYA!0Klkf>%<6v!(H}H~icrqW6^M_MyK|8<#1$)mkK5niK!GZ_>6J# zsj>)MRa@3z+{88iP0n%CYYGP9L>47TMAB(~Ne5-HP(ITLLlKe+Hw?kTxvj&El%^>X z!qo~yI>S%E!Cz6}DQ8Azp^SiIR`9L1@|`(VSW+mP83}%2*ls zEgbzj4 z6xEdZ@W2U3@bZRuF#iaEl&t zT%4gw_!3R%KyqTdZai~R<*4p7MvBHngR;rw5Jj`r?(!r?w8U+uBr|DT9|WRXu28DW zFsX;E1m_}-rnq7_XRN?@QoM8_8#5{>UY=_dQDWb#jB1iMC8k>2KBuUR^MzB>hELLn z>ISzQkpT)plcEj#GcE^73@-ewoB7FYoRVC7!PH$P6%jsSj*S8#bS%HNYE6@Nblxp4 znF#g7AzcCaG}$GtJH)oyK~$KRVamDjpOO#-i97Ug{L89n{FFFp&)q8*!V9Nnb|q@A zYi_2dA_|%=$c_f?7K~K|$)gn~tJ)f67FF;IlUD6&lH0J4d5z@Ab&xw%P zRy+!knooaJGDSTs{sc?COdH7E7aruQB-KVyPMxMzr!|fp#<)ET9qD?fN*W@oiZ)BEO}SoKf|liCv$rtpdL*&o ztF`e45bZqX_Xv<9eg4>y{c$Ma#BTrPw8jtp$X(F|RUL5hxg#-Rn0esx^ zV*V9t>?KVebc9<8PvctB%w{kD^DeO}rXUJE`bf_Eb(YMJjTOdSb28FLxlC6_lWLPG z-B1PNhYG0~>Q4#77`^<^uQ2D&*I8!7_BDhsqM09*P#7RMRp-VEg?l-_sW8cuwsDBK z>0KfH#7sOe!bpJ=Mj@*#^+>aY`$E-6>n~g3p=v_E7A9Pkt94G9Yi_7l292>m_67S+AIGz#KB9)>QRwm*CnqQ2L3~jf8X7vLZaz|yc7m(Qs|<;1>`OmI2PBHy8F^0YE@RSu z&~ecfBYonZ&dJwg*EV-Hl4VzJ$-WCO&>lQIxqIc{-tD*{@v?DuJPviaxX8M@u~RjE z3!Zd0cWf@uu*f1FHL~E4DpR3Vi>)xB{#TghGBmr%QW#&~va}>nLHEBK8+t8gKiB5z z6z%++e@o)Z!b+#>5PzR&{0BHpH;m+BvOIt9kBTXh&Ycvq?}cWVaI*IV#79|leN65b zk*^~uSi(s!RejFD*`vGoDuZwDqy+i3#U(%3`1qR(-*PS7R>dH0Q-c$U9B&u3v zAEq8$X<$6Mc}UMBfA3!Aig#n!lin7_Wlxj9M|2U6-#T|@wXCoOZd$s~2vyx{|SOLDgv2}SMK)_W%qV3{A>})`zi<9 z*Zp@!fWu4=2tva{LzICBCo@RZ)>lge2uAyN=&75k2%JJ`$Q91bg*mub)q%#R>CCtuXOD@Hm}6u`NL&pB}R(d#J(;4`~nLtQ5H0h zStWW)ChMR>Z_YTEqc3KLC@G<;-y>sb9a0^^53}(%>8UZlDXxu+;ae5sw~)54!E11s zCO>~)|ADXytwn`Gy<5pU7JZ&w()UGs1l(O5uW*oTNKP_1dZqiYB$>SJb_Q(LC1%*d zoTdHFmoOBax1y)7KW?V|9PiwkXRl(sv;#SV!}3o{EV)m))+FmJfGa=KuWuInM0>y> zj!@GOr!9Wmq6SwtmWnI*7V2wjT~$@p%qYvfwjbvV?76g14E(cG?*f%yd`48^Yn%bZ z#(jk#M&nwd41yA0iRBN;T!+K4z_(Mmdo#TjE?4oEHVOB>xzE4OFrq%TP~qXqffZ%OJVs?^1C)!UtC^c-{E?h8RyooBamCh2?l z9_9)jTS&{t+|?9k=t$J}y4&}-Z(`oEYk4`@^eB(uT8!0JjsS|lA;gk`UZ7H%+s^l) z*ROv}9ZM%V=X?_pAF?!RyIJ^wL##24qc!r+L$ROrk~etPxAzjqHQ zWLS!H&3dfIGd-CX3l{65Nl62BpPMpWJ{C^h#KHRZKm6u<(U#*t$CLS23vW2#R*VuQ z9s(`9i}w4*rxkp@q?BGUI4~@2kP#8M>-OJAI&tWV27GhB^tg@1>{-mL$9r5`>f`m2 zN1}CI!<3fZF&rA-d0wR6-TAU05La_zt{;m67yIdQ$~KT|&^c zmy1%8kZf54<&!-lWjPVHFLpU6{iqNqo$?^;q3wsG965nT; z&%L^FiC7l3?tC$v>3XCmU7ttC(t)R`xFf=4VU3m9RqaPLmg@a8%|!Ov`}J)@yY^>u z-M$0zDH0$4X913f68vf>A(2!?1MBhF_x^i3pOSEINeXr8vQF&(^O}I^>T3(9|I{vQ zAu*3PbAQoA$g6Ff^1pY1elzs7YU3clal`u8@BgfYB{tvtFFdAuGVtFE;4&F3=j?)& zG=dom&RT2jV+&zM)MNEOtNeR={-4isR=*=>W{~*OulDbD|0#HM^pAYm z|DX3LUscjTYpJdscWMt}ic=SBJxM=2`r((a?!9oxr0v9o!u2U?3RkA`lw(O#)#4rH zBQ3`3_Prj7$rbc91Z#jONEe*#EM(I#d`sdcscYk+H$(2yUZ`c>&T;L=xQD@>ZN{gU zy%~3}u$NNFipI-DhxO1wIG`R%pl)+Bh3fUgO&l-%K=Ta+g*aRcw-seg8Ss+0R!Z8F zhy=yqgF)Bt#Td}$iQ%Hf+7$)+3>il9s{oNRl_MnXOs8X6+l82S7CkOEs})<2Yw zBr?fKj0pCMlFvH*W6T*L6|1rQremu)<{8DwUJ~jWsoHy(@UIOcHy?kpO4oWNjIgOG zP3^__JhVwyYUR5?O?~z5^H;*jUpe19^{a5?!h??Nv?^J$672u`zEHBU`n_pr^TlG>;H&7iqt9TwlNsJf1CGpXfwIzHJ~E<>f*2EGG;Bg$ z+itV>AjEx<-}LcP0Y2`ym+6g#RPB-t(fPFhtS{|2r1g~COES%zmZ7oQLayFnB4txNDx+YBUZM=C?FlO0_> z>d`7M8s8)4HFSDNp52?N#=ds&lRD2NOLu}dPbuNw%|Z0&jD(usy?5`PmKH^gk;cBD zMP0_#MCDxF)1L_eKO*^$Q&dY41&xiV-$zc<9vAuk{u-g%-lrMhZQRz}-cE<8Z)mX1WJKZi zIX`5_CVNv7OxbCjtygn6{EO_hG-2TGh?FVnE2Ks{h;BAEHtoTYo5!2Q2{(y*5)HnR z(Tk@(BUPhc^)CcaLq$aeSt6W$V7}w=*>3)sX83$E+b!ieu2KSWIuybjlg!@8|4JhH zzrg&X<@VfZPGTG6S~A!H(BOsRT*qTifu=O=lGUPv7yJ)K3uJ&cieuB#M2nHCn9H(q zYXWB}=a1ymO9_4SePafuUSGrDTX%+=7rtbZ{}ZTShvg1&zaQ(Xuw?Q2%EP%}l4V_f zNJayX%2DE_x+}xEySux^w|6lF%p}1wXhzsHH{U7j@_QaimjTP>Xe@2v`P z9$q?#J1BnSsl6e7$6tQlPB*8GjB|{ox#=sK)>&|VVOL_^BreimBZ);x*5Lzqa|nO0 zyD^v5NS>r&lO6S>|3Mye>E`sa1tN|dG!mzD>ywAKktJL+Hq%K@&>z0G$RK#U9bxX( zOJlvfvSMhT{p)AJRG%#T=sH@@Mpq=PezW3tv@v7BVJwC}xP)>4b@A3R&-WyVJzgZX z_~}Ryw4%H9Wf~3pr8(lJtM4^542#Ds31;#dvM^3xTWch_))L4p7{@OZ@KAMSv`}tM zvU7(7m||hs$|lykpnOdF=w#T14=-VnL5hxyLQZa`$Qw>lQTG^!BTtV7PA zH(ZeJ^(I3+v3z*As8B9q#)DQUre9~e)9*N*{>He+$nL62;}a;XSaq|K(DveqlaOkP zc}BR4T$%t1xBfXHDQ2`p<^0I5??QQc#ozG?t>RGh1X+SoY-LDIvaG+vv^yagt-QkZ zElMV4^2;}KB;Eg)!c~O`6W)tLJxIJ5_LpxZ@9{MvvFLgo)wfGO&3nRetXBjUHp!Vw z+o4QWdX>eYaROmM>dOJ-VC{@@92w)z(!BI)Af$&+iHGW@(%ev*_SF0PA=}`W%6T-M zw0x$KxqQN;C8k~e&Hcnp?e7K$Y5B|$B0|>xm3P{p7iZ#yO|c@;un9m z?6+bd~*rb?;y-U2vpMC%n0A+SIy#B%o2 zC@s%{C|iO#Ey`en5k(n=jB0%yLa381Aiw#cTm$y5GoCJeBjNE~@OVMK-}7Qkd2l2i z0qJwU>-X#Kf>TP4EFFQ*U~v}m`4fwbaF0Qr(ub~8cF|_8rPUvcG3w!;0^AvAHgYVn z)4doeG(6k`nbi+Wc5I zVdB2rpVXUC-1)Ss14T!#^u(O}^**+Ut>5|X_th2Zag-iMX(I=@f*^y8D>`(SX%g1qomv3)hYWER6% zX%L)-1a)9-TtPK6KVL&|g>yT^y8OaPuP!%r%-g#_hOmpV=aJVT#!tHYo=JovS3Ylr z#v+zqDcZqWA(yO9u(#21?oX`XFh;;Ka^FvdE1_CV;xU!7j8=M=+$A;)GHAuS`Nn6h z&EfhiYsi@(eEgDN(vJLA5t`Gx$9f?K=P?8%7Nk-Zjp?Vx_CapxtkF{{yr&9hK2(=4 zDic{X9=Yp39L>x3ocAtPj4R4#34LC+p7g7&1a{4R+TrjsL9R)vbLVj$A;mM}MydB> zgRo`TRyPiPO!592n_6Nt{+{6<}H_D)G}v?y0?7$X8pTi$wMRY zh8Cy)t)oirP3VRB%Jql48hb*Wr9vvNBwc;t^;<5yQk$FmN2>O0vqM8&nQ+7w>W^{b zt|}Kdh3}-^9r~HyLtYZKO{YJ4&iO5HRJu}KyjQp;Kb|#{dm}zYjXmLhxjrU5Gc&Un zQ>FM07}Y;UgbT}g)GW^fhE#w#28uX zl&hD@7DVt74n43XkkPz**X!Vub;_w&Fmm^W-gNE8pH7W4Ho^zYNutq)C^d*dfCozY zacut@7)mucEX5q8a*hFgd<(mw>oZOEP`NhlNG21oj9F=Dt40@ZY0k#%yhGkSAL^^!S?UWzI6 zpeYmaHOjVQL)Uy^LUzotWV=APkcB{326=aC(De4Kgy{MyNbVU!KLY;vk{d~F<(DoATUx$F(;q?kh0k6yO7Yg zH0JswSlGcc} zDjX@*_(Fj;!Ul7-hmUZ5u?MKZevI)iYr{Bm@)xct)oR>-G|B=n;g-%btS{MnGgyNMUBXhs`pkPZ(eKAhm&?0uld*YT)fML6TjcZMlLs;LI-ug!O zt!a~4!p|7Fd4qKWnO0_ogv-c6D;}p$JL1u|{QT1jxk}w*b%^fet^7yjNsGSYUa})~ z#ZV$~6t`t{4j)iput^tXPEL9W}l%0&~euX}4BDh=mw(r_jo z2U-sF#$AdayCiHiNCj)5q^zr_cLJ{NI9Bu)TqR(TtGw~yCjnmGoj2z-9>QeVg`tEzT@+7vs0TyPNigoV)q4Tq7U8a5P!<%7rCnp8u{H(QgC*XiQm4S%Pd0{1N}EI3C9qZOXQt9)(;+x zQ!t%lSfHc%mn3OE+R#GxPgW#C|I_62P0;Jy1@ zA?89H)NMH8Cgvh<^MIHB+9ztdr|8Wm;@dY3Sq1-S3n`|~gy~cQT9+It{w?X#5cjR2 zFkCZRQTf>vMZWOyi{XRt5bbDkM<_@7&rFQ9wd?JtYk@#)LomP3y3X7A`@V_EJPB|6 zbL$ZXi`c7uvLQ!SwFWaLD|%THV@vk-7UQ=L%*M11{1z_!C}HMtC)W{jOmX9y@Nh{` zm%8EF`2#&GqI4)m+H(?+b@EsIJlCIy=Aml805^7}+}TK*L#aQ*Hbbr+9v%`5`Hv3{n!~a*xw|D7IGmTLM=j}EE5(OGNuWQq5)!aYFA1565 z+^?~Tf34JJoj&TaU5HG+Z8pCu*Oth5Eo6cla%ZJ#vNwtgniVVNaGv&6c*Jb9LSA!n zs8i)BwMqV%RJbLSw4TH0p|-g_rWSuq{3At!A4_3#n#5Ll?u#h-MXbMmZmDxPc4T9& zaV*j1GK>zt2#r*zoPfSC-wn-TosHA0)dU6w1qF+z#4^8JzkXfQ(0qZo1{m1w48B5( zzWAe~qx0-)ciTK1(8!-&Ia%MgJ~ga#9&cabzyBtRBTv+BqT-^dZ(V(T@{oQjm9DTQ|hrR!7@BcV?Zs{HAM-g_~kqUtJ%ve}*oCUl5`u!<9T2Tu@fl>pmyX zZ2oM#bLZm4i>4l*tl%*ey zbIk-n4#;tbGe)}p3cR=EW^eR6J~-N4QF@o-`}b!bklz5XhrOMhl_=USZ>UaOE4N6HoC244@IGsd4%PDmY}E?iJrHB4rS)^~g9dof0@%Jh z$0Ztlf3DSC-rdqDLxoDLD2r$Tf3EhEmz1^ zyUk+@NHuYz>&mckhtEFLi5qUKi76>S%CZHAMMFINVTZ|SlgC?N*j166XMcC0-nQ;^ z9uG_G4psPCVZI;FZ+f9HW&TV(Nyk`qohb8^>e7SQmwV&4uobzzy&XRK9sX8U&SChz zfJ^;_{W=%6=h{-3IwAR#=lf%M0@n3Cwm-iFYCLTkZ~`o@4Jb3bLKE|Ls@C{M!0F$2 z*V?K}N=h0V-QGr1Lo_&RX^mm;^-f5@+3|u?*U15hB3+Pppcq{39Kwc+HZJ0UDXXhxz)QT?i*8E@Pl%1;6EgRJBARRgH1WNK_Kwh z{K#+7ODd0b{CoFk?yVD+NA`auP}u|1=KB9xgL-E_R;1wQ=m_5ov5gIy!NI|&wXIe6 z8XmCjOa1-P({;N44Ev3ek3DQ{*C3{afPI6%5HffLey##@a&vKc{~F-9b?cUh<7ZLp z;T(^xnU0^mAk{^fXQ-Aw7|N)#87ngVyLj>GooCmsUWKXa*MT^A3;};&JB>eDh-TkoCWTQ9s;8ZVNzGYhHafOZ=jDTw&A8Z{i1f0S3La3+nnx2BxLb>V^k%R$>*SEAgH-CQ#dHSr=2jT;Cvs+KDh#h`*g-llox1+)Ze)rODvI^{* zoFI-0hD66}+`0#0;bA=OoCEg+X4!}HfWVG>M{o_;ObLk;tf&PEYJe@B3WAWDdMvUA z+!rJWfK`SqkIca=;BFQ3n}FFI2+Z{KCgFm66E1fFumIlG4Bxs;z>z8GG~XT@8=EO; z?Fc>$=?0s02h?lagB((3APxFOzU z|KDE?9bd9th)Lq_upCH+bcwBkj}Ny?S|FB1&AUS(B}3fC-}D9T0VL7o0Tout6!zOb zyYEGSbn%p4;pH`LdGyt`JlA6>PNdmxk{FRC?BH{DLRx(Ti5BgTmbmG5(JywH2954GYk2%R{L zEG)&IJM&na35jj$nW@GfsZ2HfJ9kq4-UJ7S#CY9yyu?dlTXY!0Fa4Ua&zQnRW9PTj zx3h$ZdY;3o0hP7}Lbmcg`;MNT!uA!zI_z2kc!X_;JpC3lSSfom071Hg`XLuVu0043 zU%by0T!Bby{}N2H$|+($wF&>AlkoZhIZx?)Puct!(>%DquW#@AVrg8VNG~rhx71>H zpv3lpBz^YoJ~xw5P*4CNHU7r7s0%crA*PMM2LNEhjb-07hg-`Qabgg2DS3ZY;%n%6 zcJ&;uaTN}x`;dNnwKK}n_0ldAvQ=j_)K{b86)dV?i zuEiO|!=GLf3<-xD(@wvCe0BF>()4AIvqmFJ9zWh&tpk_976WZn7x$SV6_9YwVd3Py zle`N#h!No^CS~5FTR}qeAXyR<6QiN8ZU<4cyE1}pcYzXUIm^Mg2%tyAVMfSqg7Xhg z{dDEBAAk#HY`g+`@Lq#61H8Xy!U|xO3xEjNj12SPgV-?+a4^t^;Nvg$wd(8ZefC!Q zAt7XC(ORh8zJ0s#R2A%WzwRR_)bLyuBhxfXzqg_@PsH((MR>N&r&7ykC{N^s-LM{k2FQ!38yzRhK2Wd+4_97_lBaGzl&(ZGUx=ZmqH2d?chT5w3`*<`uODBq+(#*ap^-tAfBZ8uh~oGMe0)PV zV_w)!^A8D;8ZMQuuFX~E0FAK0-vN8{L2`F$|4A@$pd0C-4}(uwm22^*=>F(zgEbt5 z!^5)yFyfM=kDG_b0mPCMv}gc65uIn()z#IMxp;|>%Z|xY2Rs4FjB=F1bhx_c*U*Mx zar=YKPX-$Rj=(;RfP?}45FajO%&$qwY0SSn1_S` znwPN704P$h)c|lriFiS?9DQ8L)hBp}D0x{_o$HD^Vs)bO1K?#SxqA2R9f7!*a7knv zTg;)H*{W*3X5cYH1V)Fo)bf zTs;>efh82!3%Kdym67~~u7Ci_iao>tDxYP5Qfj}704GExw-W3vzmK2Lq#{L8+;Bn?`dlbK&FA(VSoDf z2(Y&%P&2Tp9e!-u2dZngTp||*ZM6a?(o^f+}0?K&-?C; zDS>uwV(oEnl~ZY&Ytsj(BZ$rqzD4}tqXm6mk~VAvz%C^fu)jVDg%$pwvN%Ed1pK6> zm9!)Z_@Z!~y;;B-o>(Z=hL)%8r7`EtR=h29U~<@%ZgE~(Wk{YqZ#S1Q=7E~xQcB2M ziG$W4=$~w*PQq9RDhwu&n9GH9i7{mdw z>Z%S=M~wmUxP1B}g6B@HFJ$J2J++@de+Hx!02ouZ=BAy8(yYoYt^~2~82|(&03CsL z?{m042XacXYH5~;Q(k^P?8|=E1`XKiM_g8LQ_jxLa6=F?Yle;387dDBAjGNQT4t|< zK`7v$jKU&oq@2FKKER46SMEWyVzJOQ*}Q?vW) z7o@*Nw>9m-c_gC79TEiO)@&hLm(R|9W7h1HM5wAl1PuI5FZuUNW$T+bSgd5k)m<)<@4u10LquFst%IRK>`l|Jo)6RA*9!& z22UufJMFu}Sl|n3lL4IB9CNVt!5T~oCA$bWkF}#e+rdy&)46~VB_JrsMbCdB=DPjV zL%?)U>6^X3r_Nb(7-GV~)0qj&jC~4{m=sj&vT8Rx0F2DoKRcNPf{BIp;K>C#EZpq> zO^!!g^q|R$2sS5wdj5k)aM>9QObBomt7AC@8J*}Oz{CKc*-hoavkhN3NhITcu;(6t5gY^+HFeX&PcFZf2Y_~3Ud9%K#>Pf~JyheL0Qv%>`T>zW)9Kf? z;*D*JFAt<(;f3Icgdhh8Ap%Mr6;eh|k9wl_80dKp)Ow)8u;ug}aQ6K4bZfmg_pEbE zQ?vNYyP-T)h`*hxG2~Fo7=?F%5j2sxajW*y1aYY)`2$H-VTAjg$6wC{WGJ)d`TkP* z^_;5|+%GP&>*&4He88Ds7PVpX!=uS({*zq+XZst|P~%Qd54(0i!NJ;Jo|z)tTtNXW z&ja-m+#yvPvLe(2UvN4=SU_90k56Hhwp*6sAsrp8j)kONQlag0u2=*u3PK%f_zu?l z?!S$O{HpU*Zg608^67Lejo|68^sddhHYmX`%mWEM7jzJ;A8_p@4Z0-Xi7T-Hnd1_a zwSJa_zmQ1b@I7E5U1ujd=~oS>Ds{>MDg3I!(kQUA;De#n>1UVOkj?hf+u&f{Kt{sJ z=~aF1+TTtpY8*swePlq&01Uoi0Fo0R3P<33i;MSbnx=e!(sliQ%c~fRsdJnYw@_nF zDoC{Wg`DBkcUjfD0|UMLlPrp{ciX-A{qWbm>Zpr_WrclI`~m$HjelzULS)JHJLF@a zj1Who8$6_rysLHMxfMA}vmj7l&gkSf>=L^e#R1son!qZyd6(_fdBh=gL_{-X8D#!n;O7H8PJmJOea`< z%_2f^^2p`$Cz(WTAj(Gprz-&r-pfhvIMP2(%baa0)`1L}k`%FPD?4dGyutB)lO#?k0X0)B*CZa+Ic2I4pZHC5%3t?ie; zyCdb_Bl1?pl(c?Z>FZA=`0o`%K+U<1NTzUTlo3nk0Zg3t#;S~Dci;E-Vn0xm? zxL9=sZZ!kK7N{Gc_2RatI;!RLiUuB$4E-cgWQg+N6E_q7$ z;=DYUWLnkpyYCf`KSSSptXOH`Q4iTle!$IKKS;{vm{V*6V5X64LNT*F(YV3p!%OH*lKwgWV#KhSBzYFLm_ z=tUoWIXezGbAob|dOl5=^>nXX3X)d!ur|Vt-)+ z%=hS5cXv0FT=+-a*ph3|rrvUpzLPMVd&3h_J;*2kOsEQ#ZfuGULlp!NdhjLW9LOA> zF(1G>SX=-qTJQ|Aoxsbtl86B|a72p>>02-^0$pr{$^$x!&#OQjAXn`x-qS{|w?UT0 z>RnJvUSV|Z-W7$*3J%7l?ScOJ*0X?<4XoM)bOI<|lheX!pVaA3(C{wByj?{=xSqf+ z(B9iGSFl1B+|u68Lco_-L4biNDxGVtue}1=ot)L1vAMYkfb{faCxDlevwvWq?(6GF zaNjeqnG|SA*mfgU{sO5Kd{K%)@Byj9<8i{7k;2G6D8s=0JwPRZ2{|LE8z6avpSye$ zCKFsx9~SZ5Sw6mW<-o_g#br@<*WceC=&W+cCqD#YmNt|D1`5tY6FI5-@23&}DVX~J zUxnhPZ9n(Sv@3?U(+ezdAXkx5o;KAuWhO|V6pH~FC#LJ~H(sdQBt2O8js^5EAaA1) zsB;Mr#04R-&za`yw&tb#T2?L)z6{(cu)Sv!fB6GBuDGK_w}x@uZxT z8ndt@c{qOlxN1&a#U^hhX@$)0#9%L!nbl!(kk_z1W|*)|@PNlA>(d}7dH}yh@T^9> z$*DjEbE5V%%m()U8qJ@5X}zM?=vAG|eSFawClHoTyWE|f^8MY%7e8RN_CX zWvjHNW=W@`o?4Tvp;6shJi~P0q(ZD17Ux%qV-m3GMIa*`5tvg{Qn`vwx%q-W#e-Z^ zf>o?QdHKWFf<_S+%dtd7wz!&ivL6OcnXV!~swj+g2|X(^7I_#qXp^aW$;uADYtm)e zBiwJ!XzxK5lfJmY#cOM9>)K{4DYm`i&&sNG+s;iLVsb6q#6J=#T8Hkx)55_-(>7hc zwLXlItIKW7_36}Ed@89_ls_<8{;%Z%<1)S^6(h<87HK*yQqWZXYA&>Na_U0QFXP=)CIM^gE z7KzGn|HbT=O(nh7U;p@IQAk92V7C5r>gd5abVpqMFB{cSXD!vSpoR{ie!K^M_dLiy zcGM5PfATE0^R>sX=kYQddd=hg+|qxp-5}bUEy^cqqGqV@d z-+{`WMztR8ZSCO5TjlEMRQ5tjCmhG00}shYp6&)6SZo-n6fKx=FppK?{w}&^N7h{y zMQZDYISh!6FP9W5@mQzZ7Vmp8OjRYwb8z-#HG6|jX9K6U;f{N!^O?w~zoOsEu_Hth zX{&hf)hh18e5QkuV)ZY)IsV6IjjR114yQ8bO@-SJ9Ng7;uqw^NKmoOrckL(nf}|hN z&uR3V?|qVa`oPu#MFCCNpSb56y8e{1DL=&wZ1uAIH|=#q%X#6cx`-u=-1#Wq|0H`b zMpuLPm?fRkPLe6r;6e>^58s8smXOH&mpIKI%&=o3J-$kDgfM=VLC|}8q(Io`(`8 zWeP%ct_jA5)yq|Kvoot_3VZ{oJzH-@lJIZf3iCaC#t?LdG8yy77){eQF9{PJ9ar>V zr%sJGj3D$3HWPng>7HQ9R8yQ?3^VU9Z2#A~&TwM-Axa1%T2!eM^2Wb7^&5bc0#YRW z`m~s=7#?Xd+!{K?Sb!uk(L7u%)P9mp^WSV(Mq^QouuOffwYMcC$;J;CZ@##zV&NM7 z@Ok5$&76JXTj9&)Tg{85bC}y2^;e&-bv366o=jih2vrtbg%ocQFIJ|K!hT>;{Jz>D z!1_4uKyI^dJiEA5bYrvX9y9&or z3EL%-ewzu=V`=lQ9Cmv4M&XI|H1|7wR3Av_iKwTs}3WMjvP|OUP?DTYX zg{%fsuNk)*LI1S0v@{ath_ULl2?*6N@CUNnG)sbnww9I*fykP;JS&k*{2P!Rxpc~M zfY^W#4&aVt!Dpj}5fzG-L5s$-lwRTHZUwOd#!&(C@d5S%&T`jWdaw{DJgcpCap3@<=Q0eq3#yLCk%=K~<##v)2kv`+vd%{4n1qLFE7Y1m?i zf6*v0J9`#v1|1SJ(DV#opSgc?`Zrc`T-i199=^My%4G_`13(c7d(8LU-S@9T>k(`Q zUojVOb|Ul%09NDUL&r<5w>&S*MsZ}SfhJyqE$o!aGMwBf!eb z>jVW5+Ff4UY0$_V7P!_ABM8)+S=JeN_Y>-2BG1Q2ng||@AdRg5S|RJN?z@>pzb z=+ptZmNH5n#1NfJU-lw@W%B)y-j-}Ai3`*!?}h0)zxDMGDjkpaBW)xVz}BRTvrok^|4ko_~jJ00tx~I(i;GHc+J3c0GkE^g6;{ z&XhgYoY~dkCOZdVPf^=(p)NsW6Oy3rFvGuQdS-55boKsIFNL{QgSeaNh6V ze+iDfgH&*^BJy}vk~Q-i-Xv=^xN4%(jeFt@&)hnRdwqi2tOa3<0aMn?&LQJA;~;6AWg(Z&{afF&+{g zy!V$EJ6yO+%`bwN!P17~K(Bot^_A(qLgQRr=sB7m18@)sZYoD5jY_ih`EyN8O(=|s zA1v;FQE>_EGeC_kR8$+^htEYuM&dGmL9yjzMf{#Gca$|cGO`eK+NDeDSk|x`Mae4q z^+ShU(mMqu#hsfsS$KFFPqxt;u>jvu*HqH6V*khy``l479egZsAsQMQY%fWUSimSl zD05hfR2t1 zWd5@n6XURzp+!pki|0>%X`bbVl#6sL+Vsw|)E$aTPeB6K;_7 z^4>SzWpyK|)Gjn*7r+jlJb4lv>kvT%dg8&5o5YXQgJ*mQoF1=)MdQWuMXGn-wxc}+1+Av4 zN=3(RSYo+f!w5ylV}y5Yqnm)*ysoCDafP?^JUH2gYg68nqL&BSvgUNJGw@mf*4P#A z-(Lp%$j8SgXpjNEvEN0?GJ`>*$F=&+6>X~|BWrSz<4I1bU08*(esM%u5Xmfv6|sap z0<>njdegdGy#Fl`GkEz7Iuds;+7W_=3ln-DpIk=tni(G_=@=_3KP8k*$SM%nn5gfj z$nS8J^ZjPy>N*XG;@v$J^2wKYO9sgjd}72e{X|l9Ya;OM8#l@gaD9L3Ro!svLc;2hgBQI`>d_a?r}hWcXzjol&Y^8!W6#eX63Wq-b&~v_uSA) za>CVsk7Z`=#iwHL*Voqi`}sYpt%a><1)ot~yNf>DwyX@o90V`neSCTzc)JqpWMpLA zN>|p$!glhn5>m46P-kYn#jmF zZ2$Bs0O=U;a(LnkyiKVg%MI5aUewfl{vYj%D^oWLc?MkD9rzKHM?xZR#ytA&A5S%o zAqfiN&DEm>0!%#lAS#QfBoS;8hq2g{qjnjwWDf4usjx1MKNT_f>=32O!jB(678jdH zSv@W*0gubd>sv!ULIg^Kav3!KlG^f>AiWQ@&7Lg#pOb?B~zS?Ce51Om#QRi&qyH zVLkhfT=~-Z0P9hY@*bBpOqO6YCACacq+`F2adlhNJ5FAs3U z7R=-d=>i|0LA}JrCP>|kHGS#Qr6P;6Z=XM37;k5+e}CoM$RRsByL0ExX&Bi*YcW#m zNgOo0m7X3uct``n7MoF}z9}!q=)F;iiHT$f23)J<&^aACq_U}C>yE*>?|}Ekt*Z)< z@mQmsun+L|5YYbsrak99!QPj=m^X8 zETKE8dLmOH=_ViZInX&tBSnKPG~wkPj?HIOs+q;*<%gXsvA>H<3ynRjOq`D-UQfPN z{x%+uqVqY~<|ouooMy|it7)QJKaG#yOiOcnU}GWzVWw6yeh1TiE_u#DCfjykx~z2+s4o9yKBKw?!%W*Di1O3)};=@jc?nhmHis|Bq%s|>YIy8^VW2IHdfZR=u4ol z#)iKH<`VHG9aJ^;*NfZYah+GlnNO=)s|nuNz6?~lu(0s;m|Qyj`Et_L2gX-z`NqxF zpA{OLm?$bLI$4>sP>Q)wXc}t;{9NE`@SqPT{}^pXx8l0KvaqFShRc30ud06!5AUzZ z;GbgEZ#rMTtg;lP3f`<3wI1)pNeSzGx{oK-gaa{eZFooY*Mv z;7h;fYM?#(>Fj*WDY=*r)oHmW0_6x_yI#r@JQuXzt0B0Ng;;Vr|%$5>jSH_OY<{|okmH98kewQ24q z*C>`E0h~c1XplLBb=Q-$e=0 zaYK;0D8xwLTrz~hbSK?;3yT5dMbjJ~D4Q=@q%EV+6q zl7uc0DdXNZkF$=8YGR*Qz2uHV1|uLK;0uZ#%>xQSX+FNqc12HeWVVQlmm&Gs)p^l) zawx4qhx7T`{y>qOXCVuYE4%)~y|!oHKKC$FX8$oxSDWL(Rj8 zA9q2s%f!PI=N^1lv$)?Dr6GzKmai!Z3Fnctan%md>GAblsR6tc+{YWUgtl==5h7AV zp2?%Jnil{;L!OD`LusL3uZXC+un-X&``B-hpZ9|;WG(Co^b1DVq^1Fe zx1GYPF356?tE)1cMoEC8WTN}--Q;8;YE^6NcgT%sf#EH+$kW>?WcJgzT)6Y&$3XN` zC|Ls6R)obaqTIZ8?HahfTjs@GFJD5z;eoyT>aJ4Uxj_`tBKQTt}-gUlw;W3IpT*pJ+ExvHV06hOaTu*H3afw0pM` z9x@t>0JOx6+hdepkYlgN`_OF+BJJSAj_f*8*za0q`*;n-7a$J{qnoInKt_E=K*0ji zn%v`RZTP@jmb{02iWRYQ1?~H*RGE4FwR!PDdHLViLr}bWM>6epeOn?t?mnAy)(@Jc zLTHBp_ig8r-E?XR>&^L98c5bIJmalF3!UPPctJ=jlh_?Uzhk*TO4r`iwe8!PH+6I^ zEK~%sX`A%)bNr4lVFrekh%K~Z7skfMh)@J53n5sj`vuxw25xRKYBI-Ek`8#n(-4v3 z8yHgZdZ*Uc*RS&^;k5cV-%+{js#O+stqR(y{WI8=jEwss)Bvw@r^{JTP|zwVJw3fG zmh6 zXYk1CATEJI7R{(gRFG!x%qpO}(@0TE>RC^W{&d+(goK8+K6|EzyTc=;e(`iZ@z$+S z=V#`6OMOiP@6f-Y3@rmzh7Y|-s>Bm^aBx_lc!KVIpLLb&rJo+CC*xgnQCuV>Bmfdr z5;llzJpuOmdcW&gY$|8xydIZ6*J`vIQzNwp>URI~E(~@^6(aG-mDkk#0BZ%D0naS6 z-*s$Fnw<_#3zs)JG!J94!cVfDK?);CE!@GzpWmOG?+t;(9-E&Rr&fgm7v$y&7FBoh ze)3Oti8%;NHD?C&ca6RLXJ{3c8@KxE{IBr!H@=Ko@GKT8o)NgRqn@6gxHOcvJgltd z4Swgn<8$KT41idmtkEBSgZc*QF=&%Q+nAeDZa(DJrCKdXD8Z=x3eh-@gGFGn@j8^y zwzZ7GQwE`c;AA6tEVde5%7yi%J?sYd_}a zKYdz4r$^eo8>laOI@-`JWA6|uUcGvSZa5t%4;njE8AiZPQ3@-!m^kh^x}TcwxxRvz z!aKJitO^v{>RMWmUudyt1P1;^+(#f|X%sFh?){;fZeDCY2N)nWGExVUP-^N)h}8fH zdb~rEFJ@ikf~E;5Up+1_KmQc|0#@(Ixw+U^9m7EMJz`Iuv)^VC=CAWQX=SV>TuVy} z)bLpZ@)1$GFSjU;%I-#*H!G<)2W>doT#q+wv;n(^|izsc{{3*yrJMQU=wy75K!#q;zW zJH83LiTCn#kxMga@1oMVo7;8K^_*k1YyV54%KGlo zsYc#cA3+L1$llS|B9kd7?cF@@zVWtYK4PG~Jm{mwpX^aBKoFobb+omUQ71vTzO;UG z<=EERNU^CO6_%nN-+BTzQ?h@ZqI*3jyJLr*mdva9%G@Vf?uw6Sr$%qD{C-<#BDing z*~L$-=v^s)f0itZ7WPJ0iyo{eyJ`KnUu~#^?TZDHN5q~MmOk}cXTpr1tFpx8k(edS zPP4_!h4UTO&@pVcyB2(&q-VKC`}31fUcxJyT=nY42ceOwVvJQ`feHSUZzYZ^N%j;s zn(jM%{)#7G(HGXCPpa-#)FbjKzaNoiTbp;hsGu|0(@f1M8MW)O7ZYC%)m7WF`~#!o zQCab%`j7C$N;BuxvJRyXPVoE$9v=Wf!!*Vf)R{JdN!Lgi_1T*oqyO*4FRO_~VCyl;u+C?KSly@^pBV^=q>QA{9 z9xpd*j;CA3$lIJIz2v5km|9(1qS;Sp!amAyG)&mf`(KT{{=m4tp`4u7d3WtQA=y|i zQHhGvf}H6p?fb&-y^Sx=nEIR}!sl(j`35bMXS8AQR?gASRY#)ePWZi?q;n0us?_hh zr6;+ueDh^S$^D59>ZaVYo-R~EikB!a=}I&?WZy_u_q>$Iqw3CTsBIo|@?75698@=e z*kK`BSzZplv28CUA*e^)sl%4=cUvpn>kU%kVsy4eLAsx+d!Ey5mAam|zV^3|KrANr z^3{m(=djccEd3l>^77;x2&5L5ak`*!>Z!l>u{YgEFEfdq5b4W29J5BQc-2%g;j4U@ zu;~JMhlF@5`xj07WU@>5;!lOf9MR<~&_AioS|lgP=eT2>E2UjFgYJt$zVW&6;FRL~ z8=~WKdka*9rz{YEaSL0_#Xc7))44mOPn?q}=Y4#x$Hb(``-<_0q^G5!MX7|g1L%*TXff)A z`-fb`qONL`8J6)H@`QbiaivpE-APB~7tpi2K%i$r&Rdatbt$AytB_5;@0js}N|w&e zlQdrPrc!Za8U4{LkF1R=NgPw_vrkSYH&YRkRC_wZJGBnq3oldBwXAE5?#s-gUbt*z zeMC<0569ml4&nZKwsKb$_*}bN=D7>Q)NigCRC6+j_kFy-k)-f7^TgzIS+-Jt+j#BK zfXt1L>$g?J4tr;{D%fdl>5W$Sp*?R>|7GW-HeG}2Uv8cAlfz^m=_WpXV&dk$o>TJ6 zs75D4Y*FjIaG;YZm(IoSlLILS&zNr*{Bi&LtM|;k3}qe_tv}gX%8Jo{+yh^I{Ik$6 zE)be0!1hdJSs#}3W96G)NQn2C60fO|K6F>}d}fc!=GSl!LjK;5+E3M51kMWA{5M|0qVS6!QlP??2)zR-dhKCB?5fhUw4tT(oRMfa z_09*E`LyrQ=ouQ?nejoUGEI#!!(cVwag%-d@SJm{Rr}Yw|INy1AS!n2C))#Cis;!-@UUhUh6hB@V95H>fOZb@W^M}Qau8+p^x_f3;slVjj zJDexPo|jdCR;7vgO4(u3e{5twyBZ-ho~XqoYGxZ55tf<3ZzFrkxJYyAA{rP!P;G5D z)>?2whCe}g>s5YDb8}YXTl_l0W&!r>6J_-8Mkwe^MxSq)2T%R=q7O+&GPSEt`tHqe!MU-=TFIR8I!%T?uW`d z;p>g?kt`_|7b%YD*50nVCJ-?GT+ibyJu_Jrrd3(0a4k`&1dya8457|2`TDl>+hg^byh^(w(7P* zeCw7@#hkDHevZkFGVT|cCG@VT9lZ2Nn0?~h&I*R@gup1CjnV&?-Q4xEMtT-u^>qFG z&R4IVx3>IolHxeJhdJbKkIT#UcIBwQ&2i?%8hN^Yre1Qpin<@a+x!q=8U;R(-k_f< z45t~dNWFB1zU_eH!`2hf_^Qxc;}>3VljhuQ1xQvd{grd&d1|qLV>m2C7s_9~INBr; zIMdYQA|;(#ii&C_Pqecvnjz~LgXiALp}FsWe>eU`Utx`!2q1(YO6NPa*`oF3rDM+o zt}VLu1NH&XqQc34{m1IGVBl?3Jl>P9o17~#CyFIBn7p#!gE%*jRZ>T6_y5dsD7Nq= z6SQ(jZanvBc+RI{oHxlfo9PsbY1o{D;rSK%Z(GTxR--C{#d1Gt7_kTn=359A+?xy; zNw+pVm{~w2_Ni8xBoZkXlF!=zyH(R>+TL>S*bB9P;JodFbRuzNkgK0kIl|i+WLp+^ zJZ;Rnl=aGv)en4bkJVx~$Iy%yTzagaAC=W!5wmhDDyyM6I)6iX_+Y7dag)7JvkLQI zi}1KyRZmyc!k-iAES>z1tTGICPRt+8!-`#&+#?7iclpvo`R^uU-2;8D7A%y%v+*iy ze6;JyICr&D*$Q}THKkAmUwiYRLG=ftH%);&pfCyc4UO>XX)6Aw844W!mOYlWyl zHjQy>gKATxW?qxI&~zlLurlLb%JvbHs{UOSJ;ntG*yK(T9rm)TTm8q&UDyxl@us`y z(L)}aI2drJPb1~QY1$qyj@Ui&@|?9&9mavN3VuTF`U5d`<2wT43%KsKj42=fW5Fr8 zrj%?W)I;sR5LG_fRNB;e)Tpb${sm&k2Z(JborilALNv@X;<1jqb!t--+HC_Lt5#0B zChS%<+_B%}n`` z|NpAZVmF@t_bJ5ipaFJo%RR&+|2GE_U#-Vz6cCl=u?uG={QEO}Cktb&VEO-hx&L!j zEebqLGMii0_c>a-P@;rm;540hlxVPh{cFy&ZpkIIQR3RCRBxH*vJ`| z6{e&l_0nVkH-cx0$SUY}Ej8a8OQTUn2>~@22m$IK^J3%^{BW$Mh7tHdE*6%MlLeLq z=Ebd#fW(S+f+H&K=QrD-c2p!PD@#bqcR_&|4~%ET&PBhaFTG_f-pMMFG$@qplKF|G zQ!(VG>V9v}M!#z{Yjmrvu z07tf@R@{F=;+gzUyQ*NYj6iK=Xdc_1s~oa?UkJjcN?lvrj|t=YcM>)4y5cp#@wG{S zsY2-RYg8hDH+UOh}>IG&gy6=_InSvrkS<0Th-9 zh`&(ga)#ZAh4J0JB>qIw>1yj|^2uG!;VswRGEg)jxrQgy?JfG&_4Sx6U|FAfMSgzO z;(ovb)%G}lrUTw)C7@?Vc?e_L}apP(IuA%eSx3Pr@Hy2Tn z2We)jlsFq28mg)Wy>|~^5NJEzV>@ZICAar3AbL~*gm46)DPz6<`7ld?-YGBY>#t{4 z{a-EYQ7d(nOrcQmK(rn|DTuWgD9dx6S>ol#>M;hdoZhKfANg5n6$T;E-i+uT7t$~# zw-TRk4ULRI3yV&lv&@Le&)YU@mMi|ueeZ!+@D01rl)z2vQ~w^fmoOc~t2_hNX-m(% zd9j(Isi$w2eyCN8i&R!m-$jhPb69F2#s_geJ%c!&YruQ*y3f;-3EY*ENec;%8Y~); ztB-c?%$rncAsaCX;vIC8=GZnF8lRd{SP)<@@l5gZT3<_xfT*Y&;4!%5Yli0lQMIx< zjr>Ian4O&s;N!GpO1zmy*}&eY6E(x9ix2pU@X3f!+@Kyw9r>TxmSk%Ay(mhwWh;kf z5#RoC^r~uVQ;iJSx%xRe7d=m$JbC%@<#~zyDujlR_XcJN3V?~})7P(p)IlANK`B8gKauk=i=h_? z+yBN3wfBw^Belu+%9Ij0I;W1?%Ud zseT7iiA5s?_6rm-wWaJ~!b?vZz5Z(#X@Zm!QY-~pt~*6MEh!QGppOw~*Fw2D6fN@= zcnIkq**ze@fWM4bb_)v=GY^7zU8L>+p)wLy0J~Uy#$t7}HTJoLUIN80i5(g=w6vZ+ zKITNHC-D7RUpgvJOHp85r@V3Ai^=H1(-#ty$}TQKZ<>1anFeKYzChE&A>$qsOiUa$ z32AC()occSl*M48CMWXgq1V{Q#D$DeWNJY+@N{bfxi@Ohc!yALj5R(--7ctS z)(Ka;&cTx&%F4={YMB1#=AUgxEgSS2Qwq}cwd#-BcX@pqv0|X`CNY&+9>817?1`g# z3C) zUO|;ziX)b!lO^&O0mf=3A50U!?vN~_ zK58Y(>Y|{Nh=2ax9WZB+etzZf912pr98}zGk_gTJ^Y}xg(7#QS) zF;k#c4Gj-3*09fD!{2MXE@#kCVJI=*%imvZUE1MzNA^7b^yeYBhXDWI&H0eHoKuKH zkcfvOjQ4DISxrri?>nk=40wq@_Vap$%MyaDLzF~?=+>Zny;DL`?_H#lAPwp5H8Hvg zWc^>lMp8$LB}E=1CPV+*A4t1N#gO;VdZf<@nzuQhj7xlVTl764TAK?1GB6M%$!X`8d5T+| z`o;ZA(hZFTNy{smlc(HwPB@Xz@lgl0o)~-U=e`o4sHqTh<)<$kA@tz_A|lg&hk3Hv zt2Jzk63f!Fo(nPu3X@dgBHv8(?aCew#wL{qwD})>72BB{PS=B!3`ta`mY5|HwJ3%LK?>`Zu zpC7C}VJ1QBfd@ykU8>*Vg8)?9)p}BzMf%;p?5?7^87hH2f`V;s(t!(2TS^u)F0P_{ z)Jc4Ogl`$_#c-LOk~>%4(_ditmIso<^%=JEcJI-6k@f#OqK0%mAV52oF2l`!-s8)`?I+A zg}+d!;YFj4XK-E%@7uX@=lxCYX6EcT-}1-T1F88d|g zOpH8%>-%N&uWi3&sTooxY(TSfV&@+dh7d^gAYC0tII=E<_5K0=$xSD#UDl%1WX1Bt z<9J*fk@X1bWXL~Kx}0M*4|t3!ztaE%$7QJMfwQ!A5<47;)B^&f$$s>?|F?q?h!}i6 z?x1utGc&m^KWk{9!~z00&o3ZgVr)!D)dHxqxuvDniI&SMiSbPAzK;r@*IPFVg8 z;D=DiQmQ0F9s$*FhgJBF=L$@B{yh}VHjMsJ`aKJSrJ#X9H&`1gDypRtLtbT)z=cgU zUoU{uN(0Xbu^HG^4K1xkh-hsXQv3_oVW~rw2Gs~y;}@tmGIH`md=A&Lg=nW3ylIbe zi`(wqtU;r|pW7{Cgl`b+U#a;S z-~&GMAC7|&sS-Tb=U{7NKhC2@p^^+CA|yS#=(Rvb;05*|>}M*Q$iHb{Mk9D$lKWyB9tKih+hFY*%e@>Nc%d}YFjjYAOVNt6JM`)N) z?ZJp=g>u5)p7-EE>+Rd3lYQKA@*&0d(H%R{Ixg_4R7PgGJg_9`G*e(u&;iWy!qPzv z1YEm2RmMOuT|t0?{t%smW6Nz-tt|EJAGDUvSR1~)z!VUk=il&D_mI_&N3%+?Z7l;m z2S5!HNl22OvL_{P^v2S9DTtBNDAB%{P;1}D^kd4aj=%B1;cnN*brH-_@_e1G z5RPbG=kf=a2azKZ=gSPm;V}=x+b7lH{Z*FeWZ7L0qpHM+hSO4a5TP)irV7||)e{p# z{gWhH)M9zMPX1wR3iMDY*h?q~nA%>}8C?8*snDtLRnB|&+oZ@a0j9@(;myK#_g_yK zh=}@DuJw&FpDHFv>U|8PnNUeaWl>O4VvS)E6Vsm?oGA{;r@DMcC^Xayk0j!F6#YHp zZ{I%;IV-`AYD_b`)^G6yh-v*aS%=CYaD7kgo5+k<7FG1RyUU&LDVE<&6=ed5Gx~I^ zcFB6@Q&*Rs0q4pw`!$yP%t!jF{%*w4v8)>J7q)yEP2$!zYrfMo{m43DqvzM@HPiZc zv>qCFmxi7uR$7W`Ts)<)v!righ1}@S6hxTFymw{KH=lSw2g2)B+M)8so-eZG3?{s& zt2Tq2D(-&=FB}r0P9iaZ0#9s*xGk4zC{poaHRsA3 zn6Ycnl}+EAEq3`}m=m3DcZ7Jn)6SWL;NhmPcXBuI76e`W*z8>9vd8&h8~-3epqU+^_H~+ga=Gsd=mZa z)YR!WE>h$E!CJ=^Lk^!@305;^pvdlt@Rcn!y(UUA==Kn*y+F)FfF1z(%YRMqii%kH zQ;CeM9ym~m)e5ohH}LE!TjL!g`hP_yZPs8O z6R@Ojb1Zvn?fN<6ZL;v1_Tych&Xo>=G+8E-Y2B~w{oO7{m`QeqjJ*Hq>J2UF>A>hN z=ZoJfYD7Ezld1v-IIVa`KSY0@@LTh?*Zrg~ygZD@9Y(hk1qVb2wU7n8er@PQmHh4} z4SFeY`m@r95#S*16}N3b>3|V`at_TDH#$h`zN5;Ui{#%Khn}a2Q@9_JsPjhl7oAF| zK$mmn!ii%866!drI!n;-)-&fyXy6>qYRnzK^l&0)RXrx9!Q#7yGG~TT;1eLL&~F@I zrvnWHAH1rM&%=Ny^*_o)k&nzHY+sz%<=k?KHwwxCX6&A#-YIlN>+nz?ba{RC`$3u_ zJ@Oo?ztk0#It+B@8i27K8OyZ9Gr zTH5U;UO!~^K9Rg`Z)d}O^tU7(8-S2{o2c@u*Xo}-S7vS_up8IbKi4ta4!%?*S``%) zB+3$tvW$S*%}UHRJmNa`2hP0?5sZR*8)_1;^mtntSwc`Aa!J@AZoWZUm(t zE<+@$0)}0PplO3fKYijac(LGd4B#8td@OIH^@a22JN^v_e+noI+6fnzNz^V1ii%^W z)Y7(_G7R;0fB2nAKk&f1G?8Q_nuHL7NkEiTRBz#)MhyVnf~@}%Nt$N;{*cN*r5QzxNH)kQhI73aV1n6VN74eEW9z{3mr6a$W09%p$n${refeLlqksHuuRx zR#H+D)4e|8ANTc{zA!T>e>i~~K--R^26IwUW@m2y||V>ITF zhG5i64TS!uPoFj~_C{?1t;SAhaS63nE=|gh+2xT(=dHpqTSNp5@Y;jHaTsxP-h?O3(FzBR@9sZk|1Rv{ zJ)tOI1Ve66ANoP8g(QCo1V4P#7(oHWE_#$zXn$VbwMpf=s(PO%u3{IkL6WSj?Ed`; zTxSAv$Lj)q0ArNJygbO5u==1zi?;|%OOfqIjRiLlWSM%k%6Aucpm4m%$LmC?BEe2a zc{m?MCrV!=)y!I^rNel;)z))R{NsXdoqA*THznVt=|CU#EX^e}+{LKCTt^-) zVjd2+f?s@cGCL0sG-y+!qoXKz=ib+|Jygv|{8;tki10CzP5=gkLb>b3kvn6mwf9R; zuB!V>?!#n!KW54r@!A3J3GUwA6qfCF@~1YGZg81|*lZWfoq1`}6?Z9)Wn9OHJGYT} zX-9>LUH-yH@AW=wi@8B{0qsQ7EOi>URMUaXfYRTBherDLU45=j_XhU}Wai%UuP7FA z*2J0{_gL4M?aNAePQ}{ke1kum-l)j{J4Q<*f9MdQ$HIbzj&u5O-uLd}10#ojnDubm zt1x_n5CyLVLl$y?Z&{Wi4smmHV`|1E9uELlz~I|HTSj);RWY}O_Pgeu3VEpZ*ND<+ zRj2Ro?oLlk&;oWS$B=Fv9Q3Atrws$cHG$JB*?XF0Bh~Gu$JTs{D`|@q2Y+cbtPhl2 z`E$wpukG2tFDt*KUa{d2Ts&oJO8Ca{3Lqk>fmugfTwHhCK5EsCfE^kK1=t8;^n;;` z??F>qPYeF3hvvn=53oTnFvQN;*%^8fxZ1+8koX364sGs!(5$O*?t$f*YHMuuy`7#I zk%f6h47&M3x}mf?@-XxSYCVLvOg(1Dm^%JL&H*+e8|rJ!x(PwC8#z>=fA3FdSST>eB)daqw|PvxmZI+p$yLVqs%2~2!On_VMA^=Y_wH@2qiH}ZuZo)u z8+%nwuN-(pSEZEO*g^wk-0|bbv3^9xshTEeF0Azi&4+H&E!5qoyh9#Bcc~A!Zw#i+ z>v!$EwYLT#2x)lraF){huxAp}P4S*IpL+7>mZnMZQ&UqBM!ue&)9>qlAQ|*uF0ohS zo6gXq(Uy4Pu>P##wr$yMry&<9G1~?|%s9U357P(KQuys7EK+2Y*>}}5*fE7sFY%Qy ziAZsDVY&g-Rem#X_o?hqD&y`V#`*$RwXgh042!@}ul3tQZr7utU_LAsiURTqmk97v zCeO;w(FZU*IY2-Kc!n53X2{U2g0cy|4=lvqERC(_&dnpe+_!7|aNa5Ri!k-5_*YBS{DJUoin=52dRb+l>*dUtkPM7}yAt-w3QuER~ zjg5aXz4i93Te}GeS(UuG@F&NrLAz%a%^nsJRqfBVSP3vSAz;G##m~==+0;in9VtI3 z{hJNM@@9uhQP3t%O6Sd4XSnFwuv>_B5_TBq!-;WwE1}PL zWYS2#r@_(+i2B=y$DF5+-+O|GhMffQA+&S-7{h^R2*(J}sDYWIdwPihOqkmW-8q0X zpd5no@~P9ag@2Bt5F#Y{+qQZ8`kuqgaRBN^51l>M5k&0tW)~pQLjWce_JzhyFhir37D!onM<`2-_p2zNE6G2wAzyP)LSiD73DRZC2>?lq5LZ78?aVy4)AT0L*)O}f^7HuXNG zfHxp`#f>F3*%LCg5E^F8xV^9@s&K<{EGjOJN5(xZJiHBkHr`)!q&=VwYy)74I)FHJ zbyWjWkwH!tw6(57;ZFEIac|JW{rUX^3%e6b1xzz9CH>sUmE&uI=7$!^_Ex%X5&qBs zLm(321A94SR3JCtbj8*_uHXc(s62anTdjguvPo+!8Xb@|OSu@rgamL?3YL(V7`mI^ zVF@ttQ@M;6467kVIDKDUp6SVM1Nt$k+jl#h@jm#b?fNIX8y!-B9gvQZ%U?mWiJBfyJt_+eIT!5$z7oH7h?okY1&0#>PsU?2 z5J8w7FQKqOU59Oml4SkQAM{6}os!>vK;a)uwawGl7fN7U`WHACQ0}3Lx(mtffi%U7 zZ@aqokx0)52H3XT#0aV0-UD)S9OoZS+buvn+tk#AFehsFq@kv!CN(uRF0T6;`4%_n zV;d9u#_tU=9?@jGo0c|$Cx&~dtF49fmiA}}?aqa!qI#*8^;U=Y4KrWq6Yy)G&Ju$h z5y^s>p*nv|H0kzbGpS40fIY1J{(UhZ;BArFR@-MN#o^NHT_#I_FtiH$Y;N!YIr&fg z6xt*UT*5O=1H#Y%Aa+%z^2w zqa$4sWjz8HCSUWt6&5Fx8JP(e?UXWj&BegRwk6^7+}s}wn)*c3ae(cO!XnoN5~SHG z8b(+?M#bj)u$2%r@CM7Ect`(0{VsF94yXyrNX+HArt{9Za@XNYj{sE|85sdhmUV_! z8?j4u?P&EaO*uX}xpy!wB4EOl<{`_4S`~XwTv0&*-UYRziwH|N++hju)XH3hY}Vc( zybA1TfY6JlfKB3g5sF|83wW6aOU!9}EBI$Ox03hn7|?^RXA%b!;!UEK7)E@=igm_I zmw{ThePF;B0RdF48Ov?}lX7x(*bPz!K#4|rdzV3*+SYpRPHKVi7)}P%DoPQW)SL~N zRCyMg5AGAn%{$rH2Jne6#`MVjnIUu6-B%7!5pe@OlsWbrJT6czuN(a(<+jBgT4uY= zG+JqVteaigO?nukq{@rlU<4yd$c_74S*ObFkNO+?PX915F_Cc_d|i4>MpUG>t`0V6 z!aMHu1y^vczi7w0_lguoK@cbnidai=`3n;6z9n!(^?hs=Bb}k22U)NTCsanM!*xkV*?tWTo@forA@w zL~+f5m+OUen+q;-+%Zl10_qlt=>aT{_{7%vTY;`(gByg~?*rH1>fbdL#u#+)uv9x& z{`so(H!>zh{r()>Ki|K-AI3t>aC?`m!grzj!IrpB_qb{~yQ{3v0*9CxC?iHVUPM2? zWji-vV9yfT*x0~J$Dt0ws$qm(3Pvh}J5q)C;-9E?;)mQa;Htw7AT@$vV5dXQF*S?R z9UkjWOG`u6M4*7Gt`0vB2|<6qH<*1~7IxlrPj+~IzTj>_i4?uT4DgFCcC@jK+P&LP zpGU~UribmI0RQuoI646)np)&20s%2AX7zcEz8u{YLdV-;3u17lW;Wx;Rb)H_RdCs- z;IMvV{n%Csm@J|(j7^yP@Cw2SwQO(nP>4H^Hesg$h=60CSInqvz(m;RMn}%T3}Yr5 zRs?Aji2Y8t?QTbGdgrCSs12tJJLY3>vA{Wi>)vuU(bPg%y)P|*hp}b-w6=ssMGrRt z$!i#4DugVWcb&xPx25%fupomU^>cfYJH9cQB`&;}9ngL-wF?Fy`t94HjnD6QeT?@< z3=72nz&PuLm5Ac^7D@QPfn`Ab;IGpqooIdbWWR_e>A=0zl%dEJOC6cBvuVs@ln!-g zkx4%Nx7%dqAN{|kqeWBlTi8?|v1k{e(AKsn&Oz~;e7DYf)Ab?q$2o(itpa#2@T`dJD%P1 z)XoCNrC3cOmc2c8uA?F*CgH<}50)m`^{lov#0#&J z9)7KKF6SZt&OmqmWgDVAa>xvFErb&=#;sx`Al%;`sN9l^A+^BJf?fo4!kbxQ*@Lt> zJPZJ71NR4;eO~oW?OpH8CfncVUggaNwfVBXempI{o=uy9IC@Q1 zUOsN;f#+>)g8clSaC0mg-`@?5l&d>D2h^TDo1CAIohpwJ-F)M$&sv^y4kn0KtUYab z@U-wt`@SbZMm=L5#JEDtJBEc{Lc#-^8MqVsF^LExF;;~D%AXO17sVex7onQk??{Vr z_7iX^qP^$^2#$Ic@w=t?B%ug}z*aRt(2d5NWw)Z@t}g?89r4FC+bv8sU+gy&4102% zMdPupxXv43N2f2aIkl7i@>OTvdlwvj!;tcb^|@w=Gg2It6&1z=-4!g_iHZtp4~(Sw zLF5@u&LjOtAw(K6ckyBQ(-H^^{cn66^PLQY2Zeg5NL)X(ysHPI*i$?j%tiwCE2WmwBr0xkpoR2SG80d{!L z4dK0e_oAe6ui>N%!0IfL zI0?M=rqeIDAu${vIDUpd&&$w*t#{h^TD?}^j3oOSI!Mhp?)0Rju-zg73wTuU@1s9X zzjH@dIIt1D2AXSl&~d&Jr#KT66HrJiSQWM0i)^*rHFmy;k15M$(PEhhArW`DZ(mn` zznS4~wY-G*CAkv?&jcW=TiCNLqiQWI^QCKbUT*F!5OAoRAxbaqhn?jVz!(IkLc7Kd zghQ~(WUJIezo4+eTHPlsJcZows1PweHz&ty{zH26-oD*|+7Ei=%Z^_;Zk*HC2b>dq z8nM$;^q|o|dDlO)>f*RW$`)QoxZU$#Q`{ga@u+x4zHslZ$Se#X-GTW-yLOfKxL_PZ z14>|wvNuvcFZyfmsG@JgR;v%_P3h_BGxndPx+NR@7Z?fMBdbu^cCE?bsFVoYyy@JkKlA}w<&Oy~w zHjr&2I^;0Daz2O`L&zOZor1)Y{TQSw@ZMDXMjcCmznjz17Kjl_44_u9j3(c_ z8B+hDF)*;&wLhK|`$DboF$Ig`-U3|}>LB=8iE|B5mq6C}0H1{V5jn9cJhI|{wE&8+ z%<-j-_B(Cb_4jx#!=HVMijR?V@l8w`4^ZNu+gn^(;vd#9yv31SpZziP%*Xw|GIJRM z-0<_l`q@2%JdH#e#}pA(3I}kg=qR(E{b83rtr1Dpa(irlUhfG}446U9hlyFQ5y83s z9(UJg2!U76wA6aX7(4RfeU!eaNHcrOxpTO;pLec)rLvhS;N#FxEn+TO2=qgeW|ve_ zUZXbyI#%N9u&SFLYt>$Q=o&c698O_$Oh8RgazvHv!#NP2QLmtV2k3w8qfT)@hD=wW zqr%34O>`26AW^JBPY>|F8;FCuS;>WnrE^C?&0R(s0;jiMTJ4a zpg=I}_Nm_9JYj5Uz(MfM0xL0j?5QgffAc1RW>PFbp!e+ga|C^pe)-jLt;85niMp*K zoMzwxfUu+=y0C|j?^;YEP6`LXkB3za2e#@rcd=xXU)eeKI_$BU<91Ds>xhPS0Hy$J zx!%}+`0xgJ0zg$&%PM69Y#^|Z@X`JL9cbL}1~_Zu55N$&4rljhc+N2a&ekyxdrod0 zJ1(F&3GY}`4E;wkp+7pv1PX|7?)3Hbq047$meY33Dl9$git@ZW{GY27auN9O&>5uO zb(x^t!V@F0u<*1ubVGACtWNFAiK$)9RoB` zb|Y&ACG3NLZLB#Is}AQ$MAp~WX9=~}JOBv+Yc@P$_Ow3{r(w#)#@CvPM%@aG`PY!p zEf)8;-Q8t?E{G||AQvQ@pq=rC6Aqi9$S9kNQr?i%5O7E@zZW77BbG549B|P5F6H*^ z+bH+&VNjPMx?nS-hJcCJ7my56bmlj*D*~cJ80b}kQWOKPTd-^;5@C+EOw568+~$!7 zPOlQZ63Iet5dsV$DFDSVb+%K>#Z$DPgtF9#=^@Sk21s zt(B?_ox?X-)U{w!02|{?DhmpnTt&5g(74Vp&J0wkJo$O ztoSWjyuGHF!hjI~&oMv;#lIyQ96-9bcSRW)8T6y@v0>QF>SPbOFDgeAnu0iggNex# zQN(Y&eXC>T5Ncj9a*Y@v1#+UUzTN_+S6swf7b${(M>}#__{E6_%HloNoMih)A!qDC ze*~L2%6uI?Jy@xEF0Uj2?#1o{I0TdN5DHr$8$_#cG*)FtwGIRW0L3r|Jv}-35#Ac< z3C`vK4L6Tg4}&-Wxu5APSbQZv50G=q!LHB|iHo#j&y9DPMOkdm34L7{syIHKCRF7S zd8-T9$CfQy5ItZW#&E(D7!2I!z2BR5w&Wyxp7NOJozR~(9q*SlPxI~2uzDPDkg4Pr z&dothHR$!D{(@T5tI#T);3Q6B!hd``p&Y^lmN$2H?XF>15k!&RM3WqH#a7d(6s%+Lc^=E!EkA>P|;3| zVgNH7JQa49lt^+gsh4}+omuqMz1kYbu`HuHxQs)H@HP=@*JmrcQNu{=1q~A1w1AVb z1eR$ZZf*XgGW`ltR1Hnd4Jw_@f#DbyVOs_>5H8(Q zy7gBX9!9ajJy9=-8rjlv5NHh!y9p^WK?w&s2Klo6zBzUOF6noL7KH~nx=@=Ds9sbS z%61GJK=CAWo4logmz`mhl*!;8t62%A5lt3`ae zvYk2=zCx$#(Co|%aij}I$hh55^DOxwdH8)mEK?pG^8!kXE3jq@tiOMUM%Dijk2K$ujHBSqTmxK6-k3 z>gwu5wy-GsfNcvX;oeK~#8Diy1F+>j$~Wvw6=7R%d0zSG4o7RCQa~{j6coT+)Z^Mv z2fx|xQ~w7e@lS&k0rb5*af|H(sxQdfk;fWuR|T3Sw` z`JJBmh3pSO<(1`$qu$q4Jb=hyxEf$YjEcfJRp)WIlF$xI>Y3&*;+EkR*9ug4I5-04 zKPVOzw#FS;{?w{eDE>uQU<3Fhp85xL&4@In7h|tCX#vRpJHZ$5{b_W9?qz{#&jb(K zFT#qtTZ-=rtmee$`*B1i7=H2MQu7|{)96R@`6l~UnUcX{T{-f{Iwm{P_jPlrv`X~n zZe6x;ysUZ9!<$E$sib*GslS?H>Kg_=i~*OQni@j9K%`XYXPe4fx|HOAA$S8#7gcEI zlbonBgzgY+#&y*TsQQ87^0A&UIv{9Jv}x_=R*7-7bViD;H&~-7n-r?-b+%3?*A$or z*X3+~MOAiP&OpXVEK~Hu^cOvEDNF zwmDog?r&`PcwCsB2NuT*I8mwGBn`tyE@*K z%_SiKj-Z>0U5vx_116zIXI|@}SVp zJ%>XzoY-ZAw%^Kk+n=ZBts!iDRbs3CG+);q*Z)J;cgJJhzwKZ4Wh6U^vNN+c86i8a zBng>CMuu?7m}8@$KBZvT$e*@#@#_QA+8ZxS4&UFhgY(Tz)3`UhP0qXS z4}Z4LY_v(<$YN)od&yCxe($>D2`vd`GnbzWh$@J6Q!3>uqHGE}IE3b({jhC|r9b51 z(ITIwV7HiqROZJS?GJHp8lK;JOZPmNwt;uzyk@yaiOM&LRS8Qb47JhL4u?CVk8y=J zMYd%$qU%3;uulJFX5ZdQc~7(xM0O?S1eVb4{sOWRIFWE*C_5m`*r7G1;Q4l+GPm;= z)nE>#`qL>q2fRb~H0@7+8}h9o=v05+$vyTuvsX9NJQp`84C|@8%S;n(Rpl((clNqc zf5&pz^3?WnwfB5qCY&}uldcVxvp-&$uE#X^<@T?vXLpKrR`9g`CCF|Fe0Xmjg2l(! zw7ru?h2djC$3P$to_G>ud#EdeZ3ti>s3BH`l2hN z>^NYOH^=)e(s<2{wu0SQhw1Voi7zRqLh04MRQ|dC$?C_E$>LwzK5s9GE%PnhBGEsU zzt(IbJGXItoWa85Qs(;rL@-tbGrcjB4eFF|J5SYbG2GeZ&>eWqr#W$yve0<%Bj5%24gDOG3B4>q}csYoyW zCXu&0!ZcKhs`<+g<15j6A%gF|H2+x{M+xmxHla{s`tpzev{KK3E$idfwr#jxIE88p zFAopTmMur_tm$Gbt@at=KhsC{g!EgmMtA09kS>vV^^6h)Yo+O}d5juwgcynHv(xS4 zvN5Du55j;U?N7;s?~KXU-kdBJynC1W>Lp>dAlex#lYD{*&&K;>W{Ye zGRxWg!jI=aT>14P>^&sEKeTT;QorB)t7`3~k=4YH#WYtxzDxFHV$%v9f0tQ2ce_dC zn&hj$DtGCOndT1lrW_mY`S^o&ljz+jBaxcwBdk$ht&WW_-u}=$OL;%-v7;`;Gg{^D z6YuKcK9l(T;Z1<@Lg`gi|V<*_x{Ewb?-!tO;R+Yt!n4 z<|C*BsQGpJ|LPH1D8K!ATc|TJ|M^Da7tBlSHr-mFj1gl<{BM@0jjlbfQ~5MRDYTe; zq4|~QWaCp#lwz{TlaCry8Z*+3sG*h#;cDRNIc;)_DLPuz>lkyPeNCi#o6SyP_DyH` zl_~qwsC+s&O{1^$FzG5zEc$F>X%+To( zGM`i!*}D31cHh?L#U+XoDKV^7b~Ft8uU+KV5&Sb0Z@j-$A~jXC4Lnq_wXVTk z%6ZJja_jvKRzE|arbx{8PI>?A@(?sX4i8`VI~T#SoKP~*Tb!V}Pqiw1mQYwi6N0-1 z5SCZq^x^-{e)%$3F};fBi%|6_0HliLaN1%qPa86T&Jb*&h(1BHrG@ zn&2HLaFK3fg`29NV8%065`Y`R_5--OcYPc<5T?bB(@Cpss9UqXr*w6riMgS0CPd)o z5c_i*1b=w;9&D0I9XX%tLcOH0)sQXPCc5_b&swf?OOC*K2%2Jfn^^0u8hto7CHJ=d zy&MnK{8IyUPkHV$tET06*lnRmodZ&G0E$NNk&`#w86pI@)#SdP(mWc*ykEsLL_pN< z_)3W8{y~>x9yNn~SGEs__>~0?9C*ez`R>n)4_<8-nlyje4m9r!N*l}7-n3ZMozGOw zvc2X{RE0NFe(A>iGcO4_RNMuJd1ONt7gVcJ`>eU6Cc|i8CD|iy(f05D}k|M>rJtZ zz87T|(?_}$UcAo#D6?t6(>!e4*J9RD)9+-oda7S;$$y#aM^cM>5eWF+Ui`T z3=RZv@&_$6%wQSr&t#bcYYp#F=)io#@|v0qab2nD_H}LiS?kEdAzf77ptC}e3ZwaS zbp8OxQ2QVZ#*vv%T?J>DJ#LVoBY#UY7HE#X6 zM@)BBq7~)re>^?I#COLplx9Th-Fe>wE#VLB8uT7!@mL&kv-I<5t(|kZ%03WQmBu_e zF*r2Tb>!@a^s^u8W}n1lM%k85Fx_*}6f-$^QZ&>%)xD*DkKN@l-KX!XsD3N0c?upNCf&D`_D-LG8l)N+|yALH8cyvXE6jQEuz+{}FWY2mDjFcxbb*1_I*yG<;(c zaCUh%F(4nSxGwC_$8zVL!ci}JxpyCbS`o#_vz;-{Ks9Dt69htOZ*Q2+xNuTT511NbKPy19m8Z>l*?>4y|7DC=lye* z>Fl7StmEApa1d~*}jf-LtNFOfk<}Oa4-oi87?ab#^Z|5+VqI z)pQ}G>(yn@&S}zKKp0});Sdy_h-ESP<+G}%DNIdD0~WY%mBt|qSc6?wxDnTtDj=!jZ^{E zZ8Ugob7E)AA;@aP;6rOmK$m+V)r&=kjzKSUGjuR05`-paxESbW;E#}Sj|0&fFmZNt z)W&c`oC#!yR{;gUX?7#Uxb}7*goM#X0$u@T=mkO`_!}zX0AGN%)o++yJ*CWtS)pIV z&N&jI=a5O?h5Yj+xC^uk<}d!59_>YpL#X+|EO~f(7GN?rl+6qR18?3+3N5^YR3Efy9DYX9+!AYtj_6QLq&+HE@N_H63;qADER`01T=jDcZblR z$0)!`TiRT}-pJCMV6TCG5nvm-(2uM^W#c2FfS1R{{Q%Ms^bJtQ(2=}Mi2i{T_iW)S zp%DcDf_PQz+F9&9;;n$!t=-4| zHhZWC;-oz_ zsk#N2?i<(*d%<=9Wcv*KA!%tJpx)U-S+720Y1O<3W8+yh=P)t=b%Ljxh=I+}R>PkV z=oct>D-DFu^xz;xGapb6AsGUg=MrbdcfgUT%*DQf;6yY&HOT#R12o-;Tlnn80{M4B zrR{~!Lm!;Sw}V<#;d2DAB&KZtNIRHEvt6GMdA+uKg~9(WQ(VQi^YY=7|AzB!Eh11Z zAZmzAUwb+03~|u17vZO41rQ*s0q#MDgRQ{I;b;~A$N=yPVpKi0wEk@s;v1yu7z4S3 z0p;MZ50@)pH%yjws(BFwtDr!qc|wNgK882qDE)!@2y{k0!S_9Q5KKH2Ii2mM|1&3l z;CxK3IJN~xZ4R*CdqJXffi*moegLZoYfdQj>3_5Od4GL}P>%3vlLffjHA2A~YYj3S zRAt1%j1n>fJXz0;Pi{|da|6c$+CI?d3jlDH^EnnJkP|I*8!kd12qM$YGCWG{;UJ#_ zuiC!cql6TFO;|WT7}F*V+zo7Op2Ak1T58)csSQw>mU}9D51WP$qjBOFbTV%; zb@Yi7CmJ6=((t|l{N2^&2UsSYXB?0jh}}U{>M(Cu6d0_KKE4k%8xuW$*fC63CkQwg zyJ~gh1U3~vKpFU2|1!o$o`4$m%vd9~#gthI%tZz*Y%+Y=Qig{R?1rr8Q=pva z{0IjK*Pe$u7u?6s?A=!PuuC9erz8UIZ2WNLDh989!TElwUx+vrJP&Qa-l%*kw=bYv zhiVgM9~YaaVWG7@>zz9F7mnF#P8Z$0(8!&JjLpPxho6rG25%<`jJw|)0fW)(DCf6b zo7Y2c%~>qg>8}*o9br27)SfKXmL=1mEaK9zE z4D@z;0H`F6E);ekD!Kd?_$i)l=G-@gWrUbHI^W>Z;XDYXD0J04LSy2&>}>Tk_mq-s zQSSVqBWpMP9k^&pZ-I%{eQVg6&<{yTNgFkmZKnXwW{l$G<` z)6gi)==2Hq4kE0;n)Hqzkm14b{2@p%!L10F`-1(0Q|;?G57W{NHVRJMN9a&@VanQL z)KWM3-+hgPj2q+c?JfE8_R@()94*^Zz2dW#Wkz*N9UIt#Sv+oc#RIHtxN=?z!8XuG~s96lUg; zA&_KrxZqChD6s~06#ftlx*J6HaADo~mjVCH1yJj!7pTX@0;GInUtNVl1$GmGjM=VT zMJhf#B*RidE_3S2)$1R?cZ9G(&g}>AB-bHPgf6^rn6MJ-D)=L}thskV(W8X`Pexlq-1mXS$)<2x2)}P3@$}`*-C=&m)Yxi3{vg z?VV7IP)n6ES+RHf*cijv_chZ?KVaDqM)IY15Gpf7y(xIU;Uh|2#Bs8>hqQO~Eq^=< zhRb0I92^}lW@akjcB01)gQOH8e81cnpdJphgd~*^{>3fU{yuTkY1q=z666wsH7{9t zk(z`Rh1SajScvWTIMj+%`BM7|byf*c@z?R2Boc+i#E^c}R8@Ha3pxGs$pMMv^YaY= z(6&iSo12vAL^BAURhQ?0mO`|S>{qyV9i?p<(9$DqU- zF&<)$z10r0tEbRUin@dr>To#1eD1h~L-&pz>c^$MFpT)IBM<{>!*KIa)cX;s;JdMn&Z?{ zqYaRVSApu(pe+wKw;x2N;lx#U9K;#*-jo*Kf{JWm@SrJzcBukV#1&jjSjv&c&^lSl zFuXBZ0j_?=`MOY0(1Z`-=E3qGfmuhZH^QOBj_K@kS%=$iqe4?wCMqIQiobveXn}Hr zSNj6EtMrXVVyZIknJQ!N7OPv)i7i*?l?xGyUPYXT8mx^v|27#J{_WxFO|J#Tf-z2I z^hSt^ntq#JGRf@Wb42x!-k~Oy+iJiH=1}Snm@Lme^?p3$aLCgW4Sx$DSAo6m2cwR7 z50t5}t9s#+leM17mYa&RVLVQv--ocpFj{zg9Ja#1_KnC7B0YF$%WYvs`INnC0;i4p zm#eA>x%10RvZNo)2Y@z#KY+Sa2;xu-YD1SQURY3W0FXZs5rFju+lj+}#<&!l1+g8} zya-);q6LSE>F>|}(-eMYu^Y_drn-$xLql28e5uaR?*=O-7&6F+6VM`7SWw_M^!2GG zy@n~NZW0snCQaTW4M5QnFwN;#jiH$)Gq=b6H-TgC`AVXMV?4V*Cg|b-t1af-<9c2e zbwVJC(nCFrGTsaYkTRH(%8NnW2q zF~UK8o0UrJ&E##rP3wGa7xRnmRv&aOnN~03#XDeB^#KH>#4t1{k$(V_5gZg$i8nTG zYZ!`SLz;OH47GmTJ(Tri_tnney9mZVcmt<@z28boG!!lqGCfYEclhuX9qIE6t*_F#y&wQ`~Cx4mdXwU>FjdJ5yKBc33$ zPy(NbejT6h`0YhFl8;ED5Z6K)NOnA4+4)Ztm-R7HW!6%A9u5R#?CG%Iu2`Z-X!)+& z#M7hLeO#H~E~Zhu*lWND?2I?|o12+=eOb|#<4dJTxZngLW(|Sn9q2mK zIL(A&0GeNPy$3}d-i@^Bf1Y4v=I_`C4-U=3&qU|f^>Nr>NW6_)i+{GY>s*RcRvu05 zoafct-U6*VC@kVnD}u;q0ImrCGfVlfck`vERnk zoC{c%KPY8E1LGLnnD55G3z?HAc^#r`5mumtzlPxVB!F3%ryPv(fHwrU=kau4mO=|V zH#?j<($_p9+XZO__QTTLJPfkzfL{H^=uzMmi*x5z|6_sOd3NLFt4j?5U;98%AUJJV z-{w1yzB-j#Cis326HPNB0D`rTyas+3Vc2m5tov}vh?(ISHNtmp+uf;XLOu~N&mE+a zMAU&1L`dF1{u8f?T^l)JwBI3E2pOt3)XZQr7&-!p{B3*0uaS72!)hM?n*2z;hcN7B z37b*l(ZylNujtVkvwl18H8_3d0Jg(*n|TKK`O`aK{~%OS4BOX)=mb=PDvnL`2h z8JQuvSNuViA%@!h7q14}&#UgAnKdRD}5S1X!xsHzrmn4%-L$vOjqpTuU%KsfY|3-q)Cn#+mA2m@Qxk70!pM z)p9=1?9y7S2cHR)zM^Y~mBS;Jd)0`Tzo$p^!hXzag9Rm&q!30DZ9OU~-w?}b;9(`Z z;rsi`^^?N+s+F$z<$_cdw2vVYRvEbKX+#OwtdjJBsrW<~soV0Jdt|pJ9IHJ&DB)pL zJKuoBv=dnc!m+h)7z%shH9=vMf|Mzh@vuQrtpULeC#obUalsj%J$H_Cg2ae=1L+0Igtk0*3duPKR zP!ZjDctIby&UvD*8XNEtl~3>fG$}s^c5~SsyDPK5V7)gZp27B_&2|MQiqd|~B`!&K zK*O&i3`hTZ^REw3fJB-JVaac(uT+W*iMl-@DH8M5wD>|7Zw+6Eq9o2WkaiqMC!*>h zduXezMecyc*jU20ixmN+DojTN^6(90l73(#XaM*N4hkHkGn^H|n`=nr;jhYi9fzA> zw6`HDhPRe3Cvqd8UBr#xS~9V000{?)I__@93)<`wf4uaIb7%&$1PAIeVmnv>yrnbZ z3iQne!NDl|?S5WS%v3%Mp0$9|JPQ9wRT0A&sphKeUqo#|$_Yr1MnKv9P- z2DT#!CFpJ4mo(6^1J{qi5Yt%R+kwyE#gOe?1bAcgn@I?3NnkKHu(IeUs|#skNqD6E zgJJ%{Sr-u{TR3e*YpB5zh6#-fPcb6(;{>eTZ$$Cy{r6_lN^Q`6tKNsMTWC(4gcK;| zZ0K+?#Tk@*da%}9RfSkSxly_+uBH7#1QI!TDJ;mPt4H|{A(cZg07&NgJd(FtSUFg< ze9e%Edz?jErBQQ^4f}K{h_M5;*!N$>leGK>b#JiFN+T^_|T?^9WG%#G9o050`$2tk?NE0F#iafIxFIz90O&J{0qCD8XO9TE?JS zz$~UCJr~r{c_{TS5bdA9YH$Dh!~IH^xkd}Z3&POXYS?D&n=CYzr=302zlb>IK451I zqrtbrdl5-ZgnN;%DqZ}~107uvVFi{ZCX7meM*yo43@tvUg}2mxVz#Ym1Ud#OnvaND zi;L02Lyzqz>>`Axzz=-c7RjN;V~A)Kt<|GiuK2C#~`$-gUiK)+T@%+#)9sBeBl8h}xgzJB*j z+y-a$+3ek5YZ8P_NG2n=bA%;)arAMn`p(BFLp0%d*fK|T*P{{bK7tBdn6iTF_uifd zAcFZ!3%Ck5fFa`VgSB`DD(kO7WGo27BVglTIfxbP`_)bN1X-@+unjtg>R&wd`U*&< zWR|&F3V`78ZpljGh>SV<{DGz}n)P**l+J!&hHF|u*tb<}t9uXZ4bhl{bbjGx2N1vK zV5cDzvMpm}$I9q{zz3`z45Sz-I;3;hD{zPJB0jx#Ev40f5OzV3gY!yc!cx>lAusmf z`aks0e+^{m5zksR8tQT;%MV-Slx4Zr_$q(va^cqcb@kIKQVL*`mF)|tlF0DXiS^w( zt;kS1DBztAKY>Ul?Ti-z042Cb81*kVBP0Yxq7Wt$7M*BqtG?qc*TJg<|Akm;#GoKi z9h$8!?~jeOe}KEf$c2URH%mVtTSxTX0P7hE3x&x*)~5wG3?CiVzVQ$X+9zP_k6r)y z{lS_OUIWCqajlnDrpoWprqu{X372Yf?AS4+yAb>QjGJ6Jk>TkVdDH&d-Mc3ct>HHL zBW84Veg$x8htY4}Orqg#9dKWSJ+SUX_Y?fn=Jbvj&v_7Ujv`ptf}9!|3ojHTA&~5O z19s^F5&2>;9*>;!MBSl&&RyC!fn3A5Ju_S(W1;%-x5K1hI9(IKo>v&qKt#9{<*%GD zQgh&Gz+MHS@{zOGSp!^h#BW_zJP#i1AGF`OmfA556qjHxn^gj0TE{~MGiZKFfG6P5 z;_%717rnFX5n9#P;aXdn<;tG*<1hc-JWu1_9&yCGf4RaUKL|NA;SyozVS4RrJ(Bze zPiRAc)+#6mEN~k+mT~tRNRg4yZz`+7H(+t&`fK3*?r5{x_We_Ol>z~&{fm! zg3U<{MNLaFyTT_cs};if^yBP43a$iQd;Dwkp3L2IwpJg-FtL6wTk~YwC1nV`rw8Hck&S`C}Tf1|6F^r&;qgVqka3%XB zaM~Mp-<)yDS$rhXc(yFDx7K|0!nGTv-`><24K7I7ZqpoYcI)8(B_k=kzjmU1>+aeE z`)eNO%1aLSt=tG6nG!VqbaT&_h1K`>bg07IzA|YvRaR8cuQxj2%J8aqm*l$E-~g7# zxw~b)BI_h93mOZMMU59VPqfjZV(dG{StIoEfkvWD3!`Q$ z#E9_^p$5eihm`ds7(b)NuZph8VpRXG(yMH5kgxUi_cO2_{Zksi@@mWDK>khsJI`hm z#V5y0#+ zp=fdc*N3a#g6o>+0!F8pUnmuCRV`=m-ei&MRu^aN#fDbD)lsozfup{!c}~U!T^ey0 zzBJ#UY(MJpM^x7S<86Hy4eQTCwnu;hf)OrpM4mI}4y&svoS~soS?`G^f zFiI}14Re?$YzSg}0)%37L-7Gdp`giv)d2IB>0UjpJ$$oH%d$&Z)>IO;9UQt838H~T4#?O|=QGH1G)>P^{7Wz4DjzQILEpOU29JCuBE z$GPoZy5`C9_esJ}N}MLFIjA)q0!q(cQPr=Nk&Eaqv}k4cH6W|^B!6S+QwbeHwHI?Y zH!{T`=G8=v7@lq987o_7Ld&1C8iGJyoC64a3d1SP&CSuf@|h6f1jYY0Q>^Cr773FG zvf7VpLVag6`Q>Q{i@cu4oufCY=}+fyA9)sk zeV)E)TeVF61vlQ#b;b;$>|X1VjRpr^zmu=2+JAk6%SieV zDJLt-4Vs(lx!rEM%SEuS>njU-f6-ey!|FNTi>d-|<i2$k8}k-?K*j+dyfM`n zFv2px`ePrSb$!$tI1noWJl*b<1kFX{lb-Dh)i!isT$cfK1e3Z8B zyp!NG70oHz`{#vUmYsb4LUDZUDeDy@^1{&}Ry9ACp|89A{Erteo=NC_muXP9|G_bC zw_yo8iFP*ysVslyqixfH!y$2OuLJV>&ipQ}vJDJ)A3)wvd~7;DH$BrtbaOf;^vq$K zmD&kl3c0AggTwid@6nN!8^7(soW_N%!3WgSl)wl@nVm8l2|OMqd@v~AU+n5ORylNV zh;o$dH_x^_urGy7%gVztrdJAm4HmsSHUz}X=JmJL&I@7&m za}Amev}Xzix&}68t&|SFdf{R;>3K*~OMGB2ZR*)zGiAl`7lQ2O?xi~G`j;{Bkm&i9 z4hFXRjNfk&Is+tIyS!cC!v!>sB`&29%Dt0%7+C)`VRev)Let0fOCU zb9gIrbHT=Vjf=rdM+Uc48TEikfJPCFm~@-`jvOu&V8ggZJI`~*c9)t4X15*sz6mT+ z*Ne$Fql8u0zBRK4zSyfY(y7YRX1p|7B>rQ^$eo9{Q6EfYdjq#mKrj8b*P4R}J6-fhgu7%VVh#N!Me?rEDhsrCx>$eqe$lo0 zxcTOFs@XR$qL;j9+hbiCmzr-juf9q@_M4G4^4NDKYW9y^z|WQgKG}V^PoF^s~q69*S!_)_d8&grLUknz9kKyLD<4 z4|l5^HK`FI*}Vk34YU|2Dq?IHK*)&$U9;vDQu{Z5EiF7csYcT3;kHD{%`OP)2#8BT zTuqH=7zAcC2NZCi!(_-+0&^BXE1{Y(OBM2?^HE#>s`LjYN-nt2mza(Vg5&9!CJ6Wg( zxEX~Dj;ztZkwi?3XKpMlj^a;vA(nlMn);@FqB``>5xhPRc?nYjMCaB-P=ejK>OB1; z{*=FrQ7JPm_UzRmps^eP;txI+AXZPzW(Q(^Q>@On-R8Eu62sxrmcPeA3Bah%r3iv^ zf+z%wzS*dWzK#-Ds=%#bH5k94ZMX@wVh{}~6~s{(1$0Lse~Sm6h&@52#5L-;2S?95 zw}tg>)bCK+4MkNHH3L9Hn-$z1H<$NI=G)&J2#D8+%;?CpoLLNYhU|e^wf)UY;GO{Q zF*P@zNB=176LS=`UH$&R6XmyDq?Bx3v+UZ5DJ!5zq$r@|^o5`XsQP*>KN;^yZCq@# z6;*!m^z8y7bp?zAG=x^iQ-THuI@G=m^cQ}fRRKW=czb~F)6HgSyTndn+|@GT;SeB~ zly3C)eO(wmo7?x)EBp7XgurdtCcizxkNE9hS~oSLeC$57EFe}E6s4Z1#r)f+1ox<6mh;jHM>9Y{KLNoV|L}})rB7gk1q<^<+C&XK z-^u1C6bw*$D9I*ftRd@wtQH9sD97RQ!j1gq8!K9AH(U1Nx>J!HL!R%!1sZ9l6N>(J zf;V0xmU&a(rF(0it)3ro8GbxNO)!-vFwg->bm5#v+HP=33*?3JYqr}z>d3u3o9n^K z;h`+fTo|I<-P+hC|@aL3Z$#&KvE1 z`P9pntgo29x@q?kb^0*}tYQF|#N)c74vVu=#X+SYm7hotyOwfVV7`eby#qsjtZi*Q zq{RZJ<$20&Wq6MAcZ9sGtyR2ltv&z2^JE>2k1p`3{w`Nu z_-k}ZvoJ4x?36)Q`#TMt(BDfP>`T|``huL!T|1^4``YD+cI~s#BR40X@PJv1*J$(0 zp7>CDEzkG9yJY7z=l|vcti(|kM(&D8{oLa^Hh8^yk@2%!D}UqPgL@a1MO)=6KfF$j zFTH(sK$UZ}+shjH4Jjili@Gc8jq+8yly0VOlQX%8L~z-5%3s@aipHJAlAdiOX@;bI zaMFp?zwFgzJ~~pR>O>cQYcaR+%0Vgm@fL}w&&`{d8rvS~lsOuORfkA$)o!emK2gK; zqD<_O05Oz5?Q@8vTFViMsiOU*b(yiF=ZZI2i*hKmXB_?1;(T{N&0)^s#fhF45ng4_ zqM;LBG|P8a6>cYFl&2|k&rX$;4AQ^Ne5EyFti4HNmsz^=>#UT2Aomr<>rP%-Q?ty= z=FA7oY7N#xobFK9KKiq8G+u+3R;^KjKAop`CFEmlPqV$H(LL$QA~w&%hC`$u8V#-N z`fy$KSoUdXR;7*nJbz*8`!yulLz*vdCW|lEF_Yab5F^pWE~;|ZP_+nTUH-9TEy-O! zHTueHvg?~}y2HZ3s&xUyO{8%#2}2G0{AHJ-^$P;qyC1M)-Bf*BR{d699+-I_^^-e) zum7IFn%6zo(J(Rd`N=^KE1MI~-0nv$(%25PtrWRTRz7u=BNb=A$#s>wyJb)$ z1Q^yk?$rY)4UQD+D)h8G{2oC9cc5iM9NSmT)QpzCE<6gq9=|_z{OD<~*KgF*UO4zH zs;9BFE;k|s$lH`~`7YJVK$4!1WzaUv>)V{}Qw^Aw>S2h}xYMG@BmMv{mS+wL20~c@ z6f+@O;W0ls%5evuS7c%_@rXI>li#bKTS*$_o&^~P<1wP}H_CfGT~JR`Xy-Hbauo<~ zm1p4o;7u`ew~*ix)+)^AU>C_Gr{=8?CC*!)zfyIOxJmn zcgB#+o@7}6f?_6FzIYKJE!fvWYp%|_l(-p9wdT*5PK$oi>tFVDlpqcV&Ztzu!_sfc zp6r6dB8nyO0NnJ8awBcQGCZYL_7sX+?~@t1t+Ck3#>RuJ^o4Uar%21wxqZ(z#q4A9Q|9`U6rqwI zqsB|W>RiJ)Hm7V=+wflt3&2CTY_wC`VBYsja-CJ6hi+7vO8P&+9@t~zYUOZMt1xQ& z7+1(^U${D;8Nlb>8IktyTK>B<7Ulc{-=F&0z0Yjwb6EU$4&-|>nJRza2WS|`w~u_8 zwGEKrNV0!mIT+^P)9u(_&IeEnUWIt%-AN3=l2no1=gy|4g)2VsJX$WVt@`HQjs9mU zD!#l~JyrAg-dt#Q$@Z$HcMmYqYQpi~75--%E;phyxr%^8(kSh`=t|XL>ZX?NM!>&E zkN)q!gy`Er5fw;Hwc|Yw_8iJhdkeGotIce}o72(KSqsiSu>R3oKIc+j5DUZm*2Ew? zxz`21Wjz4STRqT5jkIa?zMCDJeNrT)phiwio0FE3l9H8GX-7E{uHIi7AFQa=PijGh zW%~E;@R6p)Wj$pZcE# z^{m7QAFh}=b=EG8jzAm;{)Ac|YCR+imnqc$%+bG-n`d@LL7bnp2ynLnxx0$7>*Vov zUa7cqg@r&%!pgH{PZFwP|4s!S>&v=#l*84iRT<`d>V}H~z==0VR9x1LHEQ#&- zkL|KOma2B*vy0+nroehqio)$<1WAcK^U}z@d&C3&*QS{YDLDa2#$qs&Y$c;&FTQXf zqj3sT=}7iX|FPcx**!%A=W_;$Ky3HJ)(toeC6`!}*>`Ea7d=@y7kc}b#{YgBhSAv+ z1;CgNK3M^_oN}AfcMR(8Cckdjw*Q~`ew!G}T%ZI4sDU8JT7s5@dx@*0K?^UL!y(ah zMgc4mLbHIkg3=P#x1Q|VLY%-L!O?>$-cK*Z$sRkDl1U-zxjiQ-X1D+2HU9IIlxduV z=$>E#|Aw)({rVf}apf1rhYJ6k#nGA8ZG@=SPO`^kk+odNtK{YyhpN2KL9T_dG`r1A zzb$F^yUP*Fh@ZXfJOk~k7U1U^6#8IE$*wamG&z!#{U`FAHyD7{R*d4K=vvh;4I+s6 zuVp`)Ay1+wk)8~upUsnCD;Z7;5iF?+Gi>sOLvi~T(lZxIx~!fM zTbsjp?5PLu+ktJ_Hq^f~KT0rIN7@Neu|!gHDVtCo)}y^l5*3uYe0sNZX{G`7!`$lq z(A23vLYjJTK-T}&wa|&=gb6mar=QLXc+)&Pqd}D@NEgkf`Lsu2rzW*ywT;xoGCQ8| z?Rq&P6V`iJhd?0VgaiX=rv}M|jnh4=xLoCMseYuj;GUm3YPug+y_BgVInwk+^j=gs zmzp`m+g>vM#)tA7m*5V6lSpN+6yuZY?~LEj{?&X$nVOo+MqNfL6ibTnB0W5K*~ZNJ z`0O}Tm;Rl@9-CA>HVJP*112FF&g3?IYO=^fHN|)~n%7Yld|&mbzfAY*npqo*@XBwG zrlR_CF>Oxj^~F%*`_D}HnyBfs1F~(+)F<2?d?CB=GsI1oQggXHWcW-9mmj0b&XCcM za#1d(l8^r6MXWzzg?9eo6@ADXBf&;XO_qElDHJo4;O)ppouYrhN6uA5NQqJR??h=v zaV#}yIFOx+H7$$tlRQ>KH z`iDw=UJ<^x-1~IyoK@f>m0A4Yq!v8avRd7q?PXmoqHk)=AzDnm7@2E*kd!kYODao` zBsb4(oDRJ3&ty|2Ky5Z}N5x0wXc3Z1G@F5jRQ=nIOUTAmW+cAqygw%?R94ESzsi(N zD=(qm)h%b>$zf2EF&9eG^X$D^R<5n^LBYhXE5>7@biSea)6vpD4q;5RBzH$PNmSAItp*2hL)4Hvz@Rsq$HRb1V z@?Iqo8Lg4Z4ke@|=BsmSDo=8M#L);W_&PDHhUHKS=OoL08EM^9KCPzfDhsQqsPLs` z%?vs0R?+UWTDkflmz_FQ!HZukPC8unVpZY^dgnYvm24hyl{phx5{c!+_JDZG|7@y? z*`-hBdxatu==JO@%@uAAx<8VtbTIBsj6PwzX&2MZZZ^uk4N;NNTTZ{XF_Gsh=kOxY zGG%;i&|jD5Z++j2+%h1&a^v@px^x3CL!p!`3SY`%Vwg{NI5h6S`-^w!k6U#445 z8!A)GzUE{rZhLcISW?G0B~4wD$&J*UWqXr7CBrt%ddadEt4TzWZ@uVosc(jG446F5 zSZWz44!`mcpJCbTP|Un4Ct%&_Wj+r|-=+Ko%nL(?qt) z?TtI{%39b=!$}|Tkjy5S%HB@LLKPp&X!_x%-W67=l&OZ=|5@t8E7#J$H@cDPGbBiD zucYK9=dDSHj?Z+QIZ-CB&E_CZy-3o##3qrG`6AaMu*_|;j}U46&(YLWDP#+?*djrS zQ=qot<=UQiH@A?DTAux@s5Qxq^eFxJ3F|F3ydvQl^z5-D%+=wE?2c^pIM1D9vMM4! zny_!0xMBZw$VvJgx0`r6+Q~cgk4vybvS)k5*$qCJV<*Lyq!0btUu^hG+UO@^OxIC1 z!SB~Tojq-Nrf){!^!slS%{C-~(d@8vlE^yVlLBJVu`^mmt;4&-J>`mZ&dZYpsVDEx z6(oIsGR2-Ua#Z}Q1l2?5urC(!OB17+kOTS|6>)Wo*u9vUr5n^OU8sTBl*q-mbxaF&vSZ zT-6#W{Y)EeND^V=mo3W_EMuom5wUPtlsR>}oVM)uH)9j;6hle&6nP2K+4JpWJ^9GA z7}H8ESCYb#Y|HH5{wAwaWnSgxUmli?TZ^iQnvgQc*YzoO^dx;gl1PLI`$Gv4v1q-d zR<%fDyz4`gY~x7LR3_u%Y>BSq0kS)-6PFZi2QTe=^B8J6UeW+Hm)WoyNBP!N(|7zL z?CW@G8T6!Ry&sbGsG5~EFZ*Yg$cTt$N%mP}(Ue+fiaE^fJIusns6;KwYch7rnwL#N zeo0@?J@y%OJ&8;3p@d-vFJm#C%Ox$^=~0U*_ER5k)H;$Jyd$zG? znG&g31ohApA}eHVsw}I>Ixld}{3pFS*W4KYAsr>0M`K(}F08S9TtdgII6*}+ zN#fJ{D5mkfnb!T*(5utzUcEbA3=IU&MynV|Oq9ln8c^oN*GC&rk8*I<+EKszqIvj0 zX*Q#oOlJ7{kJSyc&7lEVvZW~|^}3OEVXP)w*hNch#@-|*sfqel=Xr(7+l7dbB1h*o z&B|R|S-VT8-#%#gtkRDqCYpnKqwDVK0QP?gIB}7C^o>cH)G3PXCX41YBqsfh4Ax$+ zy@aS*6pW*9lpDLoW@fONL>f?w_nyg+4~PM>*x=0!_bsS5T0F9}i!C}{Q z^U7=!*7Gi&Sr)c7B3Jo-els;=V=|y2Mbj(0@JFQ?GO3FyiHkOAdJfhe(&J5{klI8K zb5Y0XXH)BmDQ-6t;mAs|ir?<@Qc^6>!@u+K(ycOctC8;R(TA}rCMAaYZ89kq^k2oe zDr;8MG=03IyR2e#<1$RyFK}IrksK3kg<~Z;m{a%*AI+~Kyu4RjGdj~D2*8a1O zhZKJ9{Y}H;LKxJ4A^UDqHhMN|(j`3D;@~gmt(Pjp=}3_?s+ZYVG);IkY^5&y&uo^= z49GDgk#fSb$m>P?D(HT2NW@!i3}BI%c%n5xmN$@6rp~xDW-Ut7Ps@9mGn&cJU>m(* znu)`u6q1Og@Fb&|2$i)c^<1!U*8`TvYEm@a8RiFD6L%gs9BYv+XmNLEciDMMj|x)> z5&g@?dXcu`uidVEH@RoXDS6gw1I;t)_=`qDuC^AjBVuw%1`I9M)O(bvACl-y%`9&w zhiSW1i&rklm~t0n3>K#d3vBvv%;Z-opWbCQu4wAdWrSq$fBYbdXDXW`P3<3XoR?vj z7tfH{9+d7=L<$ysJ#{XCi^bqZhImWyJxMCcn|0nI%$)6a4WDiNV@gsV%XF!K)+Ky6 zTdR%4BqFxQ;jFMw*gF3JNb*F~WReXh9R%tI#KC=P3}HWvFyW6#)!u|m?XdGfLqL}j_oXH@Vi zG3Xs;H1;CN#=TlzSJioIP+ymQl|j)ukLucx*WiLNy{3@0o1$DftzWEAzd22n7)e6! za-7A9Flu35n&NtC8?(Bt(&FO#8TG{$JUo24s>)ScoeNFxhEN_+@(q-eI5{P-2c_K6 zDbl0?2R_9hsj`|KlD(TH^DX=ipB6N|yqiN-COXuy)1|7jhmj;vFK76sp0i6Q^$(-9 z376(JYC8GU92~4o@B7~i<+C_dM2_rM-t&( zgsi1RY^CmZNt?s8u>s6i9;QhRWo?*}S|oGcf}L(=D;= zi4w7F)ay)Dru$X=G%MTx-(W_Ix=@`L-)GSLc8vA=`4Du*M|>82Iw~g zy8f<7VeH@C%zla-{Mbd}V`VX|A&qf^;=xPC@9!qAc5e{!j?J#hw&~tGNX|47axY_J zC4bf96T1~GPut8?BCSJ?nfBrui;XRfWp)r&FEl*B==acTV{{@j`)e(ZoKGbgY3sdc zf6#}^W^?M>QX3ek(~C*XmgtM6W^a$=x*jd>wNu|d(!E|!OkZMPFs??Cvay7XKh-s$ zjE7ZoN;)OEh9xGGNnpU3cSb7?7EgoEh3Kl^Sv<1iabAYAx~#Y;rqHrQIbL8mX+o#rnI{5@(E5+IHfMumi+Tn{#?WL zB^xOd)1)7Thk~`aOsV#^xj8$o3T7)vu$4^df`wl-6Ld(Py&l()8=c(yY6 zs_LJwoy(kZ4?f79K0F~Wt1`3cMtzwmMMbvama@U+481D8q=m$f6tgOmoHtHdt?vho zWJwWno4*614iq&k6?>gQ6G`D+_ikfK{@qQipI$iI)b}K}@$IR;oLYBXU3Dq0OZL3V zhm%&TQfboKi=htj*_nsW&BeuLx9Y#%h)DaaMkSzG8r@VqKwE4cBc{2Fu{dLMzet^WA zP=y<1BkLrE{+#gL+L>X?DzU*PHk&iOO>dK!k;BNhrwogw>-Su>P0eY~34TO*>>gIV z^OB61-|mSGnZat=)COMFnC9y}vG#pfdhOG#@z7L)Z``O+@Q6wi_Sv&+fp`=!aSqNArC9N6VUyyr_@|L_}}o801)IjJ|l zX^h+-Wd^w+RLi)i;jzY6VG>(xvOQf&j@+*c zsehZr$>v`Zg@qN2Yx{W5ikgb_Djv$;@mi}exv^*C-R88!nnOt!J-zQMak!J*=vD3b zlIlz{BSf!@ay4HusA*T;wC<3MlGdSt$n-du#Lkd@#&e!yBKnf$&%&bmrXhs1} z6{(W!MIh7(Uj;&=IN>pEN%4BE^te2wCk1q|N6YARGUl*%t>S46+|A=J!1WgFZgP9Z zOG0}ko!Xf}jw7%9Zq80d8;Cr!mb~#pEix>|7*21q)_N%x92|Y;M@JUwIwC}G zr&v4nw3BW1hu{%<5L*ogrY^XkTL<=ttt%4aQe`SKzH%Xay&!xS z&lBtf@c;vlHCH@J-+xH%@}jcmdHo)AcDUE08-c{uA5{{y?&DPSzg%c~D=Uaq!!*VE z&`(8Q!$d=>Jq?~irx|IlJ~iayIEfFw0M| z8P~Wcrs2g8%p|P4E%B8{?h8TFWvVk*)5Sxq*^=pNdMK@k6FGA#a&7V4b78A8_c2rP z6CQJ#&P7+c+AtBDnHWnWv5)X{QUs!#pYzynY!>1{Hx$;waYkLO)Rz{boaK4d-@&Fc zIh+nt4B@286Ye%|>xkc4Mh+ZUE=a}2MZ?4`KPs7bAmZFe@oMtA#-tfTTBV0Ml62ZA zKZT>2aPar)1-DP+J7f_YeXehBxT}wlW3Z6-yAotjtZpflupEU^_^MR$5Zfm#CDTUt zn^$9N9w)U?g!IFbmvQ3DB+W+MDG_>n{9i)qUYoGh_41XO2NDVi7@+Bvi90G`NSN2L zJmq~XkF>BUee_fvSRJZ*zrbHrZsKd)f6oFO*8CcmMYqQAV`gu70^pN63<_{4zm!#m z1qV@ygUvu!lfak9^+Q?`*b!mCtzDXJZ%}Q3Zu4$f>V$GPKEK)U*XkJm`5^tLuI|i!HrBY!6N9t? zN6W@S2U{fuHMGagPu}-ux~yC>yf^7Kwcvy+ND<1xf}p|&9~Q12PR`zZReZ>6m%;1T zDSr^lzj|tB#UwVj`nHe8nP&nt+R24bHK88*z+*i z?WELm{p|B5$*0#qB+C8p*DXt`@5a$7nKgVrL~pisxHd)oe_+w-|JlDH5SrRuJ2WHD zs9Wo{x$@Jtl0s8-`5N;;r20Hskk;3F;CNehQ1Eo@$*zI>Y2y!ljbw~3u2Yr|Jv{u+ zJGh4$t8`5H{dY1nV}-UtpHwq_Voj>MPG>1d8VP)#q;XMi-_}x;1 zk$sVnGj{K5UrDOy<#%ySrlBV$IL=!VTZLsl+1{5mSXpzLl#X__Yd;V6YJRaf?#thb zO&4y*X}&yvTPu3J_1ku``g6*{4{dhGXARz8BT|oPxw;r5?eRpKY&JzNm)@7uIzEcx zIH(8W{Eky1RepzN?=v{Y=5Z^dkY^fo(<;mZ*<%k-e{IYgFAtxI<1GLmvN zIP~%(DnIZaVPm>Sy9b=+%@}*S`PBxy57u67y`LS3@LSm$Wj-O;>Uljt*y1rctJ>ID zqZp2@Tk))EIe8rHGy3nK_puToISDtv6}!bAttDL0`fp)*h)yYID&Cp#*u7r&>+@*( z(^;_U-}*8w?y(1MZNTNyt89^jpDVp5M<>F67JHA&GgEyp%^cogbjp}HHu;>XW_iB! zAVU-^EX>K$=(jj*zaM()e*SZvDZZO7dSV6f^J44ZMD$QCot*Xf*eA86(xRO<+hZ_D z{(&{`@;HJ2%Sp3`I`Vn(h0)^`jrA7eZ$4U0%EpLVYLqPZG*;T4`iRz9Ef?B%KK3Qb z_P1GnYpeUCz$(LiEFQDXx&l^^q;Y32N#g~r?rObJNa%Ss?$WUE#Y*Rp-=^bhAzJHC z9azLQ9TPfb6gMV+Y(_PcRF+5WzQs_B`s|09tx)-1V-05foR5lnXgsrj;Irem_HC7U zNXV(m*5PN3Ef6_L^*<+3TxnuY{$fA5RwjD-Ya`h<=8f?C^iL=@5#V!v~zaa+Iei5hXguIo)PKa32LR_`lK&F8GPGfq>M49liAGfAlM}1~q z=8-`SxDRCZQh+{aD@OZa_T0xmUkNh2&lA4MC*ak}W_vq)lROc1`Y!hS6G==L1V%*& zX)^1{ZCY6R=CVR_Iqz7vtx0>e)`g$B-qFG%B%w4U+;E;XM=PPaDT#BO< zX7GEKKaN#Aod-HeR%nlMTn00^===Qq=gm}w_FK&iVg!A^igU}R8P7ky{O(c``^IA| z;9{W%-LI#;MCazzIN<#2t%sIb{!b|rCTq5yUSBFE7AjqBq+3ym*n0mM&~3Wz^a!~A zo*645yc*b}X`no$jq%a@w=LGoKLP&7jgnR>wA)cXZ>ADOeGco^9~z%8<+igehCI|M z_dhyP4cPlMN=`f9oe-aUvEVWU?y93}hM%WURYQo3jBYkk@a|q8sy2VIo}hw%D?IKL zbO8Em70q|>MSq&iLXGbKCtkEfP}Lo;u?TEr^Ao-_?ligUR~9a8Iu}GM{OgMurh)TN zx%_~#hb@(LyJzT3T86C~}J=6Cd65 z7Wnm3^ons9x=q^6I`uDx(Fz~si_a@ZIa;_LQ@(eV?OUB}^qp!0k3159;3fD^^>wd$>R}dXkJ;ZPJhK-pb;IKc( zjhk7w!Q-<>^cU;_;NV+#DC?F;0C%xd>t~a_0=Eq{mzk#XNXwkpWM`QH^Uzy##@XD& z;0&MhB3Zm6)u?4g$yHYU{pp>T%k_AxZ2Th^FSjRVWm%t`t&zkiK2^?M)wf-Ae$Qqg z%2j3hyEE){>LGS;s%15hj)wOKTUrvxowqm*)2hCQT6^@Y&4+?RJE(N+=%NSyHn-vM zqh#}8(Lq9Szf!%;N%z3Xqpq>cfUiX^=XX0}m8iB3W{1DFckk`!&Q0wHTyD=xWBxI* zN0>uz{mB!2y>p3;MdQ6kKd@?icCET|ajn`;6wxnoG-XEKpOHoUZJ}o*YjCeVx`MjW z$-($xPrW^M0f~_3{`aVy&U#(r6GlXa06K0UDPBSj!^)uFWzTzFyIGOvU-OG`4Z>yd z)A*lvCiOszRmQ0)ZA6>?6!~QPxqlLzcEuwwd?Noap!XAHoq6}8NIIr>NNl=r^+2&Z z_wPs*1-q=Ve&eFuu*DNteZa(yH<`v!>3EQ3-`@O8!R5=^&NN76HVtSz&kIH(*6ipM zh;K2pD;BCedT_tUPEUTM^nvf*BJQyjkH>X?fY)idps~MK=MrTXt^d@0SsIb90`*sf z#WD)Z0pNB4==b53uu^(>PKQ9h*u^ia3E$|wqdrfh!;j$(! ziG@3LoRzuls~~q@+4|QZdMpLSi=>P|CBg_If^;FDZ++~$KL=>Grj^?(D&{;-xQD_J zwS}A`1BsDrzh`b09!5vG-zB3F-uyT-stfK7syfzfmYc=!pI&uQyjsd`K?e!OP&BW5+I#W| zW80H=^A8F3!< z4q`mLCkOez2L){Y+<*6Xh#W)X9eFA9MbaG?77ei-XKq?Nnc&2uV&p0D&Oo*Ry6PI zbYv;%w|Wh7#~y7tr{od1Qo$**Tuu0uIpbInN?SZitNJIiyM#c zPTu?$_Bf&Dc>d?pdW>Nor1tqjt9YtMYcAXahjK@!Gv4`jRdcWmf|4BF0R5(Bd{+i-?bRmFQq5 zP%a|2SDeF-4T{L`!x&s3_xq}>V=d7l>8hXeAm#3JNKm^`_0VQ`O*5xtWN6c9H^?U%ug7dF2!!JO76V=E z7U9C`a-~Vqwe0pV`NrC3igoOXJQ%S)0v5{}yo|%0K;t=<@m9v@yS@@m(4wA-NlJZ38mv>6Z1GbkN5hFNnjU0yz~D7$?%g zIrY_P1U&{5zTL_;`26B1oUg(37JIaenMS}(4By<(I*S97jsCT){FxnYlU|8wYL-R} zZZ56_i^%E>)6a+bzu6lO6J9s_{;@_1&djn1O>G6tN9k`G&3+L++0L)SdbaiU>kTv-vM}ZDu42?XA7?wDz4i5yaxMXP(@_=%ubg#;8IRbcqL&jL6v`379PVh8Vaf!rtI%6kCO~)?6aQO zS8?Z5*jOrO@i#6H91q&7x!ZZTLKXw>86;Dh$<%0)r9DmIYU3D_n-BPzi@Ii1O@8GZ zF>7n!zJZ(d-;vJ;H`>e@BQcfrg!f}*sNZcBkr)0C_V*Hp95!_l3SpjyrRg1i8v1DK ztbPx^*n213vqb*VV}PCJx^J_k#kuxmh*eUv)5$!!=o0*l{VE1!>ixqMtbtjeI1diJ9B4EK08nAp0{5B#jX+S&r|u(j1x*E5igqj z5|~eCxGj7Fy7YgNKilGG`pD5fm;55CY%oaevPNHG?77|*D^gdbX-}K+(QRY_y`lEX zm~VEkEa3co%sr@L)Dg)SB07^cib(8A1D*DMdimn+7^ReaulEL6+(e%OABpv*X$a&z zUf&Ce)%$a~5zx3BME=^;FQGa9G0klA)u!m_-26>nivz8Vf$i%?O>wf(?m}D@BX5_k zpmf{IwoG+%Q?X zo-HzvU=t^3cT6?&;&Suqq^Z&8#3|rLfaj#C=9*kpp}Pcq%AHQw-W=)Y3%U6V(c@|p;^@?&yF|fbuMPR&+Y5JY44Z_0(rPzl+Vh*AdHUXdv%l&1P+U_{p zz5lDO@%-Mw#m-sJl_-M=kx8&7Ikn6F@PU^rzxXIpyE@qa`72@xx$lP-KN>?Uuh!<4 zM4LS#GUi+58ppU#e!rk0bBBYW+$dnq+q;r^h5$4f+02T8qVIp)9S> z;V)*IGDkM)w22q2o;M>siQ%R{Y9^|})U;(-WYQj+P5fcba=l=Py;=NYbX@8I&OGVgr*xBQ!&%Cj* zUz3X(1q<|?3DFcsh2PeXPmciC^#Te1+g(u1e?tP1g z7`Kc9wg$vWlxXfc$^!k1A5$O@l<0J0X*FHtsWtxqKGlk17L=a#MThR9SvkogEk%9evFk z65HAX$weteYC!Aq>Pyndp>yBRw8m$w5%$6 zG4gP8S|t0)cHli(YUdU8u1~!}^uLOImO46<$$gh9$#q1|E?orOcd~^2_O80vMXvYS znHxHsS?hi7=;2DO9bh=aa*=TqX`*H;E@jQ~k|b8D6g-SHrqkW^+Rjb^^Q%L`R>y}n z?B)7b=OqS(N2BtuZ)dvp4_9MiCKh*x;+dEeNyUC8j9mV{&YeQ-v-NwZeCmAVSmk|m zg0hNcxd5FuQage1_BSylMQdsIxw}y=SX<;Gz8k~b%)*Cb+;=@{vCcY88{C(XgQiM^0!QRg%Ptnpp4qsS0157nTh$3jbO2>PunuoL6HAd&X)BF~}Bp z-c#D#jFs(g*R_)=JMh+L0-Kpi*uq;Qne#SVd%%~ywLB)gtIJB}N&C66gpYgOXYZ*3 zF6lMHiFaghI^XEwsji2_W;7fwcb#W@9=3&85l{;TT(8U02tpZjEJ#dh@*ax%?wD1t z3hn=_u4t*V7+G4m%)=LTZoBlt!d0hGW~Ab>*k8^*Z(klN_w--x#ScY)f1F*j_GNUH zEe#jrh{gq=RW+JoNUFYC?pFS zq>As`l@-ER?4e)celB-gN7^bI-}n13mC!UTI+En8BEK=YYiKi)@g=soBWIIl`j^g$ zU6WRAN~yezT{RSxrYS6RgF`-P%g3di7}&V?g*!>@wVG?lzoj-4%#nytTMm)4!4+XA z{>t-NdLcu3V(Y-G>kbs3EYAjSStMK!kGJZDr-4iylfE{F!X1pXn#yGQzQD?tK_vM1 z<$~=P5x3~L#iWQsk!$zu-(HKE^Yf+TIUVL;)X;L?%K7ke-fqbRW;e>j!IkjD?xJSf zR@+2SiBq}hL|$9@Bk$2Y>|0!LN_tYRD99qc9K&7l87Ag|W{L-+v$J1wd!)nH6w$|8 zJ53^B)IcE#{6Jz`IaaA;r$D&m$0ZdE-NZlT^(PZFN%A|7qq@W9{iTb zHCA<%e-s%rCp2xLCu||-Au(HiVDuxkw+zP?K~2A>8094HX+LKO?vv?`2~3j-p$e;- z#SywsOo}mGS(SJ5V;&*HMR<>x2=-%+>hkoa@wwvk<&H;7i|e`uRECZa0=X@QHYRFQ zkaUh`Oo60Z1d3x|{$F*TEx@!J_;(ja5@{WJ@N9+&pJ%$=AhP=&cHJ5T@s^IN*z`jH z#JdTNbIPs`8FEL!qPMlvdwwXFKU9vZhC{Bz~=6Sh5&KAEJ zmgZYUvF9Wh6y45JxK!%-*qD99QX85nM4da<55BKPEp3Na7ggur5c^7`1kzW%>(OHs z=b@A8$hwCEr@({|JK;vr$;d4-{*j(!#$)Y6yT>#^cE&NybK0w)c##3&o_v+*@L~#q zmljScwnZZKkSa2-jPRl3lr$qfFamo6<1uZ&dQH+*A*kmh@=CcY;T zMarP7jr__)_xzL8gxb9QH=$1{}VL^T+RCwLZ ziId}osSlw~dIobE4DEG6Ml(t;q>=lTT~jC?W)ZbQ528Vf zK*f-_5XNpwC(3;|nn?i{W+q4cudzF5;_X2X@0S!mFiiOp9?i)4F);G$mLx6xIUFKE zA;tJnig%58vsfj@i=)m%-tNvGQo3O_-@l5HF(_D^4!-cZc-CEhl%o4PF;NJ;m}SiH z#e-VRI0yzS93l;4RQCAqNVKcne>eM&8eL`iD2@Fm7O5d9ots!pTn9I%H6@)wQ7PI5 z>}?JU^|hF}CU$VF{EF|B;M0*f2NT?KJBt$Hj zE^rR)4IwS$@ZdhXeKHKvkzPJyj4`m#C;~fNcMk%-xB4G^$r$(}3txew^b%c>)ky+T z@gX1IK_IfG#3rwlppZC{qK+Uk37$DZ>^BhWYQ~c%!Lo7Pu)tyQj;TpI=OhSOuA3=8 z0!JT#o^{XjwYecNF3cIhsXVRrL{ph(j6LBFYl(xH*$C@NvZSP8SQW0=;FFMa&Zsp; z(>ACy92bh9{OZ4+sk%v~Lz(>t)-5Zapv0dbe^K?x zKt~2ws@v|tT$kFN*TFJW(;d$GXz%DESc0YC$krTINfv}2PozBs0*&NbH36g*H+1kF zrwIkNydJ_u?tUbZS!v!gQX-iu%+Q{vw>sv0NL>dhrBXjEDSjn(%v zW%<$INV$rIcC+@I^q@hwu+bpsfzRm(!{Kn7H-K}NKafI4lBUw2H2Nvtat=!>f6SRI z5P6>i!pRMnP3lJWbH+V}(80fW>`H& zzF&m~Vfy%$#T*+$y7e`jp@XGO7taZslITM*Vqhz5H4{B-Q&7Ov3MKW-xW<1;4cz zE2EBlIA;eT9)t+nZ0l*9TzQfdog~6G^dm7X2dP>?S|=fcXX=wz6uuC`&2BXXDUl8q z+)%0T@1zzyIxsth+Zd&BAEg*2i0DWqo|DoQag)-SI%y@h1&gD}y!y)NWch49G^bJX z^cR=%+e|LLNNJuJ7Af&haBNr=5hM&((KHtZmEeSQh#_wOfZ*i*S$tir2p{B^3^#+t z*i4&n5XLj)X@&Rb+>VO=+DRdC*nFrVU_}%hsAZR7%L6roQMONgFwQxU@PR&_|&eQIrzl z6NM-f@8+dKU{b>rJpJ^cNN9$nWGf46{5R;2PwHV3uwj0QhYRSks@7#L5}n+TYPmf^ z4h6JO(%uJd*mT@jk)d#@&Wqls20Bnk0&7`Es&;qOJzE%sx*9|eAqznxmSXsgneQ;C zj3lB9{9@T@K}y6V##N+P%#|elKHg&DURD!lxdXCGoe;aNg90zkEj+YI4h}uu(IJ6| z5yFT~0|`SuOGT0qMG{Itq6YP8g(1$2Q2D6G_&-8m94QiT{GNEuPP%Vv=yBq<#T4Bk z_rzq;7UHEjFkVSd)=4RuuXIa1Brx-1k*v$(daxOVsuhSpr`@4MUvAF zZ>0+i7RQYfhau_Ua4|KgIxI#V0!NCWDMBEUX`GM<7P_V=b0{(Hp+}E~3kf!xw}V0A^a4&0TMyq=##_WwOd%u?K?iyP zEf8!X9P}8!NioR6!#%f9@sC`$Z8rX_)+R7Q6+_{078Yy5Rv9Q7^f>}EkcAkdb?eIO z4zktE%_)~o04nwz9qF(oNK~rH$N|^mo=6c3@ef&x%qmFgX4JL2wATgL83s$7M{omAJI0mmg@R;aJT^#yvBT}j+rF9BV#G#AQ&tN z87j@yoF;?8PMv{u_1N9Hcp_M6n$*T^a+nxgOhT`slN16W<$!m%HBUx?eQ;Fm6}D%; z@ud8jdo#d5O!%(SE!|A_y8z`zZ4gWf8K}3Bz#E9xf&6WCl7I5BbY11YPtA(L;4OBU zo$?l>ycm+Kf6QkvbJDNu`Kg$3>jtrqfw`aYfDsxXg>-px^(UkwQ1N&xY z?v+PN)bVwMnJ@^7J63LNF|{?Ge+x`RH1B;9gh3G~kBBJ{ljv-!+b!!xmDHwHQ=zGL zxFz+PVnf+mNGB(+S?o~z(>dF7^LMSSa;=ayCn=LfIjWnh`DfrcFKB&1o~*GeaOsg9 zl14ho}8r!DjZvQ>Iy|@^6Ub;BA58oQxbb463o-zI?G!trXuQD;`896!;;O zU=XFRu*Oktpn| zI7AKeVsF$Qx`&93-isH;kdY#C4Ni9pZ`+%hPccCoAwyLLb^M5D_7A&icpLpex z<71KNF%s(x`Z%~!p{7s>2JGlVm&X;{T-sCyKmFc`psb+#yLoi%#&I<$1}+*lLy$WS z$fi)|g^uQ!ZaP~KBP@Mv9@k?rJJxy-9tpj(g^a`x74OC!RZZM6qdWAH@!q;Ub5T`) z$$eJvkbaDFH&p@ie>M^}D{JSM;?WukO`}lHuj)B?TdR)^GaO3fKogVB4LPP2?;s3z z!G|=S3|Ll=t`o*{GIdr?(@i`@^d1N)Yg)3&pJ!8On?S_YF^l<~c`+H3j+iAF5n`|^ zPT23mE3E&v#dZ|A#K(zOaD?}+rrFJ6%Vk|mpCFYog6Pkjfo(b^5z+9|yApB<`J?Nf zo|Xv>N$3Bt)6p(qIL24a!1U9;CoeGp5sM-siXJ^E`j<);ozw_~j?q$>Ww@XeS9^7v zO`~pS1TYsDD=YEA{wYF#dkbf>=*Fy z+}$+P)z)TTSw}W;(}#Ks5vfb@JOF+%{eF#@x?pUVD{ia^9YP3v)NBmHu|;0XeJ~PE z6h^q=H7xLCGEs%Iv%Xv5>W8;q>G@~X3?JRviFO0oWpCOd{FwjRr2IUY6QQF$KGQcg zBU zkm{=BPvTbhMu3}HK4J9dcziE{`bY-J?ww)qq^F^ z52DiCzu)-Vk^g-I6;baWsf;PtN{6OLc2j6-Yr~fU`Ka_gVt{O)fCH#CKfgP^dUkji4mK-ivpNAT|X}q zJo0nP2qk#;Uszep(Ske29F4#7b5?027G`Z@MN;hG# zhpN4A5ZDbWAJPJ!_*;$X_u1bg!4(NY2_z?%OXi^jeB!BPxvt&B-Mx)B4^cJxd$Q|= zF(cyUsO5T++{m--sclqI2o?9F{vbsN5(w9xP1H6Y0fFW5aUGO3K4%Y;G=h3C6FLL= zS0F3Qzgb$nGMMS}6`Q#c=)xiS1q99sZuSUJ(yu6X82Gn8Tl5BigNk+SHr}C(doi;a zbk1f3UbXC|odK4}#S*iqO&K0N|LWYtQ4BKejQx6%{d%AMMnka-wMjNP<|u+v*aedJ zAx+ADV-bpbvVbc2oybmtmI++R3XZs|IFo~t$h@!>YI!2rma0L{TOtOjjD$L%O!$1 zR`>`C^3P+6{Nj;}@>O7g39-TUwN#X&vx9=@j~VTSo}-GYtkVCiI*;cGaq6azU5O+c%BB0E+rbt2-!b{yph>e8zm(RP9b~=mdpmX+LiMk%{!(GNUaqSh7iV z`M-xg6@E-^W(epJ35*D0p!A_wz$u7;%vK}_WI-Jn(Hr*n)h=E{H(35;gB?aD^wi$Ptk0^ zmiZYT5vnl-rpIUYii-t+JRU?$YNO2i=?m%qtLu14N+c5K`SWt~-HEQxdd0Z{e%t9v zpQz|<)+X}*8lwSPq2d8q$hbJ|5(Oe+M3iPKK(-Nx&`&&9{pTx%8WokDH}aGA*=wb@at<>leO-s1ZuedJEzrX@p1F&zgfU(YI3JN zZN-Y>JbF4{^ntr`?Of^q+TnNP+YfWf%!sCslQX8e+R2|MC>Ri+@x-J4fRYx8l9`oO zXa6nQivSBZ(APIk#!jo!-Bev5U}$j&i$KZ(!VrA~)k`1*4iVE&v3WDWIrLPpc?GpT zQE+@0l|^Z^1k^cfQTpy`8SQ3EY1ML7uv@JFRh5ZJ)zMEZI1r9bYudlfiAqL`{3K>e z8&8HP%p7|x;5oH-4uJA`Jpg>5AX%Uf?g5oW^g!0WjZOYlR|*gh|I@f+O;J`+MS=^^ zz|Xv$rvOa$%xgJ$6;uMHuqu;R378D3{`-k2h6PZ$G(1uNKKy?c)y;j@^v%IntEA+8 zDZoVy-CPc#C>#K)mDkb|0Bk#H=rVvMdfLV)kK%;g0-TfA#+Qpg@@!*+RUiS>bnF`I zsLT+xl<>9xDCya5NO5s^L`2Jnm&pI#offQ&@gkMu;*$4cLo=Y`Bc_3tJ-|c< z0NmqUGvLdMNQOuCYq>*yJ1$aM+T*9WZ$LF}d;uH-s4rK`Cm_3NuZC%#0bm%wDTsGa z+eGFH>AIu_x|49)MZB<#O7J}H`Lgc z@b!%=ayFf~LHh~6g0kO~Ir^2%Y=;wuhle)c;&BfpvXbz}{Qg^<5PNrg=$SFLHA>WDGP1 zv8bHHcF&uhx%_@;KaqL}Hm@y9L}NJJ1u{|8V-%<7{b)~>os-iZpb<0zxAqw>XLoxRIis*z3a+782+DU%>DA(u@b%b!Pjy& zfEpA+1CiO+hws^&4o84nJ+%#Z>>7zYX)b@y<^SBuk?G^0V-q-AqJoKpp!iOxx(Lpn zsZ`Ld0ub*@AVc^9``_g5uZ_;5QHWX;z5z%iRZUzf9 z!rip54RJnF_f{tNj&!(OGP?SV*ay;@MlJ)7MK6C5lzpDNK*^wj-Yg9CEsy?RCv_Bc z8_y}J1$L+~jdFY6fQmyi0PO%!Z_li1P$ah!YQXG2B*>jd7a8MU3d4=Lx38n3qi=FSZOWUfJ&cOTTZ z1tLWG09?EVzI$$8bBDHNcLzl}0+9i*Jz^}Y(^t=cXcS71K2b%Wi2T<^SYFeQ79;Ug zBUx1T4w6GuH=7n6GWh6m%aHn&x28Ly>cx05%28!S&(-}h0W;YjVEC@TM~Eab%2!yN zIdVUaHeNcLGK=;5eRtjyXd$NSOAQKamI5c*2LPaT<5Ww>zb97mdB1I-3Ua#T~r-_SGHWt z?gD`+L#YuSVE{vIIsRNh4HzO#fqee5v{5sJA3z;!T1Wq$qj%{Cy9M$nXdOU6AE7e( zhFO&ab0D=1_%&yMs4-O%&ec3FF3fg3^J8w};ZI^SrG$L)U$1h%00u+z*??oYQPcEO z1MP8?H-g}y7(wH0y=(i~?BAJ`ztya{`9v;|JInBSrFseI$p3knmK6bpRiE%#~=>nYX zrN044NeZMf8xNR{Tz{Nu+-q6B_r^lM(B|nbm`1dY(T>Gd`!hBvd-MHtYImD_R%sPuunub^8!N znvf$U68cte0h{vzRUANS*x2+vuFh@(Uqx|T`us1%J4=`;WMyShkR1T;1nT9M)lYbM zT*tL_qv!R~R=x6uDO#poF445MOTn6(x6XLr`@gqyQi}>x!RY9d&De8l(}aRp0!MvT zX)2v!A+7FsW6@kDCQq zdrQ17el(Y&-MO!mkIl;(h(V|r^(s2;L)zNiZ^3w5&qzqjc5%>h^&n<=rhK<~G)VLH zAkz8d_eb)#s;(}~{QKRiDCQZngT9^g(;5XDfQ)Xnzh8Kn2HeyH>Q`^Ltp)*p>M>oV zLcz!fv;x6bIAjmBSX%QSv1mdMv_7cWC|{#tjj`*+deftJqUE@CUu(04PDsG59` zFZf?g?zD|aot}Xbp}toBj3iP@qiC$Br)PB3W$NQ|rK?Ny=$9R;1mo6YrHf@i`mBFu z<^m9Qz9+4%t?>gLTyVM!?S(!Ol?Es~4jIngUn`*=@@5LZNUIpYPf+}gx|h9>@77Fm6+Pv6M#9-sVfKKjwrqdp97Tyf3kw~AXZoDtdG?j zK99uyMn~7sPL>w1OioLi4LbdoE5O16VXqOGb}Cg4l>7hJx@XqG=JaW4h-!OyKfnXU z&gTg@%iFWt+uNTR8YU^+>yRIR@tDQ;V|O;OC?$p`s$ToMuM8hyS&~XQ z!;dL)f0uv!xCaoNP$+b-1td&BKYV9r2lB-F^DpCw?||(f=zn>7usW1}jvWNv(9zN9 zr!BI*V<~w5RUv4GWL4aSAXBSKJ+5@tM~@r;HX5?M_t+$iGCXH(rv=AP?C%o;zW)Bx zYUfmESfBwUL$il;i?lepGTMKQO-ukL#w758nHhr|HHy1;f%YMnh{)XR>@%js${%*G zcCKHwei93Rjv~4M{tb}IbOZOPbJVB=-TS|N0}adukg9NubnimtQ)nGuP)g!ouk%GC zCMMP}GQywE8d{y4n2`95t_KZ&PKqNfFW&>;ukQ-OMJfqy4J@bwU+TTVUXwKOHow+m zVM*;nM@J{15z;d-C{bfMJUS8<5&{VIQ(qAv?%9XIIV-h11fwBZ`tuGgqHmc7lwy9q z<=s26N2x#`{RLp((9qBTxLT)#KFhH9TWRip7Vqf>6e@r*x&nE`kLhUvets5G9N=uX zUuzo}+@+*U&&r}9At50qPKb;9US_~YO-+5?0o)s9;Ff4Hig0nlmw;sy7#Ik!JRla} zM*x}rMc|B^o0}omS|#IgCy5FLcD!!~T`o3*{Yd#)+lGdA0mUadIhpmgA`2-1<@C0< zqd(_0*Tg`B`nmpXmHYDQ>gs@J6_|qiz?vdF$X(Dk8UXDrEtw?Ii%9>O#+dx`)97_U zF={}e!NJAt9~dBe{mqWo2hh|2)QyLOqg6zhhuc-_WS%%(sS}02jgiPPsnmn~63f>p zij7qj6ALtal&Vl5BO?R)%<}H)i zf?0kfB_%28^x}e6*qe02jE#+L6)+FoHncnk8PD+k_UtnlZX0M1pu8A(H7-~5&9a*Q z0}2NQFpZjmiclKVhc1QHOU41I92X8pzJ9IwAQ>&l1jGwag_^1=30SVygCBOhDn35D zEG`dd3GE!TSV+6&(FruoWTcIZvcU9CO^uMl;$&^u3?wap2*pOa{hj|2>X&`F5;8LE z%*;Z#wc<5y`Gbs6+Rg3p6RTvLzuog}9>dOrAnp8x{|E=&6P%C6b1eb$^YfzM^zt`T z=Q=}j@>F1ind#|~uBlH6@$tWQcWJ>OoGX1ROk%jn#{;m~0jMZwo0%j~Z6*XsB+HC) zaU8PkR2pIL{KCS7_8qMUWU*bEEToCdssP=bA(6A-#Lp9VZXAX%L6xr;txXi>7RR8$ zLaH`OfDwe-E(ECbKvxp1m%NUR1$`aB#svM&T|v{9m9h29y&DNNeg3=>L^wbIM6m|q zddxwW26I!u@@w$B;AMSO&g3d>+K!3ed2i;h2sQS+s=;R20Fxa|c34CW_#l(U1sYJ??%rMycqair66mT_>H%!oF@U@| zI|oG(UfzPm9ztKBe`-G#3X>orBO{}rprE0_f1D0*U2nOqVt{SRsrjKmn6*GdUEntO zWi^{e#dAM@3bC^je9-X}$})UpRsBOnMTLlnNXc&oqo!FC3_8HqZ#IKVX~M$7L_|cu zLFI*)b%u{7`}^%cpL1|0?EJ1;mMZh=@=!b(GQDSre0kH*!4dBkv zWoM_4dIKa;oo4`T0m#h01Y`rqcG~%h7cDIf=q0UatVy`A(8%8XgdLNXw&LEpb#Qb9 z@ZiaP%f2G>0|WLw3HPW4Tmx}v^QQ_Op#RL?V_B&O;tk*?0NIqG)sSa8CF4LQpNWad z1TBs_`aj;E9gf9%yX4cS!|r$nPypQff}c$&T3zYv_8iPlN}wF;Dqg_YHO zLy>2DYs=KsluiQ6?G%JMRE$Z!u?ez^t*!L{eyzuv(zguaIB4w*5Gf+(TR(8%wwqRV z(@%f;r0PQ_@I;x$y6P^|G8z~z(7~ByFNS1=Fo|C%65wFwOri4KHw~!hO~ytp)g2(E=H@uz5w+H z<2|4es9jWo!+2os_DU)@;6j7*A@cTS)3)!@r|c7dG)vOEcX)kuB`?v9@d6@@z6Sw{JiKIV*bdE`Q>?+>`6t)+pJ?YjVaBXeR8sb&Tw%!Ow`1inT4f$XsF`D z2RYW;wbsL?ASMES^2p?*WB;vATQGE?1wm{v{yZY|qlbsK@HNWfN1*S9)iQhv@%T0K zXV-*nVVCja^Xeaf0m(@G>$A-}c0At?&g`dTOEb{CuUgKhFYs8WPs8hqi#L{f5<$25 z{Q0vTZv&771;a6j+2OKf&=%)sAFmTJb3RZ*(<#ZBC@e2m zDbUb=`jm;8`4%i#b*t1SZ7}xwY=CCrN~5NJ}c?)8jrH=#bAn8$|-h}ObmTQUB9b}%Z3 zEMv@v5f;#s;1-d!Y3!f*QqhQ6Zg=C}ZNzw#e5u4CN`drZmwtQ}z30;YK*3e~&aW}a zn|y_W;^JZ;FfQo2MkqF_k|{8d@njSX?OAv8d3r8JIB2y5)z2De9!wCKltGhKJI#il zsvX*F@o0S`L}c*VPlI*jFNQm)rTr`+Y@JBl1m1>=^Xi)y)?)WtN2MnmP=R*JdOifEM)h^_$2Uu1YktwLb$U zGeALr90kzVIgfe}OAbLhXiD?(@b@k%xEK|sfI4cTt{)mV!umch?iC){z^TE4-Ii^>XL0!$w83LU6~$y zMvg=9BfB*SHj6W^%;R5p6_`;Pg65}yN1xpCh&U2P{q zWn-cW!7#8z6Z$|cyt~t-?kAW-g85)+5X=O-!ZCD};5M|CqnMnVyE;?QLj-7x1L~7P z0T&yaJxIj>*0<65H>SxmU;Mq>ABqbkmMa8*IthGd&QUG&!e$YW@;;TdpYwDYFcB09 zx(B)D4wIlK#Q{{^C+=HQfQT9?g{UfONIySgmFRAXvpo4dcjtnHKMub33&@m+YbWzY zaEkdP)JKZkeh|R<4rCwbaB(`qj&I*UJ_9CoPyVKPfTa3>gM$McWNHnB!h^aUgw^t* zP2k+Xv4p+H!0HH?$pa=F9RmZpGpU~GDdn|vU}!hixG-Zp2Rv98Ulx;}_t&?4d?~|- z>_}s*wOcE7k_LAqVfZ;{w?$r+q9J}45-Nn0k~2Z#FQ1bj*hM_c@XV8=Pw^S zouw8^h|a%O*ztnw`X`u#1DYXdIgqP3J3E6-{5M<{3U+p^-~GQfm~&BnX3)A$c^1MD zBCC3fTU1MgbwPL$!P~!LlYGC!Hsr$(=8yB=U%1p6hDo&j{$mLKJbTvW8wc&OET-)~ zq;BVMGS-s{skqcLp57t~ke8R&*VnhOxVPW!r@;0;J1cO+yi%{ez8*{;vi*)J-3LY@ zB$q2-u3{I=_wJpYpU*XVkx+RE3O0aX^ySN!ceWTTX!0UzqC6_-fY|m_NvR*KEU~h( zW@Kc5&gy7o#Y`NzXZq5`1jK=l`SWJ>ao^+xKyMuVl{~ zcUH1z$zDk%QHZjVSx7>%_a2p1A1g&vW@wV^WEWaQk|>2j#_zbF@BjaKJx`zKN!{am zU)Oma=W!h8dF{T|jq`o_^ryx~b$j~{B!L1{P{d)?VJ{y!zorfFLp#OI%*!n^GBP9( zK?4^jaFyMt*B^wmbNDRSO4HNRIDIMTH^=Ma#?){LLUxZrO1o<6ThwrYvbeNnVFftfBPkS zn!9s}veBUoW@chqUS7`YxkWYV1*mILUe}ae1yU%%fI`7Myb_PcPWCTW=itm@SdHfvN_Nl+=5xQ#n|EKRztEG(MBceGeBl;eWpZ*dTkiB>6B8258!_!Y zcR`GwJ+74(SF+=>V{8;=W@cX#?xA=yCd)j#^ofiOu{ZB)tz|OJcJ15uuCGr{UENxe zWk_^sCEh*YJV!{e*!*eI+Ld0V4>%0O&jmIjFHf31 zq1mc5ts>~24AZ!Rni{SgUd1x#rezG7D)hfmFDEjq@!Xuo7r+7-8W>D}`OEIfFZL(?$LmMz{PG)@apN{I8RTP8(c)XT zsEjQ{v(<`qrEPbszdl%Gt_hflVl#?{dHnIE^JmV0{ERM>xL$p9E!wcefV}6@fFLco z;;L}YBHGJ+XjNNZCf}2no6F12KKMLrd-sX^92^|eGc$-DxEyw{qvK9xCDS^Y zm9!P`|KorKA+3;{{QUgPOhpK9_%hFfR}w{nsX6~gWnp6=qB=P{Fa7>KI5dRn7$xWy z?g8PUAm`y+!sVk*ggYHy{Nk8+{ZKyQy1f-#;nwDa(1E)m&f$V&Y&#!E>q}&ub~yq@ zhekr2yDYaN&c+Jyw8~qQU+s0(4&4~V0VDD6cq&FlG-(~U0D&#FXfQdtW2)USCD zoxWjs|A>ePS#XEv&fy+EamFKHEngIbO|W`8$3`c|X5x}Yt|PgMU%+~x5XPit@NC$N z$lVXCs^rzw-VO|uS5!m^vGb`8`SF)ql$#zrc=}0T#()3)ck|}Wyu5WB5uBuG1fkg2 zhvz^2Ct?(bjYQ2jnI6ls6zDSdtho3yP6~)`>d*`nymHo6%^yD86nP|`XKGU<+x{r3 zv(qHkY-VQ3CV9YNt3>o{KLUJEdd z%>Y1$OM{U2wF+4O>&8u^vUZJC&K)fK_U(I;0T!B*oBRCx#%dsP0QA1Ef9J<8K##=H zxeTxsPEJ`EYIGXAG*1PqbzG7Iw+5}@N?uTFCr+I@Ja{l%oI9y4z0$ebTCZpkm$RL$ zav*Piq01lgGUrPiwbJFBZhe|OJlSMkr5PL()Kz#|NQpf-8i017!PUrg(N8V4icLxf zkt}hiB(7z@b?a7MULH;`I3ZVj2ardU-MeG-$juk0xCA$BU@w;7LD;Ov>f(mO@Vgth z-_{I)_s}6ynTHe1wa2#q4bhv0N#&N4>EXk#dwcP--pj%;2zB7*ACT; zYt1k%{q^e?u(pYb35X#+4L=ua>l{$5Is~^HL1!%U0<;PDhnn5fAEBkJs|@s(ku%f3)*jh}P{UZ1O{9W)p4GWFTccZim{D$F)ky%D(RG^tpJ^ zd+0W^!Of!J+OX{{1qB6s2uU`T6+r^7E70oQ7L{g0MV){`>)lP*hZe+qQGmeTyq9 zz>^ct&N`C2hy_ZF#?qc(VdD@`iBEe3V!o+~nwAzwXamn&L_`EnKX3o#huPUD@>RVj z?5o~~mpRftYe-J)mXMm32KFil+tQGfq}!@-YD)y_`K+^Jy)tj=GwwUSTK?cMZV`H% zmX>CF?_<5^2^*U++!@}-MybT_n4tS~F;KJrI6Ye#B|H$;dOmAJ4IluyO|`!hc3J=t6Nf)QunG+0Nd|j$OtPjzEilXzJZYguLCg?*QLb_=w zD#GyNN008P%W*Dcv(y9ISQ!xe9k+!oPAcXySy*BFk*tgKpK7u_ft@DECIa%p{E#W)ORa*RgL^M%|p+09VJE58U~^ZbWL^^lpt zku}-<`2PJJGM?bR00O7PlmA{#h(t+VJF<@u^IAEnZ7&o!5N~GUwbj)m5)EF5F0CB| zr&8pZ8*^RquW&gONz`w;aJJl%kB4XW=g%W=_>>PnVydLf?g79#Yhn^_ErZDX7ntX3 zZ$523KN~&uBZo(kw%`9geQ1^|j^jSNbf9T*l8l8iB z%eLZKxKVfiu3a&$lQ;HW^Z;XO%|?AY?}mSLh65MpJq|M!g7ZF^8#)AJcVja%ru<%T zX}*^(J-BemxjGkBOYx?I97(>0J71@#U6883e&y!ohGHTtn?p=* z7IL4r(C=sYYENLRgfb^8Dk?AE|KY<^JRpE~Xofz#^6YH9PJBTlCg*$`{cxMsA43A$ zt6U`sWOV2Rs6le=WVQWg&4GcRJbfB*kL3+xZ@LblaOLPWBe~RQwU_EY9OO?Az4^0y z?6JRqOHi*l^i8?3(QTT$8|m%MVrr#}d4Uq8{pHI_>*~lhC-09>)&PplMUEH|w->^3 z2N}1l-QwTBP@<6w9tSOnFJ7E1I}#qi#&D}RM$dJ@L`nB`5zrg}Q19#4v7xI-BS2yt zPW9XB>*W{8SkG|^h{x{&MBg8}k<&V9maod}_P%P8^DI^C>CTpC!yNAS^dFc@5*o-3 za~}Q-X#`AiqyIPdR(VLWNQ^mMB(XwSk$g?-#uvz?cv9esGU9Nm-GNVj>ggls zl|J`Hf?}Gaj2LGQwZ!}ie1i0cLNa7?Aa z=%UZhoFF9y1(e7^D|4Iy1r(u_M|Pa$CmdsJ6hlE7y_{iDuB@v113L_u(9n>2Mi0Rm zvf>^YnL>_RcyGi4{3@C;i<(wJRh5O2vEtr6PKFp6uAa_L6p!?=FLXDk6+k1+Z)MZWo_X%-`~+S9{BbN~J^uZKlNlc>&pIEVtY z)2)SR6=URq{jAp9w7O-;m^LR*UQoY*vR;SvREd=UZsxPJT*ht1QXGl0_KyOCf{Ok# zD51B}vehlz{FvH4&pdk2{6yrh7yxSg*<;6)a67u6xi@lWEp4Dr1=&LLn-{MiR#%TT zU65G5JTdK5+0gRhF#9fxfy3cI$Sq%6%_XmwAuiy)X}mf>-TCuBQLhh5{OMvWyn+kD zfvEt7Wb7X)D=8f-GAFD1hkKnyxuq5>--gZt=^-JHjEu0g!~THiLdizW_x|QO|eR8rj_2%gbS2H#Ahs;c(dhDhQAXJ;TEsih=U`6C8PV z?#%iLKP$8dJgFGZs`~ncvD!Ni9{dCfEEKIPD|3VU0{)8R#6$|EsDotOtYX5$9vAKH zZ<^cnN>_#{MMZ}|G}8$D4)u=Y)S zOL+;rSrQ^Eb}wQoBH`WQVkZC|78Vwu{#e!sz2mkPThASyJDdj_SXEPFA)AeY(%MR{ zv2@_ZfW(`5J0ELZbH+k)ou;*a|0t725XDslUWZ+NE~xHPc=v8%&zB#g)lrt$8e1l6 z+?`5-+}Uq@O_dasd2CVs#AlL%DSGMGFUPrmg8dIwox?kZjjbomZ{h)<3R_=azx?+{ zOfZihJI9joy5jp!DHr~jbo(*AojhH|Y3^*uA9qkkUpKtujk+Oq*e+4SN8yd}s}HiX zv!OSdOTK>|rmdgcTR3a~FJ{>R zKv|NmY3GD{+Ox=F)E{~9g3!{^o;-PSRjyL-OzjwIM+C;p%d3N zZMbqBVwsP>Kk58`dj1^G8Wjx|pT+cA`GbXM#(%g!&^T2f2sL10A|$eN?(Q0hPpDS` z<@0lM!HV1mSp4_*XMwW&ASwr**d26K=40^($$rQz&pW2NcobK(k=0d)3yf-yVUwhkhtzIg0%j?K;`t`M{&j$5~C~+x;r*N^m!uxZNA%in=-vA1$Aw zppDFN8yjA#Ok7F+b9UBbPC;hnyoun0{ojixnWlbt%<^YlX5uoOI66Xtx=?*AhzSM)K^ze`Za-H!Z6@gaH1%q zCOsUBnW}~rnTFt^JI)!&5sC%}B7M8(RMS(F0>gNF;A?##ejQ0mjSx7BrviL?ex8)CUGTv)=# z1vlT^+ndtn^fY8`u&2ip$QALJ=43d7X;g1avUa9^c$u~`1pqm!Q_yfa<)8gA%6N-cb# z!x~kzCV!0k$*ZBEV+1x6V&>xFqLG+s%s7L-ek)#7XVXy0mfKI0>^Ent@2b)^ITrGpMQs*YyZzVKJqu~@apOA$Yv=1zWdkfg|5b@rqGe)QAjf462LvRlaZ-wvH8 zchPDQRo(FLVI;)IJ4=&!I+8K!UT&?A%`V#R-l+bVxiR>+CQ$$DsaASk+r|ptPLbnh zk?+9buCK1X2N%zEWuiIa;B^^aAD`xT(RawB6#Dt2It;)6%`0gR{ZBh=3swsFGa$t+ zIzEjyru-_qHRkRi5b;3#8jY8UdaQ}};>UcC_`Hu5`}3sPN+$gy{zN@bXB9rrEXVWY ztl!3O+N;f2Hdv*^59N`rc@HyJ{L8A`2NwSG=g&sTJic%svR0M{+&`#qEZDo#{k_V( znE3br9JMcYoZ0Grlq{^h1y>^MF!0)JYo9ds7RVwa zQX!V?-!HgsRaseC*qMGKroXO&(UzZ*zD%~|y4cI}>g;jEHLn{7sa^H@PwTAQ?ww_M zG}8O(Rrt7wmewh;*B?4n?ptoPFl4%Bn%P7VckP10lgh951KVBtTKAhbe_q5eq9#U( z&}t$bo7>g(V*J~>{&jYS&I4hG#m>c9W-%#D>568AGlxg>_=gqc$2i)C(-ON9&BUY9 zBBwPqcL&Z}|4A^*U%bSmt=r0@b!s{~{CxCv6SD@V0}^)6?PNRBQ5)Elo z4P=gfH89uOmZflUkBn@1ZbV>9RgGIXx=py)*nAL}pk7sv%>%lS%!P>7X+rxWC73Gc zn@mGGNt)!(qbURP%lxhKP=W9bUcH)se*31Qr2^YU`IqzQw;zShN9oXVbY=Coy2cN) z)f7%%)?J$TKJf0GZ3&Ykiy(irM>Aba7`QsI1b+FB!`IJ*Hh+QifBiaesf4&V&E5+B zmOeDpl-kKQ)YnsApPH$cy|oZ7MmBq2q^>p3x{)zLhir$D^)awQTwF&zvnnW_$ZL)} z91uB9v2A#L^_d#S)?{;ac{!Z56f+B9t}=BBqNyy#y1L{AeQ$?`lvGrxwPVYV+;qIv z!1x^mhL8rg?im4ZtJ!?5V;M$sSNba6({oIGg4W^~iva;>nT!YM| z_hSPXWUt%Ff-%c^6(N|Do7)5n9w|h}#@38^ojmytq;^$RRgr!ih3wsm3d$!`j9O`E z*d~x2FwnJBkT=VB+tb{7h4HK4Rjt@Elfw>;a&$^1H{T2lv=nkCgs{yxo?s#{EFK>9 zQeE`Ov`*3_xY@E95)@w^7Fi{CK#1N#m^)!k4`2JeME3gRbRF zGkcGVV#>sBJ5HNt75gbJ*3yl4k!zYWL5#h5)85C&2PzW~WsIItS=l0>Z^i=CZAB=>@V zv5D&9_3PJQMqsD}yS2Eq^casgT}0o6k%1@P`SrWHBEP>`quUG^RFFwTw#kwh(MW*?9LGL z8JG}c?62RyyI;RpMDF~Xu38)PHu1gWVTK$=cT54VSZ!On(AMUm^ zZsp9}YKYzL9=@|;!c4i&@KnWH{h?_oyKztYn4cu!ES;-ZrFNXgb*7AljpmH#SDD~o z9zKkHPWEHHp%hw#W&@C)K24e#gZuU)dFDXls^;mwt9y=VZ>G)Lw1r-rN%OKg6n{)! zDS@0?KFH_!#0KHHf2-K`>6Pae<@1B3j9@0ErPn(SmZvzg_v>Qu*b}C412<)SrS9M1 zx{pHZ7861VZJ&k1HU=OlL2`y_^YY~_{Wul?_&BF40z9SF_fuN=;!0Gf{WO>kz0osH zB;FzaX@2C$5$S9A+M+XW{p1Q5_A2{WiYy+rwOyY|(`Mn3ClCla<(5F;=RQ4y+#3S? zU?&TTK$?RgGcQtkFvafGM&E1hW1slLJ#LEpRyDh_#`b3Ki{9dfj$w(8#TBwFbN2~z z`^rJ8nR6C#=|@<#87k;`B8~HJ+RhgNK>VDSwJ?VT)n49~XSyz6Hg+=mBN^#;( zy(xySVx|RwVESwKt^G=LGj)Sg7AuW_zrk!577`d48S8DYd>br9uz=+Du&j*kLJpr< zk7eEoGDd4zGO2pEfk=_SMLts$@-XOzZmyiD-0wL~6F6Mz(>tMdkeCU>8}mC;KklqH z4pjXb8cnd4p-p19O;vy0ZQi@u6BLSyiul`qetbxB6l=0$adssrKZGz1yq|sTTG40f zn2iW&^~J)~kY}Kr-1KA~dq=OJ%mnT<=Sbw7>UFa3U#=RPA0M|3bOOh5OZ&*1`j&?V z&MjY;oSmGKQ&QkDkLYFOl(QilvkZU?ja>-;dN5=zx3}P*P`#$_@q-r<4W-S!2`Y8M ze>|G~AL5%;{@UUQUeuv~k%@2tFhG|$<>t(^?x9~Uw65mkNM-=hEZV}u6FnP`A3C%| zqBsFnwMoggeUypaYe$S;#f9rI&i&!X1z ziRu?k${{xwo>`Yqiz~f0+GQkal$n$5a>r$>bGetT_JdEg$wP}lIuVno^TeLlU2eO1 z#$)OCTMqP}kL6)Mf89kroVKiDS;e!^Coj{B3fRksHoB%IdA-qU_Qva^qTmctjnfS zq3z34M+v65C^3q2$Af}`jvwb@$&jF&6Xx+B>P+K^vgoub@nuq8H7VbCm&l}+6MOau z*UhYFS{rX+-2S)n{nA7;dAa2{$^fuOZ55>`|DbVt$;Ot$TRFTRq~KzObnJ%P&I?>7H&;lUWCZ zI8sgtHmC5IzdR5;{e09qiX*fZ(g`xvUdPIBZ;EYs>k@am!YYjZ8Ye z2pqqp7%_spiQFV9E&uuCM?&A#_K-bhol~C5SII*51u;PxMq!&P+)T$2#O+cfc->n} z`Ndr-X3xXxdq&eMcQ8dh{ZOTr@Wi(!<3I@;Sv9Y^hDZG)Ft!jEmX?=Y=DxQh2Py=m z@~}owy;xzbV0rmReW~`>e$f=0BtF+2Ez)<-Daw45uk25Mz_QR7E7Wd$NK3TlTlM4? z(bL%1v&*GsaL^)U!9X!F<3BPPu0cD6m66|7E__TQ(;uGx{rWfaG(jS!JyxP3NJT4g zT50N6APytw+dtT4lR}=Jo~NG%$EXT^w@DY8q3pX?G$4|%xW#LF=c$>nje~o}7R>Fz zP+`m)mgdKl;veW=q$TV(SI${))st}%14V9ad#Kpde5mZMx%LY;ccC=e^&L56Izi-h zQLo6>KeGj{?v}Bz+@ht9;;vHSWT1YTmF~vB-*#ShA0!4uC-lgFMO4c$sY7;$h`I+d zP{&lpg}z+zJxBFJ4A+${$~k_pxErQNT=&m6DWUFUuG+~ip=j_i*`;r&@wB{U;BK@9mxtyr1Hhk1s$i#QhJ0z$y?+H|xll1G!5R31c zrPOB=4!<3Fi$O?j-uT5{>i!efY^m!Exy5W-86mcTHx3+^xc!We>p%Y7zeYqdZZef) zE{=43;*BQe;+^RRifT?Trgx5>2S2$wYa)}9CU{R?i{bXOK+dc3n#wntXe*d1q85DE z9_qX_6t7=Qa!45XqkB|{w=G;S{`j?59~4&VO8c2v{xOG!fAmW}lRm?Du?-CM+)yHExHVL;qax`f@plc#`oUr8jfe!J69IjQoh@fdjITNzFLPA2|ry+1KobAo~^7-@c znO=Uy{ugfKkGVM)IQ-}!XHct0OiIRAw}>+_F!=fSjDmTtdIgG9PE|Dk){ACkYVpbQ zI}U7CWE`D-rNbe?MmO<;ZICbJuWA zkWK6dwFc`s+&?~mE}|JGr4|eDyng(+1%JAAF~#mA1?L)Z+VgjPGifZf&JhwePRM3| zotcrvy+ZBn7`(29><{_fWsdQVhQMJ6@>pXa8V@HYMHnWL3ETVt!>ea~&PBGXH){;&Fryr|Q7AL{4=5kANCGnh(?P9{Wdi zP*{L85tUZp6_>v)#+3wSm1NXGb0hRy5~TqK7KRcq+)PL3!&_={a&iE5h~nak20xa; z9e^y(Ih@h+1^))4gY5?hD}bg#P%xI#q}CRc*#X;Io9XH4r=AAeKMUc#oWse`hQA5? z11h*0$P8rc5r^mBW@mMNlZ9ScnHxd4^!E0K77w)qYe42e7H}8;$7iA$S2n?>)Q(HP ze!SO^9HJhof?otOuWkVM)xPg|Jvs6?mC7{0q?D7t#k75pV%g(g*1VZ z=esdbI8h<$#mv~=Xnn-^SIez;FQJPA^2x1ILG-0nRJI;mq}<3Emkp|qw8g)r~H z@8hG?cqc?_8$t}UU@0jnhyM^NRL;H@fTL%5{^-pj<9BsW$){gR7;u|y_6zm*O!o)G zb5k&gO5`e19Tj3>GybtlM`qDTVAOPdIsR;C*Nh8?@YJtDE4I!IR&(iVpJT|ci(lq6 zxzAy(t2h=T&#p!8*){RB(ZWlWf3$Dng0hZQv`Nb}>hWf;MZVvs7M*>^6<_Y_iU~hS zP-^X@NbI`@u?9u@L(wPHOVQS>Lv`Y0we>Cv*y>9?!sp!&B>EI;b+K&rrCv^z`i3(6Aw}As*R34OWqm z_zLU_lWnIo(`X^W0T^3!FQE=Ee6KEWI54mgwe7nGxx+>AiHURYA3@$O3?SQL38$sB zTI_;TO*CWvlfy;XYp z`skkfi>=QjtR+zQ7emf;w7h6By+{-U1nS!zD2kdi~V|!gcHC?!a zWyOm6$d7piz;b}ML)O_XE#3U&#m*>xgMTd3YNn;X|E~ec;dS$|-+%uCKW{bI6Y^UA zt)_~-p>c@e%r@~_}| z3Geyd96<>P{e84rOvAdQ>tH^538N^^?Z2u(FoE3zxk4D;F#J)1(LeP0en2xO%m_Mi z5mJg}bGldVF^m1D^7-tjQ-rg(Nn=brwFIxj8k@K`+jB=6A$k7deSy5inBH-;&go-O}+{S(ANSB!cT4dwfk+*D1v?>i=Ztja)?AiXVvI_>-`Ywy2Wk*Ue|o zwqUy`fZm8X2u*gUtgRan=wPad1D|OvQz;sCCBE`5U)w>D65&ikZ;=DcOia{a7uVI* z_3)V6{P!0IG#ElA0-wQep{e;ECkQbPj#}trFmnzJ4Cr)AWOap`Qq6Vud$fK;r)!Kw zIbMX0g$1V8K!1OK9IE5T-=HPQMR5#oog4f^*Zf$OAuWpl4>z}((@VNbm;ORq04D*$ z8JT4p?nON6E5AM)LR*3T8AqJ78#h*cT|z(q3WTtZ&M#2d&yWqkTH&M6cEBU5rmo(I zKL!LbHZ}(53|PgQx;jnN1E3OTC1doC;a?@CI;l^UtXNhb%=?NkH^P;e)+HL zd^-rq_mF`R0N~<+Xd47U80s^>py18iT>2t?^D_=PCb1WoSkSqK9q2V&b`-E6;z48J zuVORtcTX>?T}@Cl__sH^r@o;f?f)Fi8W&t`ZO5bOcLJT@alxgff|o^9oS&b^90h76I2H0rtatDIYlkY$(t{uSQqUj_|>%9t<_8Iy$lgX{)Lmedr1BU1f^@<>0<-qR;f z9--yL*|`=Yey(2SkhzbZ06`#5=xey?ic7{C>5CS94P`a$HsYxNYifQY$YFZU8DKi2 zG@(r-CBnz3rGJnGZ~$#jp8UJ;?h;TZHhuh$ob`6jn!yLRZ_gls<*Ity0#SnU`|$of zx*U(4JjtkQ{N$1s5swl5TWATYf%5V2;i+0zbhId5-2`uly@c}X^y2{LH%DPTwUoy0 zMoSuab_E0NK2Rd80_qOPZl0cizXLcLg|Synh{)=jzkB5HV{Ny70?aM=fm@X*h%*Pg zF-R$rqYj`e1QQOhwD2SB;N=~wI3X7n7WUq@N;|^*K79!d@g3C`1HX_j=~F+0s{v>o zQ&JY!Hn3xWaQ*RE5y)Hlb=8^6PVqa5!tvgk^2GzIR9sA98b~gec;cf$VAxn7RO zP}yw#Up%jN0OkI~e__FEX^8d8HxO-EdnCWjy!U~+04ZaEF3Mc9Zj^j642h-;(`j7$he&nWW^73+Vq0-<*-$_;$8kKL}xY0Swf9rUaH`C=?7&Zrl^%%h) zyR_S-1_%6gj)J~uhNYF2%HK`#tS$sdxjYOpO0XLn_ofTz{1 zMvx$(9Uu%02*&TpL(Pd3YVbK@kD_}Ebx1~#tKVR` zrF0wpJVH0N5=x7c@JS-}jCwspih?~1dH{|Xt-lPLJgjP<(9jh0q4sQANr{+Dwe7vb zrl!(+P{jF{r=&0wo#9`2iVihAXi7WUtD}HhoV$;sgogndQaBIow~?2_Wm1DeAFNOk!1@a&`|Bt+8b;Vw>yf>FMgWV9V#T#$$WB+4145dz*(Ysn zgHdVX`$VZ#p{Eb;0#o@|b8~pFD=js(_oruqk75hOzrvu1p5useC)BzqND$MnEX|~t z5F=&qWj-U@2mhI;H#a7*;faz;azU}&agT8g=U2jUW^VF79IP~T)Q=q-f}b8kNcKT# zQdV9D{QyEk0D&6PKI~BmUTV`s8tLAH4y@rycaK+)ns8tyg1-mngq26$0rnfzwfLgp zL8!ei!_~>h7YtMiF&Vbua#l*bGQW_>Lg6lnV$-S3;Fg24gOoPUF6tG}xZ{IttrYe@il-A+-=^3dY z^!Kkr=c;LGBEW>d|J9x^a0CDVP5U(gc<`$GH~{w!&^pJfy5BHnsHepA3cT0oD345r znK+zbvtzYiCHiA&{cWnc@%(V|Nfj5>I-UcmC=34uKkD#s9sFo;^&%2pg;av(A{Fcw zB+dw<7#F#~s?lb8dMk5dzosW>)s&UJ52`7hi$;=#c@(6Mb$$FUBAoGD6gDl8q8w`x zPU%m*n)ERc&3O8B6Zx~JyBjWcI=Tx0G$=rn)YKZPs&pza3ZNF<#Y##YDg1GB)u@i4 zC7`icFA)~bd&l9FYw>GMkXKX$e5|~CSM;lelk?StgaaUn(B`0toOR6lH z%&`{bUIWE#$f4D_oE_aQE&3l%b{8M`@?8AaRnsrXQ)o0&aeNV7RwkKX@Oge77)F4D zgNnzjAW<(ViYe*y3z z%ZB`(K7c|187~&hm4ERurrbkDy-SP>#V|9o75HcPchD^)SZq zVtfUP4X8`lj`8u$mfD&jbsg9YPf_hdTSZeG)K=JmQOkj_nVOnXusdY*7>yu+VXGlq z_%6SH|AtnI&Z_3AU#Mr&tN6buce%)@J|d&;!8kZ+X=zNpIE8sW{QQqe^BqyNH~GcD zm4>~G%mi-u%GO2@sv^{l_=-RXaV@J@CfwtP7==Xl1zk?l)0iuG`_UteenLOnrMcm6 zD7{Ht??5{R=!pqg^BcD9^m{Wc9)839u%d;-2P%shd8Q$7pkM@`=mh~K!FGxahLILf zM;@a#xb2-w!`Wt;m!utT9NXpuxVeCE3J(LSa{wGi1P?~Tm^r2UwF=_>) zL)Pu&t7w;*n)(`T6W9vyh!i~ zoOdEsEalLJPv_(7Y-FzE>|#kVx&;pf@J9s}Z?t|xQP)v{V`m)mDF9c?@7&2wPhZ41 z0T^g8PpszABR-)WHq$Y+W*M40eRjM_&>7ofO+H(xKYn2TkwJ*zIR^}klQQ05K%Z$z z3Fei@T>FEr1QI2DWyQ+f{Tuq4i&6#or*pJZ^F6_K+S>~j^vTJ{yrhj>c4r#kI)&}! z%I%wlc0E$79Ev|+8&qls%*^UwzD7$52pp^xy1kJpW0`m(g;+HD$P&vYyQ`@YuN{r| zh9I0qhRgL%xc}4@<$a_ub4&Ls?RQ8I47*;NH?ibpiv+fcESg(ekD~84rAve;Rn;CF zUZ$a;o+L0twU31MjvQeX5$#emHu|8vI+WkD)InROK+PY%Tj)vJ)(CU%vz*{m=45A; zS44+T99nAQO!F4nnm%3mi)OejgfWC@nA%yd2K!`a3iWk$Nr{Wc3cS^)dH%(34dfAd;foq{ zL&18DF;F>i^lGVHX4d|*0pTevU;H3MgHccaE^yTd4>K}gI=o$0oh#`K##kYup~x&7 znM)Pi2W05#>Ixs~1Zu(z6QW{n<^B6Cm4!NlMMRC|<(CY(*y#_U3jrBn2U3j8&CfqU z^BVdQXTE&V9Tq;fGgn$AaYtT&<;>-;Q|`(65@E3v_Sm#w(2WcY1);3`g`de6rXDC# z`U{6Ld(+qBT=XPL287jkOBJ|}ik-PzM9X(dWbOH?`znQnWAWV$YoE3$U_q~<+qm@uP&r18;Q?c+ReD2ZHJ90y6)G;;3|8SARN?WB<%vm2 z|2Gq0@xAwG)g;!31n%72%Ft+cYv05yTJkSL@WAr%HF-*s@1oRqIVKz+S8_HvOLfHK zBGe{82TbxHy$&-o;>m;K6~JQH68;x2;&;&FFmbKlJz3cn_{b%m>cZBvjKB^0k9HeJ z%u?MOdC7zpS3&=>@F`289upP)jA|2A643BZ>^p27G)Uv2pr~!Y69u0FOE1aZzW?%@ z?rzecKE7IV$7+BB%pB1_Y{P?Ta9|bi2~@;Gnoq?r92sPeVrFX6UG*uP6zOu+5MZ$^ z)ivQzZAAgLjR~S?L!JZsgcyc63hN-292Wdp#JAQ_hP%2cVreu<^Nit_qkF!CChlj1 zELG?I?oEGxddJka@88i7G>eX!@85ycD1Wl(%B7wSKWrj@s;aBYQBO33&Zc*3C0RDc zW4j>o%xCq>3{v?zlPIk~qKv~D1>Y;II)HW<^`PUM5Rl=R1HtL;U1{{$jjAzs#6}*A zIV!2niMosG%NbYKH}JIr4(bL{`X2{z;^A=@METW|gg(~cA5rWQ`h2~Tk%lb#66eW{ zg~T$XG$N);0yRd*?<;7~CRMf2I2$mWWzLA_(4tah8fzG%izOG7QH(LHu_0{I*jXWQ zgGto(8m&S}i;)lr?x^+gzf&;HGH~?c_a~~{O7u-~v5o+g7)#&-whjpQXo(Ru6%}fQ zqK03{g+N_M)X*9NozXJ{kxa#XkVvPAt~3m5JBe=95D|nFMYLSccuAfGlZD3Xw&KS) zqyc!Cjg36Fe}RS)&4jjEqeu995fQ~Ed4w) zYOVSIB)&yvqz}D$!!_69(1#ow08Uu~(Bbg|&G)#IL2hc+(|x9gs=X zl}+wYc&T$QEhpKqjMAFr>Yk4rscU-b5tkzT#kZNrbjFzzrY7Tc8`?-ip$fD}#1Mi2 zIs&uEDKI7kq|NI3I>yeUBT;+LoIl!XKqV_zpZYd(FKo8@2U$O!Pnt6XlnFj6KXSaq;xz z=j6PI(~i$dSdMv57d)!7nRdahh?af7*At@T6AxKa%KgGM{5#c@#4kGbV1(!yAW4$s zjhO~G5EyHq@83}mfC-Kd-F%p%P*qzCMlFUzlJE#^*teev$l!qiNfc%PcLJFL#eh*x zS){+$we9?~XUfU$({{lhE2;8a_i+P5$x>pSNW#wU0CS7XO>1dAf0+aBBGaRW*PXc& z{kx4bIrJ_|FFgL^?s0o<)A!2b(7$K>ZnUghqRPmu{2?$+~n)sC6((CG!ZQTGVii?X8f>2p0Dze}G^!U*uH)Y#^0I<~$ zCgU^qj1SOLQyF#338hKw-pyzq(Ah7`HHE(BlQuSOXy@+eK!Z1+3Aj_#`pc;C!Hr|U zPa@_HB(+7#tJGOXuTTviUu9U>+w9xo^6kx=<4k;i`2s)Pk05`=I3m`mOcom9-hozc zG|nd^Cgveg7wSfZ-@!1~zu(`=VUCfC3g=7{dL?xzf#Zv&5)C}ayPHoPAWLSs&qC*O z(8MHJKtmCCqJW7+`~?IDdO|`7gI^PQT*Q@b<30qNldg_Ct%m7MG^X<> zvSUWOV4>Nc|0CFkboGWS{{jp;n{T~GixUD2IFkrHBh^(3ZLTpQ^FO;VYF5$P`BCQ+ zj?fb-Qlt{0LoY8aL5jtM+eT1?iHY5aCYT$GJemOPQ7NVTAr1jPPRfPAWL^oL{xMTr#n5vhlZDlrg$n+lZ^I) zr)LE?+7LR!D>?JbNB2qcpeK)+o_=6(5FsHcIT>^mBE3UB?R6e|edCr2c@oH>Kma4-~@#P$Cb7qHra-K@T#JhsU8%dhO5 zyfr)DURYJ3G&J_)91U+=53mQf!NVCldlScDfk6A>Bk)BD`H{|XAyjAU|;LW;)31IJ9*Vgbz1iiZV5mH`n&&%l5j14;?c z>kasf&%~-IpZCftDhvNZUSuYJ;U=G$+T7UqJT=wAL#9z&T6*p3RjQl|&3WWB1hlB9{~85u|I>;z;Ef`&p(3^orR1d1w}3U3}p-=N&BHVcjw zWL6Ava=Rk}IZ95hATKZY>uW(WC&au6mcSfWcMSU#75)AF!E;v^7X)ZvFVGj4gMxDN z^RusC7k$VU6hJt8tG=F-%mLO1%mjd~7q?9oy4;5Vf*wPNQy2nle)K5$p=)hUEjzKF zaZG*!+@n=1Rs%o|tXB;xWw11Cve-Y^%Fuc+N24>K>JzJgw~jSAHILV2MFZ9}Kt3G# zDbPU4d@2liYN=4kw71ueV4!Y70)0Q{G=G+V(wZE{fHr**o9|B@+bc01ksmpFkDOpT z(0D=8_pq56m7TbxIr$HWEs!c83CYI-*HuBzf;8fSiAyj>$S9k*I4S0u(3U-LC{lI( z7A{LY(&cazL_`N_2uN&bl0&sJYmlqr$rb(wgC#(+Vki>O1f)J{YU-jSL9600!FP)# zOkU46EDUmV)KrOPFTSlmdF_xmyUDp@2V^ft4-bYvL>|rADsmf>>(vocSsQWz#D5Hl zQl}~S8#nvO+Hc)N=L@O;8fxl@xstng(M)K8*8AZIlRs3I8=njxu2RKts?e*OqgGMo z+k>{t)>bj-VhResu-!3#47eD~hgP7atMoH7;e}p{?b0p~2BUY?V zpH6Gf4-eP5a6!q9AG9HfY_qoqGhhpZ#l9zZl1A?XWEIS$R#I950LIC_jG6$xB{b;e zn28T+EYotcu{Gie!fu4ei3g535+xYgq~QQD)xp?tkT3S1fq?;O{v~`CI7=i3OI7s` zscJ4N!lwkB3U6oGO(vxbq)tZ{+smH5Z!$wygqAEA6FaOimmePt0xWPl3KO86I@eyl z{y${4JI&M+C0(1>dCAEm+S`qm2b>J|iGK_+R&ZJV?O?#M+KOSHAOpb1AZll3XOo7y z!*CA68YZp_Ji6Gjw>59#TkCB1*E2INVR~NXGxPHy$laLBe(BPsOipd|qoQnp3nZ$R zY?wtNo1eoed6*q7{zcb$nhh^61XL14;@bnZWfQF3?Kp zqQE#D>pHgq{AHOvdrEKJ(h-Dn3_BS988L;1&Z`vwj{j*~098JNwI|IuQ*bsy3?0sm zlA?2Ohmnw6nCqpg`L{guYh%Yi0d#S7r6Jb==L;cc1Y|7#5=AwsS_#7}@Lv=9KRExW zQLsdX(7Up6aDdMb$IMZ8_j1$(bwxBz{Qv7=SEPt=(sx)b0t!npI*F16Lrd_Dnr&mf zUocUNh!o*;Kgg;c;cxk8%pf|?#mD2*j4_Xs&1HA*;(P5^RK)n(6A0iZrxW7iF@F;Qj+ zPDDv24)*txsgI)!Oig7OqAmBg#{w4d6Y4e*)#RgOIP{g7=&x=<<9|u@-W4s?aaZ!0qGgOOh8c^8Lp_7 z!T~qnL_$>r7~<^?kL`&pF!PvBgb0_ow@|jMWUo|+RHU-A3nkfG zq{ylWnMG7qDA^LCj7l_&C?m7Xtl#;$pX2-MkLP%f?)(1uc)wq-Yn<14p4Z>Mf5Rfc z!9v9jItgOx{nXS@DxE;`@*m_U{XRDIl9H6uMSgLTFl!=nM6^WhgJjiyN?RD^z`AS1(m5iWLiV3*Jw zW40=xbV;3o>JD+`NIgWXI_VJym?15G6`fX7goD7PXzn`kb6UA@sEyJ&r5T37ot zPs@94Np6Y-zy@&KboTIonZe zfNIi40v;xs*gEp{E7w1xt3E#XYbau$LfQtypPZZ~T=4#WMM+8em{QoLfB*qc1$h7H z_(XnuZ&wD(B+!QLBqTKcyo_-Ms&9d6e8O0_lN5jon1 zt+Ivb^*JdeAt8GV=kYfv`WJ}6%ZDG@;0rJNW5*!q#55`q_aE65fGUOeDGQ6q(NS4| zDKE%xwqg#GhwzVLSx)ED>WI+$`EaTZA!^d$@XnvwTVQU|GcW+X`_$8egaE6vrluwg z34L=rvPN>YYe`!Vc34-n^bsP(ViJqZ`~=AVaj3tU_ALqO88AtV$E~M_W(W<~oXThQ)^q(ZV-FPYg96*6iKe zJLQdM>uD1-m6)DhjPZMn+_+BexS%vPA{1tf@QG!vFBx9mUmvn=A(mw!z(9V)(wBIM zvz5lM`5N)#m&+&ZI?f77j?Q{I2C^k3Ea)3>HC{BBA}XNcTkbAQ3A}b^`#&wKs91C1G{ZApvq`{OUcM zJ;p6N^`FIljJ@=&^18exnMEFB9YmcuLd)TsABQ9pb4JSHVDytG?l{5Ly!pp{jZ+D> zZm8Od04>nd<0TS3_dj_Pl|2x>uy1ki9HS#6VMR=+XrNan)W|O{KMW7o2JiC)Lx5br zwETjU@Tm-CFFSaD0C~b6q!olzyc3}taVOQ+3=gS?Z(2Qftv`-#@}A^b{k&cR3&UF_ zx#Og%X<1d3l$coPO-%4nv*r{P(Wv=^DPzdk^Bu|vVkjoiBvC}jOA9K9?_-mzCMdrFpBM3p%f(Gln{5O$Nm++GCtVLlI_?oL*=25CMP2sn0R8vMRv2 zOeGWe(;FL^NpBT&)^G$GAX2;f3X>Fkz2d^c9%p%c0M_AxbJ~=_C>!yG`b1UJ@sV{G z`TGddfG5D)8{LDYIf&riDm+#lDVN3mj|*UiG=cqBKr112Z;%YJv$ggjog`h%sqB9^XR@a9 z@?#=3JS*15w*wTIPt+z^Do<%mx_r#p^IlZW|BFi?jhYK%()KQO`$q+jkEqM6t9sI` zSy6Vg_zMoXoez8_a+Yg9ggYVV5X}Dp#q~u ziH$esc5Q;;v{XSUdW0I3g)>m;;fNzzfoO@?4{1W99l|pnwKf?8?+6-YJY>)^1+V=D z22b?(-*QCZB-aM2Da<%2Md;)7;ctaDPUtf?$BzJ^4z+{xt8yksN8bV$n}-|=YDT2T z#zq^ES-^hDAFi&c`SSHEsKia6x}&Rt_xIlK@(Aj(vY@@5I(EzrBw=i>CQhexY=8Hz zvb-D~zFqI%gZ{P%#=yDr=YczRO}ux9P1NP_7@&eEe?c)svwSl)wmmO1HFa`s4s%f( z&NxL}aon{Bv24N3juro75<8qab&8ZU0^|j7k`L?Z%A|F{ZFu2^;I}zA7)zfiCyS+r zr0dxI?EiEJD_|`US`%<40oLJ2fmea1;LN#mbXyGIoDjTo&CMs~=LtN}(7rb^ER$pa zKu|QHAVNE~0JsUX9Z$BA$0)C${CkRv`S2lB^trEJ>n2rPaB@0y@L=!M66RqxMtaB9 zwgco>)?RBo_8a+y#66D_{f!K-0PQHj0;%NS;@;+KftKgd^PzQubnAcYSS3J7;G-sZ ziF$Z=fK)C&;j20XE|H78C5mdu%fT>2MvRDv80Be5cxil}12G0STgd28`D?hGJEIUp zVF96a$UJ9ocvu@-yI``L{|SjKUc;kKC)L(#i2?f@jpYNudN06_?I6(c*8Z!Gn{_+PaK!;+K>6T#H5qGS8PYm zsvmeU@oe#_q_xD&bMp19b1yHbkp>0s{7IyFsgOVS&sO7VcXAYk@cOB4Uxi`npY{*b ztfQq5KARYyUk+VbIvSX&2aMl(Wp22chF@#p!pW6D?W70(Cqy57een9<)0buIbgBTW z{*b5NzYip&!lsD?$XH67TJf1|vI_tjc7!GR5A?sSzJ&LLdINQsD(^g@5`nyhjxKU8 z4RZ{}rj}vY;lQ^$|Jk#62V1aK2x!2egzmC`Rx7K17eAt_GQKZQop%al2s+0=n!PSV zODR2dWAl{MXo--v@vsA2RqNb79a8UN7)~cYkM(t9V|kArA!$r{*W9?#fxdigW?b4~ zEYamF2sD^}kJO>8#?m6817^6EC>PK$XzeH5901moD+AxYfdxM^Jsm4xr_P{Of9Ri} z#(F!yHDY5|ow=!P2?{Ie*k2pP<|y!T zVs@-`@8~)o;=LUm>JoDOI?2NhlShWy0```i!=Mh#MavQLcp}uzT!u=w6Rh7m}r~AViv|o2reXr&sKNY+uK7@fyN8QHManG zgeo!0-)Obd%91DBi7XFhVoF4#edq37MFj;AJo&};u#^)x)~icbK81iv(}$8DNgY`r z7-Yqfsjq{BFJHZaq>g35ru}E@;qW3m-Z1sghqiY=O_|S5tgA9`Xf7em{&J{3k2pnV zC5ZS159HcZR$#$+s{l@zg#e^Sg~62vKV^PqT=%`l?gl=~qv>lyY0%ad{W(r4 z=C%8!OIUNIi};G(4`EdB5!LNB=uN^b%>soQjZq|maYgoou=oqm9(qc26Cgt{(n*eN zI(S528jL8b)7shgR=P1V^n&nNhU5|1>~2gZv1Krn;RsC5Fr1{KLTbdy`ws}iK%+es z7_Db1)f)zm(D`s%^ove1)Xs^-7WSEBeSAY2_B!!Zu=I=JVV)TNX=|AXZ6Td;P%s|QBU`a7vZ&$Jxey&NZHg+L_;0$>rc&DNme+< zv#=y+ehLX8QXez_x8l}^!=nH#K2t8RKlZ6w*1}P#QA^yttpE@1&V$J z18~MHwh17*p}Q2bt`XLfL!AgPE&M)TV-snlVI&jfzFiAXS$aE1k1ZAa3nLf)^!;k+ z(&_AGvP@53-Q(*+y@w3`XE(&$>m)yWd+2*m?Z zAqp;VU*Lh}0iZ!j%F5ch`?K}vVTFa#ugp~>J7nK$oJyCn#D8c;tLCoi%&*;gD?_53 zXW6=OCB7DJIwD4{7caKjd^!9S?wc}aotz3XGQLsnG1An`Mhl17hxsm$V<0qG zo}}Yo<<5-9OL5WS@!aXph@%$z?Lz)vsHmyIx@NufZX7R*X`zspOhk4Gmxn6F-eN1hrB~t z>?x2IU{&(+^4ZjkNh+7wZ7u-?f+`BE8BCx+nFJyP)+Wd|?2kt=JoXO=us>9P+sr#M z3T!_B#h4nwE{K^K`{nksp7E7-k0c7oe&va^IDi1~>nJEGdAPWkq6{!G8FBlvlJ`e8 zTZx4-t7}srg!mpUPYjfx*BP zP4dUQI>#u6RzIvv>2M96ji6i=%xP)RC2kQd&=OMV0T4NKmZsHwFWqPC-Hq&UfNblf zsLfop^_B2f4WLu1Z$1RbxdSpMur-Ht%jdrhzTg{fi;<15ULyXsRd=ewfu46IHK2>w34(QW80IyLMGQe=Z>{En5A!s%nqxg1?7{GqO5&&fV1&vV->DVNxp$ zX$*VlVI;FV#Z)~}U_fo80mwQP6_xM5rG0m^(5E1)_c_ah3ySfm$KkVUx%q4O0>Ga` zPTVdud6=(W|$8s6n^*sz?Ek@s3dG{M<;%IU><_6fEENZ*RaP8 zzd38Isuy<{LbMF`>}*_BdAIYBl6-RueJQXIf(%_#n5Ox5Y9VzS^_SLWtyYrK+w@Lb zub5QjRfo*qE!NaVAqNj`o|@m6S3(R9aAj#_#fIKw~x-aKQ4m>~gRA6NA@{-E!MkR^3rrqndiOJA=E*XonrJ&f z{_G#4&e;%t2|r=IxE|w^=Jq8%Y-ILrr~y&xSd`On%1$_`+qV)mZdw zuXi+bDukvqDTXdx2lIoTK2GBUIa4X|nn=u9F>cBSF|j05Ih#^+9#n!&d?s`RbXr1! zp#6mI51|VkG!7lA1$6d&%Ulq#paj8hqWz#-^sBJ5XoxZ^r7J5&_Hbv0gSs->Cj2Kb zK@|{iadX@F_wU)+>N!jipkg6l?s_~L!GW*?K;u;?YokxbNs*;SOD^Xt8vt}73=Blz zZD1X(f$NSSG6ir8vIZ!pjZ@jC5)v9{q#aL0h$uxK{tkKVacCjM;!2N}|s z=-U847ohmUQjzOII9_EK8Dr)#vd&Kqqu8)Qb?L0=i0;G1`9p8U7B#)?czJp@F;>HH z1MdzSgY7&WQ3a^MR&{vT`q(jGCWHyb|5TPJDBL|fkam5qUR{Qpri>fUMVXU(HSX?c zQY(#E;@UkdD6qdT{(29^E^cS^g=i~5I3a4LVPPaWemzi9;&JQGEo++ycf~`XgvrxP zo0*B*GRr+LJmI@%c@ zP%#kYdh;ic4(LsKZSvAm;1DjRX}z!u-0hVHQUv}0BBz=n13wgh0M@YRfgD8ND4=1K zPFzWS@hQWCi0^K8h`jJ}*MHu#4i(M4;t!=QARz*0RLR5Y@ZmOuDF_+tZEeG<$2!ln zX{g)B?J*?RZ65Vx)Ym(HoIsJm{1W}`?f7_tA{kiIojac(X99rA#FJlra%TPm1LtgD zJ6XOXscqkUp-9!WK%?D)iN8^m5j;0%zbKS0Aq4Rc#V^}u-{bFDl=bP{dV1$vfmZHvLVoK_voi}I7po-A4e}@A^PF(u!h_3 zbs_rt?PGzbl(6d3oL^G%T~kw7lZ_!J{TdospTCpx+_V9Q3A3J&f57grstw9DoxP&Q zoe-gajmmiPP3SAx-^!0Vj!~Zz-bJk+^;vg4*KxOeO}zY4Y+%uYS*3MOu|&0)bpp;q z2u&bA4PIQSOWtIUG7PMIQkoxf#s>ZlcQP|)r>2mNG5v40k%3|qqL=pp*2hbS7O(jb znm){$P*j5jxe<9py{h-%2x|cT`1(Rj2q24-iwihUV>S2+1nzFk2*fA|7|DlueF*!9 z05{4WH~`Jc927km*kP*}K;xmAiX=~sj4)!|)qJ?+JG@SuOANii6Tqy|&+p*8$F+cs zFt-JhZ!qA&sH!{dKy;JMi<+8xOsc^k_f}B@D^ePJ@6LlV54m@82Sg8Zn9{>1e)KDf zkjK#FR3I<^gOm&h07w%^UXYSQg+1k6Q&zSJAOnm~6S-z}oYu6I3z(u1(37=7KvZ~8 zfMYQ7#(b3`g1C-Akq>*n&Z!8i21is6NN?z-BcDAZEP{nE205E%@T;mS0uBfM4kl%B zHz74q#uW1ft>FNeZX6s3LB~e12PNkeFfOc`zdgL-p0hpsab#J4VY}frqe+!mEa>zQ z5h9@_qAmDXPWt>aK3~Az78$-V8y6Jx9!#)MK_JC8z9fI9)h9lTQna^Mt15+>fdLsf zBq*p3v_2qdn9Shc-Q3zjcF=Y_(DIjGMB&rN$rc1}M+a>4Nr2*3gNJOYoq82|tbvN~rA5h$)Z? z!~Oy67R-O~!uLr_6ATRHIq5HpG-!!ZKKH~XJP>T4sbDy*vK-IAK*grx?1krv*r9=$ zFh~IeGlg$2Mxg|P?|o6x(Uod}oLH=ir}!6aa9c#T-A_%0xT>=9$kC(WPBkxHtiiE_ zyq7#7DD@Bh&AaL8zkmIz!uD#sE}2`hi>yhCUcp_*BXr$jiEdoiq3qVw53)Vf?z3-= zl49=&Gt{600%1*jfeJ+5XE}rgOan)ys2&>FJra=RcOuFX>lbWRpgK**Up61t-6$EH zIv_Hb&SJM*noqTl`u*j4M%<<|zP`Rt+5`l=0)&f61xPo5Pvhzged~huX~_A7wT&4e zGl3PYxnMopk7tES4Jq;Xv17^i?qRsif3p=T(B;L&$0a4v-*3gl7=U@RYnP&&9El2A zyfYwoq2xeU4zdd9qTqniv{6n{_6=oMl3KqYP5KQp9f(d!O5hu((9?n7HY$bEX+#7t zp(>ag0m~dCe-U?qX#nl>#EIyGhrv%Ei73J_NQYP%xeT1C;#aQ@^+1K!gkJ$CB5e8M zU^(1tZ-El0t-Wnx7UBc^0s`PlLmA$JJA+FY2&cG) zh6b>G@;}=h7BuMrgu8*2dV6kSW(jO;1?L~0@Df(F>|Z#sL8uvX=@+MwSb**7>%T!0 z1fZpG=ZL296D_@8S5WmeHfpYIAa5mA=p7Bod^Mzkm6BKL+rl8HXyA%}`zQA59>=_0ng5TseJDG3`nO4N2e9V`y zTtNwmZ(qLb2Y*^nFx>wT$$K4VT?2zj{9JVWkO(KGq+omo3oWEnDth`0Wfn5Cpxh-V zCBb?Kd{okS*4J7fJVDp`1#|}7kkFYdRlg+Q@%Qdc%+BIa8Zpsxt(|yQFHraJ-n>u_ zY4#PoSzJey9f*O@Z$SG&Q1Ezr^5dX-^lZ4G|NFg^#201b^0jM!Q9 zzGLwzwvpp+_U?UHSUA~wlMO)u@#Yl>=Y?K4Ihv0#62veJl^-%cdEGxiZOgt3>X{NmnRrpi8xTg}mqgBVf_U)vZ&XF0mb4NIYj8Dw9qdlr;Up0@ zgB1&SMm8;>(y9jzeCX(SjN6A=9kCH`En3>meipq?pFd*}iBLG7O0U36&R@ilqFph0 zH3CyiYn10U9B3$xtUDYqOmJ`(3=f>0o(`wE{6wqyxs%~*?G`$v`?@aSf62YHpU?T~ z{uV9|PwD;}ewSByAMUR$udji3Tcdc3{SJ|WV(NR!Kx#!=FEh;xO+5KxMbDlQ#B3-gu`E-Tw_tdF7;I*P0!1c+R!nU6$#G-$2 z*pUkWIALNVBq+FFTpX1K3KFQVpdz20o8x6?UqjPuBZm#8u(1DzgO17%UlCrzckx0% zw6H5P5gWTf^mf8i8NU$7&S*nIofvoTCU~eKLlgW%p$Nh+0q!3X0+f&K?FNBCHbOSU zgu)Sj%g>*UN($tvefv7zy^~Z`-9+PtVGwFvqWwd1LYasWS!?ImYwS2_7a*>dM-%w zD{*=emLXKaAOYwdWF@rn#(yisTY77~seJBE&%P);MPPS%OU$rruS1k0X$ z8}S^D3ZW$>(o2!R$MIsU@o4d#K_(m=r4M|b`jf$x4;BU&FB%;?2I}pZ`oM#6`Zz7Q zz0T-@(-quchWHKT=}4T)p+kf2E0{76XvFv|Z~&*(x6#6E%c08Bu{Md$;wb05!%R1JSo&wY2pz$jZ`<;0q`s{kVn zMXmZc-^6#p|KkFjA$Vn?$fu%$YXeRnW|0-8rG%Aj=tA0i_!3ln691W2>P$BTJWZ-6 zRW3k)M1aH8k|k^}Bn|um0>rL$cqfQr?9L_N5_w^7(Ob}n$^=R)aOHy`HgEOVyO#GUK zsI9TR>M+VtJk4Lk4zw>^ut_`hHPNL_Qf24Tg*$?!vb|~ARaC{O0@&Xp1VW2}dKe49 zU;=<`a9;a8=||jmq(=U(%9V!j`z17lkFj5iYqG&VE5Kp$Oh6S1TjQy*u>-LE$__zq zg<&n$;v%n>56&Q6LPAg23wU3FR*(X{2sqxtb;XR$dv6Pnur_C)*1)a6$t3vsX@mnI z!Er;xz<>!OA&?i--))DglQQS(^VF%c0uXcP9ug7-*J#flo;Cli6y);x*~ zcso@g)8b?QBNSnwWJ!KLfgL*CK%6UkpECXc=Di3$FFY_(v$M;^a2%h2Nie|sq@+GX zG!W7Vj-U7MbDF#6|F%5U=TBg1_F5R4cDLL6`s_?^D2so92yrz-Dpv^1D<19b$;4+~e)4qcNnV8%DX z_zTo2_};dcMH@Gumd9IT(ZjKXogbEB`4j4qSCiiV&|>qC5C<|82b*l@#aK#Qz&w}o za`?a@14B;_fz#xrXGWq?Nx$ap6H{n7lk)RXrz2Stb`u2#s>)OM z0}lE`yZ zuY*-_y)`v8@vaa~6RlDHBYwcA%ILoQjV2p3XR>LAI9mW&r>CbkHv^Rq;8#a;dVSNw zVlRj{#l>f>tr_-DDNQa3CW$A-*E!fr# zTSr1?*=G>7+{R^-?5UiA!-1!d1R-_=%laZeJC#{L837*q_0Z5p(EW4d$h?nAXv4s| zJ!PL6us-nr(U9fO%(%N3V(jY+8Z_y|A(43~gbZf$SO zqk5^B50Zc204o4N2cKca&t*B8snzqOgi#=; z##9L-6ny_tEP2j_ml`U3OcD@Y=RcPWgXsd)ick$Vf#qF>TaR3a#~7Z)mVt-(2%rl) z8AUa%r)Y{l<1ne}CqyB{|e+2I7|(0|hI|gSS0B3*Ac`MO^%xpNk$n50}5PuTcx^yVW&Tr@O_Kv z{0Whn=IQ~?I0~DSrCu1+!-DMD)29z>{(i#dHXM8;7b~kF@KUl*B4(x;7a%{tf+6MZ zU4%+xZk&T3h(M?X&^7=UAW9*cV-=Iz;Zx<*G#D8GI)bIyy&pcb$m^jh27)~Kk^EQC z>C<Mrge}Kcjc9`T?iy-_q57asyD}T`Ft`X*Hi?cjLx*T+Y`l$0P7W`a_U5Nf zg>k}>NlZ#AzDVvKv?HbP;_w_I9*c`s1Dy^ z$MD7!>cbQwfA!b)Ak(2%Lt%v;4gZU}6F(0B@_jJQL4=cakn0<88wq+fr`FyGPBgL} zq-1EP+%8?JzcLXIZ6iF7LN;cV29DwN{Lh%_6+DFCwMckW0D=(2(LLPi(39yYqo1I( zz#3%s>okW{R4gR!q8J-E)>Fr1_6fJ)$Y*usam}ulWTK@5pEAh=ky^#Y0n7mDq^L4N zBm!xVVC-}16g&?v?2cv@iPU$>K8mc08^+JS0P$7Pt0Qa{U~xrE5xB)n%^nGlWDo2K zI*4Of$2-^H!k)*#-hOAvr()0@HVdHbBA7ug3wV@Zgbn8>ugXomJoirYet0+>QjP*OsF2V&wR98B=Z*Sx&I z|B9l;1BUZYCB$&3V^D_TTKM_;u3_O~ivV+X&mf@G-&0eBHBfl^XrvJ@@c|`gt0DE% z($sA1>nq1+qHAp==07_Mj2W%O$!mS)Xs=+I1$5j+p0oBd??2s!yx^it;rvg^ViRvd*Y}YOkU;%lpEEy)V<%MqfBgU)&9$_o|bv0 zlv?%+wh^aww;1<5v2N;VHW8inw2pqxzt)JYxWd91c`Rhm(9%Z4Q1TEF=^?=Zj0g%+ zd(FsynPi6C;W+Rp&QYnKsE`M(WRc>D<%fhZrVXXn=i!IqS8iFLtV*=ZUP(wQj)^-%(BuI9VcQG z!W#M_FkBENMwoYIF6z~@wNbY36Z?YsKN%mHE65R;!iRc+?4q^6Y^&GU-Tw1341zUX z$Ziu+v1LQIq>Tmks3XwILi>p-p#~-f?G(!F_c|errMR;@NH!s#=ro_<%~L-aZ$zEV z3%I%Tx$$MfojZDmHP{Q$78u-3<&{PN_;P5_gE{HUNYJQQn0kj@nL*)|^5;398#f+N z^PH`O5ueq|%X`r;Be}~DWzWy(y6UYt86e+J} z@gLKSMN@PYV0&;a2xvD%ZC zJ`cYKgwT$U!m6OY!J3Qo6bq(Voy;-qm7*U3yK{*R~U-k^_5Cf2v z35&K=co#zwpIJ2o2mR{efCWDA;EA6ETMk|oZvzt(Poz*Vsey0-?M9Djj7Wq2*3WMp z1N1c#a{TyC;4~OCBXPpO`8$fiX6mCxMv@>4#l}LP5)8#A=KA0j!d9Dj-5i*fk%7Sg z@HVtFIF=w?Kr8NrehL&-b!&>)3_NLIW}UcIh?O|w3JO<2+JjFIAn;rRN@+C_B> z+@R4x4hU7L^FlxYUyo@!w`1Y+e6jtIg>-efW6V0D=X2!>wiiPVgnp~h&|H36CW5nI zOLVqi=Nd&SF%`cq6KjFBWl3ld<e3dZj3;nhs!X4JrmaXSj|L{s8RnSL=UvUR+rCwOv`N z;V%FYHqEwkO10rAQNeiE<;0K`zYFSqRHZ;9P*>vl0bn6WGEeWx=E8gc0&Vme3GMBy zVZ`CoG*a##ONpt9(9|w!Xs$Y6x^(x>9rCa2GxRT*oVC!{i(@^ugalBKx82=1(cSOg ztA}h8#BF+}c-QDFg3&+#2LnIgBUm7S@8L=qI=4;QS;EjB#J@i_7m*HSHv|7e{w-O9 zz3@Sy5s;aMCX+u09{?~6r8IU#WrB4@Xw8UcsCq8i+vgzvi=BAmgStA`twRTF=zUL8p-iOlfIO{kD z397fI4x;F%uJ^vx;a^ zzBb40`wfR4sR(whH2cYG)ldG&F(=LB7&+SX(QL^-xHCwbaW~_pU)}hYsjJv&bGu3g zkyVm^S>R?A6gc6~1EOXeLO~7VY}m~$=RTbJy?Yf9lyKQWbRNMg zq@pAVC-Y`GaiArGc|knl4YlZbEiGFVJy3)p@8I?mAgSqTl7~;B9YcQ!z23WbM#v_} zoRGz#4MvZK+lV}sdiDCie(bb7cyJJo5rB9wG3MSCt)GWgON5>G`}Se_rwa(=?c4o8 zHgMi+pMo-!3S0!;kG;K+@HOxjK#n~J=|O2Hn14WbL1cNoiD}hE7Z+*)5|~jYB|)$- zHaq(?FOPJF>FYBhPZH%&6bfMA+|Uwz-4&^a(TFqbC)QQKhrsp)4ULB5zg@TJckR|B zw@Pan{RV$Cj2l4OK_P~>hhH%0&-e}CI(GjOIY}v8I)ryEr0htWGX|yT65Zsyuw|Yt zzLcy@u70=QjOAfY4m36!Fm{MFIH(hdGDZv80W>ub$zG>F6r09;20`6-0CHroP57;u z){cNYhSSEm13=G{?Uq$@uZ}&%lM;;&PMX9-#~2La(E}D2H-HIs%IUe}C^;0!7@Fe< ze1Y_(X$MIc?F}xCw~r6WngGX}$Sj?NNV39+OJtBMqS_}_nV+6^y>tnT**hq%fq~!a z1on=^jh7PIg7y)0Xbh7^Dz_Em)}2rh?0-%L>_u39`~JPup+j6LSvy*%h_5t_G@$>) z%L3v@b~!wdxzL8}unvj{v_W|0wuv3QsSDC3vMb1!p*%>?StDnChu#4sA#`GB_D5pNBvtwgw;MXJ}dsI~PZ?adY z@gwo~N5#eBcu%>x;T;YqzMl$gw86W<6le#nDRNEIcT=4=K7)Y|+N@aKH5_WcJX-Rr zzIEG_pkI`eL-ZrPt&Jwb$EOM@1HZqXDXLFEg(&|M`i_{Mgu)Xk5vquhGE{tc4G{F7 zID59!u>y3^Ah1eN7$&^Mc{llpIeq$r2fOB?F+l)#2Qp7^M(S7ZGzq{q0Y{F%~DFEgq0C-wr`p#H>6=T*>#BDbE{oyFBv80ZprJ_Yg( zM^<^>G(3%=yh_PuwJiFXXmRuTM%obu za`GrJUPVPk;e3JIh9QkJWPHebNdEIT77b#P=b8RqZyWnLF~PtgM<%z%eW4hI|`Q0_S69zA`E zQX&nHQfygYlU#WodudRxK->>w3+Ka7zJl9bgXw2Z4zUF|7~#3c65;+Kc4e*zk5m;MRL8Xteer#a2S3l|yG!NJyk-&uGia*J6 z?B-qY)NQf>4eJC9nXv2_2O-LQfpe+|FWK(~&E9z>Tm&X7Ap_`6dsz zctdPfhaZ53Z4H?i=!FexE1V)0Jx~P+b0gr0fJ;eF39G9Iqn>I%0=qPGbAo~X(yupYc0thWk%hqr8!Ic`&S~huGL1s~#`oo3Tl#D(=PT_^7i4u$%BPwc>SIMk z3h$$ncfa-ZUB>OfL!0Suv5|qtF(w(X>+eVD@%;@$9Q6*IA8;ul)1cjs$DIXe_PVXjp5jnsVxnyGxIwb89LF<;K6Vw<0ETF& zFs~P2yWMIB|3~4Q1wM!f$l&+|Mt!7y zy}afSyez42)4s=0Y`i`^nl;A4(69@ek^!C}%xdxxaaV)!1_IPbC)9Fqe+E{oKl=_v z{M)xQBaGNYjy&pzQ5Betlfo5VWBO!|^TdG8c%o~>xkG0W+2ye-8a66FXJ=u~#-Dwj zOziN~Gk9;KI7Xg^n&&GDrmtUNe}*!Tpr~eFA~4Vq0Ufn$`u6D&R=^-FVhr01yaAaF z5GBO7wcxq}dEG65zmEd&;&~X?DP}F_EH+E*wpyARaF<-Y=2iaK8jmQ!w!Nm`zw=eM; z($l$4mTTP|!D1Ccyb8RGMg`BCFc!h8nQVU$NI2epwb>2YKd=XgPc@T=P{<=311X!d zAd*c(Jw>ol!Hb!6!$gz7>`=ZB)&Q(ywhgnwe&Z$LlTeWn^rN7ULVr>VKVIYlln<$M zw$9FLFx1zHX&D?`N1*?oi@Il@z(c+#=duHJsVG;-1MiejPk>&_%|no~fVV(R)oQ|` zfUXN4*2qDea=ugzQgvv(vAF8m>=#x>M$M~EVey;_u1(?Om@&G#y3+2E0EZv;X>~Jbk2j2g+JU<+Qij$6lwDFm&DF`1Qo0E)CrmsiDPg zG9TP|)c1%ADgRA=Q!z5dQ^!1ZfuzeX^f-ty2-w&u4<*iJSc?pO#Y!IogBX}m@k<2w z`-7r>AkEOEqVX|VlTKT+0TpxXHPGuy~5 zev8ipi#WppO_J=pVGo1#yH&DwxaQY}G_6Y>ES4}VJRr#|9dw7mE&#Z;H*btHRe-Y= zC@YbZG4D&ZFk7{L}^GT9dBGhwtkOR3j9Yc zsXcn8s6Gh%kxQ52Z{JoraDW-}Pt_>2*r#2}d;_McG@N($pNm-Nq~rW5A z1ySR1vM5mi0|1`l?%v&l)ixlrl-laRSO(C}!U9OD$lqKwmSE>dTa=FA))9Qic5RM+ zIDEZVjO5{%IJ<9PQSSu3J5gu2421(TS|e;R!BEmTP3{6d8B(rPIU=bDTow1B+A~OP zND_K_;B!faDpJQwij7lD*qfW*%gD&UuZIU@8wCywwz;9mz#As=WtJ$$zl`+`ra)be z9(9F}DyVpvyi4q%jZ^X56&|mKF%@DZhIgcqWG<_@$C*#lk&EYh!AlyC8aY`e%}_z1 z5}OP&RQ)dZ?eKc^5J@C`Q!KL)@W@j??$U@mbJ>&3uwyg)w-8c|&jW{Ic zPWBpIcJ65O_yu3Buqyn>K{CDp6@n;K| zy*SImJdkVny!x0?K%0g}zQO*r4m|BWl9u^^V+#wx;3i;#BTb~)Y6E8&r-#3bM@L74 ztNpt5UHgy!zayY^bPx<7Jo>y|XM&TS8#o)e=sXccHPXkyxbP+Z*oo(fS6%k^=E!iEI(C2W(he@R?g zI+_6$1{jPXYYVnW=a_^{##90gLlY`xQOXbC#DX5nPMqQ)LR#;`ulVHYQ?zrK>Y#Q* z3;`)#XFtu0P9o-M6jdSHftvS%r3Hu$4|a9`yo?&K(?$kDpN_Wv`gavX5vse!i?Ml4X!wh)s3Cy0@y%D5n)^a@hb6+SWpWx>B*@jhHW$s;% znTUU{9nf!5V(3WmJThF&vV79FopeJgWTu?|Cee-(vnEqQ6))@iEPoLQ1WGT*z7urZL ziYuD*m!GzAoa@RQ=9|C0dhlh$CA$=!k*&=p(w4ewmkzFG{8jT1e;oeC2SXzyZn4x` z*On`Tg$|{RWxh^7=kodWgWW?%zU|(B|8&hU7ngnUY-^K))ua_Ur4#nwITyXS;`BGU z+njw)Hmja0U%7oalwq(l@^AHnPYwM?_Hi%ZR)g<=p|#)CdX-U0cIS`BMQ>Q*Ta|hr zMawpgI1`I2jWCn@(DmnVA6RcJB7H)s*(Kk9`;EOF4Re2R%*_*}E1^-k%JC80B{tXI z444((x%KkGqC-zJ?J%uBLuQE0JGzzT8o!wio4ZtWM-Jb1eUV}Q`?}Q4`j+SCGfrI+ zy!_?)zUaN)agE1u@4-yQ5{+TM2_91xDD#IxcDB%tVtA_fD8_#Oz)4#CJJ>>W`q{ZN zCMHCK<0zCCp}RmNgaokV7MWEso3FIapGo+@+!_zt$LV`3JM$a(VtYE_>xjiy^+25= zZzEvHIVK?b!-C5d!)V-wQo;8$bn#;-#DGTLhD3>vF9epCT8s#Rge6B%ORW9-*I#VT zFysYCXpC_QM9!o3T2^uZ6cCm%9MC==F!`g=jI)O6$w!jT=RGZuP%gex8b(EWaB`0p zBOncQ&)Aw2fI`o(SNNEGcxD%HJX~^lgfXPkh{NcIyS zfEY1ApPip?0L~w$4?cAA-Mdwg6Cm{aNZ+co`F@1zE177>r0X_U;@%%lX8z%R#3F6n z%y~CgC=FexuI`eFBcmIfB#$*?GpwNIZCH?2ej*`5t&_7qv)kqeQB0jv%h4t#BI!7z z30g{ro9VVzZW4^GvK*(g&0i0fEs(}DDOdj7f9{o6z>B~I+E7wXI*MCMW2x;b5^vl5 zm9pcustx7J+=Xx|%UrCY+3S2)zQ+8^E^-NQ{>QQJJ>DSAel z!kIJ`;(Wg6j9shoe~&*oLzzc+PFbCEjeFanMPyXiHu&a2^FbDgb9yyGf&K1QdkorW z`t7^AqOZ6+PYm20;kL@U;`nf=Vn<>1_21H$?5bz9d7l*t&h+xIIJu-w?YhtNTw_w% z^MLazzpsoBiHh<7`!DfQ`k7AI8?uAzQonDZGlv(F-@r~O9F|CT&6)8x3Fvcz-K zN=y0xtt)NQg*_e3UL&u24nAQ0R7(F_n#P0wV^m1xZ3;fMboPX+ru;5WW;dmk_qN6e zd74GGjblY8DpIiAj}&}BK?mve{e_zel2cTC0#n}DZ3nt2gK;BUNw4~B}-B?>&n){9+9ao=X zxbo`40=t4M%aY5Qr|qA%Qx29V_TMo%P5Vy`A`!H*_ye!1#$495Y~(}jv_o2q*?cXB zS{}7|dwMRcu7U(T4>F0&oAWs)pva?0c)v32KgiJ>fdNBTd;0*Gwcj4XvlpNpZ~z-` zc`okoYg|0u`{=sgtjDdNA6+KC5S25NdYVl1!#TZp^^eEO1sGVVgwtCU*nHaGgz-MA z=Or#Ra5jiO+~ zSA1c%@#P`jJ;!%D$-N-EeOU7b$#7I3%W-Pjb6ae02{+W`xah1Kd_@9rvi!yh` z8MOgwUR`FJ`({+T%!@xUM#bl`p6qRuXG|T-q(2i`Ntdx&evH-m8fbSGdo;me(UzHeG((lYS${hPDJLOP^wN6lDi`sumc{7rq@k!ijZqc7t(2S zUnF!$vDVIQbKd9qYT{W*NAK?}uHzN;@>(`u*h(0e&T4F@;|!SRw-Z?6}c8K4Ikb=CxLsVJ^Zhg&|~ zMNNI=_;Jk3Jkfun+aE^6g_I0^mE8&xJGB-60@fX|!;f!z+8>P&MkqR0&1)H4D>-*7 zslu)@o3oqAFmJXZPlW(3uyEOxUungoX2K_BuRqi{zo|VzV`MLFWd< zmk$f3QHd}42LZ8b_%~e)B2hCPogk6y2bG#{n)ixL#IS$r{(}eGLjm)+a48dh5V51a z!%|j0%M{7z@0Op*!9L!esp!V8GNc?`Q+Ir0;B168f`mkKe}$t;23M0>SYBdH#TkCf zq~b!VXz8iHjsJ9%k6rglR^aIP_1os6eE^XJhm%|yECzpnDyGb&usG={$^K|tIWLsO zXl<_1_RPabMQ+c1Mc(QWQWUB4#M`eQi+nqveLwnuzlj z$;uBz(~W2(FEbuMh1>Xv`ATOQ>!&k$V&0+d@!Z%TL3>@5QD#BZxY|nGS)tW<C-FKrs86eC1AN=L45sH=UihkHp32W{~86~a^+8>DyF8Ua`VJ%U}z`n=6OQt{buJHP)FEuU@i zVVjW?ID0H~qcZFIa`FE3nCuV48&}tU*XuMswR$tS5M5OPYujZg(pgsnQm{Wtl3l`5??2_fwaYyaV{*n08+=h)r=4p)kxvEQw3%`DBypJ#K-#Y&AFUQ~uiLZLUd|s~@ zl=p7>J>{IIeydt*E?3O|b-lfwQ>jIrEP1)p_(5G6x7pQ&R<-?K)#kobB8JlCjzM5) zwK{zTzbY=#!T8SZZZOW5eGl3CIZph# zVS8~$kLmV~U2#}>4B_9#-ivdixFrGttm=-$=rAE7l= zkya0X;-qQ5XE1tZc1zN>!R)ZF1T@z`y7|X1eFBl8HE$}l`Ov@tJHG72Fre-j#`?m&qa$5M)Je2TKx>ZXyQL)-YG@=o#g59p&IE{u1=|P zKsc|1P|oR^V(|A2lz!H=Js{^c|IARiN)u#eeQ?Hh&{Ri}z3F)1iE>H-t{jKGDuYMz zx{ecz4wN6QEx*g39$!BD;a^bMgXoG0do|P1Cq*WuM)!D#tv$J{pAA=Ca`7dFm@eh$ zLyV2TWQ0`bmQ@Zh-@QC~6f{AGL|y_bMOiU)i-mb6>93U$$z_hFv)(vn06YJv4#TLC zF0z$e^{YgnVeN}~Qjdp#>ySj;QCW=K!k88~$35wWP4JRaW(^njjZqm%zmg24&1K(~ z5rDa+^xUYFZwLAJYxy`BDtsYIz1Pm@P>-K&Z^|ZWA%TNd1w`%o~D(0oZs)d zyGI%eTgawaZ9hFZTHvg^9Q5>wsrQGuv}W9&jNGf}eUZUxdiN26|> z1y6xrzZMat+~Gq1%_!ZgObe5u%p4r+Q1HG(cG%yA4KEO8N$=Zt!+vw5mnW;ZbR@B~ z`tjgxiB1i3rh}o!MoL`jUQR~~-_nQ->u{FWHiLD=OmAKrfa|&8hWU{Z8F+gFzQQa4 zR1o*S@&=zu$#+F*_hLYu8mwi=^D4}}F!#{uI$x_A?afU*PyaeJ$1A6p#fnevNAuB? zN_w7=B7#YQC?@T&6Ql2s$?3}=OjHcg9htJa)aQ1E`GOBC!2%US%Um&Fh2*FBjHUS% zQ|=qY5l0+782<_iiw=iB3k%LrTe$x)$a7T4+#8YisMk5t`~{*cBvRl&VMr9tPhhQA zbgRQA4%kdsmwxJd+LTc~Y6TIi*?`#O^9$9sTl>%K6mpWLep7>b+>HR;eRa;|cinLetC$+YuL%#H z&o48cKkq&?v`-ga=GUDi(v)j?F$feEM^EzdzMlN`)7aB<-w8pJ=>n^b#ZmEvQU0Zi zkmW&`lpy1P8kTkTf{k#2`HQV_3vUBL_6f<;y*W(Uh)D1j=nyEIu#!fD956PBuY4GS z1VI@}WZp*oebL`4?tZlh9Bq@Y>)=+5N5q7Sirm@`dcs73M8 z2W^INg38hwT4fG3ph%EmpfeAJtNZxtxP}^Tx!GVfw=Cm_*i|q{*9A-hb_Uh3(*3)5 zf@pNLfN^j#&`_u;)6~-;F(Pc>#o~4s&vL6nK!Rs$4aEd4H#DOA4$SQR$RLnIV`|GX zC*E-4&18PE?}`^1?#L*8=f1`nWPk0v+XmgSueJP{wB{rMa_KlpzIWh^YKpqellMJ%yG!Dnl_Y_D3FMq^uq4mNPT>Jd_7}mz( zlwOsOe|67&uJB4X&bTQ|IG~G&ho2qVCr@)ic}ov=iM80B_4Xz_@LTQ9qVWVNO3>dI zomAA)bDBAJ!tT^5s8`@Qy%5-z6o0$SJxwR zWo8l!M-t`1tvwIaGHGPidl^0JVzYbT3C-WuD&{?Uv)Qhk*7V-7p6`KG2aR8N3p{XT z?g_JHwg2nXZRWiC2TiFR)LQTfCThCYYRZU@i7<6L`x!uTrY5 zwdd20?lQh!&e*vcfUM;|zq~V}aY$hIN zMWu@HpUjrZ;9+otTG!S=GnP&F>rK{yPitSM5sN ziQ7)TU!F^FnqK>aQf;wOX=Mt1XngwdzQQ^b|3(o7AH1(}dh#}kn-;0w?WC*&8QdER zKmoMBtm`J47_Av) zBOTX8-K%&D+*FvKtqgDb1uN(D4m{g-AhjTHWSDZ)JUK9Fg-<1qLC>h=sKwqmX86M7 z*gNM84%g^j8!o}Kh_(O*=V(V6f(C{CfOYQZtoLW*-0v4sGU9YHVdto!t`1XfOyg$7 zg@uEL@a5NE1uBhIqyGDA=XaW%l!8kf$SJ6ZZ}C6t?A(JU18(txu%PHw<5kDZ^54+5 z*~_df3}3_3iY|ADy$tSoV2`eqvqpGQ(I_P`&~oVNiNxHvP;aM?xwVyVoXErg9yoJ@ zR*g~wBMsQ-a8nZEmsqL5;eCNMG@L4-1B&fdo=N>qZ_o^cp#f&9ISoxrY=hg`rv%q# zdNR+o#egxD)!gOMmkgTC5{shM7H)~XUuT$%1i;C)C{9T9LyD`-u4JLG$WkU2TW8%H ztv=Pdn=yX4&39!Fo+PYg$ujbDj2ZyaXz9^U1|}!cUS5=!*8&-u%L>%29`b`=B<|9L zK*w?5VYX53#reVWr-L~&&vPvP<#?T6Gr!k5&|i1}pe9U&rjcKr=DlkuvX}cRc$~3D_E2@&m^(RI-Yeg0rk6@+h1yggn(-y8pFV-T5g6X( z%MQ>Z!JmVpI)zj3r6=#v>9yvQn6)hr^*9Jm7Lr+pIS5uL9N{^8W6{HfwV<-^t0;*< z1)^2>b^yy()&B}YfrZ78!bC+~SS8vh@EOIeTUK7~SUiAFKD@xZ=IoOnpAyiGUWRZS z2Qx{=;UxqTc>ZXZCeeeLo1Z7F4cAZ>Kwbr5paYjUXpsPcW#%uZEuirZVd>w<($G8{ zN9!Gb4N^JDs;YXcemp0#Z!f@o0UYw#@$v~6N7eNA$1$e{1z`yC2k_lcT%!m8_Cllj z*Fbz9IZh|buHSSK{3nd10&v|$Ek-3gIT?E8%6cXytG48qOKd&U;%>b%aXLsSiR-t& ze{#F+kNcUle3?%R%*h}|;OzQq8r@VbY5pnNQ%7s82+!w6oNd6~VQCEa*A5-k+Iqv8 zR_BdBeW6$qb7pxfJ+Zo zB`8%KYPZknbpdZCJKokz>d(Yx01GG$!uFqD8SE8Jxx1vuwQQ!q&R0_m(#H)u7 zyYQR2-RQ+5t}1g$+CAv008JTksM`lFaxYI{&DpkXBUU@`mK_=-s;WZb(6AnlD} zoK}QFXc+~h6Q-!#RH385-fk39AQ^Qbzpr5<0aj=uuozPp`Ma8F>Lh z3fN9HTc-&3;ZtoeRH5UMehB_gL4l-O07yxGS2PM<+ZURsU*iM29He@U&7L+J$MJcQ zzM{!aUAyj?SC&0|Xvk5ILk%U5^=8WqBcp^$nKY{MTJ|x% zPiQT}0qg*78Ax<+5aE=m^Ej6qxZW2m8qOgoIIKM6^<_s*AMWW&4e|KWyI-4fiRG(X z^)uScMF^^XzPq$70DH`wKg#wumD=btw0hNT$0(mp6sdLeiHfz#A|r%@kn40hXnu`tP0F(%)^jM z&VA{2L?{8%1k^?l@Bn!RS2!#m2(AlW{y11Y6@;%L{yhd7 zp6*?rrG>%{d$dG{Fpn^VbsO0F*o+zPWsPkY31?v(gF0cP!322`bYrlXi%rD97eUd} z1>r5oH$zE+0s`=3`GVfsf@H&U->2O9PMd$UY@ALMKYV$x z_(1$$LrD7kIiX?11yLuSx}D+^*mEdwo#kLosyHRNF2c0^?@%gT1ozjoLD`vK2OqC| z*z14q5P7TBDJ?eva^KsHF=RngpTHx1Jy0B`|vI;>dew~*d=jUhv>oyHE+H^P&7bsM|$S!YPfzuYjb z$WY|nd7XgzX+;?&sw>&C$oiM+LD8Gn0$fx%)MUmBdFsY@Uzfczs}CDhQ3`;#cTsy2e1K{z>l` zaz6-VQ@WA0-)l8D!=V|}9NQvDL$igfsY)>%97IbBc>FkIawAH=O7Udkru5&i44pl= z1gtD9A*)_l6~YLPOd`>Y*WpZqBaVY_fi82zFexL!>>h5BwoNB5Oo4QXZ+c$FoxirU z*Me{8+qXdw$B1dYo2AmA??VZTL}%%9`ZcgUQCn~@t;qt*Pb08q2=N7X8R$GP&npJs z5iDHXrUdfOXOiAw!P17h3Lpv|QIKiT5u=reOdK5;Sbke%t4#>O!#8bb+X3>BqGAP( zkECqCTth@Un`NjptKhMjs2&x!NR=w#`#WqOi+#Q|pt)Bqir?_O(|ggmQDf6x>s#uB zms!bs$X-SKn%q}IdXjRk-?V(i)8l33%vZ2$?4~I@Q{u0iT-VMeZF)_is*|52t=gkx zTD$r}W&o+Z-Q>9f#Yv<@!tWyQr?4QxgqNs(0U^MFHRR4Y^!wmnGy#60ZFAW28v0QY zi6iUNJy19ir4~XiCdIh{TZ7I75mxuekxgnF%nmRynsnE4Pc1Yz8F)-9x}G{UKl$!p z6aRW$1xVl*bZex%k{XrXEx55uy51EEb7PCq+KV`bq6{|`;n9cfsK<4UcX7hRgkiVX zrwb%B+)Oa ze7SEnFX)tB8v$F4EnoZ?05SE>eVK=r#ctt-5=`q@+IWTVBIzSb~*?siqfv zMD#(e!5T+ywR@1BK8)O4P5-HOG{5FOqdEyFMd4;8C-(z8gLN*)`5=0vuwVpP505e& zIS#tKLbAZS-`gEVBS>-Z-2)(KK{*&n_6VBEmjZ$CA$YduFAea4`K>p zg!En{!g4?M8xLB8RiO+5Bc3{_KX5}@l~XpQ(yQ+u{qSMtuF~>oG?pK53Orco0SE2~ z9xlNuf_S4KCU#|bpJK8IyQfyhMxA)K7oUf&dQSk#!D#^r{aIU^u@DD}gh8Y)IFH!l zY=dketuPWp0Lfp2jm|RMM2rhn%z9(b=~h{k5LLfc7J;8YkOnOS=yyt(ql&yX_9c@_ z-1gKR45=cqV+VgmA5mH+Y!%Ui1XO& zJmI@d(n1-ZIaMSO3^cf^CEmDUBe|J_sUGPw0ww{AV^`4-z_KE*Tn7GwM_Gd5F2RcI z&3{boW*Q9A+i!JfV`E=yPRkL#r*faqH7U_QNyod#=p#lJ7Nl(C&Fg`W{rowWk8X$j z`SB|m86+jX$^$q>s?33RXSD-JR2q{+otrmipI&CimLpdqb6>T4;D!1XcrAW8YV=^= z6DAu?@Rbn}LHTxt3v!1&pVHqa?&@xxi_@?1zn7Pnk#WXB#I4gz%rJ1d}={k96CUpciq2bp3)#}XiVziOkFq^0hdctNXTV-DWCOMpm|{vW>`-r==6rEG@(p9L&@o9toG0q$ zTD*nN5^Qw(-xj4Q)ms#sH-^`L2lfghl1#i+Y?8RJFwn>zz%Ll?aQvY?Mgq`2xX|~6 z+7+smapwH_iNW&6H5Nj`!cyEUa%Xwo`93R^c{fpDsD$X=<`zDRxtd}t8(5fw-(4G=|k zQz3LrO*+nbTd?7gWp!-J1^%!dAIhGl$>vek%dTb)*%qJ^EE>Z)jbP9vi$Xt!B6{ z1aNxxE1ayCh{tj19(4z_6d3IaYgMpyEi6)sJ*_8lbVjeY?8J#XG_-+^V(7XTOjgKk zz97Y^Nyd@yr4}O+39YVnWj}9u&qP|&!BJ!$X(^N~I)@K$-D7u!Iq8G%u_~c5NgEa! z$>ZNyZfhfL##hStNo+sdTk7iSvc1^x%op>9?I$s$_0&u+f&9hClmOk>C8 zr?7o{jfEsMC~b)fgsP06Kge1niTHD>;)x@XYlyolq@@D|upBTR)Qb7Nm~I1M6W!Xi z_{VA9wO;~8yZ|xzQwze2DQ)VJ{EXD>2Yj*J4CKF~E*b!diL`@zwIwzZ)fIhUDgpo+ zn17YHrIHvX{Y;b$0{*j=`p1>usx@sgFf)tCE<)UCWYjQSap}_9g+>2PQWgt`$7HHl zN2s&;R^zy{*{uQk7ozwnQ}krHX0!`o!-)Px>ONJNOq!U)f^FSr*uP^-R|O+pf1@X{ zehia;-8iNc%}6Spyg-sxn|Q=6krDr@_xuH6iVFS2?-Dui_m zti!01o4cs9IL8N7RH`4}%q{p{D1D81*S~kYOCn_q)O->nvJX6Zl#0PhA6Y2Fz>VQ; z6y^xSg$+&=;8(719^~<5d+E69r8VZ^MNF$6txx#8QDqcPM7Tg^p6{;uJnLO-wv4n} z4rwb8o!EU3UzV}pz5mV{7}B_E8ir1DjvA0M!q5YVgSKODqV7D%f_}HB=jK4mL1(4F zR?d=~uuIcw`B3g(TWH*bP-r64!}Bzajv)kn{Z4$pQxrT^xnCL6D4a|x)yJY={`VAj z?J&2Pqx@3VV*wW(9X_-=M)v8Z>bXz6xd_Y^NB3dB4WC{Di_A4~4aO%!rAU)xgoQ`p zUdnbw)}|>EH5WovHQ7YE=I1BloyT_(??18{e_$aQiiJwR*n|Zoyww3Z6`MKZChZ8N zvucx9ye94_A)05bt$c9DO}$&3=QMcI`8APrBGE(U6QGy@!P+_S#eu*!?Lf{zVdI~~ zHkiX1X_W8;ad1GH$DyXr7KF?dgKq~L8#OWv3L^qi-kZEVgu%j0!D4r{o&63EJ&Wg( ziwIm$mU#+P$POtAvQMa?v$Zn5;IRc~4G8};q5t_4Qh5i5a4RN5T9J^jjwKRTS_icl zxGa~bnn=v9;-k4KGxaSQq;HbZ&FFTcIsvqi**hlArH#dh*^GJwFXP@;O(IUP(J?9p zkV1{uH?0q>0ifFyGx20m0y;5V;}%a6An5_Cortb}Je$Yb6*j2qew*22!)|@1O4pSD zJ@-2HAOvAxHX6j(R-kJ{a!wye$u?vP@T+enj{HAK)s)C}O%BPo-#{kZz8&58bxgr3 z9QC-d(U2ing)ccsk4`90c)XP%4~Fw=0(tF0(dE+@a+30~#D?z5+cp7~hIP=KMmjN;@$?vc?%r-1On$aX;KwNY< zZkTNc2+gXnq_h;WHC(4|ylbytWeTQc;#1C0C~^3Zq4{S|_ZLM<&M1BG;&a#5*S}s_ zxxa0i`0SFF0g%TTk2&kvhj$_-_vXW9gNu%mVSrBHrI3)?ZvhI7^{tvO{;ab|%((?d z`E3EKM4%hPGN35Jluk(3bGre0VXRQ<_FN)!9xmAI^LB-Hw#HziV|J^cuW*RTzgFIIm2Vc0E=9J!zNbKWwO>h;#2XPb3-HU?Q`D45o^AYG@>bHm@~)G1jwBExy( z$dM!DcTE5Db|XeiU%`I{sU$#|buYruJBb4yURl|%---TuAobF$eo%Vhv07)N;hJ4S zF=oSvAB;{65GG30$7M!>)|x;gjVmsZDKd zCjkN3*$MO&0c7Xk=9Y)aUZh(|KEGxZfBzZbHKrmQif5NT5>ME(XUNPI+eBlUQCb`U zlJb3S&hC7E;=9oQp0>1~4vKLt){sVj{|@On#I?sGWziH(*zZGF-bsaA%`NbIrej0) zxcZgT|Df=R?}V9iXD4jF1;fzb9fida98QqEsObmon6P*fJ-FldV*d`_eK)gm4e!H) z0z}tg^5)!|z(`|bOW?a5`V@oBm2GV9BqwicT=0r-wbP7pYFA>{MHjwKlPbd!v~kB&m_%%(T5^N5y@x3laJ;v(<==4y=lul!yiz8W?%kZX=E1-93M?JB8Rii0k%oiV1!zI@vxMs>0&FbKrH0-JYN| z0&o-&6im<&(C2`9?f}3!u>EhXQ2%VIp|wpW*)%fgnGL4HT0=~&ufL(I6`JFCv@W3% z#*ki>)PlKJHWw);Yco2X$kU3fJ~gtl-zh9cd0rVrqvHB|NC z%%9Li-I-M*8OPKlVq_cF`Uz`_G6FCdf138I?;q zC0scdl>fZ4a2{`fy=-`WZ9@SVZCSffN1^vw1|x95gGRY)D6o7YIwcs(u}{EYoK@fz zPC@{wS~&I7Ya|eWS@E7%pWFcb^~Q}av583|Qtw}&nbl1_^MW7u&cE4Kyw=v86vymt zs(Y>K)ZB#cF9qa8sH4+_FqIPYEevborfy7m{WCC5SMM0Q&DH?Zao10Jp}C9<4r<&M zYGbov-*w_L`}alHjq!`JT@*aqOSd7I(NLKQY%RI{`!6CKP>TmJ^wh@(>wk62o=;u} zlB#Z>?*E73{-)q&C%R$B9bCZqYc$}L%d{X{}l1U z0d%PT=%zGQ+1ma^>wnMn2`WppzhTFs=K>WkGb1Ca!TnCG^!v$Kuzzzz90wL)B*Xz| z4Yp+Ho#Ur$wKJ?|*BDuzxe_h-=VXVzy`*E0G1(ErxMEdOX~uZnhZNfg_6ULnV4h2_ z6VN+M!p#KOtb-S)69L8jciWYuq=ga|vR5e#=Zm;JWBvHjgzd4D8U04T-}7%2iLxY6 z@Mi0nAgXO;7ypZ_wtZMfn6AJNjuf_|@iZPBygSfVk?NQ|useL>1aDRi$_D}sH(K|I z;yx5K><5;Ps7(=(5dU-Rp5{^nzDT}ea_p%qkngLumvMRZNc_No6<`OXU#QTL;bY0s zt4m0Dg=2x%b=`7VnmpY?p)Kp=n8lUIAE6und!Gd?q)W3d^Pe1&WK=Ijodc^`B(2pO z0DnI;b9Q%^36<~r3REDnf9S40dEpw!-I)G9vZ*4)E=wR z#fJIE4ZVd8@;A;#Av2)!jn@$F9^wr z`%K60fb-{55n=8>H|{?_^!t|o=iC3}ZU5hI|Fhq}U*zB1=J#v=zrOw6xB1tq)Pu6` UKV_T=p~07?ny%`76^nrX16qgKV*mgE diff --git a/docs/source/images/rbac-token-request-chart.png b/docs/source/images/rbac-token-request-chart.png new file mode 100644 index 0000000000000000000000000000000000000000..21bf470fd34f9e7c10f6e8128b170c1efd1d7a2f GIT binary patch literal 494274 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