Skip to content
This repository has been archived by the owner on Jun 1, 2022. It is now read-only.

New auth0 role VIAL WB Limited is not displaying in the Reporters page #633

Open
ugotsoul opened this issue Jun 3, 2021 · 20 comments
Open
Assignees
Labels
bug Something isn't working

Comments

@ugotsoul
Copy link
Contributor

ugotsoul commented Jun 3, 2021

discord convo

user affected: https://vial.calltheshots.us/admin/core/reporter/370/change/

@ugotsoul ugotsoul added the bug Something isn't working label Jun 3, 2021
@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 3, 2021

Related to: #612

@simonw
Copy link
Collaborator

simonw commented Jun 3, 2021

I have a hunch that we don't update the roles we store against reporters often, if ever. We update user roles when they sign into VIAL but reporters works differently.

@simonw
Copy link
Collaborator

simonw commented Jun 3, 2021

Code in question is here - it looks like it should be updating the roles if they have changed but I'm not 100% sure it does:

vial/vaccinate/api/utils.py

Lines 154 to 240 in 9b6914e

@beeline.traced("jwt_auth")
def _jwt_auth(
required_permissions: Set[str],
request: HttpRequest,
update_metadata: bool,
) -> Optional[JsonResponse]:
# Use Bearer token in Authorization header
authorization = request.META.get("HTTP_AUTHORIZATION") or ""
if not authorization.startswith("Bearer "):
return JsonResponse(
{"error": "Authorization header must start with 'Bearer'"},
status=403,
)
# Check JWT token is valid
jwt_access_token = authorization.split("Bearer ")[1]
check_permissions = True
try:
jwt_payload = decode_and_verify_jwt(
jwt_access_token, settings.HELP_JWT_AUDIENCE
)
except Exception as e:
try:
# We _also_ try to decode as the VIAL audience, since the
# /api/requestCall/debug endpoint passes in _our_ JWT, not
# help's. Our JWT is an id token, not an access token,
# which means it won't have permissions in it (see below)
jwt_payload = decode_and_verify_jwt(
jwt_access_token, settings.VIAL_JWT_AUDIENCE
)
check_permissions = False
except Exception:
return JsonResponse(
{"error": "Could not decode JWT", "details": str(e)}, status=403
)
# We have an _access_ token, not an _id_ token. This means that
# it has authorization information, but no authentication
# information -- just an id, and a statement that the user is
# authenticated to hit this API. https://auth0.com/docs/tokens
# describes this in more detail.
jwt_auth0_role_names = ", ".join(
sorted(jwt_payload.get("https://help.vaccinateca.com/roles", []))
)
name: Optional[str] = None
email: Optional[str] = None
external_id = "auth0:{}".format(jwt_payload["sub"])
with transaction.atomic():
# Get full metadata if the user doesn't exist; also take a lock on the user.
reporter = (
Reporter.objects.select_for_update().filter(external_id=external_id).first()
)
# We may want to update the email address and name; we do this
# sparingly, since it's a round-trip to the Auth0 endpoint, which
# is somewhat slow. Again, we must do this because we're getting
# an access token, not an id token.
if not reporter or update_metadata:
with beeline.tracer(name="get user_info"):
user_info_response = requests.get(
"https://vaccinateca.us.auth0.com/userinfo",
headers={"Authorization": "Bearer {}".format(jwt_access_token)},
timeout=5,
)
beeline.add_context({"status": user_info_response.status_code})
# If this fails, we don't fail the request; they still
# had a valid access token, auth0 is just being slow
# telling us their bio.
if user_info_response.status_code == 200:
user_info = user_info_response.json()
name = user_info["name"]
if user_info["email_verified"]:
email = user_info["email"]
jwt_auth0_role_names = ", ".join(
sorted(user_info["https://help.vaccinateca.com/roles"])
)
external_id = "auth0:{}".format(jwt_payload["sub"])
defaults = {"auth0_role_names": jwt_auth0_role_names}
if name is not None:
defaults["name"] = name
if email is not None:
defaults["email"] = email
reporter = Reporter.objects.update_or_create(
external_id=external_id,
defaults=defaults,
)[0]

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 3, 2021

Can I get access to auth0 to test this on staging? 👀

@simonw
Copy link
Collaborator

simonw commented Jun 3, 2021

#access-requests or Jesse should be able to help with that.

@simonw
Copy link
Collaborator

