This file is indexed.

/usr/share/pyshared/social_auth/backends/facebook.py is in python-django-social-auth 0.7.23-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
"""
Facebook OAuth support.

This contribution adds support for Facebook OAuth service. The settings
FACEBOOK_APP_ID and FACEBOOK_API_SECRET must be defined with the values
given by Facebook application registration process.

Extended permissions are supported by defining FACEBOOK_EXTENDED_PERMISSIONS
setting, it must be a list of values to request.

By default account id and token expiration time are stored in extra_data
field, check OAuthBackend class for details on how to extend it.
"""
import cgi
import base64
import hmac
import hashlib
import time
from urllib import urlencode
from urllib2 import HTTPError

from django.utils import simplejson
from django.contrib.auth import authenticate
from django.http import HttpResponse
from django.template import TemplateDoesNotExist, RequestContext, loader

from social_auth.backends import BaseOAuth2, OAuthBackend
from social_auth.utils import sanitize_log_data, backend_setting, setting,\
    log, dsa_urlopen
from social_auth.exceptions import AuthException, AuthCanceled, AuthFailed,\
    AuthTokenError, AuthUnknownError


# Facebook configuration
FACEBOOK_ME = 'https://graph.facebook.com/me?'
ACCESS_TOKEN = 'https://graph.facebook.com/oauth/access_token?'
USE_APP_AUTH = setting('FACEBOOK_APP_AUTH', False)
LOCAL_HTML = setting('FACEBOOK_LOCAL_HTML', 'facebook.html')
APP_NAMESPACE = setting('FACEBOOK_APP_NAMESPACE', None)
REDIRECT_HTML = """
<script type="text/javascript">
    var domain = 'https://apps.facebook.com/',
        redirectURI = domain + {{ FACEBOOK_APP_NAMESPACE }} + '/';
    window.top.location = 'https://www.facebook.com/dialog/oauth/' +
    '?client_id={{ FACEBOOK_APP_ID }}' +
    '&redirect_uri=' + encodeURIComponent(redirectURI) +
    '&scope={{ FACEBOOK_EXTENDED_PERMISSIONS }}';
</script>
"""


class FacebookBackend(OAuthBackend):
    """Facebook OAuth2 authentication backend"""
    name = 'facebook'
    # Default extra data to store
    EXTRA_DATA = [
        ('id', 'id'),
        ('expires', 'expires')
    ]

    def get_user_details(self, response):
        """Return user details from Facebook account"""
        return {'username': response.get('username', response.get('name')),
                'email': response.get('email', ''),
                'fullname': response.get('name', ''),
                'first_name': response.get('first_name', ''),
                'last_name': response.get('last_name', '')}


class FacebookAuth(BaseOAuth2):
    """Facebook OAuth2 support"""
    AUTH_BACKEND = FacebookBackend
    RESPONSE_TYPE = None
    SCOPE_SEPARATOR = ','
    AUTHORIZATION_URL = 'https://www.facebook.com/dialog/oauth'
    ACCESS_TOKEN_URL = ACCESS_TOKEN
    SETTINGS_KEY_NAME = 'FACEBOOK_APP_ID'
    SETTINGS_SECRET_NAME = 'FACEBOOK_API_SECRET'
    SCOPE_VAR_NAME = 'FACEBOOK_EXTENDED_PERMISSIONS'
    EXTRA_PARAMS_VAR_NAME = 'FACEBOOK_PROFILE_EXTRA_PARAMS'

    def user_data(self, access_token, *args, **kwargs):
        """
        Grab user profile information from facebook.

        returns: dict or None
        """

        data = None
        params = backend_setting(self, self.EXTRA_PARAMS_VAR_NAME, {})
        params['access_token'] = access_token
        url = FACEBOOK_ME + urlencode(params)

        try:
            response = dsa_urlopen(url)
            data = simplejson.load(response)
        except ValueError:
            extra = {'access_token': sanitize_log_data(access_token)}
            log('error', 'Could not load user data from Facebook.',
                exc_info=True, extra=extra)
        except HTTPError:
            extra = {'access_token': sanitize_log_data(access_token)}
            log('error', 'Error validating access token.',
                exc_info=True, extra=extra)
            raise AuthTokenError(self)
        else:
            log('debug', 'Found user data for token %s',
                sanitize_log_data(access_token), extra={'data': data})
        return data

    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': backend_setting(self, self.SETTINGS_KEY_NAME),
                'redirect_uri': self.get_redirect_uri(state),
                'client_secret': backend_setting(
                    self,
                    self.SETTINGS_SECRET_NAME
                ),
                'code': self.data['code']
            })
            try:
                payload = dsa_urlopen(url)
            except HTTPError:
                raise AuthFailed(self, 'There was an error authenticating '
                                       'the app')

            response = payload.read()
            parsed_response = cgi.parse_qs(response)

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

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

            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:
            return self.do_auth(access_token, expires=expires, *args, **kwargs)
        else:
            if self.data.get('error') == 'access_denied':
                raise AuthCanceled(self)
            else:
                raise AuthException(self)

    @classmethod
    def process_refresh_token_response(cls, response):
        return dict((key, val[0])
                        for key, val in cgi.parse_qs(response).iteritems())

    @classmethod
    def refresh_token_params(cls, token):
        client_id, client_secret = cls.get_key_and_secret()
        return {
            'fb_exchange_token': token,
            'grant_type': 'fb_exchange_token',
            'client_id': client_id,
            'client_secret': client_secret
        }

    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)

    @classmethod
    def enabled(cls):
        """Return backend enabled status by checking basic settings"""
        return backend_setting(cls, cls.SETTINGS_KEY_NAME) and\
               backend_setting(cls, cls.SETTINGS_SECRET_NAME)


def base64_url_decode(data):
    data = data.encode(u'ascii')
    data += '=' * (4 - (len(data) % 4))
    return base64.urlsafe_b64decode(data)


def base64_url_encode(data):
    return base64.urlsafe_b64encode(data).rstrip('=')


def load_signed_request(signed_request, api_secret=None):
    try:
        sig, payload = signed_request.split(u'.', 1)
        sig = base64_url_decode(sig)
        data = simplejson.loads(base64_url_decode(payload))

        expected_sig = hmac.new(api_secret or setting('FACEBOOK_API_SECRET'),
            msg=payload,
            digestmod=hashlib.sha256).digest()

        # allow the signed_request to function for upto 1 day
        if sig == expected_sig and \
           data[u'issued_at'] > (time.time() - 86400):
            return data
    except ValueError:
        pass  # ignore if can't split on dot


class FacebookAppAuth(FacebookAuth):
    """Facebook Application Authentication support"""
    uses_redirect = False

    def auth_complete(self, *args, **kwargs):
        if not self.application_auth():
            return HttpResponse(self.auth_html())

        access_token = None
        expires = None

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

            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:
            return self.do_auth(access_token, expires=expires, *args, **kwargs)
        else:
            if self.data.get('error') == 'access_denied':
                raise AuthCanceled(self)
            else:
                raise AuthException(self)

    def application_auth(self):
        required_params = ('user_id', 'oauth_token')
        data = load_signed_request(
            self.data.get('signed_request'),
            backend_setting(self, self.SETTINGS_SECRET_NAME)
        )
        for param in required_params:
            if not param in data:
                return False
        return True

    def auth_html(self):
        app_id = backend_setting(self, self.SETTINGS_KEY_NAME)
        ctx = {
            'FACEBOOK_APP_ID': app_id,
            'FACEBOOK_EXTENDED_PERMISSIONS': ','.join(
                backend_setting(self, self.SCOPE_VAR_NAME)
            ),
            'FACEBOOK_COMPLETE_URI': self.redirect_uri,
            'FACEBOOK_APP_NAMESPACE': APP_NAMESPACE or app_id
        }

        try:
            fb_template = loader.get_template(LOCAL_HTML)
        except TemplateDoesNotExist:
            fb_template = loader.get_template_from_string(REDIRECT_HTML)
        context = RequestContext(self.request, ctx)

        return fb_template.render(context)


# Backend definition
BACKENDS = {
    'facebook': FacebookAppAuth if USE_APP_AUTH else FacebookAuth,
}