Beispiel #1
0
def view_submission_list(request, username):
    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    id_string = request.GET.get("formId", None)
    xform = get_object_or_404(XForm, id_string__exact=id_string, user__username__iexact=username)
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden("Not shared.")
    num_entries = request.GET.get("numEntries", None)
    cursor = request.GET.get("cursor", None)
    instances = xform.instances.filter(deleted_at=None).order_by("pk")

    cursor = _parse_int(cursor)
    if cursor:
        instances = instances.filter(pk__gt=cursor)

    num_entries = _parse_int(num_entries)
    if num_entries:
        instances = instances[:num_entries]

    data = {"instances": instances}

    resumptionCursor = 0
    if instances.count():
        last_instance = instances[instances.count() - 1]
        resumptionCursor = last_instance.pk
    elif instances.count() == 0 and cursor:
        resumptionCursor = cursor

    data["resumptionCursor"] = resumptionCursor

    return render(request, "submissionList.xml", data, content_type="text/xml; charset=utf-8")
Beispiel #2
0
def view_download_submission(request, username):
    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    data = {}
    formId = request.GET.get("formId", None)
    if not isinstance(formId, six.string_types):
        return HttpResponseBadRequest()

    id_string = formId[0 : formId.find("[")]
    form_id_parts = formId.split("/")
    if form_id_parts.__len__() < 2:
        return HttpResponseBadRequest()

    uuid = _extract_uuid(form_id_parts[1])
    instance = get_object_or_404(
        Instance, xform__id_string__exact=id_string, uuid=uuid, xform__user__username=username, deleted_at=None
    )
    xform = instance.xform
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden("Not shared.")
    submission_xml_root_node = instance.get_root_node()
    submission_xml_root_node.setAttribute("instanceID", u"uuid:%s" % instance.uuid)
    submission_xml_root_node.setAttribute("submissionDate", instance.date_created.isoformat())
    data["submission_data"] = submission_xml_root_node.toxml()
    data["media_files"] = Attachment.objects.filter(instance=instance)
    data["host"] = request.build_absolute_uri().replace(request.get_full_path(), "")

    return render(request, "downloadSubmission.xml", data, content_type="text/xml; charset=utf-8")
Beispiel #3
0
def xformsManifest(request, username, id_string):
    xform = get_object_or_404(XForm, id_string__exact=id_string, user__username__iexact=username)
    formlist_user = xform.user
    profile, created = UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()

    response = render(
        request,
        "xformsManifest.xml",
        {
            "host": request.build_absolute_uri().replace(request.get_full_path(), ""),
            "media_files": MetaData.media_upload(xform, download=True),
        },
        content_type="text/xml; charset=utf-8",
    )
    response["X-OpenRosa-Version"] = "1.0"
    tz = pytz.timezone(settings.TIME_ZONE)
    dt = datetime.now(tz).strftime("%a, %d %b %Y %H:%M:%S %Z")
    response["Date"] = dt

    return response
Beispiel #4
0
        def wrapper(request, *args, **kwargs):
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()

            response = f(request, *args, **kwargs)
            if hasattr(response, 'status_code') and response.status_code in [401, 403]:
                return authenticator.build_challenge_response()
            if 200 <= response.status_code < 300:
                digest = python_digest.parse_digest_credentials(
                    request.META['HTTP_AUTHORIZATION'])
                nc = "%08d" % digest.nc
                partial_digest = authenticator._account_storage.get_partial_digest(digest.username)
                parameters = {
                        "username": request.user.username,
                        "ha1": partial_digest,
                        "nonce": digest.nonce,
                        "cnonce": digest.cnonce,
                        "method":digest.algorithm,
                        "uri": digest.uri,
                        "nc": nc,
                        }
                rspauth = calc_rspauth(parameters)
                info = 'rspauth="%s",cnonce="%s",nc=%s,qop=%s' % (rspauth, digest.cnonce,
                        nc, digest.qop)
                response["Authentication-Info"] = info
            return response
Beispiel #5
0
def formList(request, username):
    """
    This is where ODK Collect gets its download list.
    """
    formlist_user = get_object_or_404(User, username__iexact=username)
    profile, created = UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()

        # unauthorized if user in auth request does not match user in path
        # unauthorized if user not active
        if not request.user.is_active:
            return HttpResponseNotAuthorized()

    # filter private forms (where require_auth=False)
    # for users who are non-owner
    if request.user.username == profile.user.username:
        xforms = XForm.objects.filter(downloadable=True, user__username__iexact=username)
    else:
        xforms = XForm.objects.filter(downloadable=True, user__username__iexact=username, require_auth=False)

    audit = {}
    audit_log(Actions.USER_FORMLIST_REQUESTED, request.user, formlist_user, _("Requested forms list."), audit, request)

    data = {"host": request.build_absolute_uri().replace(request.get_full_path(), ""), "xforms": xforms}
    response = render(request, "xformsList.xml", data, content_type="text/xml; charset=utf-8")
    response["X-OpenRosa-Version"] = "1.0"
    tz = pytz.timezone(settings.TIME_ZONE)
    dt = datetime.now(tz).strftime("%a, %d %b %Y %H:%M:%S %Z")
    response["Date"] = dt

    return response
Beispiel #6
0
def form_upload(request, username):
    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    if form_user != request.user:
        return HttpResponseForbidden(
            _(u"Not allowed to upload form[s] to %(user)s account." %
              {'user': form_user}))
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        response['Location'] = request.build_absolute_uri().replace(
            request.get_full_path(), '/%s/formUpload' % form_user.username)
        return response
    xform_def = request.FILES.get('form_def_file', None)
    content = u""
    if isinstance(xform_def, File):
        do_form_upload = PublishXForm(xform_def, form_user)
        dd = publish_form(do_form_upload.publish_xform)
        status = 201
        if isinstance(dd, XForm):
            content = _(u"%s successfully published." % dd.id_string)
        else:
            content = dd['text']
            if isinstance(content, Exception):
                content = content.message
                status = 500
            else:
                status = 400
    return OpenRosaResponse(content, status=status)
Beispiel #7
0
    def test_authenticate_nonce(self):
        testuser = User.objects.create_user(
            username='******', email='*****@*****.**', password='******')
        otheruser = User.objects.create_user(
            username='******', email='*****@*****.**', password='******')

        nonce=python_digest.calculate_nonce(time.time(), secret=settings.SECRET_KEY)

        first_request = self.create_mock_request(username=testuser.username,
                                                 password='******', nonce=nonce)
        first_request.user = testuser

        # same nonce, same nonce count, will fail
        second_request = self.create_mock_request(username=testuser.username,
                                                  password='******', nonce=nonce)

        # same nonce, new nonce count, it works
        third_request = self.create_mock_request(username=testuser.username,
                                                 password='******', nonce=nonce,
                                                 nonce_count=2)
        third_request.user = testuser

        authenticator = HttpDigestAuthenticator()
        with self.mocker:
            self.assertTrue(HttpDigestAuthenticator.contains_digest_credentials(
                first_request
            ))
            with transaction.commit_on_success():
                self.assertTrue(authenticator.authenticate(first_request))
                self.assertFalse(authenticator.authenticate(second_request))
                transaction.rollback()
                self.assertTrue(authenticator.authenticate(third_request))
Beispiel #8
0
    def test_authenticate_basic(self):
        # a request for Basic auth
        thirteenth_request = self.create_mock_request_for_header(
            'Basic YmxhaDpibGFo')

        authenticator = HttpDigestAuthenticator()
        self.assertFalse(authenticator.authenticate(thirteenth_request))
Beispiel #9
0
def xformsManifest(request, username, id_string):  # pylint: disable=C0103
    """
    XFormManifest view, part of OpenRosa Form Discovery API 1.0.
    """
    xform_kwargs = {
        'id_string__iexact': id_string,
        'user__username__iexact': username
    }

    xform = get_form(xform_kwargs)
    formlist_user = xform.user
    profile, __ = UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()

    response = render(
        request,
        "xformsManifest.xml", {
            'host':
            request.build_absolute_uri().replace(request.get_full_path(), ''),
            'media_files':
            MetaData.media_upload(xform, download=True)
        },
        content_type="text/xml; charset=utf-8")
    response['X-OpenRosa-Version'] = '1.0'
    response['Date'] = datetime.now(pytz.timezone(settings.TIME_ZONE))\
        .strftime('%a, %d %b %Y %H:%M:%S %Z')

    return response
Beispiel #10
0
class DigestAuthentication(BaseAuthentication):
    """Digest authentication
    """

    def __init__(self):
        self.authenticator = HttpDigestAuthenticator()

    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'digest':
            return None

        try:
            if self.authenticator.authenticate(request):
                return request.user, None
            else:
                raise AuthenticationFailed(
                    _('Invalid username/password'))
        except (AttributeError, ValueError, DataError) as e:
            raise AuthenticationFailed(e)

    def authenticate_header(self, request):
        response = self.authenticator.build_challenge_response()

        return response['WWW-Authenticate']
Beispiel #11
0
def odk_submission(req):
    # if forms are restricted, force digest authentication
    if getattr(settings, "AUTHENTICATE_XFORMS", False):
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(req):
            return authenticator.build_challenge_response()

    if req.method == "HEAD":
        # technically this should be a 201 according to the HTTP spec, but
        # ODK collect requires 204 to move forward
        return HttpResponse("OK", status=204)
    elif req.method != "POST":
        # only POST and HEAD are supported
        return HttpResponse("Invalid method", status=405)

    values = {}
    xform = None
    raw = ""

    # this is the raw data
    if "xml_submission_file" in req.FILES:
        file = req.FILES["xml_submission_file"]
        raw = file.file.read()
        dom = parseString(raw)
        root = dom.childNodes[0]
        for child in root.childNodes:
            tag = child.tagName
            if child.childNodes:
                body = child.childNodes[0].wholeText

                if tag == "xform-keyword":
                    xform = get_object_or_404(XForm, keyword=body)
                else:
                    values[tag] = body

    # every other file is a binary, save them in our map as well (the keys are the values
    # in the submission file above)
    binaries = dict()
    for key in req.FILES:
        if key != "xml_submission_file":
            binaries[key] = req.FILES[key].file.read()

    # check that they have the correct permissions
    if not xform.does_user_have_permission(req.user):
        return HttpResponse("You do not have permission to view this form", status=403)

    # if we found the xform
    submission = xform.process_odk_submission(raw, values, binaries)

    resp = render_to_response(
        "xforms/odk_submission.xml", {"xform": xform, "submission": submission}, context_instance=RequestContext(req)
    )

    # ODK needs two things for a form to be considered successful
    # 1) the status code needs to be 201 (created)
    resp.status_code = 201

    # 2) The location header needs to be set to the host it posted to
    resp["Location"] = "http://%s/submission" % settings.XFORMS_HOST
    return resp
Beispiel #12
0
def formList(request, username):
    """
    This is where ODK Collect gets its download list.
    """
    formlist_user = get_object_or_404(User, username=username)
    profile, created = UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()

        # unauthorized if user in auth request does not match user in path
        # unauthorized if user not active
        if not request.user.is_active:
            return HttpResponseNotAuthorized()

    xforms = XForm.objects.filter(downloadable=True, user__username=username)

    audit = {}
    audit_log(Actions.USER_FORMLIST_REQUESTED, request.user, formlist_user,
              _("Requested forms list."), audit, request)

    response = render_to_response("xformsList.xml", {
        'host': request.build_absolute_uri().replace(
            request.get_full_path(), ''),
        'xforms': xforms
    }, mimetype="text/xml; charset=utf-8")
    response['X-OpenRosa-Version'] = '1.0'
    tz = pytz.timezone(settings.TIME_ZONE)
    dt = datetime.now(tz).strftime('%a, %d %b %Y %H:%M:%S %Z')
    response['Date'] = dt
    return response
Beispiel #13
0
def formList(request, username):  # pylint: disable=C0103
    """
    formList view, /formList OpenRosa Form Discovery API 1.0.
    """
    formlist_user = get_object_or_404(User, username__iexact=username)
    profile, __ = UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()

        # unauthorized if user in auth request does not match user in path
        # unauthorized if user not active
        if not request.user.is_active:
            return HttpResponseNotAuthorized()

    # filter private forms (where require_auth=False)
    # for users who are non-owner
    if request.user.username == profile.user.username:
        xforms = XForm.objects.filter(
            downloadable=True,
            deleted_at__isnull=True,
            user__username__iexact=username)
    else:
        xforms = XForm.objects.filter(
            downloadable=True,
            deleted_at__isnull=True,
            user__username__iexact=username,
            require_auth=False)

    audit = {}
    audit_log(Actions.USER_FORMLIST_REQUESTED, request.user, formlist_user,
              _("Requested forms list."), audit, request)

    data = {
        'host': request.build_absolute_uri().replace(request.get_full_path(),
                                                     ''),
        'xforms': xforms
    }
    response = render(
        request,
        "xformsList.xml",
        data,
        content_type="text/xml; charset=utf-8")
    response['X-OpenRosa-Version'] = '1.0'
    response['Date'] = datetime.now(pytz.timezone(settings.TIME_ZONE))\
        .strftime('%a, %d %b %Y %H:%M:%S %Z')

    return response
