Skip to content

Commit 52b46d7

Browse files
committed
WIP: add /api/me to get identity model
includes fields: - username: str - name: Optional[str] - display_name: Optional[str] - initials: Optional[str] - avatar_url: Optional[str] - color: Optional[str] - permissions in the form {"resource": ["action", ],} where permissions are only populated _by request_, because the server cannot know what all resource/action combinations are available.
1 parent 72da3a1 commit 52b46d7

File tree

2 files changed

+63
-10
lines changed

2 files changed

+63
-10
lines changed

jupyter_server/services/auth/authorizer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def user_model(self, user: Any) -> Dict:
6262
user_model["username"] = user
6363
return {
6464
"username": user,
65-
"given_name": None,
65+
"name": None,
6666
}
6767
elif isinstance(user, dict):
6868
user_model = {}

jupyter_server/services/auth/handlers.py

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,86 @@
2121

2222

2323
class IdentityModel(TypedDict):
24-
username: str
25-
given_name: Optional[str]
24+
# see the JupyterLab IUser model for definitions
25+
26+
username: str # the only truly required field
27+
28+
# these fields are derived from username if not specified
29+
name: str
30+
display_name: str
31+
initials: str
32+
33+
# these fields are left as None if undefined
34+
avatar_url: Optional[str]
35+
color: Optional[str]
36+
37+
# Jupyter Server permissions
38+
# as a dict of permitted {"resource": ["actions"]}
2639
permissions: Dict[str, List[str]]
2740

2841

42+
def _fill_defaults(identity: IdentityModel) -> IdentityModel:
43+
"""Fill out default fields in the identity model
44+
45+
- Ensures all values are defined
46+
- Fills out derivative values for name fields fields
47+
- Fills out null values for optional fields
48+
"""
49+
50+
# username is the only truly required field
51+
if not identity.get("username"):
52+
raise ValueError(f"identity.username must not be empty: {identity}")
53+
54+
# derive name fields from username -> name -> display name -> initials
55+
if not identity.get("name"):
56+
identity["name"] = identity["username"]
57+
if not identity.get("display_name"):
58+
identity["display_name"] = identity["name"]
59+
if not identity.get("initials"):
60+
identity["initials"] = identity["display_name"][0]
61+
62+
# fields that should be defined, but use null if no information is provided
63+
for key in ("avatar_url", "color"):
64+
identity.setdefault(key, None)
65+
return identity
66+
67+
2968
class IdentityHandler(APIHandler):
3069
"""Get the current user's identity model"""
3170

3271
@web.authenticated
3372
def get(self):
34-
resources: List[str] = self.get_argument("resources") or []
35-
actions: List[str] = self.get_argument("actions") or [
36-
"read",
37-
"write",
38-
"execute",
39-
]
73+
resources_json: str = self.get_argument("resources")
74+
bad_resources_msg = f'resources should be a JSON dict of {{"resource": ["action",]}}, got {resources_json!r}'
75+
if resources_json:
76+
try:
77+
resources = json.loads(resources_json)
78+
except ValueError:
79+
raise web.HTTPError(400, bad_resources_msg)
80+
if not isinstance(resources, dict):
81+
raise web.HTTPError(400, bad_resources_msg)
82+
4083
permissions: Dict[str, List[str]] = {}
4184
user = self.current_user
42-
for resource in resources:
85+
86+
for resource, actions in resources.items():
87+
if (
88+
not isinstance(resource, str)
89+
or not isinstance(actions, list)
90+
or not all(isinstance(action, str) for action in actions)
91+
):
92+
raise web.HTTPError(400, bad_resources_msg)
93+
4394
allowed = permissions[resource] = []
4495
for action in actions:
4596
if self.authorizer.is_authorized(self, user=user, resource=resource, action=action):
4697
allowed.append(action)
98+
4799
user_model: IdentityModel = dict(
48100
permissions=permissions,
49101
**self.authorizer.user_model(user),
50102
)
103+
user_model = _fill_defaults(user_model)
51104
self.write(json.dumps(user_model))
52105

53106

0 commit comments

Comments
 (0)