Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Bug: Global apigateway swagger security config not overwritten by specific route configs with empty security #5893

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

Closed
victorperezpiqueras opened this issue Jan 21, 2025 · 6 comments · Fixed by #5895
Assignees
Labels

Comments

@victorperezpiqueras
Copy link
Contributor

Expected Behaviour

I have defined an apigateway rest resolver with swagger enabled and a security scheme with oauth.

I have two endpoints, one protected, and one unprotected. I explicitly define the unprotected endpoint with security empty, so I would expect it to override the global config of swagger and be unprotected.

Current Behaviour

Currently, the unprotected security of the route is not overwritten. Instead, the global config seems to be applied over the specific one of the router. This only happens if the specific config is an empty list.

However, if the global config of security is an empty list or not defined at all, defining a specific security config in a route overwrites it.

With the current behaviour, if I want to keep all resources protected except one, I need to remove the global config of security, and put it in each route that i want protected.

Code snippet

import json
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.event_handler.openapi.models import OAuth2, OAuthFlows, OAuthFlowAuthorizationCode

app = APIGatewayRestResolver(enable_validation=True)
app.enable_swagger(
    path="/swagger",
    security_schemes={
        "oauth": OAuth2(
            flows=OAuthFlows(
                authorizationCode=OAuthFlowAuthorizationCode(
                    authorizationUrl="",
                    tokenUrl="",
                    scopes={
                        "email": "email scope",
                        "openid": "openid scope",
                        "profile": "profile scope",
                    },
                ),
            ),
        )
    },
    security=[{"oauth": ["openid", "profile", "email"]}]
)


@app.get("/unprotected", security=[])
def unprotected() -> dict:
    return {}


@app.get("/protected", security=[{"oauth": ["openid", "profile", "email"]}])
def protected() -> dict:
    return {}


def lambda_handler(event, context):
    return app.resolve(event, context)


if __name__ == "__main__":
    test_event = {
        "body": json.dumps({}),
        "httpMethod": "GET",
        "path": "/swagger",
        "headers": {
            "Content-Type": "application/json"
        },
        "requestContext": {
            "requestId": "test-id",
            "stage": "test-stage",
            "path": "/swagger",
        }
    }

    result = lambda_handler(test_event, {})
    # store swagger in file to be able to check it
    with open("swagger.html", "w") as f:
        f.write(result["body"])

Possible Solution

Either clarify the docs of the enable_swagger() or make the specific router security options override the global security even if the security is empty.

Steps to Reproduce

  1. Copy the snippet provided.
  2. Run it and open the generated swagger.html
  3. The unprotected endpoint is protected (I expected it to not be protected)
  4. Remove the global security config from the enable_swagger()
  5. Rerun and reload the swagger.html
  6. The unprotected endpoint is now marked as unprotected as expected

Powertools for AWS Lambda (Python) version

latest

AWS Lambda function runtime

3.12

Packaging format used

Lambda Layers

Debugging logs

@victorperezpiqueras victorperezpiqueras added bug Something isn't working triage Pending triage from maintainers labels Jan 21, 2025
Copy link

boring-cyborg bot commented Jan 21, 2025

Thanks for opening your first issue here! We'll come back to you as soon as we can.
In the meantime, check out the #python channel on our Powertools for AWS Lambda Discord: Invite link

@leandrodamascena
Copy link
Contributor

Hi @victorperezpiqueras! Thanks for opening this issue because I see room for improvement in our documentation. Actually this is not a bug, we already support it.

The OpenAPI v3 specification defines an optional security mechanism with {}, so this means that if you add a security scheme on a specific route like this @app.get("/unprotected", security=[{}]) it will make the authorization optional in that specific route.

Reference: https://spec.openapis.org/oas/v3.1.0.html#fixed-fields

A declaration of which security mechanisms can be used across the API. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. Individual operations can override this definition. To make security optional, an empty security requirement ({}) can be included in the array.

Please let me know if this works for you.

Image

@leandrodamascena leandrodamascena self-assigned this Jan 21, 2025
@leandrodamascena leandrodamascena added need-documentation PRs that are missing documentation event_handlers openapi-schema and removed bug Something isn't working triage Pending triage from maintainers labels Jan 21, 2025
@leandrodamascena leandrodamascena moved this from Triage to Working on it in Powertools for AWS Lambda (Python) Jan 21, 2025
@victorperezpiqueras
Copy link
Contributor Author

Ah, my bad I missed that doc.

In that case, maybe the current field description could be extended with the complete description present in the OpenAPI specification:

def get_openapi_schema:

security: list[dict[str, list[str]]], optional
(old)           
            A declaration of which security mechanisms are applied globally across the API. 
(new): 
            A declaration of which security mechanisms can be used across the API. 
            The list of values includes alternative security requirement objects that can be used. 
            Only one of the security requirement objects need to be satisfied to authorize a request. 
            Individual operations can override this definition. To make security optional, an empty security requirement ({}) can be included in the array.

I see the rest of the params have a simplified description too, so idk if its a standard or documentation choice.

@leandrodamascena
Copy link
Contributor

I would prefer to add it here: https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#security-schemes

Copy link
Contributor

⚠️COMMENT VISIBILITY WARNING⚠️

This issue is now closed. Please be mindful that future comments are hard for our team to see.

If you need more assistance, please either tag a team member or open a new issue that references this one.

If you wish to keep having a conversation with other community members under this issue feel free to do so.

@github-actions github-actions bot added the pending-release Fix or implementation already in dev waiting to be released label Jan 22, 2025
@leandrodamascena leandrodamascena moved this from Coming soon to Closed in Powertools for AWS Lambda (Python) Jan 27, 2025
Copy link
Contributor

This is now released under 3.5.0 version!

@github-actions github-actions bot removed the pending-release Fix or implementation already in dev waiting to be released label Jan 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
2 participants