Beispiel #14
0
def view_download_submission(request, username):

    def extract_uuid(text):
        text = text[text.find("@key="):-1].replace("@key=", "")
        if text.startswith("uuid:"):
            text = text.replace("uuid:", "")
        return text

    form_user = get_object_or_404(User, username=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    context = RequestContext(request)
    formId = request.GET.get('formId', None)
    if not isinstance(formId, basestring):
        return HttpResponseBadRequest()

    id_string = formId[0:formId.find('[')]
    form_id_parts = formId.split('/')
    if form_id_parts.__len__() < 2:
        return HttpResponseBadRequest()

    uuid = extract_uuid(form_id_parts[1])
    try:
        instance = Instance.objects.filter(xform__id_string=id_string,
                                           uuid=uuid,
                                           user__username=username,
                                           deleted_at=None)[0]
        xform = instance.xform
        if not has_permission(xform, form_user, request, xform.shared_data):
            return HttpResponseForbidden('Not shared.')
        submission_xml_root_node = instance.get_root_node()
        submission_xml_root_node.setAttribute(
            'instanceID', u'uuid:%s' % instance.uuid)
        submission_xml_root_node.setAttribute(
            'submissionDate', instance.date_created.isoformat()
        )
        context.submission_data = submission_xml_root_node.toxml()
        context.media_files = Attachment.objects.filter(instance=instance)
        context.host = request.build_absolute_uri().replace(
            request.get_full_path(), '')
        return render_to_response(
            'downloadSubmission.xml', context_instance=context,
            mimetype="text/xml; charset=utf-8")
    except IndexError:
        raise Http404
Beispiel #15
0
def view_submission_list(request, username):
    """
    Submission list view.

    Briefcase Aggregate API view/submissionList.
    """
    form_user = get_object_or_404(User, username__iexact=username)
    __, ___ = UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    id_string = request.GET.get('formId', None)
    xform_kwargs = {
        'id_string__iexact': id_string,
        'user__username__iexact': username
    }

    xform = get_form(xform_kwargs)
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden('Not shared.')
    num_entries = request.GET.get('numEntries', None)
    cursor = request.GET.get('cursor', None)
    instances = xform.instances.filter(deleted_at=None).order_by('pk')

    cursor = _parse_int(cursor)
    if cursor:
        instances = instances.filter(pk__gt=cursor)

    num_entries = _parse_int(num_entries)
    if num_entries:
        instances = instances[:num_entries]

    data = {'instances': instances}

    resumption_cursor = 0
    if instances.count():
        last_instance = instances[instances.count() - 1]
        resumption_cursor = last_instance.pk
    elif instances.count() == 0 and cursor:
        resumption_cursor = cursor

    data['resumptionCursor'] = resumption_cursor

    return render(
        request,
        'submissionList.xml',
        data,
        content_type="text/xml; charset=utf-8")
Beispiel #16
0
def odk_get_form(req, pk):
    # if forms are restricted, force digest authentication
    if getattr(settings, "AUTHENTICATE_XFORMS", False):
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(req):
            return authenticator.build_challenge_response()

    xform = get_object_or_404(XForm, pk=pk)
    if not xform.does_user_have_permission(req.user):
        return HttpResponse("You do not have permission to view this form", status=403)

    resp = render_to_response(
        "xforms/odk_get_form.xml", {"xform": xform}, mimetype="text/xml", context_instance=RequestContext(req)
    )
    resp["Content-Disposition"] = 'attachment;filename="%s.xml"' % xform.keyword
    return resp
Beispiel #17
0
    def test_authenticate_missing(self):
        testuser = User.objects.create_user(username='******',
                                            email='*****@*****.**',
                                            password='******')
        User.objects.create_user(username='******',
                                 email='*****@*****.**',
                                 password='******')

        python_digest.calculate_nonce(time.time(), secret=settings.SECRET_KEY)
        # if the partial digest is not in the DB, authentication fails
        twelfth_request = self.create_mock_request(username=testuser.username,
                                                   password='******',
                                                   nonce_count=3)

        authenticator = HttpDigestAuthenticator()
        PartialDigest.objects.all().delete()
        self.assertFalse(authenticator.authenticate(twelfth_request))
Beispiel #18
0
def odk_list_forms(req):
    # if forms are restricted, force digest authentication
    if getattr(settings, 'AUTHENTICATE_XFORMS', False):
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(req):
            return authenticator.build_challenge_response()

    xforms = []
    for form in XForm.on_site.filter(active=True):
        if form.does_user_have_permission(req.user):
            xforms.append(form)

    return render_to_response(
        "xforms/odk_list_forms.xml",
        { 'xforms': xforms, 'host':  settings.XFORMS_HOST },
        mimetype="text/xml",
        context_instance=RequestContext(req))
Beispiel #19
0
def view_download_submission(request, username):
    """
    Submission download view.

    Briefcase Aggregate API view/downloadSubmissionList.
    """
    form_user = get_object_or_404(User, username__iexact=username)
    __, ___ = UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    data = {}
    form_id = request.GET.get('formId', None)
    if not isinstance(form_id, six.string_types):
        return HttpResponseBadRequest()

    id_string = form_id[0:form_id.find('[')]
    form_id_parts = form_id.split('/')
    if form_id_parts.__len__() < 2:
        return HttpResponseBadRequest()

    uuid = _extract_uuid(form_id_parts[1])
    instance = get_object_or_404(
        Instance,
        xform__id_string__iexact=id_string,
        uuid=uuid,
        xform__user__username=username,
        deleted_at__isnull=True)
    xform = instance.xform
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden('Not shared.')
    submission_xml_root_node = instance.get_root_node()
    submission_xml_root_node.setAttribute('instanceID',
                                          u'uuid:%s' % instance.uuid)
    submission_xml_root_node.setAttribute('submissionDate',
                                          instance.date_created.isoformat())
    data['submission_data'] = submission_xml_root_node.toxml()
    data['media_files'] = Attachment.objects.filter(instance=instance)
    data['host'] = request.build_absolute_uri().replace(
        request.get_full_path(), '')

    return render(
        request,
        'downloadSubmission.xml',
        data,
        content_type="text/xml; charset=utf-8")
Beispiel #20
0
def formList(request, username):
    """
    This is where ODK Collect gets its download list.
    """
    if username.lower() == 'crowdforms':
        xforms = XForm.objects.filter(is_crowd_form=True)\
            .exclude(user__username=username)
    else:
        formlist_user = get_object_or_404(User, username=username)
        profile, created = \
            UserProfile.objects.get_or_create(user=formlist_user)

        if profile.require_auth:
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()

            # unauthorized if user in auth request does not match user in path
            # unauthorized if user not active
            if formlist_user.username != request.user.username or\
                    not request.user.is_active:
                return HttpResponseNotAuthorized()

        xforms = \
            XForm.objects.filter(form_active=True, user__username=username)
        # retrieve crowd_forms for this user
        crowdforms = XForm.objects.filter(
            metadata__data_type=MetaData.CROWDFORM_USERS,
            metadata__data_value=username
        )
        xforms = chain(xforms, crowdforms)
        audit = {}
        audit_log(Actions.USER_FORMLIST_REQUESTED, request.user, formlist_user,
                  _("Requested forms list."), audit, request)
    response = render_to_response("xformsList.xml", {
        #'urls': urls,
        'host': request.build_absolute_uri().replace(
            request.get_full_path(), ''),
        'xforms': xforms
    }, mimetype="text/xml; charset=utf-8")
    response['X-OpenRosa-Version'] = '1.0'
    tz = pytz.timezone(settings.TIME_ZONE)
    dt = datetime.now(tz).strftime('%a, %d %b %Y %H:%M:%S %Z')
    response['Date'] = dt
    return response
Beispiel #21
0
def view_submission_list(request, username):
    form_user = get_object_or_404(User, username=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    context = RequestContext(request)
    id_string = request.GET.get('formId', None)
    xform = get_object_or_404(
        XForm, id_string=id_string, user__username=username)
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden('Not shared.')
    num_entries = request.GET.get('numEntries', None)
    cursor = request.GET.get('cursor', None)
    instances = xform.surveys.filter(deleted_at=None).order_by('pk')

    if cursor:
        try:
            cursor = int(cursor)
        except ValueError:
            pass
        else:
            instances = instances.filter(pk__gt=cursor)

    if num_entries:
        try:
            num_entries = int(num_entries)
        except ValueError:
            pass
        else:
            instances = instances[:num_entries]
    context.instances = instances

    if instances.count():
        last_instance = instances[instances.count() - 1]
        context.resumptionCursor = last_instance.pk
    elif instances.count() == 0 and cursor:
        context.resumptionCursor = cursor
    else:
        context.resumptionCursor = 0

    return render_to_response(
        'submissionList.xml', context_instance=context,
        mimetype="text/xml; charset=utf-8")
Beispiel #22
0
    def test_authenticate_invalid(self):
        testuser = User.objects.create_user(username='******',
                                            email='*****@*****.**',
                                            password='******')
        otheruser = User.objects.create_user(username='******',
                                             email='*****@*****.**',
                                             password='******')

        nonce=python_digest.calculate_nonce(time.time(),
                                            secret=settings.SECRET_KEY)
        # an invalid request
        fourth_request = self.create_mock_request_for_header(
            'Digest blah blah blah')

        # an invalid request
        fifth_request = self.create_mock_request_for_header(None)

        # an invalid nonce
        sixth_request = self.create_mock_request(
            username=testuser.username, password='******', nonce_count=1,
            nonce=python_digest.calculate_nonce(time.time(), secret='bad secret'))

        # an invalid request digest (wrong password)
        seventh_request = self.create_mock_request(
            username=testuser.username, password='******', nonce=nonce,
            nonce_count=3)

        # attack attempts / failures don't invalidate the session or increment nonce_cont
        eighth_request = self.create_mock_request(
            username=testuser.username, password='******', nonce=nonce,
            nonce_count=3)
        eighth_request.user = testuser

        # mismatched URI
        ninth_request = self.create_mock_request(
            username=testuser.username, nonce=nonce, password='******',
            nonce_count=4, request_path='/different/path')

        # stale nonce
        tenth_request = self.create_mock_request(
            username=testuser.username, password='******', nonce_count=4,
            nonce=python_digest.calculate_nonce(
                time.time()-60000, secret=settings.SECRET_KEY))

        # once the nonce is used by one user, can't be reused by another
        eleventh_request = self.create_mock_request(
            username=otheruser.username, password='******', nonce=nonce,
            nonce_count=4)

        authenticator = HttpDigestAuthenticator()
        with self.mocker:
            self.assertFalse(authenticator.authenticate(fourth_request))
            self.assertFalse(authenticator.authenticate(fifth_request))
            self.assertFalse(authenticator.authenticate(sixth_request))
            self.assertFalse(authenticator.authenticate(seventh_request))
            self.assertTrue(authenticator.authenticate(eighth_request))
            self.assertFalse(authenticator.authenticate(ninth_request))
            self.assertFalse(authenticator.authenticate(tenth_request))
            self.assertFalse(authenticator.authenticate(eleventh_request))
Beispiel #23
0
def download_xform(request, username, id_string):
    """
    Download XForm XML view.
    """
    user = get_object_or_404(User, username__iexact=username)
    xform = get_form({'user': user, 'id_string__iexact': id_string})
    profile, __ = UserProfile.objects.get_or_create(user=user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()
    audit = {"xform": xform.id_string}
    audit_log(Actions.FORM_XML_DOWNLOADED, request.user, xform.user,
              _("Downloaded XML for form '%(id_string)s'.") %
              {"id_string": xform.id_string}, audit, request)
    response = response_with_mimetype_and_name(
        'xml', id_string, show_date=False)
    response.content = xform.xml
    return response
Beispiel #24
0
class DigestAuthentication(BaseAuthentication):
    def __init__(self):
        self.authenticator = HttpDigestAuthenticator()

    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'digest':
            return None

        if self.authenticator.authenticate(request):
            return request.user, None
        else:
            raise AuthenticationFailed(
                _(u"Invalid username/password"))

    def authenticate_header(self, request):
        response = self.authenticator.build_challenge_response()

        return response['WWW-Authenticate']
Beispiel #25
0
def xformsManifest(request, username, id_string):
    xform = get_object_or_404(
        XForm, id_string=id_string, user__username=username)
    formlist_user = xform.user
    profile, created = \
        UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()
    response = render_to_response("xformsManifest.xml", {
        'host': request.build_absolute_uri().replace(
            request.get_full_path(), ''),
        'media_files': MetaData.media_upload(xform, download=True)
    }, mimetype="text/xml; charset=utf-8")
    response['X-OpenRosa-Version'] = '1.0'
    tz = pytz.timezone(settings.TIME_ZONE)
    dt = datetime.now(tz).strftime('%a, %d %b %Y %H:%M:%S %Z')
    response['Date'] = dt
    return response
Beispiel #26
0
def view_submission_list(request, username):
    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    id_string = request.GET.get('formId', None)
    xform = get_object_or_404(XForm,
                              id_string__exact=id_string,
                              user__username__iexact=username)
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden('Not shared.')
    num_entries = request.GET.get('numEntries', None)
    cursor = request.GET.get('cursor', None)
    instances = xform.instances.filter(deleted_at=None).order_by('pk')

    cursor = _parse_int(cursor)
    if cursor:
        instances = instances.filter(pk__gt=cursor)

    num_entries = _parse_int(num_entries)
    if num_entries:
        instances = instances[:num_entries]

    data = {'instances': instances}

    resumptionCursor = 0
    if instances.count():
        last_instance = instances[instances.count() - 1]
        resumptionCursor = last_instance.pk
    elif instances.count() == 0 and cursor:
        resumptionCursor = cursor

    data['resumptionCursor'] = resumptionCursor

    return render(request,
                  'submissionList.xml',
                  data,
                  content_type="text/xml; charset=utf-8")
Beispiel #27
0
def view_download_submission(request, username):
    def extract_uuid(text):
        text = text[text.find("@key="):-1].replace("@key=", "")
        if text.startswith("uuid:"):
            text = text.replace("uuid:", "")
        return text

    form_user = get_object_or_404(User, username=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    context = RequestContext(request)
    formId = request.GET.get('formId', None)
    if not isinstance(formId, basestring):
        return HttpResponseBadRequest()

    id_string = formId[0:formId.find('[')]
    form_id_parts = formId.split('/')
    if form_id_parts.__len__() < 2:
        return HttpResponseBadRequest()

    uuid = extract_uuid(form_id_parts[1])
    instance = get_object_or_404(Instance,
                                 xform__id_string=id_string,
                                 uuid=uuid,
                                 user__username=username)
    submission_xml_root_node = instance.get_root_node()
    submission_xml_root_node.setAttribute('instanceID',
                                          u'uuid:%s' % instance.uuid)
    submission_xml_root_node.setAttribute('submissionDate',
                                          instance.date_created.isoformat())
    context.submission_data = submission_xml_root_node.toxml()
    context.media_files = Attachment.objects.filter(instance=instance)
    context.host = request.build_absolute_uri().replace(
        request.get_full_path(), '')
    return render_to_response('downloadSubmission.xml',
                              context_instance=context,
                              mimetype="text/xml; charset=utf-8")
Beispiel #28
0
def view_download_submission(request, username):
    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    data = {}
    formId = request.GET.get('formId', None)
    if not isinstance(formId, six.string_types):
        return HttpResponseBadRequest()

    id_string = formId[0:formId.find('[')]
    form_id_parts = formId.split('/')
    if form_id_parts.__len__() < 2:
        return HttpResponseBadRequest()

    uuid = _extract_uuid(form_id_parts[1])
    instance = get_object_or_404(Instance,
                                 xform__id_string__exact=id_string,
                                 uuid=uuid,
                                 xform__user__username=username,
                                 deleted_at=None)
    xform = instance.xform
    if not has_permission(xform, form_user, request, xform.shared_data):
        return HttpResponseForbidden('Not shared.')
    submission_xml_root_node = instance.get_root_node()
    submission_xml_root_node.setAttribute('instanceID',
                                          u'uuid:%s' % instance.uuid)
    submission_xml_root_node.setAttribute('submissionDate',
                                          instance.date_created.isoformat())
    data['submission_data'] = submission_xml_root_node.toxml()
    data['media_files'] = Attachment.objects.filter(instance=instance)
    data['host'] = request.build_absolute_uri().replace(
        request.get_full_path(), '')

    return render(request,
                  'downloadSubmission.xml',
                  data,
                  content_type="text/xml; charset=utf-8")
Beispiel #29
0
def form_upload(request, username):
    class DoXmlFormUpload():
        def __init__(self, xml_file, user):
            self.xml_file = xml_file
            self.user = user

        def publish(self):
            return publish_xml_form(self.xml_file, self.user)

    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    if form_user != request.user:
        return HttpResponseForbidden(
            _(u"Not allowed to upload form[s] to %(user)s account." %
              {'user': form_user}))
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        response['Location'] = request.build_absolute_uri().replace(
            request.get_full_path(), '/%s/formUpload' % form_user.username)
        return response
    xform_def = request.FILES.get('form_def_file', None)
    content = u""
    if isinstance(xform_def, File):
        do_form_upload = DoXmlFormUpload(xform_def, form_user)
        dd = publish_form(do_form_upload.publish)
        status = 201
        if isinstance(dd, XForm):
            content = _(u"%s successfully published." % dd.id_string)
        else:
            content = dd['text']
            if isinstance(content, Exception):
                content = content.message
                status = 500
            else:
                status = 400
    return OpenRosaResponse(content, status=status)
Beispiel #30
0
def download_xform(request, username, id_string):
    """
    Download XForm XML view.
    """
    user = get_object_or_404(User, username__iexact=username)
    xform = get_form({'user': user, 'id_string__iexact': id_string})
    profile, __ = UserProfile.objects.get_or_create(user=user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()
    audit = {"xform": xform.id_string}
    audit_log(
        Actions.FORM_XML_DOWNLOADED, request.user, xform.user,
        _("Downloaded XML for form '%(id_string)s'.") %
        {"id_string": xform.id_string}, audit, request)
    response = response_with_mimetype_and_name('xml',
                                               id_string,
                                               show_date=False)
    response.content = xform.xml
    return response
Beispiel #31
0
def xformsManifest(request, username, id_string):
    xform = get_object_or_404(
        XForm, id_string=id_string, user__username=username)
    formlist_user = xform.user
    profile, created = \
        UserProfile.objects.get_or_create(user=formlist_user)

    if profile.require_auth:
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(request):
            return authenticator.build_challenge_response()
    response = render_to_response("xformsManifest.xml", {
        #'urls': urls,
        'host': request.build_absolute_uri().replace(
            request.get_full_path(), ''),
        'media_files': MetaData.media_upload(xform)
    }, mimetype="text/xml; charset=utf-8")
    response['X-OpenRosa-Version'] = '1.0'
    tz = pytz.timezone(settings.TIME_ZONE)
    dt = datetime.now(tz).strftime('%a, %d %b %Y %H:%M:%S %Z')
    response['Date'] = dt
    return response
Beispiel #32
0
    def test_disable_nonce_count_enforcement(self):
        with patch(settings, DIGEST_ENFORCE_NONCE_COUNT=False):
            testuser = User.objects.create_user(username='******',
                                                email='*****@*****.**',
                                                password='******')

            nonce = python_digest.calculate_nonce(time.time(),
                                                  secret=settings.SECRET_KEY)

            first_request = self.create_mock_request(
                username=testuser.username, password='******', nonce=nonce)

            first_request.user = testuser

            # same nonce, same nonce count, will succeed
            second_request = self.create_mock_request(
                username=testuser.username, password='******', nonce=nonce)
            second_request.user = testuser

            authenticator = HttpDigestAuthenticator()
            self.assertTrue(authenticator.authenticate(first_request))
            self.assertTrue(authenticator.authenticate(second_request))
Beispiel #33
0
class DigestAuthentication(BaseAuthentication):
    def __init__(self):
        self.authenticator = HttpDigestAuthenticator()

    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'digest':
            return None

        try:
            if self.authenticator.authenticate(request):
                return request.user, None
            else:
                raise AuthenticationFailed(_('Invalid username/password'))
        except (AttributeError, ValueError, DataError) as e:
            raise AuthenticationFailed(e.message)

    def authenticate_header(self, request):
        response = self.authenticator.build_challenge_response()

        return response['WWW-Authenticate']
Beispiel #34
0
    def test_disable_nonce_count_enforcement(self):
        with patch(settings, DIGEST_ENFORCE_NONCE_COUNT=False):
            testuser = User.objects.create_user(username='******',
                                                email='*****@*****.**',
                                                password='******')

            nonce=python_digest.calculate_nonce(time.time(),
                                                secret=settings.SECRET_KEY)

            first_request = self.create_mock_request(
                username=testuser.username, password='******', nonce=nonce)

            first_request.user = testuser

            # same nonce, same nonce count, will succeed
            second_request = self.create_mock_request(
                username=testuser.username, password='******', nonce=nonce)
            second_request.user = testuser

            authenticator = HttpDigestAuthenticator()
            self.assertTrue(authenticator.authenticate(first_request))
            self.assertTrue(authenticator.authenticate(second_request))
Beispiel #35
0
def form_upload(request, username):
    class DoXmlFormUpload:
        def __init__(self, xml_file, user):
            self.xml_file = xml_file
            self.user = user

        def publish(self):
            return publish_xml_form(self.xml_file, self.user)

    form_user = get_object_or_404(User, username__iexact=username)
    profile, created = UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    if form_user != request.user:
        return HttpResponseForbidden(_(u"Not allowed to upload form[s] to %(user)s account." % {"user": form_user}))
    if request.method == "HEAD":
        response = OpenRosaResponse(status=204)
        response["Location"] = request.build_absolute_uri().replace(
            request.get_full_path(), "/%s/formUpload" % form_user.username
        )
        return response
    xform_def = request.FILES.get("form_def_file", None)
    content = u""
    if isinstance(xform_def, File):
        do_form_upload = DoXmlFormUpload(xform_def, form_user)
        dd = publish_form(do_form_upload.publish)
        status = 201
        if isinstance(dd, XForm):
            content = _(u"%s successfully published." % dd.id_string)
        else:
            content = dd["text"]
            if isinstance(content, Exception):
                content = content.message
                status = 500
            else:
                status = 400
    return OpenRosaResponse(content, status=status)
Beispiel #36
0
class DigestAuthentication(BaseAuthentication):
    """Digest authentication
    """
    def __init__(self):
        self.authenticator = HttpDigestAuthenticator()

    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b"digest":
            return None

        try:
            check_lockout(request)
            if self.authenticator.authenticate(request):
                update_last_login(None, request.user)
                return request.user, None
            else:
                attempts = login_attempts(request)
                remaining_attempts = (
                    getattr(settings, "MAX_LOGIN_ATTEMPTS", 10) - attempts)
                raise AuthenticationFailed(
                    _("Invalid username/password. "
                      "For security reasons, after {} more failed "
                      "login attempts you'll have to wait {} minutes "
                      "before trying again.".format(
                          remaining_attempts,
                          getattr(settings, "LOCKOUT_TIME", 1800) // 60,
                      )))
        except (AttributeError, ValueError, DataError) as e:
            raise AuthenticationFailed(e)

    def authenticate_header(self, request):
        response = self.authenticator.build_challenge_response()

        return response["WWW-Authenticate"]
Beispiel #37
0
    def test_authenticate_nonce(self):
        testuser = User.objects.create_user(
            username='******', email='*****@*****.**', password='******')
        User.objects.create_user(
            username='******', email='*****@*****.**', password='******')

        nonce=python_digest.calculate_nonce(time.time(), secret=settings.SECRET_KEY)

        first_request = self.create_mock_request(username=testuser.username,
                                                 password='******', nonce=nonce)
        first_request.user = testuser

        # same nonce, same nonce count, will fail
        second_request = self.create_mock_request(username=testuser.username,
                                                  password='******', nonce=nonce)

        # same nonce, new nonce count, it works
        third_request = self.create_mock_request(username=testuser.username,
                                                 password='******', nonce=nonce,
                                                 nonce_count=2)
        third_request.user = testuser

        authenticator = HttpDigestAuthenticator()
        assert 'HTTP_AUTHORIZATION' in first_request.META
        assert python_digest.is_digest_credential(first_request.META['HTTP_AUTHORIZATION'])

        self.assertTrue(HttpDigestAuthenticator.contains_digest_credentials(
            first_request
        ))
        transaction.set_autocommit(False)
        self.assertTrue(authenticator.authenticate(first_request))
        self.assertFalse(authenticator.authenticate(second_request))
        transaction.rollback()
        self.assertTrue(authenticator.authenticate(third_request))
        transaction.commit()
        transaction.set_autocommit(True)
Beispiel #38
0
def form_upload(request, username):
    """
    XForm upload view.

    Briefcase Aggregate API /formUpload.
    """
    form_user = get_object_or_404(User, username__iexact=username)
    __, ___ = UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    if form_user != request.user:
        return HttpResponseForbidden(
            _(u"Not allowed to upload form[s] to %(user)s account." %
              {'user': form_user}))
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        response['Location'] = request.build_absolute_uri().replace(
            request.get_full_path(), '/%s/formUpload' % form_user.username)
        return response
    xform_def = request.FILES.get('form_def_file', None)
    content = u""
    if isinstance(xform_def, File):
        do_form_upload = PublishXForm(xform_def, form_user)
        xform = publish_form(do_form_upload.publish_xform)
        status = 201
        if isinstance(xform, XForm):
            content = _(u"%s successfully published." % xform.id_string)
        else:
            content = xform['text']
            if isinstance(content, Exception):
                content = content.message
                status = 500
            else:
                status = 400
    return OpenRosaResponse(content, status=status)
Beispiel #39
0
def form_upload(request, username):
    class DoXmlFormUpload():
        def __init__(self, xml_file, user):
            self.xml_file = xml_file
            self.user = user

        def publish(self):
            return publish_xml_form(self.xml_file, self.user)

    form_user = get_object_or_404(User, username=username)
    profile, created = \
        UserProfile.objects.get_or_create(user=form_user)
    authenticator = HttpDigestAuthenticator()
    if not authenticator.authenticate(request):
        return authenticator.build_challenge_response()
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        response['Location'] = request.build_absolute_uri().replace(
            request.get_full_path(), '/%s/formUpload' % form_user.username)
        return response
    xform_def = request.FILES.get('form_def_file', None)
    content = u""
    if isinstance(xform_def, File):
        do_form_upload = DoXmlFormUpload(xform_def, form_user)
        dd = publish_form(do_form_upload.publish)
        status = 201
        if isinstance(dd, XForm):
            content = _(u"%s successfully published." % dd.id_string)
        else:
            content = dd['text']
            if isinstance(content, Exception):
                content = content.message
                status = 500
            else:
                status = 400
    return OpenRosaResponse(content, status=status)
Beispiel #40
0
 def __call__(self, request):
     authenticator = HttpDigestAuthenticator()
     if (not authenticator.authenticate(request) and
         (get_setting("DIGEST_REQUIRE_AUTHENTICATION", False) or
          authenticator.contains_digest_credentials(request))):
         return authenticator.build_challenge_response()
     response = self.get_response(request)
     if response.status_code == 401:
         return authenticator.build_challenge_response()
     return response
Beispiel #41
0
    def test_decorator_with_pre_constructed_authenticator(self):
        response = self.mocker.mock(count=False)
        expect(response.status_code).result(200)

        @httpdigest(HttpDigestAuthenticator(realm='MY_TEST_REALM'))
        def test_view(request):
            return response

        testuser = User.objects.create_user('testuser', '*****@*****.**', 'pass')
        request = self.create_mock_request_for_header(None)
        request.user = testuser

        with self.mocker:
            final_response = test_view(request)
            self.assertEqual(401, final_response.status_code)
            self.assertTrue('WWW-Authenticate' in final_response)
            self.assertTrue('MY_TEST_REALM' in final_response['WWW-Authenticate'])
Beispiel #42
0
    def test_authenticate_nonce(self):
        testuser = User.objects.create_user(username='******',
                                            email='*****@*****.**',
                                            password='******')
        User.objects.create_user(username='******',
                                 email='*****@*****.**',
                                 password='******')

        nonce = python_digest.calculate_nonce(time.time(),
                                              secret=settings.SECRET_KEY)

        first_request = self.create_mock_request(username=testuser.username,
                                                 password='******',
                                                 nonce=nonce)
        first_request.user = testuser

        # same nonce, same nonce count, will fail
        second_request = self.create_mock_request(username=testuser.username,
                                                  password='******',
                                                  nonce=nonce)

        # same nonce, new nonce count, it works
        third_request = self.create_mock_request(username=testuser.username,
                                                 password='******',
                                                 nonce=nonce,
                                                 nonce_count=2)
        third_request.user = testuser

        authenticator = HttpDigestAuthenticator()
        assert 'HTTP_AUTHORIZATION' in first_request.META
        assert python_digest.is_digest_credential(
            first_request.META['HTTP_AUTHORIZATION'])

        self.assertTrue(
            HttpDigestAuthenticator.contains_digest_credentials(first_request))
        transaction.set_autocommit(False)
        self.assertTrue(authenticator.authenticate(first_request))
        self.assertFalse(authenticator.authenticate(second_request))
        transaction.rollback()
        self.assertTrue(authenticator.authenticate(third_request))
        transaction.commit()
        transaction.set_autocommit(True)
Beispiel #43
0
    def test_authenticate_nonce(self):
        testuser = User.objects.create_user(username='******',
                                            email='*****@*****.**',
                                            password='******')
        otheruser = User.objects.create_user(username='******',
                                             email='*****@*****.**',
                                             password='******')

        nonce = python_digest.calculate_nonce(time.time(),
                                              secret=settings.SECRET_KEY)

        first_request = self.create_mock_request(username=testuser.username,
                                                 password='******',
                                                 nonce=nonce)
        first_request.user = testuser

        # same nonce, same nonce count, will fail
        second_request = self.create_mock_request(username=testuser.username,
                                                  password='******',
                                                  nonce=nonce)

        # same nonce, new nonce count, it works
        third_request = self.create_mock_request(username=testuser.username,
                                                 password='******',
                                                 nonce=nonce,
                                                 nonce_count=2)
        third_request.user = testuser

        authenticator = HttpDigestAuthenticator()
        with self.mocker:
            self.assertTrue(
                HttpDigestAuthenticator.contains_digest_credentials(
                    first_request))
            with transaction.commit_on_success():
                self.assertTrue(authenticator.authenticate(first_request))
                self.assertFalse(authenticator.authenticate(second_request))
                transaction.rollback()
                self.assertTrue(authenticator.authenticate(third_request))
 def __init__(self):
     self.authenticator = HttpDigestAuthenticator()
Beispiel #45
0
def submission(request, username=None):
    if username:
        formlist_user = get_object_or_404(User, username__iexact=username)
        profile, created = UserProfile.objects.get_or_create(
            user=formlist_user)

        if profile.require_auth:
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()

    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        if username:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/%s/submission' % username)
        else:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/submission')
        return response

    xml_file_list = []
    media_files = []

    # request.FILES is a django.utils.datastructures.MultiValueDict
    # for each key we have a list of values
    try:
        xml_file_list = request.FILES.pop("xml_submission_file", [])
        if len(xml_file_list) != 1:
            return OpenRosaResponseBadRequest(
                _(u"There should be a single XML submission file."))
        # save this XML file and media files as attachments
        media_files = request.FILES.values()

        # get uuid from post request
        uuid = request.POST.get('uuid')

        error, instance = safe_create_instance(username, xml_file_list[0],
                                               media_files, uuid, request)

        if error:
            return error
        elif instance is None:
            return OpenRosaResponseBadRequest(
                _(u"Unable to create submission."))

        audit = {"xform": instance.xform.id_string}
        audit_log(
            Actions.SUBMISSION_CREATED, request.user, instance.xform.user,
            _("Created submission on form %(id_string)s.") %
            {"id_string": instance.xform.id_string}, audit, request)

        # response as html if posting with a UUID
        if not username and uuid:
            response = _html_submission_response(request, instance)
        else:
            response = _submission_response(request, instance)

        # ODK needs two things for a form to be considered successful
        # 1) the status code needs to be 201 (created)
        # 2) The location header needs to be set to the host it posted to
        response.status_code = 201
        response['Location'] = request.build_absolute_uri(request.path)
        return response
    except IOError as e:
        if _bad_request(e):
            return OpenRosaResponseBadRequest(
                _(u"File transfer interruption."))
        else:
            raise
    finally:
        if len(xml_file_list):
            [_file.close() for _file in xml_file_list]
        if len(media_files):
            [_file.close() for _file in media_files]
Beispiel #46
0
def submission(request, username=None):
    if username and username.lower() != 'crowdforms':
        formlist_user = get_object_or_404(User, username=username.lower())
        profile, created = \
            UserProfile.objects.get_or_create(user=formlist_user)

        if profile.require_auth:
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        if username:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/%s/submission' % username)
        else:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/submission')
        return response
    context = RequestContext(request)
    xml_file_list = []
    media_files = []

    # request.FILES is a django.utils.datastructures.MultiValueDict
    # for each key we have a list of values
    try:
        xml_file_list = request.FILES.pop("xml_submission_file", [])
        if len(xml_file_list) != 1:
            return OpenRosaResponseBadRequest(
                _(u"There should be a single XML submission file."))
        # save this XML file and media files as attachments
        media_files = request.FILES.values()

        # get uuid from post request
        uuid = request.POST.get('uuid')

        try:
            instance = create_instance(username,
                                       xml_file_list[0],
                                       media_files,
                                       uuid=uuid,
                                       request=request)
        except InstanceInvalidUserError:
            return OpenRosaResponseBadRequest(_(u"Username or ID required."))
        except IsNotCrowdformError:
            return OpenRosaResponseNotAllowed(
                _(u"Sorry but the crowd form you submitted to is closed."))
        except InstanceEmptyError:
            return OpenRosaResponseBadRequest(
                _(u"Received empty submission. No instance was created"))
        except FormInactiveError:
            return OpenRosaResponseNotAllowed(_(u"Form is not active"))
        except XForm.DoesNotExist:
            return OpenRosaResponseNotFound(
                _(u"Form does not exist on this account"))
        except ExpatError:
            return OpenRosaResponseBadRequest(_(u"Improperly formatted XML."))
        except DuplicateInstance:
            response = OpenRosaResponse(_(u"Duplicate submission"))
            response.status_code = 202
            response['Location'] = request.build_absolute_uri(request.path)
            return response
        except PermissionDenied, e:
            return OpenRosaResponseNotAllowed(e.message)

        if instance is None:
            return OpenRosaResponseBadRequest(
                _(u"Unable to create submission."))

        audit = {"xform": instance.xform.id_string}
        audit_log(
            Actions.SUBMISSION_CREATED, request.user, instance.xform.user,
            _("Created submission on form %(id_string)s.") %
            {"id_string": instance.xform.id_string}, audit, request)

        # response as html if posting with a UUID
        if not username and uuid:
            response = _html_submission_response(context, instance)
        else:
            response = _submission_response(context, instance)

        # ODK needs two things for a form to be considered successful
        # 1) the status code needs to be 201 (created)
        # 2) The location header needs to be set to the host it posted to
        response.status_code = 201
        response['Location'] = request.build_absolute_uri(request.path)
        return response
Beispiel #47
0
def submission(request, username=None):
    if username and username.lower() != 'crowdforms':
        formlist_user = get_object_or_404(User, username=username.lower())
        profile, created = \
            UserProfile.objects.get_or_create(user=formlist_user)

        if profile.require_auth:
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        if username:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/%s/submission' % username)
        else:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/submission')
        return response
    context = RequestContext(request)
    xml_file_list = []
    media_files = []
    html_response = False
    # request.FILES is a django.utils.datastructures.MultiValueDict
    # for each key we have a list of values
    try:
        xml_file_list = request.FILES.pop("xml_submission_file", [])
        if len(xml_file_list) != 1:
            return OpenRosaResponseBadRequest(
                _(u"There should be a single XML submission file."))
        # save this XML file and media files as attachments
        media_files = request.FILES.values()

        # get uuid from post request
        uuid = request.POST.get('uuid')
        # response as html if posting with a UUID
        if not username and uuid:
            html_response = True
        try:
            instance = create_instance(username,
                                       xml_file_list[0],
                                       media_files,
                                       uuid=uuid,
                                       request=request)
        except InstanceInvalidUserError:
            return OpenRosaResponseBadRequest(_(u"Username or ID required."))
        except IsNotCrowdformError:
            return OpenRosaResponseNotAllowed(
                _(u"Sorry but the crowd form you submitted to is closed."))
        except InstanceEmptyError:
            return OpenRosaResponseBadRequest(
                _(u"Received empty submission. No instance was created"))
        except FormInactiveError:
            return OpenRosaResponseNotAllowed(_(u"Form is not active"))
        except XForm.DoesNotExist:
            return OpenRosaResponseNotFound(
                _(u"Form does not exist on this account"))
        except ExpatError:
            return OpenRosaResponseBadRequest(_(u"Improperly formatted XML."))
        except DuplicateInstance:
            response = OpenRosaResponse(_(u"Duplicate submission"))
            response.status_code = 202
            response['Location'] = request.build_absolute_uri(request.path)
            return response
        except PermissionDenied, e:
            return OpenRosaResponseNotAllowed(e.message)
        except Exception, e:
            raise
Beispiel #48
0
def odk_submission(req):
    # if forms are restricted, force digest authentication
    if getattr(settings, 'AUTHENTICATE_XFORMS', False):
        authenticator = HttpDigestAuthenticator()
        if not authenticator.authenticate(req):
            return authenticator.build_challenge_response()

    if req.method == 'HEAD':
        # technically this should be a 201 according to the HTTP spec, but
        # ODK collect requires 204 to move forward
        return HttpResponse("OK", status=204)
    elif req.method != 'POST':
        # only POST and HEAD are supported
        return HttpResponse("Invalid method", status=405)

    values = {}
    xform = None
    raw = ""

    # this is the raw data
    if 'xml_submission_file' in req.FILES:
        file = req.FILES['xml_submission_file']
        raw = file.file.read()
        dom = parseString(raw)
        root = dom.childNodes[0]
        for child in root.childNodes:
            tag = child.tagName
            if child.childNodes:
                body = child.childNodes[0].wholeText

                if tag == 'xform-keyword':
                    xform = get_object_or_404(XForm, keyword=body)
                else:
                    values[tag] = body

    # every other file is a binary, save them in our map as well (the keys are the values
    # in the submission file above)
    binaries = dict()
    for key in req.FILES:
        if key != 'xml_submission_file':
            binaries[key] = req.FILES[key].file.read()

    # check that they have the correct permissions
    if not xform.does_user_have_permission(req.user):
        return HttpResponse("You do not have permission to view this form",
                            status=403)

    # if we found the xform
    submission = xform.process_odk_submission(raw, values, binaries)

    resp = render_to_response("xforms/odk_submission.xml", {
        "xform": xform,
        "submission": submission
    },
                              context_instance=RequestContext(req))

    # ODK needs two things for a form to be considered successful
    # 1) the status code needs to be 201 (created)
    resp.status_code = 201

    # 2) The location header needs to be set to the host it posted to
    resp['Location'] = "http://%s/submission" % settings.XFORMS_HOST
    return resp
Beispiel #49
0
 def __init__(self, require_authentication=None, authenticator=None):
     if require_authentication == None:
         require_authentication = get_setting(
             'DIGEST_REQUIRE_AUTHENTICATION', False)
     self._authenticator = authenticator or HttpDigestAuthenticator()
     self._require_authentication = require_authentication
Beispiel #50
0
    def test_authenticate_invalid(self):
        testuser = User.objects.create_user(username='******',
                                            email='*****@*****.**',
                                            password='******')
        otheruser = User.objects.create_user(username='******',
                                             email='*****@*****.**',
                                             password='******')

        nonce = python_digest.calculate_nonce(time.time(),
                                              secret=settings.SECRET_KEY)
        # an invalid request
        fourth_request = self.create_mock_request_for_header(
            'Digest blah blah blah')

        # an invalid request
        fifth_request = self.create_mock_request_for_header(None)

        # an invalid nonce
        sixth_request = self.create_mock_request(
            username=testuser.username,
            password='******',
            nonce_count=1,
            nonce=python_digest.calculate_nonce(time.time(),
                                                secret='bad secret'))

        # an invalid request digest (wrong password)
        seventh_request = self.create_mock_request(username=testuser.username,
                                                   password='******',
                                                   nonce=nonce,
                                                   nonce_count=3)

        # attack attempts / failures don't invalidate the session or increment nonce_cont
        eighth_request = self.create_mock_request(username=testuser.username,
                                                  password='******',
                                                  nonce=nonce,
                                                  nonce_count=3)
        eighth_request.user = testuser

        # mismatched URI
        ninth_request = self.create_mock_request(
            username=testuser.username,
            nonce=nonce,
            password='******',
            nonce_count=4,
            request_path='/different/path')

        # stale nonce
        tenth_request = self.create_mock_request(
            username=testuser.username,
            password='******',
            nonce_count=4,
            nonce=python_digest.calculate_nonce(time.time() - 60000,
                                                secret=settings.SECRET_KEY))

        # once the nonce is used by one user, can't be reused by another
        eleventh_request = self.create_mock_request(
            username=otheruser.username,
            password='******',
            nonce=nonce,
            nonce_count=4)

        authenticator = HttpDigestAuthenticator()
        with self.mocker:
            self.assertFalse(authenticator.authenticate(fourth_request))
            self.assertFalse(authenticator.authenticate(fifth_request))
            self.assertFalse(authenticator.authenticate(sixth_request))
            self.assertFalse(authenticator.authenticate(seventh_request))
            self.assertTrue(authenticator.authenticate(eighth_request))
            self.assertFalse(authenticator.authenticate(ninth_request))
            self.assertFalse(authenticator.authenticate(tenth_request))
            self.assertFalse(authenticator.authenticate(eleventh_request))