示例#1
0
    def auth_complete(self, *args, **kwargs):
        """Completes logging process, must return user instance"""
        self.process_error(self.data)
        params = self.auth_complete_params(self.validate_state())
        request = Request(self.ACCESS_TOKEN_URL,
                          data=urlencode(params),
                          headers=self.auth_headers())

        try:
            response = json.loads(dsa_urlopen(request).read())
        except HTTPError as e:
            logger.exception(
                "plugins.auth.error",
                extra={
                    "class": type(self),
                    "status_code": e.code,
                    "response": e.read()[:128]
                },
            )
            raise AuthUnknownError(self)
        except (ValueError, KeyError):
            raise AuthUnknownError(self)

        self.process_error(response)
        return self.do_auth(response["access_token"],
                            response=response,
                            *args,
                            **kwargs)
class StackoverflowAuth(BaseOAuth2):
    """Stackoverflow OAuth2 mechanism"""
    AUTHORIZATION_URL = STACKOVERFLOW_AUTHORIZATION_URL
    ACCESS_TOKEN_URL = STACKOVERFLOW_ACCESS_TOKEN_URL
    AUTH_BACKEND = StackoverflowBackend
    SETTINGS_KEY_NAME = 'STACKOVERFLOW_CLIENT_ID'
    SETTINGS_SECRET_NAME = 'STACKOVERFLOW_CLIENT_SECRET'
    SCOPE_SEPARATOR = ','
    # See: https://api.stackexchange.com/docs/authentication#scope
    SCOPE_VAR_NAME = 'STACKOVERFLOW_EXTENDED_PERMISSIONS'

    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        self.process_error(self.data)
        params = self.auth_complete_params(self.validate_state())
        request = Request(self.ACCESS_TOKEN_URL,
                          data=urlencode(params),
                          headers=self.auth_headers())

        try:
            response = dict(parse_qsl(dsa_urlopen(request).read()))
        except HTTPError, e:
            if e.code == 400:
                raise AuthCanceled(self)
            else:
                raise
        except (ValueError, KeyError):
            raise AuthUnknownError(self)
示例#3
0
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        self.process_error(self.data)
        params = self.auth_complete_params(self.validate_state())
        try:
            response = requests.post(self.ACCESS_TOKEN_URL,
                                     data=params,
                                     headers=self.auth_headers())
            response.raise_for_status()
        except requests.exceptions.HTTPError as e:
            if e.code == 400:
                raise AuthCanceled(self)
            else:
                raise
        else:
            try:
                response = response.json()
            except (ValueError, KeyError):
                raise AuthUnknownError(self)

        response.pop('data')
        self.process_error(response)
        return self.do_auth(response['access_token'],
                            response=response,
                            *args,
                            **kwargs)
示例#4
0
 def auth_complete(self, *args, **kwargs):
     """Complete auth process"""
     logger.debug('auth_complete ARGS=%s, KWARGS=%s' % (args, kwargs))
     response = self.consumer().complete(dict(self.data.items()),
                                         self.build_absolute_uri())
     logger.debug('response and status %s / %s' % (response, response.status))
     if not response:
         logger.debug('will throw AuthException')
         raise AuthException(self, 'OpenID relying party endpoint')
     elif response.status == SUCCESS:
         kwargs.update({
             'auth': self,
             'response': response,
             self.AUTH_BACKEND.name: True
         })
         return authenticate(*args, **kwargs)
     elif response.status == FAILURE:
         logger.debug('will throw AuthFailed(%s)' % response.message)
         raise AuthFailed(self, response.message)
     elif response.status == CANCEL:
         logger.debug('will throw AuthCanceled')
         raise AuthCanceled(self)
     else:
         logger.debug('will throw AuthUnknownError(%s)' % response.status)
         raise AuthUnknownError(self, response.status)
