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")
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")
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
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
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
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)
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 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))
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
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']
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
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
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
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
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")
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
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))
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))
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")
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
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")
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))
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
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']
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
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")
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")
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")
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)
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
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
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))
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']
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))
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)
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"]
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)
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)
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)
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
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'])
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)
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()
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]
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
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
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
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
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))