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

Easier extending/replacing of key algorithms #42

Merged
merged 4 commits into from
Mar 5, 2017

Conversation

friedcell
Copy link

Changed some code to make jwk algorithm implementations easily extendable.

If you want to replace a certain key implementation you only do jwk.ALGORITHMS.register_key("[algorithm name]", [key class]) and from that moment on the algorithm will use a different class to do everything.

While doing it, made some stuff a bit more pythonic.

@codecov-io
Copy link

codecov-io commented Jan 11, 2017

Codecov Report

Merging #42 into master will increase coverage by 0.03%.

@@            Coverage Diff             @@
##           master      #42      +/-   ##
==========================================
+ Coverage   95.53%   95.57%   +0.03%     
==========================================
  Files           7        7              
  Lines         538      542       +4     
==========================================
+ Hits          514      518       +4     
  Misses         24       24
Impacted Files Coverage Δ
jose/constants.py 100% <100%> (ø)
jose/jwk.py 96.41% <96.42%> (+0.03%)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8556fc2...fae83ff. Read the comment docs.

@mpdavis
Copy link
Owner

mpdavis commented Jan 11, 2017

I'm curious what the use case for this is? Are you looking to define and use custom algorithms at run time, or is there another reason?

@friedcell
Copy link
Author

Correct, using a custom ES256 implementation on a RaspberryPI. Also kind-of resolves #41 as it gets much easier to switch implementations.

@friedcell
Copy link
Author

Code to switch an implementation (eg. customjose.py):

from jose import jwk

class MyKeyImpl(jwk.Key):
    # custom implementation here

def register():
    jwk.ALGORITHMS.register_key("ES256", MyKeyImpl)

Where you use jose:
Before:

from jose import jwt

jwk.encode({}, "private key", algorithm="ES256")

After:

from customjose import register
from jose import jwt

register()

jwk.encode({}, "private key", algorithm="ES256")

The runtime switch is dead simple and you don't have to change any code in your application.

But the change also means that you can have multiple implementations of the Key classes and use jose.constants (I'd actually rename this to algorithms) to decide between them in get_key(). That way you can have multiple implementations in the package and switch between them depending on which library is installed.

@friedcell
Copy link
Author

@mpdavis any feedback?

@zejn
Copy link
Collaborator

zejn commented Jan 24, 2017

Hi,

To check the utility of this patch, I wrote a cryptography backend for ES256/ES384/ES512 in a separate repo at zejn@f4a840a.

There's still an unsettled way how to handle different backend crypto implementations. Currently used ecdsa is pure python and slow. There's a pull request for pyelliptic at #39, but it doesn't work with other than SHA256 - yann2192/pyelliptic#53 - and pyelliptic also does not support OpenSSL 1.1 - yann2192/pyelliptic#50.

There's also an issue about supporting cryptography here - #41.

I find this PR working, it touches very limited amount of code. Further rework would be welcome as it would allow to specify which key class to use if one does not want to use globally registered one.

KEYS = {}

def get_key(self, algorithm):
from jose.jwk import HMACKey, RSAKey, ECKey
Copy link
Owner

Choose a reason for hiding this comment

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

I'm not a fan of this circular dependency. I would move this key registration/lookup logic to jwk.py.

self.SUPPORTED.add(algorithm)
return True
else:
return False
Copy link
Owner

Choose a reason for hiding this comment

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

Attempting to register an invalid key should raise a TypeError

@mpdavis
Copy link
Owner

mpdavis commented Jan 29, 2017

@friedcell My apologies for taking so long to get back to you on this. I really appreciate the work.

I only have a couple of comments on the PR, and I think overall it will be a good addition.

@friedcell
Copy link
Author

Updated the code per request

KEYS = {}

def register_key(self, algorithm, key_class):
from jose.jwk import Key
Copy link
Owner

Choose a reason for hiding this comment

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

This still has a wonky dependency. Can you move it over as well?

@friedcell
Copy link
Author

Moved that too

@friedcell
Copy link
Author

@mpdavis ping?

@mpdavis
Copy link
Owner

mpdavis commented Mar 5, 2017

LGTM

@mpdavis mpdavis merged commit 1a23c39 into mpdavis:master Mar 5, 2017
@mpdavis
Copy link
Owner

mpdavis commented Sep 1, 2017

Released in 1.4.0

@blag
Copy link
Contributor

blag commented Jul 7, 2018

Hey @friedcell, thanks for this PR! It made it really really easy for me to write PR #100.

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