예제 #1
0
    def login(self):

        # get request parameters from which we can determine the login phase
        authorization_code = self.params.get('code')
        error = self.params.get('error')
        error_message = self.params.get('error_message')
        state = self.params.get('state')

        if authorization_code or not self.user_authorization_url:

            if authorization_code:
                #===================================================================
                # Phase 2 after redirect with success
                #===================================================================

                self._log(
                    logging.INFO,
                    'Continuing OAuth 2.0 authorization procedure after redirect.'
                )

                # validate CSRF token
                if self.supports_csrf_protection:
                    self._log(
                        logging.INFO,
                        'Validating request by comparing request state with stored state.'
                    )
                    stored_state = self._session_get('state')

                    if not stored_state:
                        raise FailureError('Unable to retrieve stored state!')
                    elif not stored_state == state:
                        raise FailureError(
                            'The returned state "{}" doesn\'t match with the stored state!'
                            .format(state),
                            url=self.user_authorization_url)
                    self._log(logging.INFO, 'Request is valid.')
                else:
                    self._log(logging.WARN, 'Skipping CSRF validation!')

            elif not self.user_authorization_url:
                #===================================================================
                # Phase 1 without user authorization redirect.
                #===================================================================

                self._log(logging.INFO, 'Starting OAuth 2.0 authorization procedure without ' + \
                                        'user authorization redirect.')

            # exchange authorization code for access token by the provider
            self._log(
                logging.INFO,
                'Fetching access token from {}.'.format(self.access_token_url))

            self.credentials.token = authorization_code

            request_elements = self.create_request_elements(
                request_type=self.ACCESS_TOKEN_REQUEST_TYPE,
                credentials=self.credentials,
                url=self.access_token_url,
                method='POST',
                redirect_uri=self.url,
                params=self.access_token_params,
                headers=self.access_token_headers)

            response = self._fetch(*request_elements)

            access_token = response.data.get('access_token', '')
            refresh_token = response.data.get('refresh_token', '')

            if response.status != 200 or not access_token:
                raise FailureError('Failed to obtain OAuth 2.0 access token from {}! HTTP status: {}, message: {}.'\
                                  .format(self.access_token_url, response.status, response.content),
                                  original_message=response.content,
                                  status=response.status,
                                  url=self.access_token_url)

            self._log(logging.INFO, 'Got access token.')

            if refresh_token:
                self._log(logging.INFO, 'Got refresh access token.')

            # OAuth 2.0 credentials need access_token, refresh_token, token_type and expire_in.
            self.credentials.token = access_token
            self.credentials.refresh_token = refresh_token
            self.credentials.expire_in = response.data.get('expire_in')
            self.credentials.token_type = response.data.get('token_type', '')
            # sWe don't need these two guys anymore.
            self.credentials.consumer_key = ''
            self.credentials.consumer_secret = ''

            # update credentials
            self.credentials = self._x_credentials_parser(
                self.credentials, response.data)

            # create user
            self._update_or_create_user(response.data, self.credentials)

            #===================================================================
            # We're done!
            #===================================================================

        elif error or error_message:
            #===================================================================
            # Phase 2 after redirect with error
            #===================================================================

            error_reason = self.params.get('error_reason')
            error_description = self.params.get(
                'error_description') or error_message

            if error_reason == 'user_denied':
                raise CancellationError(error_description,
                                        url=self.user_authorization_url)
            else:
                raise FailureError(error_description,
                                   url=self.user_authorization_url)

        elif not self.params:
            #===================================================================
            # Phase 1 before redirect
            #===================================================================

            self._log(logging.INFO,
                      'Starting OAuth 2.0 authorization procedure.')

            csrf = ''
            if self.supports_csrf_protection:
                # generate csfr
                csrf = self.csrf_generator()
                # and store it to session
                self._session_set('state', csrf)
            else:
                self._log(logging.WARN,
                          'Provider doesn\'t support CSRF validation!')

            request_elements = self.create_request_elements(
                request_type=self.USER_AUTHORIZATION_REQUEST_TYPE,
                credentials=self.credentials,
                url=self.user_authorization_url,
                redirect_uri=self.url,
                scope=self._x_scope_parser(self.scope),
                csrf=csrf,
                params=self.user_authorization_params)

            self._log(
                logging.INFO,
                'Redirecting user to {}.'.format(request_elements.full_url))

            self.redirect(request_elements.full_url)