示例#5
0
 def process_error(self, data):
     error = self.request.GET.get('error', '')
     if error:
         if error == 'access_denied':
             raise AuthCanceled(self)
         else:
             raise AuthUnknownError(self, 'Jawbone error was %s' % error)
     return super(JawboneAuth, self).process_error(data)
 def user_data(self, access_token, *args, **kwargs):
     """Loads user data from service"""
     url = LIVE_USER_DATA_URL + '?' + urlencode(
         {'access_token': access_token})
     try:
         return simplejson.load(dsa_urlopen(url))
     except (ValueError, IOError):
         raise AuthUnknownError('Error during profile retrieval, '
                                'please, try again later')
示例#7
0
 def auth_complete(self, *args, **kwargs):
     """Complete auth process. Check LinkedIn error response."""
     oauth_problem = self.request.GET.get('oauth_problem')
     if oauth_problem:
         if oauth_problem == 'user_refused':
             raise AuthCanceled(self, '')
         else:
             raise AuthUnknownError(self,
                                    'LinkedIn error was %s' % oauth_problem)
     return super(LinkedinAuth, self).auth_complete(*args, **kwargs)
示例#8
0
 def user_data(self, access_token, *args, **kwargs):
     """Loads user data from service"""
     guid = self._get_guid(access_token)
     url = 'http://social.yahooapis.com/v1/user/%s/profile?format=json' \
                 % guid
     request = self.oauth_request(access_token, url)
     response = self.fetch_response(request)
     try:
         return simplejson.loads(response)['profile']
     except ValueError:
         raise AuthUnknownError('Error during profile retrieval, '
                                'please, try again later')
示例#9
0
 def _get_guid(self, access_token):
     """
         Beause you have to provide GUID for every API request
         it's also returned during one of OAuth calls
     """
     url = 'http://social.yahooapis.com/v1/me/guid?format=json'
     request = self.oauth_request(access_token, url)
     response = self.fetch_response(request)
     try:
         json = simplejson.loads(response)
         return json['guid']['value']
     except ValueError:
         raise AuthUnknownError('Error during user id retrieval, '
                                'please, try again later')
示例#10
0
 def auth_complete(self, *args, **kwargs):
     """Complete auth process"""
     response = self.consumer().complete(dict(self.data.items()),
                                         self.build_absolute_uri())
     if not response:
         raise AuthException(self, 'OpenID relying party endpoint')
     elif response.status == SUCCESS:
         kwargs.update({
             'auth': self,
             'response': response,
             self.AUTH_BACKEND.name: True
         })
         return authenticate(*args, **kwargs)
     elif response.status == FAILURE:
         raise AuthFailed(self, response.message)
     elif response.status == CANCEL:
         raise AuthCanceled(self)
     else:
         raise AuthUnknownError(self, response.status)
示例#11
0
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        self.process_error(self.data)
        params = self.auth_complete_params(self.validate_state())
        request = Request(self.ACCESS_TOKEN_URL, data=urlencode(params),
                          headers=self.auth_headers())

        try:
            response = json.loads(dsa_urlopen(request).read())
        except HTTPError as e:
            if e.code == 400:
                raise AuthCanceled(self)
            else:
                raise
        except (ValueError, KeyError):
            raise AuthUnknownError(self)

        self.process_error(response)
        return self.do_auth(response['access_token'], response=response,
                            *args, **kwargs)
示例#12
0
    def do_auth(self, access_token, expires=None, *args, **kwargs):
        data = self.user_data(access_token)

        if not isinstance(data, dict):
            # From time to time Facebook responds back a JSON with just
            # False as value, the reason is still unknown, but since the
            # data is needed (it contains the user ID used to identify the
            # account on further logins), this app cannot allow it to
            # continue with the auth process.
            raise AuthUnknownError(self, 'An error ocurred while '
                                         'retrieving users Facebook '
                                         'data')

        data['access_token'] = access_token
        if expires:  # expires is None on offline access
            data['expires'] = expires

        kwargs.update({'auth': self,
                       'response': data,
                       self.AUTH_BACKEND.name: True})
        return authenticate(*args, **kwargs)