simonw commented Jun 4, 2021

I think the ideal fix here - for both users and reporters - would be if auth0 could somehow inform VIAL any time a user is added or removed from a group using the auth0 interface.

I was hoping auth0 would have an obvious mechanism for doing this - maybe a webhooks API that can talk to VIAL, or some kind of customization hook that lets us react in real-time to auth0 configuration changes.

Auth0 offer rules and hooks and most recently actions - I would hope that one of these could do this for us, but I've not managed to figure out if it's possible with any of them yet: https://auth0.com/blog/introducing-auth0-actions/

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

I didn't find an action that mapped to a supported event for rules, hooks or actions -- most of these fall in the authentication pipeline between when a user logs in to when a auth token is issued.

I did find events that map to a role being added / removed:

Event for assigning a role: https://manage.auth0.com/dashboard/us/vaccinateca/logs/90020210605001053900430196618579152991451933976477827074

Event for removing a role: https://manage.auth0.com/dashboard/us/vaccinateca/logs/90020210605001207488430196686485725205025274365420240898

There is a log streaming service available that we can connect to a custom webhook that VIAL can listen to for these type of events, and do its business logic etc. https://auth0.com/docs/monitor-auth0/streams

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

Also, there only (thankfully!) 3 users who fall under the WB Trainee role right now: https://manage.auth0.com/dashboard/us/vaccinateca/roles/rol_wxjXHDoqafCt74FM/users

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

In the log stream we can filter out API operation events so we are not inundated with logs: b
sapi Success API Operation
fapi - Operation on API failed

both the role events fall under these codes.

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

@simonw We are only allowed one log stream under our current auth0 plan, can I delete this paused webhook: https://manage.auth0.com/dashboard/us/vaccinateca/log-streams/lst_0000000000000810/settings

@simonw
Copy link
Collaborator

simonw commented Jun 5, 2021

@ugotsoul yes let's delete or re-use that one.

@simonw
Copy link
Collaborator

simonw commented Jun 5, 2021

Awesome work figuring this out! It looks like this is the exact mechanism we need.

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

Great! The one thing I missed is the log filters are not available in streams yet - the feature is in beta but not appearing in any stream types. :/

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

Hmm it looks like it can be enabled in the dashboard but I'm not seeing it? https://auth0.com/changelog#3ks0rPxzumRAmCfIjcFQYW

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

Hmm it looks like it can be enabled in the dashboard but I'm not seeing it? https://auth0.com/changelog#3ks0rPxzumRAmCfIjcFQYW

I opened a support ticket for this: https://support.auth0.com/tickets/00490599

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 5, 2021

Hmm it looks like it can be enabled in the dashboard but I'm not seeing it? https://auth0.com/changelog#3ks0rPxzumRAmCfIjcFQYW

I opened a support ticket for this: https://support.auth0.com/tickets/00490599

Yay, this is resolved - auth0 had a safari bug that did not display a popup to opt-in to this beta feature. I used chrome and it worked fine.

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 11, 2021

I've been testing an auth0 Webhook for the log stream locally with ngrok and mocking POST requests with postman, and I found out that the event only returns the role_id which is alphanumeric string auth0 uses to identify roles, and not the name we associate with roles. There is a way to get a role by id in the management api with this endpoint: https://auth0.com/docs/api/management/v2#!/Roles/get_roles_by_id

@ugotsoul
Copy link
Contributor Author

Here's the process of using the auth0 sdk to access the Management API: https://github.com/auth0/auth0-python#management-sdk-usage

@ugotsoul
Copy link
Contributor Author

ugotsoul commented Jun 14, 2021

Alternatively, we can use http/s to make calls to the management API: https://auth0.com/docs/tokens/management-api-access-tokens/get-management-api-access-tokens-for-production

Note the Management API is separate entity from the OAuth authentication api, but does use JWTs: https://auth0.com/docs/api/management/v2

My thought process for how this would work:

@ugotsoul
Copy link
Contributor Author

Alternatively, we can use http/s to make calls to the management API: https://auth0.com/docs/tokens/management-api-access-tokens/get-management-api-access-tokens-for-production

Note the Management API is separate entity from the OAuth authentication api, but does use JWTs: https://auth0.com/docs/api/management/v2

My thought process for how this would work:

Ohh another way we could do this since we know the users roles changed is to simply force the user to logout. Logging back in will update the user's groups.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants