~ubuntu-branches/debian/sid/social-auth-core/sid

« back to all changes in this revision

Viewing changes to social_core/backends/google.py

  • Committer: Package Import Robot
  • Author(s): Andre Bianchi
  • Date: 2018-02-22 19:49:12 UTC
  • Revision ID: package-import@ubuntu.com-20180222194912-4lqv8mlhnqc4ncd3
Tags: upstream-1.7.0
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Google OpenId, OAuth2, OAuth1, Google+ Sign-in backends, docs at:
 
3
    https://python-social-auth.readthedocs.io/en/latest/backends/google.html
 
4
"""
 
5
from ..utils import handle_http_errors
 
6
from .open_id import OpenIdAuth
 
7
from .oauth import BaseOAuth2, BaseOAuth1
 
8
from ..exceptions import AuthMissingParameter
 
9
 
 
10
 
 
11
class BaseGoogleAuth(object):
 
12
    def get_user_id(self, details, response):
 
13
        """Use google email as unique id"""
 
14
        if self.setting('USE_UNIQUE_USER_ID', False):
 
15
            return response['id']
 
16
        else:
 
17
            return details['email']
 
18
 
 
19
    def get_user_details(self, response):
 
20
        """Return user details from Google API account"""
 
21
        if 'email' in response:
 
22
            email = response['email']
 
23
        elif 'emails' in response:
 
24
            email = response['emails'][0]['value']
 
25
        else:
 
26
            email = ''
 
27
 
 
28
        if isinstance(response.get('name'), dict):
 
29
            names = response.get('name') or {}
 
30
            name, given_name, family_name = (
 
31
                response.get('displayName', ''),
 
32
                names.get('givenName', ''),
 
33
                names.get('familyName', '')
 
34
            )
 
35
        else:
 
36
            name, given_name, family_name = (
 
37
                response.get('name', ''),
 
38
                response.get('given_name', ''),
 
39
                response.get('family_name', '')
 
40
            )
 
41
 
 
42
        fullname, first_name, last_name = self.get_user_names(
 
43
            name, given_name, family_name
 
44
        )
 
45
        return {'username': email.split('@', 1)[0],
 
46
                'email': email,
 
47
                'fullname': fullname,
 
48
                'first_name': first_name,
 
49
                'last_name': last_name}
 
50
 
 
51
 
 
52
class BaseGoogleOAuth2API(BaseGoogleAuth):
 
53
    def user_data(self, access_token, *args, **kwargs):
 
54
        """Return user data from Google API"""
 
55
        return self.get_json(
 
56
            'https://www.googleapis.com/plus/v1/people/me',
 
57
            params={
 
58
                'access_token': access_token,
 
59
                'alt': 'json'
 
60
            }
 
61
        )
 
62
 
 
63
    def revoke_token_params(self, token, uid):
 
64
        return {'token': token}
 
65
 
 
66
    def revoke_token_headers(self, token, uid):
 
67
        return {'Content-type': 'application/json'}
 
68
 
 
69
 
 
70
class GoogleOAuth2(BaseGoogleOAuth2API, BaseOAuth2):
 
71
    """Google OAuth2 authentication backend"""
 
72
    name = 'google-oauth2'
 
73
    REDIRECT_STATE = False
 
74
    AUTHORIZATION_URL = 'https://accounts.google.com/o/oauth2/auth'
 
75
    ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
 
76
    ACCESS_TOKEN_METHOD = 'POST'
 
77
    REVOKE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/revoke'
 
78
    REVOKE_TOKEN_METHOD = 'GET'
 
79
    # The order of the default scope is important
 
80
    DEFAULT_SCOPE = ['openid', 'email', 'profile']
 
81
    EXTRA_DATA = [
 
82
        ('refresh_token', 'refresh_token', True),
 
83
        ('expires_in', 'expires'),
 
84
        ('token_type', 'token_type', True)
 
85
    ]
 
86
 
 
87
 
 
88
class GooglePlusAuth(BaseGoogleOAuth2API, BaseOAuth2):
 
89
    name = 'google-plus'
 
90
    REDIRECT_STATE = False
 
91
    STATE_PARAMETER = False
 
92
    AUTHORIZATION_URL = 'https://accounts.google.com/o/oauth2/auth'
 
93
    ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
 
94
    ACCESS_TOKEN_METHOD = 'POST'
 
95
    REVOKE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/revoke'
 
96
    REVOKE_TOKEN_METHOD = 'GET'
 
97
    DEFAULT_SCOPE = [
 
98
        'https://www.googleapis.com/auth/plus.login',
 
99
        'https://www.googleapis.com/auth/plus.me',
 
100
    ]
 
101
    EXTRA_DATA = [
 
102
        ('id', 'user_id'),
 
103
        ('refresh_token', 'refresh_token', True),
 
104
        ('expires_in', 'expires'),
 
105
        ('access_type', 'access_type', True),
 
106
        ('code', 'code')
 
107
    ]
 
108
 
 
109
    def auth_complete_params(self, state=None):
 
110
        params = super(GooglePlusAuth, self).auth_complete_params(state)
 
111
        if self.data.get('access_token'):
 
112
            # Don't add postmessage if this is plain server-side workflow
 
113
            params['redirect_uri'] = 'postmessage'
 
114
        return params
 
115
 
 
116
    @handle_http_errors
 
117
    def auth_complete(self, *args, **kwargs):
 
118
        if 'access_token' in self.data:  # Client-side workflow
 
119
            token = self.data.get('access_token')
 
120
            response = self.get_json(
 
121
                'https://www.googleapis.com/oauth2/v3/tokeninfo',
 
122
                params={'access_token': token}
 
123
            )
 
124
            self.process_error(response)
 
125
            return self.do_auth(token, response=response, *args, **kwargs)
 
126
        elif 'code' in self.data:  # Server-side workflow
 
127
            response = self.request_access_token(
 
128
                self.ACCESS_TOKEN_URL,
 
129
                data=self.auth_complete_params(),
 
130
                headers=self.auth_headers(),
 
131
                method=self.ACCESS_TOKEN_METHOD
 
132
            )
 
133
            self.process_error(response)
 
134
            return self.do_auth(response['access_token'],
 
135
                                response=response,
 
136
                                *args, **kwargs)
 
137
        elif 'id_token' in self.data:  # Client-side workflow
 
138
            token = self.data.get('id_token')
 
139
            response = self.get_json(
 
140
                'https://www.googleapis.com/oauth2/v3/tokeninfo',
 
141
                params={'id_token': token}
 
142
            )
 
143
            self.process_error(response)
 
144
            return self.do_auth(token, response=response, *args, **kwargs)
 
145
        else:
 
146
            raise AuthMissingParameter(self, 'access_token, id_token, or code')
 
147
 
 
148
 
 
149
class GoogleOAuth(BaseGoogleAuth, BaseOAuth1):
 
150
    """Google OAuth authorization mechanism"""
 
151
    name = 'google-oauth'
 
152
    AUTHORIZATION_URL = 'https://www.google.com/accounts/OAuthAuthorizeToken'
 
153
    REQUEST_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetRequestToken'
 
154
    ACCESS_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetAccessToken'
 
155
    DEFAULT_SCOPE = ['https://www.googleapis.com/auth/userinfo#email']
 
156
 
 
157
    def user_data(self, access_token, *args, **kwargs):
 
158
        """Return user data from Google API"""
 
159
        return self.get_querystring(
 
160
            'https://www.googleapis.com/userinfo/email',
 
161
            auth=self.oauth_auth(access_token)
 
162
        )
 
163
 
 
164
    def get_key_and_secret(self):
 
165
        """Return Google OAuth Consumer Key and Consumer Secret pair, uses
 
166
        anonymous by default, beware that this marks the application as not
 
167
        registered and a security badge is displayed on authorization page.
 
168
        http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth
 
169
        """
 
170
        key_secret = super(GoogleOAuth, self).get_key_and_secret()
 
171
        if key_secret == (None, None):
 
172
            key_secret = ('anonymous', 'anonymous')
 
173
        return key_secret
 
174
 
 
175
 
 
176
class GoogleOpenId(OpenIdAuth):
 
177
    name = 'google'
 
178
    URL = 'https://www.google.com/accounts/o8/id'
 
179
 
 
180
    def get_user_id(self, details, response):
 
181
        """
 
182
        Return user unique id provided by service. For google user email
 
183
        is unique enought to flag a single user. Email comes from schema:
 
184
        http://axschema.org/contact/email
 
185
        """
 
186
        return details['email']