def get_user_details(self, response): """ Gets the user details from Special:OAuth/identify """ key, secret = self.get_key_and_secret() access_token = response['access_token'] auth = OAuth1(key, client_secret=secret, resource_owner_key=access_token['oauth_token'], resource_owner_secret=access_token['oauth_token_secret']) req_resp = requests.post(url=self.setting('MEDIAWIKI_URL'), params={'title': 'Special:OAuth/identify'}, auth=auth) try: identity = jwt.decode(req_resp.content, secret, audience=key, algorithms=['HS256'], leeway=self.LEEWAY) except jwt.InvalidTokenError as exception: raise AuthException( self, 'An error occurred while trying to read json ' + 'content: {0}'.format(exception)) issuer = urlparse(identity['iss']).netloc expected_domain = urlparse(self.setting('MEDIAWIKI_URL')).netloc if not issuer == expected_domain: raise AuthException( self, 'Unexpected issuer {0}, expected {1}'.format( issuer, expected_domain)) now = time.time() issued_at = float(identity['iat']) if not now >= (issued_at - self.LEEWAY): raise AuthException( self, 'Identity issued {0} seconds in the future'.format(issued_at - now)) authorization_header = force_unicode( req_resp.request.headers['Authorization']) request_nonce = re.search(r'oauth_nonce="(.*?)"', authorization_header).group(1) if identity['nonce'] != request_nonce: raise AuthException( self, 'Replay attack detected: {0} != {1}'.format( identity['nonce'], request_nonce)) return {'username': identity['username'], 'userID': identity['sub']}
def associate_by_email(backend, details, user=None, *args, **kwargs): """ Associate current auth with a user with the same email address in the DB. This pipeline entry is not 100% secure unless you know that the providers enabled enforce email verification on their side, otherwise a user can attempt to take over another user account by using the same (not validated) email address on some provider. This pipeline entry is disabled by default. """ if user: return None email = details.get('email') if email: # Try to associate accounts registered with the same email address, # only if it's a single object. AuthException is raised if multiple # objects are returned. users = list(backend.strategy.storage.user.get_users_by_email(email)) if len(users) == 0: return None elif len(users) > 1: raise AuthException( backend, 'The given email address is associated with another account') else: return {'user': users[0], 'is_new': False}
def unauthorized_token(self): """ Return request for unauthorized token (first stage) Mediawiki request token is requested from e.g.: * https://en.wikipedia.org/w/index.php?title=Special:OAuth/initiate """ params = self.request_token_extra_arguments() params.update(self.get_scope_argument()) params['title'] = 'Special:OAuth/initiate' key, secret = self.get_key_and_secret() decoding = None if six.PY3 else 'utf-8' response = self.request(self.setting('MEDIAWIKI_URL'), params=params, auth=OAuth1( key, secret, callback_uri=self.setting('CALLBACK'), decoding=decoding), method=self.REQUEST_TOKEN_METHOD) if response.content.decode().startswith('Error'): raise AuthException(self, response.content.decode()) return response.content.decode()
def openid_request(self, params=None): """Return openid request""" try: return self.consumer().begin( url_add_parameters(self.openid_url(), params)) except DiscoveryFailure as err: raise AuthException(self, 'OpenID discovery error: {0}'.format(err))
def process_error(self, data): if not data: raise AuthException(self, 'OpenID relying party endpoint') elif data.status == FAILURE: raise AuthFailed(self, data.message) elif data.status == CANCEL: raise AuthCanceled(self) elif data.status != SUCCESS: raise AuthUnknownError(self, data.status)
def auth_complete(self, *args, **kwargs): access_token = self.data.get('access_token') response = {} if 'signed_request' in self.data: key, secret = self.get_key_and_secret() response = self.load_signed_request(self.data['signed_request']) if 'user_id' not in response and 'oauth_token' not in response: raise AuthException(self) if response is not None: access_token = response.get('access_token') or \ response.get('oauth_token') or \ self.data.get('access_token') if access_token is None: if self.data.get('error') == 'access_denied': raise AuthCanceled(self) else: raise AuthException(self) return self.do_auth(access_token, response, *args, **kwargs)
def user_data(self, access_token, *args, **kwargs): """Loads user data from service""" request_data = ['first_name', 'last_name', 'screen_name', 'nickname', 'photo'] + self.setting('EXTRA_DATA', []) fields = ','.join(set(request_data)) data = vk_api(self, 'users.get', { 'access_token': access_token, 'fields': fields, }) if data and data.get('error'): error = data['error'] msg = error.get('error_msg', 'Unknown error') if error.get('error_code') == 5: raise AuthTokenRevoked(self, msg) else: raise AuthException(self, msg) if data: data = data.get('response')[0] data['user_photo'] = data.get('photo') # Backward compatibility return data or {}
def policy(self): policy = self.setting('POLICY') if not policy or not policy.lower().startswith('b2c_'): raise AuthException('SOCIAL_AUTH_AZUREAD_B2C_OAUTH2_POLICY is ' 'required and should start with `b2c_`') return policy
def auth_complete(self, *args, **kwargs): """Completes login process, must return user instance.""" if not users.get_current_user(): raise AuthException('Authentication error') kwargs.update({'response': '', 'backend': self}) return self.strategy.authenticate(*args, **kwargs)