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
Feature: Accept Asymmetric Algorithm #73
Feature: Accept Asymmetric Algorithm #73
Conversation
For #70 LoginManager now accept single secret still, nothing is broken. But It also accept dict, for asymmetric purpose.
|
I am using black as code formatter, lots of changes just formatting. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks really good. Thanks a lot for your help.
Maybe you can answer the two questions regarding my comments.
class RawPrivateSecret(BaseModel): | ||
private_key: SecretBytes | ||
password: Optional[bytes] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give an example of how this class should be used?
I assume this is one way the input can be given to the secret parameter for LoginManager
when using asymmetric keys? If so I think it is a good idea to add a test case that uses this class in addition to the dictionary approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test cases about dictionary-secret already exists, see
and
Each item of above is one test case, thank to pytest.
Read more at https://docs.pytest.org/en/6.2.x/parametrize.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parsing are handled by pydantic model AsymmetricSecret
, so RawPrivateSecret
will be take care and should not use directly.
RawPrivateSecret
is part of AsymmetricSecretIn
, and the latter one is used to pre-validate AsymmetricSecret
's secret
field.
https://github.com/filwaline/fastapi_login/blob/0f0dc21d9b07f35a6b5c909c4e44d89602ecfe5d/fastapi_login/secrets.py#L45-L48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But RawPrivateSecret
is never invoked directly? In AsymmetricSecret
data is of type AsymmetricPairKey
, this is also mismatch of the type when passing to AsymmetricSecretIn
as the data parameter here expects either SecretBytes
or RawPrivateSecret
, therefore I don't see how or why pydantic should cast the given value to either one of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the flag pre=True
indicated that it is a pre-validator.
Therefore AsymmetricSecret
haven't paring raw data into AsymmetricPairKey
yet, not until the end of pre-validator secret_must_be_asymmetric_private_key
, AsymmetricSecretIn
is actually dealing with raw data.
A step-by-step debug process will show you how data flows, it is better than plain text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
secret_must_be_asymmetric_private_key
is handling three different jobs:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I got it now.
If one passes {"private_key": "...", "password": "..."}
to AsymmetricSecret
, this is then passed onto AsymmetricSecretIn
, which in turn is recognized by pydantic as having the same fields as RawPrivateSecret
and is thus validated as such. If all of this passes the public key is derived from the private key and then cast together as AsymmetricPairKey
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I got it now. If one passes
{"private_key": "...", "password": "..."}
toAsymmetricSecret
, this is then passed ontoAsymmetricSecretIn
, which in turn is recognized by pydantic as having the same fields asRawPrivateSecret
and is thus validated as such. If all of this passes the public key is derived from the private key and then cast together asAsymmetricPairKey
.
Yes, that what I meant!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current code only accept PEM format key, do you think we should accept other formats?
For example, DER format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think PEM is sufficient for now, if the other formats are needed it shouldn't be too much trouble adding them later on.
Yeah I saw that, but I think if the support is there it doesn't hurt to make it available directly. |
On the other hand it is probably a good idea to not include it if it isn't needed 🤔 . If so, I think it would be helpful to show a message that |
Current message is a pydantic validation error that algorithm"RS256" is invalid, if user selected "RS256" but not installed cryptography. Maybe you can add some documents about it, just like FastAPI Form Data |
I will add some documentation in the following days explaining the workflow with asymmetric keys and will then merge and publish a new package version. |
Annotated and Literal have been added in later versions of python and would thus be missing in e.g. Python 3.6
I implemented
SymmetricSecret
andAsymmetricSecret
, and drop replace it.New tests all passed, and fully covered.
I am poor in English, so docs remain old.