Skip to content

Schema Extensions

myapp.django_oauth_toolkit

DjangoOAuthToolkitScheme

Bases: OpenApiAuthenticationExtension

Source code in myapp/django_oauth_toolkit.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class DjangoOAuthToolkitScheme(OpenApiAuthenticationExtension):
    target_class = 'oauth2_provider.contrib.rest_framework.OAuth2Authentication'
    name = 'oauth2'

    def get_security_requirement(self, auto_schema):
        """
        Generate the OAS
        [Oauth2 security requirement object](https://spec.openapis.org/oas/latest#oauth2-security-requirement).

        Looks through the view permissions for relevent OAuth2 permission classes such as TokenMatchesOASRequirements
        in order to generate a list of alternative required scopes.

        TODO: Better deal with hierarchical (AND, OR) permissions.
        """
        from oauth2_provider.contrib.rest_framework import (IsAuthenticatedOrTokenHasScope, TokenHasScope,
                                                            TokenMatchesOASRequirements)
        view = auto_schema.view
        request = view.request

        for permission in auto_schema.view.get_permissions():
            if isinstance(permission, TokenMatchesOASRequirements):
                alt_scopes = permission.get_required_alternate_scopes(request, view)
                alt_scopes = alt_scopes.get(auto_schema.method, [])
                return [{self.name: group} for group in alt_scopes]
            if isinstance(permission, IsAuthenticatedOrTokenHasScope):
                return {self.name: TokenHasScope().get_scopes(request, view)}
            if isinstance(permission, TokenHasScope):
                # catch-all for subclasses of TokenHasScope like TokenHasReadWriteScope
                return {self.name: permission.get_scopes(request, view)}
            # deal with hierarchical boolean permissions.
            scopes = getattr(view, "required_alternate_scopes")
            if scopes is None:
                scopes = getattr(view, "required_scopes")  # try for required_scopes
                return {self.name: scopes if scopes else []}
            return [{self.name: a} for a in scopes[auto_schema.method]]

    def get_security_definition(self, auto_schema):
        """
        Render the securitySchemes for our oauth2 service.
        """
        from drf_spectacular.settings import spectacular_settings
        from oauth2_provider.scopes import get_scopes_backend

        flows = {}
        for flow_type in spectacular_settings.OAUTH2_FLOWS:
            flows[flow_type] = {}
            if flow_type in ('implicit', 'authorizationCode'):
                flows[flow_type]['authorizationUrl'] = spectacular_settings.OAUTH2_AUTHORIZATION_URL
            if flow_type in ('password', 'clientCredentials', 'authorizationCode'):
                flows[flow_type]['tokenUrl'] = spectacular_settings.OAUTH2_TOKEN_URL
            if spectacular_settings.OAUTH2_REFRESH_URL:
                flows[flow_type]['refreshUrl'] = spectacular_settings.OAUTH2_REFRESH_URL
            scope_backend = get_scopes_backend()
            flows[flow_type]['scopes'] = scope_backend.get_all_scopes()

        return {
            'type': 'oauth2',
            'flows': flows
        }

target_class = 'oauth2_provider.contrib.rest_framework.OAuth2Authentication' class-attribute instance-attribute

name = 'oauth2' class-attribute instance-attribute

get_security_requirement(auto_schema)

Generate the OAS Oauth2 security requirement object.

Looks through the view permissions for relevent OAuth2 permission classes such as TokenMatchesOASRequirements in order to generate a list of alternative required scopes.

TODO: Better deal with hierarchical (AND, OR) permissions.

Source code in myapp/django_oauth_toolkit.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def get_security_requirement(self, auto_schema):
    """
    Generate the OAS
    [Oauth2 security requirement object](https://spec.openapis.org/oas/latest#oauth2-security-requirement).

    Looks through the view permissions for relevent OAuth2 permission classes such as TokenMatchesOASRequirements
    in order to generate a list of alternative required scopes.

    TODO: Better deal with hierarchical (AND, OR) permissions.
    """
    from oauth2_provider.contrib.rest_framework import (IsAuthenticatedOrTokenHasScope, TokenHasScope,
                                                        TokenMatchesOASRequirements)
    view = auto_schema.view
    request = view.request

    for permission in auto_schema.view.get_permissions():
        if isinstance(permission, TokenMatchesOASRequirements):
            alt_scopes = permission.get_required_alternate_scopes(request, view)
            alt_scopes = alt_scopes.get(auto_schema.method, [])
            return [{self.name: group} for group in alt_scopes]
        if isinstance(permission, IsAuthenticatedOrTokenHasScope):
            return {self.name: TokenHasScope().get_scopes(request, view)}
        if isinstance(permission, TokenHasScope):
            # catch-all for subclasses of TokenHasScope like TokenHasReadWriteScope
            return {self.name: permission.get_scopes(request, view)}
        # deal with hierarchical boolean permissions.
        scopes = getattr(view, "required_alternate_scopes")
        if scopes is None:
            scopes = getattr(view, "required_scopes")  # try for required_scopes
            return {self.name: scopes if scopes else []}
        return [{self.name: a} for a in scopes[auto_schema.method]]

get_security_definition(auto_schema)

Render the securitySchemes for our oauth2 service.

Source code in myapp/django_oauth_toolkit.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def get_security_definition(self, auto_schema):
    """
    Render the securitySchemes for our oauth2 service.
    """
    from drf_spectacular.settings import spectacular_settings
    from oauth2_provider.scopes import get_scopes_backend

    flows = {}
    for flow_type in spectacular_settings.OAUTH2_FLOWS:
        flows[flow_type] = {}
        if flow_type in ('implicit', 'authorizationCode'):
            flows[flow_type]['authorizationUrl'] = spectacular_settings.OAUTH2_AUTHORIZATION_URL
        if flow_type in ('password', 'clientCredentials', 'authorizationCode'):
            flows[flow_type]['tokenUrl'] = spectacular_settings.OAUTH2_TOKEN_URL
        if spectacular_settings.OAUTH2_REFRESH_URL:
            flows[flow_type]['refreshUrl'] = spectacular_settings.OAUTH2_REFRESH_URL
        scope_backend = get_scopes_backend()
        flows[flow_type]['scopes'] = scope_backend.get_all_scopes()

    return {
        'type': 'oauth2',
        'flows': flows
    }