This file is indexed.

/usr/lib/python3/dist-packages/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py is in python3-oauthlib 2.0.6-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  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
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# -*- coding: utf-8 -*-
"""
oauthlib.oauth2.rfc6749.grant_types.openid_connect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, unicode_literals

import datetime
import logging
from json import loads

from ..errors import ConsentRequired, InvalidRequestError, LoginRequired
from ..request_validator import RequestValidator
from .authorization_code import AuthorizationCodeGrant
from .base import GrantTypeBase
from .implicit import ImplicitGrant

log = logging.getLogger(__name__)

class OIDCNoPrompt(Exception):
    """Exception used to inform users that no explicit authorization is needed.

    Normally users authorize requests after validation of the request is done.
    Then post-authorization validation is again made and a response containing
    an auth code or token is created. However, when OIDC clients request
    no prompting of user authorization the final response is created directly.

    Example (without the shortcut for no prompt)

    scopes, req_info = endpoint.validate_authorization_request(url, ...)
    authorization_view = create_fancy_auth_form(scopes, req_info)
    return authorization_view

    Example (with the no prompt shortcut)
    try:
        scopes, req_info = endpoint.validate_authorization_request(url, ...)
        authorization_view = create_fancy_auth_form(scopes, req_info)
        return authorization_view
    except OIDCNoPrompt:
        # Note: Location will be set for you
        headers, body, status = endpoint.create_authorization_response(url, ...)
        redirect_view = create_redirect(headers, body, status)
        return redirect_view
    """

    def __init__(self):
        msg = ("OIDC request for no user interaction received. Do not ask user "
               "for authorization, it should been done using silent "
               "authentication through create_authorization_response. "
               "See OIDCNoPrompt.__doc__ for more details.")
        super(OIDCNoPrompt, self).__init__(msg)


class AuthCodeGrantDispatcher(object):
    """
    This is an adapter class that will route simple Authorization Code requests, those that have response_type=code and a scope
    including 'openid' to either the default_auth_grant or the oidc_auth_grant based on the scopes requested.
    """
    def __init__(self, default_auth_grant=None, oidc_auth_grant=None):
        self.default_auth_grant = default_auth_grant
        self.oidc_auth_grant = oidc_auth_grant

    def _handler_for_request(self, request):
        handler = self.default_auth_grant

        if request.scopes and "openid" in request.scopes:
            handler = self.oidc_auth_grant

        log.debug('Selecting handler for request %r.', handler)
        return handler

    def create_authorization_response(self, request, token_handler):
        return self._handler_for_request(request).create_authorization_response(request, token_handler)

    def validate_authorization_request(self, request):
        return self._handler_for_request(request).validate_authorization_request(request)


class OpenIDConnectBase(object):

    # Just proxy the majority of method calls through to the
    # proxy_target grant type handler, which will usually be either
    # the standard OAuth2 AuthCode or Implicit grant types.
    def __getattr__(self, attr):
        return getattr(self.proxy_target, attr)

    def __setattr__(self, attr, value):
        proxied_attrs = set(('refresh_token', 'response_types'))
        if attr in proxied_attrs:
            setattr(self.proxy_target, attr, value)
        else:
            super(OpenIDConnectBase, self).__setattr__(attr, value)

    def validate_authorization_request(self, request):
        """Validates the OpenID Connect authorization request parameters.

        :returns: (list of scopes, dict of request info)
        """
        # If request.prompt is 'none' then no login/authorization form should
        # be presented to the user. Instead, a silent login/authorization
        # should be performed.
        if request.prompt == 'none':
            raise OIDCNoPrompt()
        else:
            return self.proxy_target.validate_authorization_request(request)

    def _inflate_claims(self, request):
        # this may be called multiple times in a single request so make sure we only de-serialize the claims once
        if request.claims and not isinstance(request.claims, dict):
            # specific claims are requested during the Authorization Request and may be requested for inclusion
            # in either the id_token or the UserInfo endpoint response
            # see http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
            try:
                request.claims = loads(request.claims)
            except Exception as ex:
                raise InvalidRequestError(description="Malformed claims parameter",
                                          uri="http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter")

    def add_id_token(self, token, token_handler, request):
        # Treat it as normal OAuth 2 auth code request if openid is not present
        if not request.scopes or 'openid' not in request.scopes:
            return token

        # Only add an id token on auth/token step if asked for.
        if request.response_type and 'id_token' not in request.response_type:
            return token

        if 'state' not in token:
            token['state'] = request.state

        if request.max_age:
            d = datetime.datetime.utcnow()
            token['auth_time'] = d.isoformat("T") + "Z"

        # TODO: acr claims (probably better handled by server code using oauthlib in get_id_token)

        token['id_token'] = self.request_validator.get_id_token(token, token_handler, request)

        return token

    def openid_authorization_validator(self, request):
        """Perform OpenID Connect specific authorization request validation.

        nonce
                OPTIONAL. String value used to associate a Client session with
                an ID Token, and to mitigate replay attacks. The value is
                passed through unmodified from the Authentication Request to
                the ID Token. Sufficient entropy MUST be present in the nonce
                values used to prevent attackers from guessing values

        display
                OPTIONAL. ASCII string value that specifies how the
                Authorization Server displays the authentication and consent
                user interface pages to the End-User. The defined values are:

                    page - The Authorization Server SHOULD display the
                    authentication and consent UI consistent with a full User
                    Agent page view. If the display parameter is not specified,
                    this is the default display mode.

                    popup - The Authorization Server SHOULD display the
                    authentication and consent UI consistent with a popup User
                    Agent window. The popup User Agent window should be of an
                    appropriate size for a login-focused dialog and should not
                    obscure the entire window that it is popping up over.

                    touch - The Authorization Server SHOULD display the
                    authentication and consent UI consistent with a device that
                    leverages a touch interface.

                    wap - The Authorization Server SHOULD display the
                    authentication and consent UI consistent with a "feature
                    phone" type display.

                The Authorization Server MAY also attempt to detect the
                capabilities of the User Agent and present an appropriate
                display.

        prompt
                OPTIONAL. Space delimited, case sensitive list of ASCII string
                values that specifies whether the Authorization Server prompts
                the End-User for reauthentication and consent. The defined
                values are:

                    none - The Authorization Server MUST NOT display any
                    authentication or consent user interface pages. An error is
                    returned if an End-User is not already authenticated or the
                    Client does not have pre-configured consent for the
                    requested Claims or does not fulfill other conditions for
                    processing the request. The error code will typically be
                    login_required, interaction_required, or another code
                    defined in Section 3.1.2.6. This can be used as a method to
                    check for existing authentication and/or consent.

                    login - The Authorization Server SHOULD prompt the End-User
                    for reauthentication. If it cannot reauthenticate the
                    End-User, it MUST return an error, typically
                    login_required.

                    consent - The Authorization Server SHOULD prompt the
                    End-User for consent before returning information to the
                    Client. If it cannot obtain consent, it MUST return an
                    error, typically consent_required.

                    select_account - The Authorization Server SHOULD prompt the
                    End-User to select a user account. This enables an End-User
                    who has multiple accounts at the Authorization Server to
                    select amongst the multiple accounts that they might have
                    current sessions for. If it cannot obtain an account
                    selection choice made by the End-User, it MUST return an
                    error, typically account_selection_required.

                The prompt parameter can be used by the Client to make sure
                that the End-User is still present for the current session or
                to bring attention to the request. If this parameter contains
                none with any other value, an error is returned.

        max_age
                OPTIONAL. Maximum Authentication Age. Specifies the allowable
                elapsed time in seconds since the last time the End-User was
                actively authenticated by the OP. If the elapsed time is
                greater than this value, the OP MUST attempt to actively
                re-authenticate the End-User. (The max_age request parameter
                corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] max_auth_age
                request parameter.) When max_age is used, the ID Token returned
                MUST include an auth_time Claim Value.

        ui_locales
                OPTIONAL. End-User's preferred languages and scripts for the
                user interface, represented as a space-separated list of BCP47
                [RFC5646] language tag values, ordered by preference. For
                instance, the value "fr-CA fr en" represents a preference for
                French as spoken in Canada, then French (without a region
                designation), followed by English (without a region
                designation). An error SHOULD NOT result if some or all of the
                requested locales are not supported by the OpenID Provider.

        id_token_hint
                OPTIONAL. ID Token previously issued by the Authorization
                Server being passed as a hint about the End-User's current or
                past authenticated session with the Client. If the End-User
                identified by the ID Token is logged in or is logged in by the
                request, then the Authorization Server returns a positive
                response; otherwise, it SHOULD return an error, such as
                login_required. When possible, an id_token_hint SHOULD be
                present when prompt=none is used and an invalid_request error
                MAY be returned if it is not; however, the server SHOULD
                respond successfully when possible, even if it is not present.
                The Authorization Server need not be listed as an audience of
                the ID Token when it is used as an id_token_hint value. If the
                ID Token received by the RP from the OP is encrypted, to use it
                as an id_token_hint, the Client MUST decrypt the signed ID
                Token contained within the encrypted ID Token. The Client MAY
                re-encrypt the signed ID token to the Authentication Server
                using a key that enables the server to decrypt the ID Token,
                and use the re-encrypted ID token as the id_token_hint value.

        login_hint
                OPTIONAL. Hint to the Authorization Server about the login
                identifier the End-User might use to log in (if necessary).
                This hint can be used by an RP if it first asks the End-User
                for their e-mail address (or other identifier) and then wants
                to pass that value as a hint to the discovered authorization
                service. It is RECOMMENDED that the hint value match the value
                used for discovery. This value MAY also be a phone number in
                the format specified for the phone_number Claim. The use of
                this parameter is left to the OP's discretion.

        acr_values
                OPTIONAL. Requested Authentication Context Class Reference
                values. Space-separated string that specifies the acr values
                that the Authorization Server is being requested to use for
                processing this Authentication Request, with the values
                appearing in order of preference. The Authentication Context
                Class satisfied by the authentication performed is returned as
                the acr Claim Value, as specified in Section 2. The acr Claim
                is requested as a Voluntary Claim by this parameter.
        """

        # Treat it as normal OAuth 2 auth code request if openid is not present
        if not request.scopes or 'openid' not in request.scopes:
            return {}

        prompt = request.prompt if request.prompt else []
        if hasattr(prompt, 'split'):
            prompt = prompt.strip().split()
        prompt = set(prompt)

        if 'none' in prompt:

            if len(prompt) > 1:
                msg = "Prompt none is mutually exclusive with other values."
                raise InvalidRequestError(request=request, description=msg)

            # prompt other than 'none' should be handled by the server code that
            # uses oauthlib
            if not request.id_token_hint:
                msg = "Prompt is set to none yet id_token_hint is missing."
                raise InvalidRequestError(request=request, description=msg)

            if not self.request_validator.validate_silent_login(request):
                raise LoginRequired(request=request)

            if not self.request_validator.validate_silent_authorization(request):
                raise ConsentRequired(request=request)

        self._inflate_claims(request)

        if not self.request_validator.validate_user_match(
            request.id_token_hint, request.scopes, request.claims, request):
            msg = "Session user does not match client supplied user."
            raise LoginRequired(request=request, description=msg)

        request_info = {
            'display': request.display,
            'nonce': request.nonce,
            'prompt': prompt,
            'ui_locales': request.ui_locales.split() if request.ui_locales else [],
            'id_token_hint': request.id_token_hint,
            'login_hint': request.login_hint,
            'claims': request.claims
        }

        return request_info

    def openid_implicit_authorization_validator(self, request):
        """Additional validation when following the implicit flow.
        """
        # Undefined in OpenID Connect, fall back to OAuth2 definition.
        if request.response_type == 'token':
            return {}

        # Treat it as normal OAuth 2 auth code request if openid is not present
        if not request.scopes or 'openid' not in request.scopes:
            return {}

        # REQUIRED. String value used to associate a Client session with an ID
        # Token, and to mitigate replay attacks. The value is passed through
        # unmodified from the Authentication Request to the ID Token.
        # Sufficient entropy MUST be present in the nonce values used to
        # prevent attackers from guessing values. For implementation notes, see
        # Section 15.5.2.
        if not request.nonce:
            desc = 'Request is missing mandatory nonce parameter.'
            raise InvalidRequestError(request=request, description=desc)

        return {}


class OpenIDConnectAuthCode(OpenIDConnectBase):

    def __init__(self, request_validator=None, **kwargs):
        self.proxy_target = AuthorizationCodeGrant(
            request_validator=request_validator, **kwargs)
        self.custom_validators.post_auth.append(
            self.openid_authorization_validator)
        self.register_token_modifier(self.add_id_token)

class OpenIDConnectImplicit(OpenIDConnectBase):

    def __init__(self, request_validator=None, **kwargs):
        self.proxy_target = ImplicitGrant(
            request_validator=request_validator, **kwargs)
        self.register_response_type('id_token')
        self.register_response_type('id_token token')
        self.custom_validators.post_auth.append(
            self.openid_authorization_validator)
        self.custom_validators.post_auth.append(
            self.openid_implicit_authorization_validator)
        self.register_token_modifier(self.add_id_token)

class OpenIDConnectHybrid(OpenIDConnectBase):

    def __init__(self, request_validator=None, **kwargs):
        self.request_validator = request_validator or RequestValidator()

        self.proxy_target = AuthorizationCodeGrant(
            request_validator=request_validator, **kwargs)
        # All hybrid response types should be fragment-encoded.
        self.proxy_target.default_response_mode = "fragment"
        self.register_response_type('code id_token')
        self.register_response_type('code token')
        self.register_response_type('code id_token token')
        self.custom_validators.post_auth.append(
            self.openid_authorization_validator)
        # Hybrid flows can return the id_token from the authorization
        # endpoint as part of the 'code' response
        self.register_code_modifier(self.add_token)
        self.register_code_modifier(self.add_id_token)
        self.register_token_modifier(self.add_id_token)