示例#13
0
class BaseOAuth2(BaseOAuth):
    """Base class for OAuth2 providers.

    OAuth2 draft details at:
        http://tools.ietf.org/html/draft-ietf-oauth-v2-10

    Attributes:
        AUTHORIZATION_URL       Authorization service url
        ACCESS_TOKEN_URL        Token URL
    """
    AUTHORIZATION_URL = None
    ACCESS_TOKEN_URL = None
    REFRESH_TOKEN_URL = None
    RESPONSE_TYPE = 'code'
    REDIRECT_STATE = True
    STATE_PARAMETER = True

    def state_token(self):
        """Generate csrf token to include as state parameter."""
        return get_random_string(32)

    def get_redirect_uri(self, state=None):
        """Build redirect_uri with redirect_state parameter."""
        uri = self.redirect_uri
        if self.REDIRECT_STATE and state:
            uri = url_add_parameters(uri, {'redirect_state': state})
        return uri

    def auth_params(self, state=None):
        client_id, client_secret = self.get_key_and_secret()
        params = {
            'client_id': client_id,
            'redirect_uri': self.get_redirect_uri(state)
        }
        if self.STATE_PARAMETER and state:
            params['state'] = state
        if self.RESPONSE_TYPE:
            params['response_type'] = self.RESPONSE_TYPE
        return params

    def auth_url(self):
        """Return redirect url"""
        if self.STATE_PARAMETER or self.REDIRECT_STATE:
            # Store state in session for further request validation. The state
            # value is passed as state parameter (as specified in OAuth2 spec),
            # but also added to redirect_uri, that way we can still verify the
            # request if the provider doesn't implement the state parameter.
            # Reuse token if any.
            name = self.AUTH_BACKEND.name + '_state'
            state = self.request.session.get(name) or self.state_token()
            self.request.session[self.AUTH_BACKEND.name + '_state'] = state
        else:
            state = None

        params = self.auth_params(state)
        params.update(self.get_scope_argument())
        params.update(self.auth_extra_arguments())

        if self.request.META.get('QUERY_STRING'):
            query_string = '&' + self.request.META['QUERY_STRING']
        else:
            query_string = ''
        return self.AUTHORIZATION_URL + '?' + urlencode(params) + query_string

    def validate_state(self):
        """Validate state value. Raises exception on error, returns state
        value if valid."""
        if not self.STATE_PARAMETER and not self.REDIRECT_STATE:
            return None
        state = self.request.session.get(self.AUTH_BACKEND.name + '_state')
        if state:
            request_state = self.data.get('state') or \
                            self.data.get('redirect_state')
            if not request_state:
                raise AuthMissingParameter(self, 'state')
            elif not state:
                raise AuthStateMissing(self, 'state')
            elif not constant_time_compare(request_state, state):
                raise AuthStateForbidden(self)
        return state

    def process_error(self, data):
        if data.get('error'):
            error = self.data.get('error_description') or self.data['error']
            raise AuthFailed(self, error)

    def auth_complete_params(self, state=None):
        client_id, client_secret = self.get_key_and_secret()
        return {
            'grant_type': 'authorization_code',  # request auth code
            'code': self.data.get('code', ''),  # server response code
            'client_id': client_id,
            'client_secret': client_secret,
            'redirect_uri': self.get_redirect_uri(state)
        }

    @classmethod
    def auth_headers(cls):
        return {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        }

    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        self.process_error(self.data)
        params = self.auth_complete_params(self.validate_state())
        request = Request(self.ACCESS_TOKEN_URL,
                          data=urlencode(params),
                          headers=self.auth_headers())

        try:
            response = simplejson.loads(dsa_urlopen(request).read())
        except HTTPError, e:
            if e.code == 400:
                raise AuthCanceled(self)
            else:
                raise
        except (ValueError, KeyError):
            raise AuthUnknownError(self)