예제 #2
0
    def login(self):
        # get request parameters from which we can determine the login phase
        denied = self.params.get('denied')
        verifier = self.params.get('oauth_verifier', '')
        request_token = self.params.get('oauth_token', '')

        if request_token and verifier:
            # Phase 2 after redirect with success
            self._log(
                logging.INFO,
                'Continuing OAuth 1.0a authorization procedure after redirect.'
            )
            token_secret = self._session_get('token_secret')
            if not token_secret:
                raise FailureError(
                    'Unable to retrieve token secret from storage!')

            # Get Access Token
            self._log(
                logging.INFO, 'Fetching for access token from {0}.'.format(
                    self.access_token_url))

            self.credentials.token = request_token
            self.credentials.token_secret = token_secret

            request_elements = self.create_request_elements(
                request_type=self.ACCESS_TOKEN_REQUEST_TYPE,
                url=self.access_token_url,
                credentials=self.credentials,
                verifier=verifier,
                params=self.access_token_params)

            response = self._fetch(*request_elements)

            if not self._http_status_in_category(response.status, 2):
                raise FailureError('Failed to obtain OAuth 1.0a  oauth_token from {0}! HTTP status code: {1}.'\
                                   .format(self.access_token_url, response.status),
                                   original_message=response.content,
                                   status=response.status,
                                   url=self.access_token_url)

            self._log(logging.INFO, 'Got access token.')

            self.credentials.token = response.data.get('oauth_token', '')
            self.credentials.token_secret = response.data.get(
                'oauth_token_secret', '')

            self.credentials = self._x_credentials_parser(
                self.credentials, response.data)

            self._update_or_create_user(response.data, self.credentials)

            #===================================================================
            # We're done!
            #===================================================================

        elif denied:
            # Phase 2 after redirect denied
            raise CancellationError('User denied the request token {0} during a redirect to {1}!'.\
                                  format(denied, self.user_authorization_url),
                                  original_message=denied,
                                  url=self.user_authorization_url)
        else:
            # Phase 1 before redirect
            self._log(logging.INFO,
                      'Starting OAuth 1.0a authorization procedure.')

            # Fetch for request token
            request_elements = self.create_request_elements(
                request_type=self.REQUEST_TOKEN_REQUEST_TYPE,
                credentials=self.credentials,
                url=self.request_token_url,
                callback=self.url,
                params=self.request_token_params)

            self._log(logging.INFO,
                      'Fetching for request token and token secret.')
            response = self._fetch(*request_elements)

            # check if response status is OK
            if not self._http_status_in_category(response.status, 2):
                raise FailureError('Failed to obtain request token from {0}! HTTP status code: {1} content: {2}'\
                                  .format(self.request_token_url, response.status, response.content),
                                  original_message=response.content,
                                  status=response.status,
                                  url=self.request_token_url)

            # extract request token
            request_token = response.data.get('oauth_token')
            if not request_token:
                raise FailureError(
                    'Response from {0} doesn\'t contain oauth_token parameter!'
                    .format(self.request_token_url),
                    original_message=response.content,
                    url=self.request_token_url)

            # we need request token for user authorization redirect
            self.credentials.token = request_token

            # extract token secret and save it to storage
            token_secret = response.data.get('oauth_token_secret')
            if token_secret:
                # we need token secret after user authorization redirect to get access token
                self._session_set('token_secret', token_secret)
            else:
                raise FailureError(
                    'Failed to obtain token secret from {0}!'.format(
                        self.request_token_url),
                    original_message=response.content,
                    url=self.request_token_url)

            self._log(logging.INFO, 'Got request token and token secret')

            # Create User Authorization URL
            request_elements = self.create_request_elements(
                request_type=self.USER_AUTHORIZATION_REQUEST_TYPE,
                credentials=self.credentials,
                url=self.user_authorization_url,
                params=self.user_authorization_params)

            self._log(
                logging.INFO,
                'Redirecting user to {0}.'.format(request_elements.full_url))

            self.redirect(request_elements.full_url)
