-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
AWS Lambda HTTP Security Integration #17192
Conversation
@jonathanroques @richiethom Hey guys, I expanded a lot on our security integration this week. Let me know what you think of the pull request. Here is the documentation: https://github.com/patriot1burke/quarkus/blob/aws-principal/docs/src/main/asciidoc/amazon-lambda-http.adoc @stuartwdouglas Just want to know if its cool how I implemented this. Seems to work. |
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 this should be changed a little bit to integrate with our existing security layer. Basically instead of sticking a SecurityIdentity into the QuarkusHttpHeaders, you stick in the raw request object, and then provide a HttpAuthenticationMechanism that will extract it and authenticate it through our normal security layer.
This will give a much more consistent user experience, as things like SecurityIdentityAugmentor
will still work as expected.
...-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaSecurityIdentity.java
Outdated
Show resolved
Hide resolved
...lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/SecurityIdentityHandler.java
Outdated
Show resolved
Hide resolved
...mazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java
Outdated
Show resolved
Hide resolved
...http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaSecurityIdentityProvider.java
Outdated
Show resolved
Hide resolved
...oyment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java
Outdated
Show resolved
Hide resolved
.../amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/CustomPrincipal.java
Show resolved
Hide resolved
...ntime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaSecurityIdentityProvider.java
Outdated
Show resolved
Hide resolved
@stuartwdouglas One thing I'm having a problem with mechanisms is that if there is no identity associated with the http request and my IdentityProvider returns a null identity, I get a 401. How can you make it so that if there is no identity with the request, it doesn't challenge? |
@stuartwdouglas FYI for lambda security, the authentication happens at the API Gateway already and there is no authentication step Quarkus needs to do. Quarkus just needs to propagate the identity and claims passed with the http event received. |
I found that if there is only one IdentityProvider that returns an optional empty identity, there is no 401 challenge. If there are two matching IdentityProviders and they both return optional empty identities, then the code automatically throws a 401. |
That sounds like a bug, it should only challenge if authentication is required. |
@stuartwdouglas I made some changes to QuarkusIdentityProviderManagerImpl please see diff If you look at the IDM code, it doesn't look like it handles null SecurityIdentity values very well. Here when the list of identity providers is exhausted, it just throws an exception When there is only one identity provider, a different codepath is executed. Even in that case I think there are bugs. If there are augmentors, they will receive a null SecurityIdentity as a parameter. |
...oyment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java
Outdated
Show resolved
Hide resolved
...-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java
Outdated
Show resolved
Hide resolved
...-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java
Show resolved
Hide resolved
...-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java
Show resolved
Hide resolved
...-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java
Outdated
Show resolved
Hide resolved
...oyment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java
Outdated
Show resolved
Hide resolved
...oyment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java
Outdated
Show resolved
Hide resolved
...-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaSecurityIdentity.java
Outdated
Show resolved
Hide resolved
...rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaSecurityIdentityProvider.java
Outdated
Show resolved
Hide resolved
...lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/SecurityIdentityHandler.java
Outdated
Show resolved
Hide resolved
f9df78c
to
dd9d17c
Compare
This workflow status is outdated as a new workflow run has been triggered. Failing Jobs - Building dd9d17c
Full information is available in the Build summary check run. Test Failures⚙️ JVM Tests - JDK 11 #📦 extensions/vertx-http/deployment✖ ⚙️ JVM Tests - JDK 11 Windows #📦 extensions/vertx-http/deployment✖ ⚙️ JVM Tests - JDK 16 #📦 extensions/vertx-http/deployment✖ |
3f234a7
to
60bd78a
Compare
This workflow status is outdated as a new workflow run has been triggered. |
60bd78a
to
c9fe3ba
Compare
This workflow status is outdated as a new workflow run has been triggered. 🚫 This workflow run has been cancelled. Failing Jobs - Building 60bd78a
|
@stuartwdouglas This should be good now. What I particularly want review on is my changes within quarkus security. I don't know if these are bugs or features, I assumed they were bugs:
|
Can you explain please why it should let the request go through if no Thanks |
A 401 is thrown by the IdpManager if no IDP can resolve an identity and the challenge happens even if the Authentication Mechanism doesn't require a challenge, HttpAuthenticationMechanism.sendChallenge returns false. The Mechanism layer should decide whether a challenge is sent or not on an empty identity, not the IDP Manager layer. BTW, There is no authentication happening with this Lambda security integration. All this integration does is propagate security identity. API Gateway does the authentication. If the endpoint doesn't require authentication, no information is passed through. This is why I thought what I originally did was much simpler, more efficient, and more appropriate. |
Hi Bill @patriot1burke, sorry for a delay,
I don't know what is the purpose of As you said it was already authenticated by the Gateway, so why would you have 401 reported by Quarkus IdentityProviderManager if this PR also has its own IDP ? I see it may not find a (I may be missing something) @stuartwdouglas should
Sure, the Quarkus Lamda thanks |
FYI, in main, if there is only one matching IDP and that IDP returns no SecurityIdentity, then there is no 401 sent. If there are two matching IDPs, then there will be a 401 sent. I just fixed it so that if there are multiple matching IDPs, don't send a 401 if none of them returned an SecurityIdentity. Would be cool to get a review on this soon. |
@stuartwdouglas @sberyozkin Bump on review/approval. Or just tell me you are busy and I'll ping devlist |
@patriot1burke, Hi, sorry, I'm not subscribed to most of the notifications and check things manually...
Oh, this is interesting. I'd say the former condition is a bug, so we need to wait for Stuart to clarify. Thanks |
I disagree. The bug is in what I fixed. For proof, look in HttpSecurityRecorder. If there is a null SecurityIdentity, then an annonymous principal is set up.
Not understanding your last statement. It should be up to the application layer on whether a non-anonymous identity is required. For instance, servlet can have secure and unsecure paths. |
@patriot1burke, hi Bill,
But is it correct ? You've spotted an inconsistency, one no-matching IDP only - no 401, more than one - 401. If we get to the stage where a given
Sure - but if the credentials are provided then it should be a non-anonymous identity with the proactive authentication being on. Note that
I guess that indeed one can have some situations where even with the proactive auth, and with the provided credentials, one can end up with the anonymous identity - these are likely some edge cases. IMHO it is better be more conservative - if the provided credentials can not be converted into a non-anonymous identity then something may have gone wrong thanks |
Just one more note about it - I believe this is to support the cases where a given |
If an Mechanism is provided, it gets invoked for all JAX-RS endpoints by default. Are you saying that an identity is required if a Mechanism is present? Maybe I'm just implementing this wrong. That the IDP Manager should not be invoked by the mechanism unless their are known credentials. I'm letting the IDP layer decide whether or not credentials are present. Maybe that's not the contract. I'll rework the PR tomorrow. |
@patriot1burke Good morning,
IMHO it makes sense - the full So indeed what I'd propose to change is for the Lambda Re your changes to Note Stuart may suggest a different approach once he gets back early next week. But your PR is nearly ready to go in any case :-) |
@stuartwdouglas could you have another look at this one? |
I'm going to open an issue to refer to the problem Bill @patriot1burke spotted, IMHO it would be worth having some discussion there without overloading this PR's review, even if the issue I'll open will be resolved by this PR as well |
c9fe3ba
to
3d39209
Compare
@sberyozkin I reverted the IDPManager changes. @stuartwdouglas Made one fix to HttpAuthenticator so that multiple request types could be supported. There was a bug that a 2nd request type might not match. Would be cool to get a review on this assuming that CI passes. This has been around for a few weeks now. |
Sorry, I missed this in the deluge of notification I had when I got back from PTO. |
* Will only be allocated if requestContext.authorizer.jwt.claims.cognito:username is set | ||
* in the http event sent by API Gateway | ||
*/ | ||
public class CognitoPrincipal implements Principal { |
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 don't really like all these custom principal implementations, given that we have io.quarkus.security.identity.SecurityIdentity#getAttributes() that can be used to store any additional information attached to the identity (this applies to all the different ones, not just here).
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 just don't agree. Things just don't map one to one to an attribute list. JWT has claims and scopes (which is a set). IAM has a bunch of different nested metadata. Also, we already have a specific type for this stuff in the event, doesn't make any sense to pull AWS specific security metadata into a untyped string keyed hashmap. All this metadata is already unmarshalled too and to just fill up a hashmap with this unmarshalled data is double the work.
* Enable security mechanisms to process lambda and AWS based security (i.e. Cognito, IAM) from | ||
* the http event sent from API Gateway | ||
*/ | ||
@ConfigItem(defaultValue = "false") |
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.
Shouldn't this default to true? If lambda is sending a security principal I would assume it is for a reason?
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.
The whole mechanism abstraction adds overhead to every request which will exist if the user isn't using AWS security. I don't know yet if users will always use AWS security, so I'd like to keep the default false.
// there is no way in CDI to currently provide a prioritized list of IdentityProvider | ||
// So, what we do here is to try to see if anybody has registered one. If no identity, then | ||
// fire off a request that can only be resolved by the DefaultLambdaIdentityProvider | ||
boolean useDefault; |
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 need to fix this, but it is fine as a workaround for now.
* the http event sent from API Gateway | ||
*/ | ||
@ConfigItem(defaultValue = "false") | ||
public boolean enableSecurity; |
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.
Same question as above.
.../amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/CustomPrincipal.java
Show resolved
Hide resolved
@@ -242,7 +245,8 @@ private boolean isBinary(String contentType) { | |||
private Principal getPrincipal(APIGatewayV2HTTPEvent request) { |
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 just checked locally, this method is not needed any more.
I have created quarkusio/quarkus-security#17 to add a priority attribute. |
3d39209
to
1a981b0
Compare
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 like there is a formatting issue, but otherwise LGTM.
sam local docs convert lambda security to auth mechanism default providers add mechanism if empty credential types use QuarkusPrincipal fix test don't fire mech if request not set revert idp remove getPrincipal process resources
1a981b0
to
7ca2fc8
Compare
Good news :-) |
Provide some security integration for the quarkus-amazon-lambda-http and rest extensions. It extracts security metadata from the lambda http event to generate a io.quarkus.security.identity.SecurityIdentity which it attaches to the context objects in QuarkusHttpHeaders. The extension automatically adds a Vertx Web filter that will extract the SecurityIdentity and attach it to the RouteContext so that every other Quarkus HTTP framework can access it in it's standard way.