def test_pipeline_returns_json_response_on_post(self): """pipeline step renders json response for POST request and inactive user""" request = create_request(data={"username": "******"}) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") response = require_activation( strategy=strategy, details={}, backend=backend, user=self.user, pipeline_index=1, ) self.assertEqual(response.status_code, 200) self.assertEqual(response["content-type"], "application/json") self.assertJsonResponseEquals( response, { "step": "done", "backend_name": "GitHub", "activation": "admin", "email": "*****@*****.**", "username": "******", }, )
def __init__(self, usa): """ Args: usa (UserSocialAuth): UserSocialAuth google-oauth2 object """ backend = usa.get_backend_instance(load_strategy()) data = usa.extra_data token = data['access_token'] refresh_token = data['refresh_token'] # refresh_token = None token_uri = backend.refresh_token_url() client_id, client_secret = backend.get_key_and_secret() scopes = backend.get_scope() # id_token is not provided with GoogleOAuth2 backend super().__init__( token, refresh_token=refresh_token, id_token=None, token_uri=token_uri, client_id=client_id, client_secret=client_secret, scopes=scopes ) self.usa = usa # Needed for self.expired() check self.expiry = self._parse_expiry(data)
def social_auth(request, backend): """Wrapper around social_django.views.auth. - Incorporates modified social_djang.utils.psa - Requires POST (to avoid CSRF on auth) - Stores current user in session (to avoid CSRF upon completion) - Stores session ID in the request URL if needed """ # Fill in idp in case it is not provided if backend == "saml" and "idp" not in request.GET: request.GET = request.GET.copy() request.GET["idp"] = "weblate" store_userid(request) uri = reverse("social:complete", args=(backend, )) request.social_strategy = load_strategy(request) try: request.backend = load_backend(request.social_strategy, backend, uri) except MissingBackend: raise Http404("Backend not found") # Store session ID for OpenID based auth. The session cookies will not be sent # on returning POST request due to SameSite cookie policy if isinstance(request.backend, OpenIdAuth): request.backend.redirect_uri += "?authid={}".format( dumps( (request.session.session_key, get_ip_address(request)), salt="weblate.authid", )) return do_auth(request.backend, redirect_name=REDIRECT_FIELD_NAME)
def test_form_ignore_inactive_agreement(self): """social register ignores inactive agreement""" form_data = { 'email': '*****@*****.**', 'username': '******', 'terms_of_service': None, } request = create_request(data=form_data) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, '/') Agreement.objects.create( type=Agreement.TYPE_TOS, text="Lorem ipsum", is_active=False, ) result = create_user_with_form( strategy=strategy, details={'email': form_data['email']}, backend=backend, user=None, pipeline_index=1, ) new_user = UserModel.objects.get(email='*****@*****.**') self.assertEqual(result, {'user': new_user, 'is_new': True}) self.assertEqual(new_user.agreements, []) self.assertEqual(new_user.useragreement_set.count(), 0)
def test_form_ignore_inactive_agreement(self): """social register ignores inactive agreement""" form_data = { "email": "*****@*****.**", "username": "******", "terms_of_service": None, } request = create_request(data=form_data) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") Agreement.objects.create(type=Agreement.TYPE_TOS, text="Lorem ipsum", is_active=False) result = create_user_with_form( strategy=strategy, details={"email": form_data["email"]}, backend=backend, user=None, pipeline_index=1, ) new_user = User.objects.get(email="*****@*****.**") self.assertEqual(result, {"user": new_user, "is_new": True}) self.assertEqual(new_user.agreements, []) self.assertEqual(new_user.useragreement_set.count(), 0)
def post(self, request, *args, **kwargs): backend = request.data.get("backend", None) if backend is None: return Response({"backend": ["This field is required."]}, status=status.HTTP_400_BAD_REQUEST) association_id = request.data.get("association_id", None) if association_id is None: return Response({"association_id": ["This field is required."]}, status=status.HTTP_400_BAD_REQUEST) strategy = load_strategy(request=request) try: backend = load_backend( strategy, backend, reverse(NAMESPACE + ":complete", args=(backend, ))) except MissingBackend: return Response({"backend": ["Invalid backend."]}, status=status.HTTP_400_BAD_REQUEST) backend.disconnect(user=self.get_object(), association_id=association_id, *args, **kwargs) return Response(status=status.HTTP_204_NO_CONTENT)
def wrapper(cls, root, info, provider, access_token, **kwargs): strategy = load_strategy(info.context) try: backend = load_backend(strategy, provider, redirect_uri=None) except MissingBackend: raise exceptions.GraphQLSocialAuthError(_('Provider not found')) if info.context.user.is_authenticated: authenticated_user = info.context.user else: authenticated_user = None user = backend.do_auth(access_token, user=authenticated_user) if user is None: raise exceptions.InvalidTokenError(_('Invalid token')) user_model = strategy.storage.user.user_model() if not isinstance(user, user_model): msg = _('`{}` is not a user instance').format(type(user).__name__) raise exceptions.DoAuthError(msg, user) if not issubclass(cls, mixins.JSONWebTokenMixin): _do_login(backend, user, user.social_user) return f(cls, root, info, user.social_user, **kwargs)
def _create_suomifi_logout_response(social_user, user, request, redirect_url): """Creates Suomi.fi logout redirect response for given social_user and removes all related OIDC tokens. The user is directed to redirect_url after succesful Suomi.fi logout. """ token = '' saml_backend = load_backend( load_strategy(request), 'suomifi', redirect_uri=getattr(settings, 'LOGIN_URL') ) id_token_hint = request.GET.get('id_token_hint') if id_token_hint: client_id = client_id_from_id_token(id_token_hint) try: client = Client.objects.get(client_id=client_id) if redirect_url in client.post_logout_redirect_uris: token = saml_backend.create_return_token( client_id, client.post_logout_redirect_uris.index(redirect_url)) except Client.DoesNotExist: pass response = saml_backend.create_logout_redirect(social_user, token) for token in Token.objects.filter(user=user): if token.id_token.get('aud') == client_id: token.delete() return response
def follow_user(request, user_id): """ This function follows a streamer as long as the last follow event is older than the last unfollow event. """ user = request.user social = user.social_auth.get(provider='twitch') access_token = social.get_access_token(load_strategy()) client = TwitchClient(client_id='9hfygng7md3x7maw2g4uko0ednm3hk', oauth_token=access_token) last_follow = Event.objects.filter(user=user, streamer_id=user_id, event_type="Followed user").order_by('-id').first() last_unfollow = Event.objects.filter(user=user, streamer_id=user_id, event_type="Unfollowed user").order_by('-id').first() if last_follow: if last_unfollow: time1 = last_follow._meta.get_field('created_at').value_from_object(last_follow) time2 = last_unfollow._meta.get_field('created_at').value_from_object(last_unfollow) if (time1-time2).total_seconds() > 0: return(JsonResponse({"follows": "User was already following this channel"})) else: Event.objects.create(user=user, streamer_id=user_id, event_type="Followed user") return(JsonResponse({'follows': client.users.follow_channel(social.uid, user_id)})) return(JsonResponse({"follows": "User was already following this channel"})) Event.objects.create(user=user, streamer_id=user_id, event_type="Followed user") return(JsonResponse({'follows': client.users.follow_channel(social.uid, user_id)}))
def update_subscription_status(broadcaster, user): broadcaster_social = broadcaster.social_auth.filter( provider='twitch').first() user_social = user.social_auth.filter(provider='twitch').first() if not broadcaster_social: raise ValueError('Missing social data for broadcaster.') broadcaster_token = broadcaster_social.get_access_token(load_strategy()) resp = requests.get( 'https://api.twitch.tv/helix/subscriptions', headers={'Authorization': f'Bearer {broadcaster_token}'}, params={ 'broadcaster_id': broadcaster_social.uid, 'user_id': user_social.uid, }) # If the length is greater than 0, they're good. if not resp.ok: raise ValueError('Error retrieving subscription information.') data = resp.json()['data'] if len(data) > 0: Subscription.objects.update_or_create( broadcaster=broadcaster, user=user, defaults={'last_verified': now()})
def logout_view(request, backend): backend_obj = load_backend( load_strategy(request), backend, redirect_uri=getattr(settings, 'LOGIN_URL'), ) return backend_obj.logout_complete()
def verify_whitelist_subscribers(whitelist): broadcaster = whitelist.user broadcaster_social = broadcaster.social_auth.filter( provider='twitch').first() if not broadcaster_social: raise ValueError('Missing social data for broadcaster.') broadcaster_token = broadcaster_social.get_access_token(load_strategy()) broadcaster_id = broadcaster_social.uid subscriber_ids = [] paging = True cursor = None while paging: data, cursor = get_subscriber_ids(broadcaster_token, broadcaster_id, cursor) if len(data) == 0: paging = False for subscriber in data: subscriber_ids.append(subscriber['user_id']) # Update our subscriptions Subscription.objects.filter( broadcaster=broadcaster, user__social_auth__provider='twitch', user__social_auth__uid__in=subscriber_ids).update(last_verified=now())
def __init__(self, user): strategy = load_strategy() user_social_auth = user.social_auth.get() access_token = user_social_auth.get_access_token(strategy) self.api = Github(access_token) github_authenticated_user = self.api.get_user() self.github_named_user = self.get_user(github_authenticated_user.login)
def getToken(request): user = request.user social = user.social_auth.get(provider='vk-oauth2') if (social.extra_data['auth_time'] + social.extra_data['expires'] - 10) <= int(time.time()): strategy = load_strategy() social.refresh_token(strategy) return social.extra_data['access_token']
def test_form_ignore_inactive_agreement(self): """social register ignores inactive agreement""" form_data = { "email": "*****@*****.**", "username": "******", "terms_of_service": None, } request = create_request(data=form_data) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") Agreement.objects.create( type=Agreement.TYPE_TOS, text="Lorem ipsum", is_active=False ) result = create_user_with_form( strategy=strategy, details={"email": form_data["email"]}, backend=backend, user=None, pipeline_index=1, ) new_user = User.objects.get(email="*****@*****.**") self.assertEqual(result, {"user": new_user, "is_new": True}) self.assertEqual(new_user.agreements, []) self.assertEqual(new_user.useragreement_set.count(), 0)
def make_headers(self, auth_type, headers=None): """Make headers for Fitbit API request `auth_type` the string 'basic' or 'bearer' https://dev.fitbit.com/docs/basics/#language """ # refreshes token if necessary if self.social_auth_user.access_token_expired(): from social_django.utils import load_strategy access_token = self.social_auth_user.get_access_token(load_strategy()) self.social_auth_user = refresh(self.social_auth_user) if auth_type == 'bearer': auth_header = 'Bearer %s' % self.social_auth_user.extra_data['access_token'] else: auth_header = 'Basic %s' % base64.b64encode('%s:%s' % (self.client_id, self.client_secret,)) _headers = { 'Authorization' : auth_header, 'Accept-Locale' : 'en_US', 'Accept-Language' : 'en_US', } if headers: _headers.update(headers) headers = _headers return headers
def export_contacts(request): if not request.user.social_auth.filter(provider='google-oauth2'): return redirect('social:begin', 'google-oauth2') social = request.user.social_auth.get(provider='google-oauth2') if social.access_token_expired(): social.refresh_token(load_strategy()) service = build('people', 'v1', credentials=Credentials(social)) global CONTACT_THREAD global SYNCED_CONTACTS if not CONTACT_THREAD: CONTACT_THREAD = Thread(target=export_contacts_async, args=(service, ), name='ContactThread') CONTACT_THREAD.start() if not CONTACT_THREAD.is_alive(): CONTACT_THREAD = Thread(target=export_contacts_async, args=(service, ), name='ContactThread') CONTACT_THREAD.start() global TOTAL_CONTACTS TOTAL_CONTACTS = Patient.objects.count() return render( request, 'patient_registration/export-contact.html', { 'title': 'Dashboard', 'data': '{0} out of {1} Contacts Exported Successfully!'.format( SYNCED_CONTACTS, TOTAL_CONTACTS) })
def unsubscribe_from_google(social_id: int): social = UserSocialAuth.objects.get(pk=social_id) access_token = social.get_access_token(load_strategy()) headers = {"Authorization": f"Bearer {access_token}"} if not social.subscription_id and social.provider != 'google-oauth2': return stop_url = 'https://www.googleapis.com/calendar/v3/channels/stop' channel_id = social.subscription_id resource_id = social.calendar_data.get('resource_id') data = { 'id': channel_id, 'resourceId': resource_id, } try: response = requests.post(stop_url, headers=headers, json=data) except Exception: print("EXCEPTION DURING CANCELLING SUBSCRIPTION") else: if response.status_code == status.HTTP_200_OK: print("SUBSCRIPTION CANCELED") Event.objects.filter(user=social.user, provider=social.provider).delete() else: print("CANCELLING SUBSCRIPTION FAILED") print(response.status_code, response.content)
def get_service(user): social = user.social_auth.get(provider='google-oauth2') ls = load_strategy() access_token = social.get_access_token(ls) credentials = Credentials(access_token) service = build('drive', 'v3', credentials=credentials) return service
def request_password(request): """ View that invites the user to complete and confirm data, after a user choses to signup through third party apps (e.g. facebook or gmail). `RegistrationForm` will ask the user to chose a password for further logins """ partial_token = request.GET.get('partial_token') if request.method == 'GET': user_details = request.session.get('user_data') kwown_data = { 'first_name': user_details.get('first_name'), 'last_name': user_details.get('last_name'), 'email': user_details.get('email') } form = RegistrationForm(initial=kwown_data) return render(request, 'users/social_account_form.html', {'form': form}) else: form = RegistrationForm(request.POST) if form.is_valid(): strategy = load_strategy() partial = strategy.partial_load(request.GET.get('partial_token')) session = request.session session['local_password'] = form.cleaned_data.get('password') backend_name = session.get('backend_name') return redirect( reverse('social:complete', kwargs={'backend': partial.backend})) else: return render(request, 'users/social_account_form.html', {'form': form})
def suomifi_logout_view(request, uuid=None): saml_backend = load_backend( load_strategy(request), 'suomifi', redirect_uri=getattr(settings, 'LOGIN_URL'), ) return saml_backend.process_logout_message()
def test_user_created_no_activation_nonverified_email(self): """active user is created for non-verified email and activation disabled""" form_data = { 'email': '*****@*****.**', 'username': '******', } request = create_request(data=form_data) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, '/') result = create_user_with_form( strategy=strategy, details={'email': ''}, backend=backend, user=None, pipeline_index=1, ) new_user = UserModel.objects.get(email='*****@*****.**') self.assertEqual(result, {'user': new_user, 'is_new': True}) self.assertNewUserIsCorrect(new_user, form_data, activation='none', email_verified=False)
def validate_state(self, value): # Dirty hack because PSA does not respect request.data request = self.context['request'] request.GET = request.data strategy = load_strategy(request) redirect_uri = strategy.session_get('redirect_uri') backend_name = self.context['view'].kwargs['provider'] backend = load_backend(strategy, backend_name, redirect_uri=redirect_uri) try: backend.validate_state() except exceptions.AuthMissingParameter: raise serializers.ValidationError( 'State could not be found in request data.') except exceptions.AuthStateMissing: raise serializers.ValidationError( 'State could not be found in server-side session data.') except exceptions.AuthStateForbidden: raise serializers.ValidationError( 'Invalid state has been provided.') return value
def _create_suomifi_logout_response(social_user, user, request, redirect_url): """Creates Suomi.fi logout redirect response for given social_user and removes all related OIDC tokens. The user is directed to redirect_url after succesful Suomi.fi logout. """ token = '' saml_backend = load_backend(load_strategy(request), 'suomifi', redirect_uri=getattr( settings, 'LOGIN_URL')) id_token_hint = request.GET.get('id_token_hint') if id_token_hint: client_id = client_id_from_id_token(id_token_hint) try: client = Client.objects.get(client_id=client_id) if redirect_url in client.post_logout_redirect_uris: token = saml_backend.create_return_token( client_id, client.post_logout_redirect_uris.index(redirect_url)) except Client.DoesNotExist: pass response = saml_backend.create_logout_redirect(social_user, token) for token in Token.objects.filter(user=user): if token.id_token.get('aud') == client_id: token.delete() return response
def post(self, request): """Authenticate user through the provider and access_token""" serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) provider = serializer.data.get('provider', None) strategy = load_strategy(request) try: backend = load_backend(strategy=strategy, name=provider, redirect_uri=None) except MissingBackend: return Response({'error': 'Please provide a valid provider'}, status=status.HTTP_400_BAD_REQUEST) try: if isinstance(backend, BaseOAuth2): access_token = serializer.data.get('access_token') user = backend.do_auth(access_token) except HTTPError as error: return Response({ "error": { "access_token": "Invalid token", "details": str(error) } }, status=status.HTTP_400_BAD_REQUEST) except AuthTokenError as error: return Response({ "error": "Invalid credentials", "details": str(error) }, status=status.HTTP_400_BAD_REQUEST) try: authenticated_user = backend.do_auth(access_token, user=user) except HTTPError as error: return Response({ "error": "invalid token", "details": str(error) }, status=status.HTTP_400_BAD_REQUEST) except AuthForbidden as error: return Response({ "error": "invalid token", "details": str(error) }, status=status.HTTP_400_BAD_REQUEST) if authenticated_user and authenticated_user.is_active: # generate token user = authenticated_user token, created = Token.objects.get_or_create(user=user) # customize the response to your needs response = { "id": authenticated_user.id, "email": authenticated_user.email, "username": authenticated_user.username, "firstName": authenticated_user.first_name, "lastName": authenticated_user.last_name, "token": token.key } return Response(status=status.HTTP_200_OK, data=response)
def make_headers(self, auth_type, headers=None): """Make headers for Fitbit API request `auth_type` the string 'basic' or 'bearer' https://dev.fitbit.com/docs/basics/#language """ # refreshes token if necessary if self.social_auth_user.access_token_expired(): from social_django.utils import load_strategy access_token = self.social_auth_user.get_access_token( load_strategy()) self.social_auth_user = refresh(self.social_auth_user) if auth_type == 'bearer': auth_header = 'Bearer %s' % self.social_auth_user.extra_data[ 'access_token'] else: auth_header = 'Basic %s' % base64.b64encode('%s:%s' % ( self.client_id, self.client_secret, )) _headers = { 'Authorization': auth_header, 'Accept-Locale': 'en_US', 'Accept-Language': 'en_US', } if headers: _headers.update(headers) headers = _headers return headers
def external_validator(self, provider, access_code, request): """ Calls the social backend to validate the access_code and get information """ strategy = load_strategy(request=get_request()) log.debug('Loading provider backend %s.', request.provider) try: backend = load_backend( strategy, provider, reverse( "%s:complete" % NAMESPACE, args=( provider,))) except MissingBackend: raise errors.InvalidRequestError( description='Invalid provider given', request=request) log.debug( 'Dispatching authentication to provider %s.', request.provider) try: user = backend.do_auth(access_token=request.access_token) except requests.HTTPError as e: raise errors.InvalidRequestError( description="Backend responded with HTTP{0}: {1}.".format( e.response.status_code, e.response.text), request=request) if not user: raise errors.InvalidGrantError( 'Invalid access-code', request=request) if not user.is_active: raise errors.InvalidGrantError('User inactive', request=request) request.user = user return True
def oauth_login(self, view_request, access_token, oauth_backend): """auth using oauth vendor. google, facebook, linkedin, etc Args: view_request (django view request): got from django views. eg: def create(self, request): .... _get_user_from_oauth_login(request, .....) access_token (string): access token got from vendor API oauth_backend (string): oauth backend want to be use. eg: google-oauth2 Returns: queryset: return user instance """ redirect_uri = OAUTH_REDIRECT_URI if oauth_backend not in ["google-oauth2", "facebook", "apple-id"]: raise custom_exceptions.InvalidOAuthBackend view_request.social_strategy = load_strategy(view_request) if not hasattr(view_request, "strategy"): view_request.strategy = view_request.social_strategy view_request.backend = load_backend(view_request.social_strategy, oauth_backend, redirect_uri) user = view_request.backend.do_auth(access_token) return user
def setUpClass(cls): """ Init backend for the test case: A fake SAML backend which always uses a configured Identity Provider with driven attributes. Also init common data: SAML response, SAML details, a User in database. """ super().setUpClass() # Init a fake backend with only what we need cls.backend = MockedFERSAMLAuth( load_strategy(), redirect_uri="http://testserver/", ) cls.saml_response = { "idp_name": "marsha-local-idp", "attributes": { "attributes_are_unused_here": None, }, "session_index": "unused", } # Prepare common data cls.default_saml_details = { "first_name": "unused", "last_name": "unused", "username": "******", # unused "email": "*****@*****.**", # unused } cls.user = UserFactory( username=cls.default_saml_details["username"], email=cls.default_saml_details["email"], )
def _validate_state(self, value): request = self.context['request'] strategy = load_strategy(request) redirect_uri = strategy.session_get('redirect_uri') backend_name = self.context['view'].kwargs['provider'] backend = load_backend( strategy, backend_name, redirect_uri=redirect_uri ) try: backend.validate_state() except exceptions.AuthMissingParameter: raise serializers.ValidationError( 'State could not be found in request data.' ) except exceptions.AuthStateMissing: raise serializers.ValidationError( 'State could not be found in server-side session data.' ) except exceptions.AuthStateForbidden: raise serializers.ValidationError( 'Invalid state has been provided.' ) return value
def _send_refresh_request(user_social): """ Private function that refresh an user access token """ logger.debug("------------------refresh token-----------------") logger.debug("------------------old token---------------------") logger.debug(user_social.extra_data) strategy = load_strategy() user_social.refresh_token(strategy) # update token_dict for backward compatible data = user_social.extra_data token_dict = { 'access_token': data['access_token'], 'token_type': data['token_type'], 'expires_in': data['expires_in'], 'expires_at': data['expires_at'], 'refresh_token': data['refresh_token'], 'scope': data['scope'] } data["token_dict"] = token_dict user_social.set_extra_data(extra_data=data) user_social.save() logger.debug("------------------new token-----------------") logger.debug(user_social.extra_data)
def do_authenticate(user=None, next_uri='/api/users/'): facebook_state = 'ABC' client = Client() session = client.session session['facebook_state'] = facebook_state session['next'] = next_uri session.save() request_factory = RequestFactory() request = request_factory.get(path='/social/complete/facebook/', data={ 'redirect_state': 'DEF', 'granted_scopes': 'email,public_profile', 'denied_scopes': '', 'code': 'GHI', 'state': facebook_state, }) request.user = user if user else AnonymousUser() request.session = session request.session = client.session request.social_strategy = load_strategy(request) request.strategy = request.social_strategy backend = load_backend(request.strategy, 'facebook', '/social/complete/facebook/') request.backend = backend args = () kwargs = { 'backend': backend, 'response': {'name': 'Pepa Novák', 'id': '1234', 'expires': 1000, 'granted_scopes': ['email', 'public_profile'], 'access_token': 'A'}, 'user': user, } return backend.strategy.authenticate(*args, **kwargs), request.session.get('next')
def _send_refresh_request(self, user_social): """ Private function that refresh an user access token """ logger.debug("------------------refresh token-----------------") logger.debug("------------------old token---------------------") logger.debug(user_social.extra_data) strategy = load_strategy() user_social.refresh_token(strategy) # update token_dict for backward compatible data = user_social.extra_data token_dict = { 'access_token': data['access_token'], 'token_type': data['token_type'], 'expires_in': data['expires_in'], 'expires_at': data['expires_at'], 'refresh_token': data['refresh_token'], 'scope': data['scope'] } data["token_dict"] = token_dict user_social.set_extra_data(extra_data=data) user_social.save() logger.debug("------------------new token-----------------") logger.debug(user_social.extra_data)
def saml_metadata(request): if "social_core.backends.saml.SAMLAuth" not in settings.AUTHENTICATION_BACKENDS: raise Http404 # Generate configuration settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID = get_site_url( reverse("social:saml-metadata")) settings.SOCIAL_AUTH_SAML_ORG_INFO = { "en-US": { "name": "weblate", "displayname": settings.SITE_TITLE, "url": get_site_url("/"), } } admin_contact = { "givenName": settings.ADMINS[0][0], "emailAddress": settings.ADMINS[0][1], } settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT = admin_contact settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT = admin_contact # Generate metadata complete_url = reverse("social:complete", args=("saml", )) saml_backend = social_django.utils.load_backend(load_strategy(request), "saml", complete_url) metadata, errors = saml_backend.generate_metadata_xml() # Handle errors if errors: report_error(level="error", cause="SAML metadata", extra_data={"errors": errors}) return HttpResponseServerError(content=", ".join(errors)) return HttpResponse(content=metadata, content_type="text/xml")
def test_user_password_login(rf, user, user_password): """Tests that user_password works for login case""" request_password = "******" user.set_password(user_password) user.save() request = rf.post("/complete/email", { "password": request_password, "email": user.email }) middleware = SessionMiddleware() middleware.process_request(request) request.session.save() strategy = load_strategy(request) backend = load_backend(strategy, "email", None) if request_password == user_password: assert (user_actions.validate_password( strategy, backend, pipeline_index=0, user=user, flow=SocialAuthState.FLOW_LOGIN, ) == {}) else: with pytest.raises(InvalidPasswordException): user_actions.validate_password( strategy, backend, pipeline_index=0, user=user, flow=SocialAuthState.FLOW_LOGIN, )
def post(self, request): """Authenticate user through the provider and access_token""" serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) provider = serializer.data.get('provider', None) strategy = load_strategy(request) try: backend = load_backend(strategy=strategy, name=provider, redirect_uri=None) except MissingBackend: return Response({'error': 'Please provide a valid provider'}, status=status.HTTP_400_BAD_REQUEST) try: access_token = serializer.data.get('access_token') user = backend.do_auth(access_token) except HTTPError as error: return Response( { "error": { "access_token": "Invalid token", "details": str(error) } }, status=status.HTTP_400_BAD_REQUEST) except AuthTokenError as error: return Response( { "error": "Invalid credentials", "details": str(error) }, status=status.HTTP_400_BAD_REQUEST) try: authenticated_user = backend.do_auth(access_token, user=user) except HTTPError as error: return Response({ "error": "invalid token", "details": str(error) }, status=status.HTTP_400_BAD_REQUEST) except AuthForbidden as error: return Response({ "error": "invalid token", "details": str(error) }, status=status.HTTP_400_BAD_REQUEST) if authenticated_user and authenticated_user.is_active: login(request, authenticated_user) data = {"token": jwt_encode_handler(jwt_payload_handler(user))} response = { "name": authenticated_user.name, "token": data.get('token') } return Response(status=status.HTTP_200_OK, data=response)
def setUp(self): super(AccessTokenExchangeFormTest, self).setUp() self.request = RequestFactory().post("dummy_url") redirect_uri = 'dummy_redirect_url' SessionMiddleware().process_request(self.request) self.request.social_strategy = social_utils.load_strategy(self.request) # pylint: disable=no-member self.request.backend = social_utils.load_backend(self.request.social_strategy, self.BACKEND, redirect_uri)
def get_partial_pipeline(request): """ """ token = request.session.get('partial_pipeline_token') if not token: return None strategy = load_strategy(request) return strategy.partial_load(token)
def test_reverse_urls(backend_name, expected_url): """Tests that the redirect_uris stay the same as with the django allauth. Can be removed when all of the urls are changed.""" strategy = load_strategy() uri = reverse('social:complete', kwargs={'backend': backend_name}) backend = load_backend(strategy, backend_name, uri) assert backend.get_redirect_uri() == expected_url
def suomifi_metadata_view(request): complete_url = reverse('auth_backends:suomifi_metadata') saml_backend = load_backend( load_strategy(request), 'suomifi', redirect_uri=complete_url, ) metadata, errors = saml_backend.generate_metadata_xml() if not errors: return HttpResponse(content=metadata, content_type='text/xml')
def test_partial_token_if_user_not_set_no_showstopper(self): """pipeline step handles set session token if user is not set""" request = create_request() strategy = load_strategy(request=request) strategy.request.session["partial_pipeline_token"] = "test-token" backend = GithubOAuth2(strategy, "/") require_activation( strategy=strategy, details={}, backend=backend, user=None, pipeline_index=1 )
def test_skip_if_user_not_set(self): """pipeline step is skipped if user is not set""" request = create_request() strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") result = require_activation( strategy=strategy, details={}, backend=backend, user=None, pipeline_index=1 ) self.assertEqual(result, {})
def get_authorization_headers(self): headers = {} if self.g_social_auth: # refreshes token if necessary if self.g_social_auth.access_token_expired(): from social_django.utils import load_strategy access_token = self.g_social_auth.get_access_token(load_strategy()) self.g_social_auth = refresh(self.g_social_auth) headers['Authorization'] = '%(token_type)s %(access_token)s' % self.g_social_auth.extra_data return headers
def test_renders_form_if_not_post(self): """pipeline step renders form if not POST""" request = create_request() strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") response = create_user_with_form( strategy=strategy, details={}, backend=backend, user=None, pipeline_index=1 ) self.assertContains(response, "GitHub")
def test_skip_if_user_is_set(self): """pipeline step is skipped if user was passed""" request = create_request() strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") result = create_user_with_form( strategy=strategy, details={}, backend=backend, user=self.user, pipeline_index=1, ) self.assertEqual(result, {})
def _link_user_to_third_party_provider( is_third_party_auth_enabled, third_party_auth_credentials_in_api, user, request, params, ): """ If a 3rd party auth provider and credentials were provided in the API, link the account with social auth (If the user is using the normal register page, the social auth pipeline does the linking, not this code) Note: this is orthogonal to the 3rd party authentication pipeline that occurs when the account is created via the browser and redirect URLs. """ third_party_provider, running_pipeline = None, None if is_third_party_auth_enabled and third_party_auth_credentials_in_api: backend_name = params['provider'] request.social_strategy = social_utils.load_strategy(request) redirect_uri = reverse('social:complete', args=(backend_name, )) request.backend = social_utils.load_backend(request.social_strategy, backend_name, redirect_uri) social_access_token = params.get('access_token') if not social_access_token: raise ValidationError({ 'access_token': [ _("An access_token is required when passing value ({}) for provider.").format( params['provider'] ) ] }) request.session[pipeline.AUTH_ENTRY_KEY] = pipeline.AUTH_ENTRY_REGISTER_API pipeline_user = None error_message = "" try: pipeline_user = request.backend.do_auth(social_access_token, user=user) except AuthAlreadyAssociated: error_message = _("The provided access_token is already associated with another user.") except (HTTPError, AuthException): error_message = _("The provided access_token is not valid.") if not pipeline_user or not isinstance(pipeline_user, User): # Ensure user does not re-enter the pipeline request.social_strategy.clean_partial_pipeline(social_access_token) raise ValidationError({'access_token': [error_message]}) # If the user is registering via 3rd party auth, track which provider they use if is_third_party_auth_enabled and pipeline.running(request): running_pipeline = pipeline.get(request) third_party_provider = provider.Registry.get_from_pipeline(running_pipeline) return third_party_provider, running_pipeline
def api_request(self, url, params={}, refresh=True): s = self.get_social_auth() params.update({"format": "json"}) params.update({"access_token": s.access_token}) r = requests.get("https://ion.tjhsst.edu/api/{}".format(url), params=params) if r.status_code == 401: if refresh: try: self.get_social_auth().refresh_token(load_strategy()) except: pass return self.api_request(url, params, False) else: pass return r.json()
def _send_refresh_request(user_social): """ Private function that refresh an user access token """ strategy = load_strategy() try: user_social.refresh_token(strategy) except HTTPError as exc: if exc.response.status_code in (400, 401,): raise InvalidCredentialStored( message='Received a {} status code from the OAUTH server'.format( exc.response.status_code), http_status_code=exc.response.status_code ) raise
def test_pipeline_returns_html_responseon_get(self): """pipeline step renders http response for GET request and inactive user""" request = create_request() strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") response = require_activation( strategy=strategy, details={}, backend=backend, user=self.user, pipeline_index=1, ) self.assertEqual(response.status_code, 200) self.assertEqual(response["content-type"], "text/html; charset=utf-8")
def get(self, request, *args, **kwargs): redirect_uri = request.GET.get('redirect_uri') if redirect_uri not in settings.SOCIAL_AUTH_ALLOWED_REDIRECT_URIS: return Response(status=status.HTTP_400_BAD_REQUEST) strategy = load_strategy(request) strategy.session_set('redirect_uri', redirect_uri) backend_name = self.kwargs['provider'] backend = load_backend( strategy, backend_name, redirect_uri=redirect_uri ) authorization_url = backend.auth_url() return Response(data={ 'authorization_url': authorization_url, })
def saml_metadata_view(request): """ Get the Service Provider metadata for this edx-platform instance. You must send this XML to any Shibboleth Identity Provider that you wish to use. """ if not SAMLConfiguration.is_enabled(): raise Http404 complete_url = reverse('social:complete', args=("tpa-saml", )) if settings.APPEND_SLASH and not complete_url.endswith('/'): complete_url = complete_url + '/' # Required for consistency saml_backend = load_backend(load_strategy(request), "tpa-saml", redirect_uri=complete_url) metadata, errors = saml_backend.generate_metadata_xml() if not errors: return HttpResponse(content=metadata, content_type='text/xml') return HttpResponseServerError(content=', '.join(errors))
def test_empty_data_rejected(self): """form rejects empty data""" request = create_request(data={}) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") response = create_user_with_form( strategy=strategy, details={}, backend=backend, user=None, pipeline_index=1 ) self.assertEqual(response.status_code, 400) self.assertJsonResponseEquals( response, { "email": ["This field is required."], "username": ["This field is required."], }, )
def validate(self, attrs): request = self.context['request'] if 'state' in request.GET: self._validate_state(request.GET['state']) strategy = load_strategy(request) redirect_uri = strategy.session_get('redirect_uri') backend_name = self.context['view'].kwargs['provider'] backend = load_backend( strategy, backend_name, redirect_uri=redirect_uri ) try: user = backend.auth_complete() except exceptions.AuthException as e: raise serializers.ValidationError(str(e)) return {'user': user}
def test_skip_if_user_is_active(self): """pipeline step is skipped if user is active""" self.user.requires_activation = User.ACTIVATION_NONE self.user.save() self.assertFalse(self.user.requires_activation) request = create_request() strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") result = require_activation( strategy=strategy, details={}, backend=backend, user=self.user, pipeline_index=1, ) self.assertEqual(result, {})
def test_taken_data_rejected(self): """form rejects taken data""" request = create_request( data={"email": self.user.email, "username": self.user.username} ) strategy = load_strategy(request=request) backend = GithubOAuth2(strategy, "/") response = create_user_with_form( strategy=strategy, details={}, backend=backend, user=None, pipeline_index=1 ) self.assertEqual(response.status_code, 400) self.assertJsonResponseEquals( response, { "email": ["This e-mail address is not available."], "username": ["This username is not available."], }, )
def test_single_name(self): """ If the user only has one name, last_name should be blank. """ eoo = EdxOrgOAuth2(strategy=load_strategy()) result = eoo.get_user_details({ 'id': 5, 'username': '******', 'email': '*****@*****.**', 'name': 'staff' }) assert { 'edx_id': 'staff', 'username': '******', 'fullname': 'staff', 'email': '*****@*****.**', 'first_name': '', 'last_name': '' } == result
def _get_user_claims_values(user, claims): """ Return a list of values associate with the user claims. """ backend = EdXOpenIdConnect(strategy=load_strategy()) user_social_auth = user.social_auth.filter(provider=backend.name).first() if not user_social_auth: raise UserNotAssociatedWithBackendError access_token = user_social_auth.extra_data.get('access_token') token_type = user_social_auth.extra_data.get('token_type', 'Bearer') if not access_token: raise InvalidAccessTokenError try: data = backend.get_user_claims(access_token, claims, token_type=token_type) except Exception as e: raise PermissionsRetrievalFailedError(e) return data
def get(self, request, *args, **kwargs): """ Request email for the create user flow for logins that don't specify their email address. """ strategy = load_strategy() partial_token = request.GET.get('partial_token') partial = strategy.partial_load(partial_token) username = request.GET.get('username', '') email = request.GET.get('email', '') email_exists = request.GET.get('emailexists') user_exists = request.GET.get('userexists') return render(request, 'user/acquire_email.html', { "backend": partial.backend, "username": username, "email": email, "user_exists": user_exists, "email_exists": email_exists })