예제 #3
0
    def login(self):

        # Instantiate consumer
        self.store._log = self._log
        oi_consumer = consumer.Consumer(self.session, self.store)

        # handle realm and XRDS if there is only one query parameter
        if self.use_realm and len(self.params) == 1:
            realm_request = self.params.get(self.realm_param)
            xrds_request = self.params.get(self.xrds_param)
        else:
            realm_request = None
            xrds_request = None

        # determine type of request
        if realm_request:
            #===================================================================
            # Realm HTML
            #===================================================================

            self._log(logging.INFO,
                      'Writing OpenID realm HTML to the response.')
            xrds_location = '{u}?{x}={x}'.format(u=self.url, x=self.xrds_param)
            self.write(
                REALM_HTML.format(xrds_location=xrds_location,
                                  body=self.realm_body))

        elif xrds_request:
            #===================================================================
            # XRDS XML
            #===================================================================

            self._log(logging.INFO,
                      'Writing XRDS XML document to the response.')
            self.set_header('Content-Type', 'application/xrds+xml')
            self.write(XRDS_XML.format(return_to=self.url))

        elif self.params.get('openid.mode'):
            #===================================================================
            # Phase 2 after redirect
            #===================================================================

            self._log(
                logging.INFO,
                'Continuing OpenID authentication procedure after redirect.')

            # complete the authentication process
            response = oi_consumer.complete(self.params, self.url)

            # on success
            if response.status == consumer.SUCCESS:

                data = {}

                # get user ID
                data['guid'] = response.getDisplayIdentifier()

                self._log(logging.INFO, 'Authentication successful.')

                # get user data from AX response
                ax_response = ax.FetchResponse.fromSuccessResponse(response)
                if ax_response and ax_response.data:
                    self._log(logging.INFO, 'Got AX data.')
                    ax_data = {}
                    # convert iterable values to their first item
                    for k, v in ax_response.data.iteritems():
                        if v and type(v) in (list, tuple):
                            ax_data[k] = v[0]
                    data['ax'] = ax_data

                # get user data from SREG response
                sreg_response = sreg.SRegResponse.fromSuccessResponse(response)
                if sreg_response and sreg_response.data:
                    self._log(logging.INFO, 'Got SREG data.')
                    data['sreg'] = sreg_response.data

                # get data from PAPE response
                pape_response = pape.Response.fromSuccessResponse(response)
                if pape_response and pape_response.auth_policies:
                    self._log(logging.INFO, 'Got PAPE data.')
                    data['pape'] = pape_response.auth_policies

                # create user
                self._update_or_create_user(data)

                #===============================================================
                # We're done!
                #===============================================================

            elif response.status == consumer.CANCEL:
                raise CancellationError(
                    'User cancelled the verification of ID "{0}"!'.format(
                        response.getDisplayIdentifier()))

            elif response.status == consumer.FAILURE:
                raise FailureError(response.message)

        elif self.identifier:  # As set in AuthenticationProvider.__init__
            #===================================================================
            # Phase 1 before redirect
            #===================================================================

            self._log(logging.INFO,
                      'Starting OpenID authentication procedure.')

            # get AuthRequest object
            try:
                auth_request = oi_consumer.begin(self.identifier)
            except consumer.DiscoveryFailure as e:
                raise FailureError(
                    'Discovery failed for identifier {0}!'.format(
                        self.identifier),
                    url=self.identifier,
                    original_message=e.message)

            self._log(
                logging.INFO,
                'Service discovery for identifier {0} successful.'.format(
                    self.identifier))

            # add SREG extension
            # we need to remove required fields from optional fields because addExtension then raises an error
            self.sreg = [i for i in self.sreg if i not in self.sreg_required]
            auth_request.addExtension(
                sreg.SRegRequest(optional=self.sreg,
                                 required=self.sreg_required))

            # add AX extension
            ax_request = ax.FetchRequest()
            # set AX schemas
            for i in self.ax:
                required = i in self.ax_required
                ax_request.add(ax.AttrInfo(i, required=required))
            auth_request.addExtension(ax_request)

            # add PAPE extension
            auth_request.addExtension(pape.Request(self.pape))

            # prepare realm and return_to URLs
            if self.use_realm:
                realm = return_to = '{u}?{r}={r}'.format(u=self.url,
                                                         r=self.realm_param)
            else:
                realm = return_to = self.url

            url = auth_request.redirectURL(realm, return_to)

            if auth_request.shouldSendRedirect():
                # can be redirected
                url = auth_request.redirectURL(realm, return_to)
                self._log(logging.INFO, 'Redirecting user to {0}.'.format(url))
                self.redirect(url)
            else:
                # must be sent as POST
                # this writes a html post form with auto-submit
                self._log(logging.INFO,
                          'Writing an auto-submit HTML form to the response.')
                form = auth_request.htmlMarkup(realm, return_to, False,
                                               dict(id='openid_form'))
                self.write(form)
        else:
            raise OpenIDError('No identifier specified!')