Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace pyjwkest with pyjwt #32270

Merged
merged 7 commits into from
Oct 18, 2023
Merged

Conversation

mumarkhan999
Copy link
Member

@mumarkhan999 mumarkhan999 commented May 19, 2023

Things to be done in this PR

This is part of openedx/edx-drf-extensions#290

@timmc-edx
Copy link
Contributor

The source changes so far look good. There are still some references to pyjwkest in the repo, though: Tests, a management command, docs, example code in an ADR, and the requirements files. The PR title makes me think the intent is to remove it entirely. If not, what boundary are you hoping to draw for this PR?

@mumarkhan999 mumarkhan999 force-pushed the umar/replace-jwkest-with-pyjwt branch 5 times, most recently from 052da28 to b026585 Compare May 26, 2023 14:35
@mumarkhan999
Copy link
Member Author

The source changes so far look good. There are still some references to pyjwkest in the repo, though: Tests, a management command, docs, example code in an ADR, and the requirements files. The PR title makes me think the intent is to remove it entirely. If not, what boundary are you hoping to draw for this PR?

Except for management command and requirements files, all the above-mentioned tasks will be done in this PR.

@@ -33,25 +33,37 @@ def _decode_jwt(verify_expiration):
Helper method to decode a JWT with the ability to
verify the expiration of said token
"""
keys = KEYS()
key_set = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this code largely duplicates what's in edx-drf-extensions. Can we call that code instead?

(Having the duplicated code increases maintenance burden but also risks us having a mismatch in behavior between the tests and how we actually verify and decode JWTs.)

Copy link
Member Author

@mumarkhan999 mumarkhan999 Jun 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning to move JWT-related similar code to this repo https://github.com/edx/token-utils. But that repo is under edx organization. What's your say about that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible that move makes sense, but it deserves as ADR, and will have some consequences:

  • Ownership of token-utils is currently owned by cosmonauts, and I imagine we would need a discussion about that. Would it move to arbi-bom or arch-bom? We'd need to discuss with both teams.
  • Yes, if this became a required dependency, it would need to move to the openedx repo.
  • Would these utilities be exposed via edx-drf-extensions as well, or just through the new repo? Would it depend on whether or not it was specifically JWT auth related?
  • The repo itself is not in a great state. It looks like https://github.com/edx/token-utils/blob/main/docs/decisions/0001-purpose-of-this-repo.rst was never updated, and I imagine other docs, so its purpose is not yet clearly documented.

Things to consider.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to say whether a move to token-utils is a good idea without knowing more about what that repo is supposed to be. (It's not clear from the README or other docs.) I am interested in knowing more about it, but it feels out of scope for the present work.

Here's what I was picturing for deduplication: #32466 -- this rewrites the mixin to use Django setting overrides so that it can just call our standard decoders.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to say whether a move to token-utils is a good idea without knowing more about what that repo is supposed to be. (It's not clear from the README or other docs.)

The repo token-utils was created for edx-exams, where they wanted to create custom signed JWTs (i.e. non-auth JWTs). I'll leave it to you all decide how to proceed, but it is important to note that edx-exams has its own token signing which will need to go through this same process. See https://github.com/edx/edx-internal/blob/2785fc7599e1f39fbd5387c3da18c0e74883f4b2/argocd/applications/edx-exams/prod-config.yaml#L102-L104 for the config. Note: it seems this setting was designed to just allow a single signing key per service for all custom signed JWTs. Not sure if that is the best design, but that is certainly not an issue for today.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mumarkhan999: When you get the chance, can you confirm that you read this and you are aware of the other JWT_PRIVATE_SIGNING_JWK cases? This is all I see using https://github.com/search?q=org%3Aedx%20JWT_PRIVATE_SIGNING_JWK&type=code, expect a local config in edx-exams.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap Yeah I read it. And No I wasn't aware of this local config.
Will look into that once start working on that repo.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mumarkhan999: Is there a top-level Github Issue or Confluence page tracking this work across all services where we can document these types of things?

Copy link
Member Author

@mumarkhan999 mumarkhan999 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap Yes we have one. Here's the link
openedx/edx-drf-extensions#290

The ticket does not have much detail for now. But planning to add some there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I added a link to that ticket in the PR description. I think it would be useful to add references to the top-level ticket in PR descriptions and/or commit comments so we could find all the parts from the top-level issue as needed.

@mumarkhan999 mumarkhan999 force-pushed the umar/replace-jwkest-with-pyjwt branch from 1ea2427 to c5de62d Compare June 16, 2023 12:51
@mumarkhan999 mumarkhan999 requested review from feanil and a team as code owners June 16, 2023 12:51
@mumarkhan999 mumarkhan999 force-pushed the umar/replace-jwkest-with-pyjwt branch from c5de62d to 58d2482 Compare June 16, 2023 12:58
@mumarkhan999 mumarkhan999 removed request for a team and feanil June 16, 2023 13:00
@mumarkhan999 mumarkhan999 force-pushed the umar/replace-jwkest-with-pyjwt branch 2 times, most recently from be38fdf to be72f9b Compare June 16, 2023 16:50
@mumarkhan999 mumarkhan999 force-pushed the umar/replace-jwkest-with-pyjwt branch 2 times, most recently from 7c3d53c to e28da09 Compare July 4, 2023 13:59
@mumarkhan999 mumarkhan999 marked this pull request as ready for review October 13, 2023 14:12
@timmc-edx
Copy link
Contributor

Other than the doc tweaks I think this is ready to go.

@mumarkhan999
Copy link
Member Author

Closing to rerun stuck jobs.

Copy link
Contributor

@timmc-edx timmc-edx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you!

@mumarkhan999
Copy link
Member Author

@timmc-edx

Hi tim, while testing this PR on sandbox I got this error

    jwt = _create_jwt(request, user, expires_in)
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_authn/cookies.py", line 319, in _create_jwt
    return create_jwt_from_token(access_token, DOTAdapter(), use_asymmetric_key=True)
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/oauth_dispatch/jwt.py", line 110, in create_jwt_from_token
    jwt_token_dict = create_jwt_token_dict(token_dict, oauth_adapter, use_asymmetric_key)
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/oauth_dispatch/jwt.py", line 83, in create_jwt_token_dict
    jwt_access_token = _create_jwt(
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/oauth_dispatch/jwt.py", line 196, in _create_jwt
    return _encode_and_sign(payload, use_asymmetric_key, secret)
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/oauth_dispatch/jwt.py", line 286, in _encode_and_sign
    jwk = PyJWK(key, algorithm)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/jwt/api_jwk.py", line 60, in __init__
    self.key = self.Algorithm.from_jwk(self._jwk_data)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/jwt/algorithms.py", line 433, in from_jwk
    raise InvalidKeyError(
jwt.exceptions.InvalidKeyError: RSA key must include all parameters if any are present besides d

As far as I remember we have updated the keys. But it seems we have missed a few environments.
Can you please mention for which environments we've updated the keys?
What are the remaining ones?

And also can you please update the keys in the remaining envs so we can merge this PR?

Thanks.

@robrap
Copy link
Contributor

robrap commented Oct 17, 2023

Hi tim, while testing this PR on sandbox I got this error

Does this mean that https://github.com/edx/sandbox-internal was missed? (What about https://github.com/edx/edge-internal/ ?) Or were the changes elsewhere?

@timmc-edx
Copy link
Contributor

From my notes in edx/edx-arch-experiments#261 it sounds like sandboxes actually generate their keypair during provisioning, rather than being configured with a static value. We deleted the configured sandbox keys some months ago, so something else is going on here. (See that ticket for a list of environments that were updated.)

@mumarkhan999
Copy link
Member Author

I tested this branch on an already available sandbox (triggered on master branch). On master the generate_jwt_signing_key is outdated, that's why the keys are outdated.

Now I triggered a new one using the current branch. Let's see how it works.

@mumarkhan999 mumarkhan999 merged commit 92731be into master Oct 18, 2023
61 checks passed
@mumarkhan999 mumarkhan999 deleted the umar/replace-jwkest-with-pyjwt branch October 18, 2023 10:15
@edx-pipeline-bot
Copy link
Contributor

2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production.

@edx-pipeline-bot
Copy link
Contributor

2U Release Notice: This PR has been deployed to the edX production environment.

@kdmccormick
Copy link
Member

Hey @mumarkhan999 , thank you for this upgrade. In the future, when you make a breaking change, please use an exclamation point in your commit message prefix, for example chore!: replace pyjwkest with pyjwt. That'll help Tutor maintainers notice the change and make the appropriate Tutor update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants