Example #1
0
    def test_accept_invite(self, get_audit, create_audit):
        om = OrganizationMember.objects.get(id=self.member.id)
        assert om.email == self.member.email

        helper = ApiInviteHelper(self.request, self.member.id, None)
        helper.accept_invite()

        om = OrganizationMember.objects.get(id=self.member.id)
        assert om.email is None
        assert om.user.id == self.user.id
Example #2
0
    def test_accept_invite_with_SSO(self, mock_provider, get_audit, create_audit):
        self.auth_provider.flags.allow_unlinked = True
        mock_provider.get.return_value = self.auth_provider

        om = OrganizationMember.objects.get(id=self.member.id)
        assert om.email == self.member.email

        helper = ApiInviteHelper(self.request, self.member.id, None)
        helper.accept_invite()

        om = OrganizationMember.objects.get(id=self.member.id)
        assert om.email is None
        assert om.user.id == self.user.id
Example #3
0
    def test_accept_invite_with_required_SSO(self, mock_provider, get_audit, create_audit):
        self.auth_provider.flags.allow_unlinked = False
        mock_provider.get.return_value = self.auth_provider

        om = OrganizationMember.objects.get(id=self.member.id)
        assert om.email == self.member.email

        helper = ApiInviteHelper(self.request, self.member.id, None)
        helper.accept_invite()

        # Invite cannot be accepted without AuthIdentity if SSO is required
        om = OrganizationMember.objects.get(id=self.member.id)
        assert om.email is not None
        assert om.user is None
Example #4
0
    def post(self, request, user, interface_id):
        """
        Enroll in authenticator interface
        `````````````````````````````````

        :pparam string user_id: user id or "me" for current user
        :pparam string interface_id: interface id

        :auth: required
        """

        # Using `request.user` here because superuser should not be able to set a user's 2fa

        # start activation
        serializer_cls = serializer_map.get(interface_id, None)

        if serializer_cls is None:
            return Response(status=status.HTTP_404_NOT_FOUND)

        serializer = serializer_cls(data=request.data)

        if not serializer.is_valid():
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        interface = Authenticator.objects.get_interface(
            request.user, interface_id)

        # Not all interfaces allow multi enrollment
        #
        # This is probably un-needed because we catch
        # `Authenticator.AlreadyEnrolled` when attempting to enroll
        if interface.is_enrolled and not interface.allow_multi_enrollment:
            return Response(ALREADY_ENROLLED_ERR,
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            interface.secret = request.data["secret"]
        except KeyError:
            pass

        context = {}
        # Need to update interface with phone number before validating OTP
        if "phone" in request.data:
            interface.phone_number = serializer.data["phone"]

            # Disregarding value of 'otp', if no OTP was provided,
            # send text message to phone number with OTP
            if "otp" not in request.data:
                if interface.send_text(for_enrollment=True,
                                       request=request._request):
                    return Response(status=status.HTTP_204_NO_CONTENT)
                else:
                    # Error sending text message
                    return Response(
                        SEND_SMS_ERR,
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # Attempt to validate OTP
        if "otp" in request.data and not interface.validate_otp(
                serializer.data["otp"]):
            return Response(INVALID_OTP_ERR,
                            status=status.HTTP_400_BAD_REQUEST)

        # Try u2f enrollment
        if interface_id == "u2f":
            # What happens when this fails?
            interface.try_enroll(
                serializer.data["challenge"],
                serializer.data["response"],
                serializer.data["deviceName"],
            )
            context.update({"device_name": serializer.data["deviceName"]})

        try:
            interface.enroll(request.user)
        except Authenticator.AlreadyEnrolled:
            return Response(ALREADY_ENROLLED_ERR,
                            status=status.HTTP_400_BAD_REQUEST)

        context.update({"authenticator": interface.authenticator})
        capture_security_activity(
            account=request.user,
            type="mfa-added",
            actor=request.user,
            ip_address=request.META["REMOTE_ADDR"],
            context=context,
            send_email=True,
        )
        request.user.clear_lost_passwords()
        request.user.refresh_session_nonce(self.request)
        request.user.save()
        Authenticator.objects.auto_add_recovery_codes(request.user)

        response = Response(status=status.HTTP_204_NO_CONTENT)

        # If there is a pending organization invite accept after the
        # authenticator has been configured.
        org_invite = get_invite_cookie(request)

        if org_invite:
            try:
                helper = ApiInviteHelper(
                    instance=self,
                    request=request,
                    member_id=org_invite["memberId"],
                    token=org_invite["token"],
                    logger=logger,
                )
            except OrganizationMember.DoesNotExist:
                logger.error("Failed to accept pending org invite",
                             exc_info=True)
            else:
                if helper.valid_request:
                    helper.accept_invite()
                    remove_invite_cookie(request, response)

        return response