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

APIKeySecuritySchema not functioning in openapi docs #17

Closed
dgonzo opened this Issue Oct 1, 2018 · 2 comments

Comments

Projects
None yet
2 participants
@dgonzo
Copy link

dgonzo commented Oct 1, 2018

Checklist

  • Does your title concisely summarize the problem?
  • Did you include a minimal, reproducible example?
  • What OS are you using?
  • What version of molten are you using?
  • What did you do?
  • What did you expect would happen?
  • What happened?

What OS are you using?

macOS 10.13.6

What version of molten are you using?

0.5.2

What did you do?

I enabled APIKeySecurityScheme in the petstore example using the following modified petstore.app (see both variations of security_schemes):

"""An example **molten** application that automatically exposes an
OpenAPI document to represent its structure.
"""
from typing import Any, Callable, Optional, Tuple

from molten import (
    App, Header, Include, ResponseRendererMiddleware, Route, annotate,
    Request, HTTP_200, HTTPError, HTTP_401)
from molten.openapi import Metadata, OpenAPIHandler, OpenAPIUIHandler, APIKeySecurityScheme

from . import categories, pets, tags
from .database import DatabaseComponent


def auth_middleware(handler: Callable[..., Any]) -> Callable[..., Any]:
    def middleware(x_api_key: Optional[Header]) -> Callable[..., Any]:
        if x_api_key == '58be92dd-61a9-4a27-8efa-b6a0e025439e' or getattr(handler, "no_auth", False):
            return handler()
        else:
            raise HTTPError(HTTP_401, {"error": "bad credentials"})

    return middleware


def u(request: Request) -> Tuple[str, dict]:
    return HTTP_200, {"req": f"{request.headers!r}"}


def setup_app():
    get_schema = OpenAPIHandler(
        metadata=Metadata(
            title="Pet Store",
            description=__doc__,
            version="0.0.0",
        ),
        # Option 1
        security_schemes=[APIKeySecurityScheme(name="X-API-KEY", in_="header")],
        # Option 2
        security_schemes=[APIKeySecurityScheme(name="apiKey", in_="header")],
        default_security_scheme="apiKey",
    )

    get_schema = annotate(no_auth=True)(get_schema)
    get_docs = annotate(no_auth=True)(OpenAPIUIHandler())

    return App(
        components=[
            DatabaseComponent(),
            categories.CategoryManagerComponent(),
            tags.TagManagerComponent(),
            pets.PetManagerComponent(),
        ],

        middleware=[
            ResponseRendererMiddleware(),
            auth_middleware,
        ],

        routes=[
            Include("/v1/categories", categories.routes),
            Include("/v1/pets", pets.routes),
            Include("/v1/tags", tags.routes),
            Route("/u", u),

            Route("/_docs", get_docs),
            Route("/_schema", get_schema),
        ],
    )

What did you expect would happen?

For either "Option 1" or "Option 2" above I expected that the apiKey would be used to authenticate calls to secure routes. Instead 'X-API-KEY' is absent from the headers and a "bad credentials" error is returned.

Option 1 results in an empty "Authorizers available" dialogue box when clicking on the lock icon for a path but I'd expect that dialogue to offer a place to put the "X-API-KEY". The main authorize box does offer the expected dialogue box but it is not applied when executing calls from the docs.

Option 2 results in the expected dialogue boxes but the apiKey is not applied to calls to routes.

When I exercise the api outside of swagger (e.g. http :8000/v1/categories X-API-KEY:58be92dd-61a9-4a27-8efa-b6a0e025439e) authentication functions properly. So, only within swagger is the header not being properly applied.

What happened?

I noticed that the security schemes in openapi have, effectively, two names. The name of the security and the name of the header:

components:
  securitySchemes:
    ApiKeyAuth:        # arbitrary name for the security scheme
      type: apiKey
      in: header       # can be "header", "query" or "cookie"
      name: X-API-KEY  # name of the header, query parameter or cookie

When the arbitraty name is "apiKey" the dialogue boxes in the docs function as expected.

To get the arbitrary name set in APIKeySecurityScheme the name attribute must be set to "apiKey" but that results in an incorrect header name.

@Bogdanp Bogdanp added the bug label Oct 1, 2018

@Bogdanp

This comment has been minimized.

Copy link
Owner

Bogdanp commented Oct 1, 2018

This stems from me misreading/misinterpreting the spec. I would like to keep using name to refer to the name of the security scheme so I'll have to come up with another keyword that works for the header/param name (maybe param_name?). What would make the most sense to you here?

@dgonzo

This comment has been minimized.

Copy link
Author

dgonzo commented Oct 1, 2018

@Bogdanp I'm with you on keeping the arbitrary name == name. For the other name param_name works. It's general enough for 'header', 'query', or 'cookie'. Thanks.

@Bogdanp Bogdanp added this to the v0.6.0 milestone Oct 6, 2018

@Bogdanp Bogdanp closed this in f836284 Oct 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment