Esempio n. 1
0
    def _authenticate(self, flow):
        """Authenticate the current request"""
        request = self.context["request"]
        strategy = self.context["strategy"]
        backend = self.context["backend"]
        user = request.user

        is_authenticated = user.is_authenticated
        user = user if is_authenticated else None

        kwargs = {"request": request, "flow": flow}

        partial = partial_pipeline_data(backend, user, **kwargs)
        if partial:
            user = backend.continue_pipeline(partial)
            # clean partial data after usage
            strategy.clean_partial_pipeline(partial.token)
        else:
            user = backend.complete(user=user, **kwargs)

        # pop redirect value before the session is trashed on login(), but after
        # the pipeline so that the pipeline can change the redirect if needed
        redirect_url = backend.strategy.session_get("next", None)

        # check if the output value is something else than a user and just
        # return it to the client
        user_model = strategy.storage.user.user_model()
        if user and not isinstance(user, user_model):
            # this is where a redirect from the pipeline would get returned
            return user

        if is_authenticated:
            return SocialAuthState(
                SocialAuthState.STATE_SUCCESS, redirect_url=redirect_url
            )
        elif user:
            if user.is_active:
                social_user = user.social_user

                login(backend, user, social_user)
                # store last login backend name in session
                strategy.session_set(
                    "social_auth_last_login_backend", social_user.provider
                )

                return SocialAuthState(
                    SocialAuthState.STATE_SUCCESS, redirect_url=redirect_url
                )
            else:
                return SocialAuthState(SocialAuthState.STATE_INACTIVE)
        else:  # pragma: no cover
            # this follows similar code in PSA itself, but wasn't reachable through normal testing
            log.error("Unexpected authentication result")
            return SocialAuthState(
                SocialAuthState.STATE_ERROR, errors=["Unexpected authentication result"]
            )
Esempio n. 2
0
    def create(self, validated_data):
        """Try to 'save' the request"""
        self._save_next(validated_data)

        try:
            result = super()._authenticate(SocialAuthState.FLOW_REGISTER)
            if isinstance(result, HttpResponseRedirect):
                # a redirect here means confirmation email sent
                result = SocialAuthState(SocialAuthState.STATE_REGISTER_CONFIRM_SENT)
        except RequirePasswordException as exc:
            result = SocialAuthState(
                SocialAuthState.STATE_LOGIN_PASSWORD,
                partial=exc.partial,
                errors=[str(exc)],
            )
        return result
Esempio n. 3
0
 def create(self, validated_data):
     """Try to 'save' the request"""
     try:
         result = super()._authenticate(SocialAuthState.FLOW_REGISTER)
     except RequirePasswordAndProfileException as exc:
         result = SocialAuthState(
             SocialAuthState.STATE_REGISTER_DETAILS, partial=exc.partial
         )
     return result
Esempio n. 4
0
 def create(self, validated_data):
     """Try to 'save' the request"""
     try:
         result = super()._authenticate(SocialAuthState.FLOW_LOGIN)
     except InvalidPasswordException as exc:
         result = SocialAuthState(
             SocialAuthState.STATE_ERROR, partial=exc.partial, errors=[str(exc)]
         )
     return result
Esempio n. 5
0
    def save(self, **kwargs):
        """'Save' the auth request"""
        try:
            result = super().save(**kwargs)
        except RequireProviderException as exc:
            result = SocialAuthState(
                SocialAuthState.STATE_LOGIN_PROVIDER,
                provider=exc.social_auth.provider,
                profile=exc.social_auth.user.profile,
            )
        except InvalidEmail:
            result = SocialAuthState(SocialAuthState.STATE_INVALID_EMAIL)
        except AuthException as exc:
            log.exception("Received unexpected AuthException")
            result = SocialAuthState(SocialAuthState.STATE_ERROR, errors=[str(exc)])

        if isinstance(result, SocialAuthState):
            if result.partial is not None:
                strategy = self.context["strategy"]
                strategy.storage.partial.store(result.partial)
            if result.state == SocialAuthState.STATE_REGISTER_CONFIRM_SENT:
                # If the user has just signed up and a verification link has been emailed, we need
                # to remove the partial token from the session. The partial token refers to a Partial
                # object, and we only want to continue the pipeline with that object if the user has
                # clicked the email verification link and the Partial has been matched from
                # the verification URL (that URL also contains the verification code, which we need
                # to continue the pipeline).
                self.context["backend"].strategy.session.pop(PARTIAL_PIPELINE_TOKEN_KEY)
        else:
            # if we got here, we saw an unexpected result
            log.error("Received unexpected result: %s", result)
            result = SocialAuthState(SocialAuthState.STATE_ERROR)

        # return the passed flow back to the caller
        # this way they know if they're on a particular page because of an attempted registration or login
        result.flow = self.validated_data["flow"]

        if result.provider is None:
            result.provider = EmailAuth.name

        # update self.instance so we serializer the reight object
        self.instance = result

        return result
Esempio n. 6
0
    def create(self, validated_data):
        """Try to 'save' the request"""
        self._save_next(validated_data)

        try:
            result = super()._authenticate(SocialAuthState.FLOW_LOGIN)
        except RequireRegistrationException:
            result = SocialAuthState(
                SocialAuthState.STATE_REGISTER_REQUIRED,
                field_errors={"email": "Couldn't find your account"},
            )
        except RequirePasswordException as exc:
            result = SocialAuthState(
                SocialAuthState.STATE_LOGIN_PASSWORD,
                partial=exc.partial,
                user=User.objects.filter(
                    social_auth__uid=validated_data.get("email"),
                    social_auth__provider=EmailAuth.name,
                ).first(),
            )
        return result
Esempio n. 7
0
    def create(self, validated_data):
        """Try to 'save' the request"""
        self._save_next(validated_data)

        try:
            result = super()._authenticate(SocialAuthState.FLOW_LOGIN)
        except RequireRegistrationException:
            result = SocialAuthState(
                SocialAuthState.STATE_ERROR,
                errors=["Couldn't find your MIT OPEN Account"],
            )
        except RequirePasswordException as exc:
            result = SocialAuthState(
                SocialAuthState.STATE_LOGIN_PASSWORD,
                partial=exc.partial,
                profile=Profile.objects.filter(
                    user__social_auth__uid=validated_data.get("email"),
                    user__social_auth__provider=EmailAuth.name,
                ).first(),
            )
        return result
Esempio n. 8
0
from authentication.serializers import RegisterEmailSerializer
from authentication.utils import SocialAuthState

EMAIL = "*****@*****.**"
TOKEN = {"token": "value"}

pytestmark = [pytest.mark.django_db]


@pytest.mark.parametrize(
    "side_effect,result",
    (
        (
            AuthException(None, "message"),
            SocialAuthState(SocialAuthState.STATE_ERROR, errors=["message"]),
        ),
        (InvalidEmail(None),
         SocialAuthState(SocialAuthState.STATE_INVALID_EMAIL)),
    ),
)
def test_social_auth_serializer_error(mocker, side_effect, result):
    """Tests that an AuthException exception is converted correctly"""
    mocked_authenticate = mocker.patch(
        "authentication.serializers.SocialAuthSerializer._authenticate")
    mocked_authenticate.side_effect = side_effect

    result.flow = SocialAuthState.FLOW_REGISTER
    result.provider = EmailAuth.name

    serializer = RegisterEmailSerializer(