Exemplo n.º 1
0
    def response(self):
        if not hasattr(self, '_response'):
            if self.data.get('error'):
                error = self.data.get(
                    'error_description') or self.data['error']
                raise AuthFailed(self, error)

            state = self.validate_state()
            client_id, client_secret = self.get_key_and_secret()
            params = {
                '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)
            }
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Accept': 'application/json'
            }
            request = Request(self.ACCESS_TOKEN_URL,
                              data=urlencode(params),
                              headers=headers)

            try:
                self._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)
Exemplo n.º 2
0
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        if self.data.get('error'):
            error = self.data.get('error_description') or self.data['error']
            raise AuthFailed(self, error)

        client_id, client_secret = self.get_key_and_secret()
        params = {
            '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.redirect_uri
        }
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        request = Request(self.ACCESS_TOKEN_URL,
                          data=urlencode(params),
                          headers=headers)

        try:
            response = simplejson.loads(urlopen(request).read())
        except (ValueError, KeyError):
            raise AuthUnknownError(self)

        if response.get('error'):
            error = response.get('error_description') or response.get('error')
            raise AuthFailed(self, error)
        else:
            response.update(self.user_data(response['access_token']) or {})
            kwargs.update({
                'auth': self,
                'response': response,
                self.AUTH_BACKEND.name: True
            })
            return authenticate(*args, **kwargs)
Exemplo n.º 3
0
 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(urlopen(url))
     except (ValueError, IOError):
         raise AuthUnknownError('Error during profile retrieval, ' \
                                'please, try again later')
Exemplo n.º 4
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
    SCOPE_SEPARATOR = ' '
    RESPONSE_TYPE = 'code'

    def auth_url(self):
        """Return redirect url"""
        client_id, client_secret = self.get_key_and_secret()
        args = {'client_id': client_id, 'redirect_uri': self.redirect_uri}

        scope = self.get_scope()
        if scope:
            args['scope'] = self.SCOPE_SEPARATOR.join(self.get_scope())
        if self.RESPONSE_TYPE:
            args['response_type'] = self.RESPONSE_TYPE

        args.update(self.auth_extra_arguments())
        return self.AUTHORIZATION_URL + '?' + urlencode(args)

    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        if self.data.get('error'):
            error = self.data.get('error_description') or self.data['error']
            raise AuthFailed(self, error)

        client_id, client_secret = self.get_key_and_secret()
        params = {
            '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.redirect_uri
        }
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        request = Request(self.ACCESS_TOKEN_URL,
                          data=urlencode(params),
                          headers=headers)

        try:
            response = simplejson.loads(urlopen(request).read())
        except HTTPError, e:
            if e.code == 400:
                raise AuthCanceled(self)
            else:
                raise
        except (ValueError, KeyError):
            raise AuthUnknownError(self)
Exemplo n.º 5
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)
Exemplo n.º 6
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')
Exemplo n.º 7
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')
Exemplo n.º 8
0
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""

        access_token = None
        response = self.response
        if 'code' in self.data:
            access_token = self.response['access_token'][0]
            if 'expires' in self._response:
                expires = self.response['expires'][0]
        if 'signed_request' in self.data:
            if response is not None:
                access_token = response.get('access_token') or \
                               response.get('oauth_token') or \
                               self.data.get('access_token')

                if 'expires' in self._response:
                    expires = response['expires']

        if access_token:
            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
            # expires will not be part of response if offline access
            # premission was requested
            if expires:
                data['expires'] = expires

            kwargs.update({
                'auth': self,
                'response': data,
                self.AUTH_BACKEND.name: True
            })

            return authenticate(*args, **kwargs)
        else:
            if self.data.get('error') == 'access_denied':
                raise AuthCanceled(self)
            else:
                raise AuthException(self)
Exemplo n.º 9
0
 def auth_complete(self, *args, **kwargs):
     """Complete auth process"""
     response = self.consumer().complete(dict(self.data.items()),
                                         self.request.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)
Exemplo n.º 10
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)
Exemplo n.º 11
0
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        access_token = None
        expires = None

        if 'code' in self.data:
            state = self.validate_state()
            url = ACCESS_TOKEN + urlencode(
                {
                    'client_id': setting('FACEBOOK_APP_ID'),
                    'redirect_uri': self.get_redirect_uri(state),
                    'client_secret': setting('FACEBOOK_API_SECRET'),
                    'code': self.data['code']
                })
            try:
                response = cgi.parse_qs(urlopen(url).read())
            except HTTPError:
                raise AuthFailed(self, 'There was an error authenticating ' \
                                       'the app')

            access_token = response['access_token'][0]
            if 'expires' in response:
                expires = response['expires'][0]

        if 'signed_request' in self.data:
            response = load_signed_request(self.data.get('signed_request'))

            if response is not None:
                access_token = response.get('access_token') or \
                               response.get('oauth_token') or \
                               self.data.get('access_token')

                if 'expires' in response:
                    expires = response['expires']

        if access_token:
            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
            # expires will not be part of response if offline access
            # premission was requested
            if expires:
                data['expires'] = expires

            kwargs.update({
                'auth': self,
                'response': data,
                self.AUTH_BACKEND.name: True
            })

            return authenticate(*args, **kwargs)
        else:
            if self.data.get('error') == 'access_denied':
                raise AuthCanceled(self)
            else:
                raise AuthException(self)
Exemplo n.º 12
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
    SCOPE_SEPARATOR = ' '
    RESPONSE_TYPE = 'code'
    SCOPE_VAR_NAME = None
    DEFAULT_SCOPE = None
    REDIRECT_STATE = True

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

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

    def auth_url(self):
        """Return redirect url"""
        client_id, client_secret = self.get_key_and_secret()
        state = self.state_token()
        # 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.
        self.request.session[self.AUTH_BACKEND.name + '_state'] = state
        args = {
            'client_id': client_id,
            'state': state,
            'redirect_uri': self.get_redirect_uri(state)
        }

        scope = self.get_scope()
        if scope:
            args['scope'] = self.SCOPE_SEPARATOR.join(self.get_scope())
        if self.RESPONSE_TYPE:
            args['response_type'] = self.RESPONSE_TYPE

        args.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(args) + query_string

    def validate_state(self):
        """Validate state value. Raises exception on error, returns state
        value if valid."""
        state = self.request.session.get(self.AUTH_BACKEND.name + '_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 auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        if self.data.get('error'):
            error = self.data.get('error_description') or self.data['error']
            raise AuthFailed(self, error)

        state = self.validate_state()
        client_id, client_secret = self.get_key_and_secret()
        params = {
            '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)
        }
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        }
        request = Request(self.ACCESS_TOKEN_URL,
                          data=urlencode(params),
                          headers=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)