Commit e3453028 authored by Enrico Zini's avatar Enrico Zini
Browse files

Tested /dm/claim

parent edb6ee61
from django.test import TestCase
# Create your tests here.
# coding: utf8
"""
Test DM claim interface
"""
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from django.test import TestCase
from django.core.urlresolvers import reverse
from backend.models import Person, Fingerprint
from backend import const
from backend.unittest import PersonFixtureMixin
from keyring.models import Key
class TestClaim(PersonFixtureMixin, TestCase):
# Use an old, not yet revoked key of mine
test_fingerprint = "66B4DFB68CB24EBBD8650BC4F4B4B0CC797EBFAB"
@classmethod
def setUpClass(cls):
super(TestClaim, cls).setUpClass()
# Preload the key for test_fingerprint so we do not download it every
# test
with open("test_data/F4B4B0CC797EBFAB.txt", "rt") as fd:
Key.objects.get_or_download(cls.test_fingerprint, body=fd.read())
@classmethod
def tearDownClass(cls):
super(TestClaim, cls).tearDownClass()
Key.objects.filter(fpr=cls.test_fingerprint).delete()
@classmethod
def __add_extra_tests__(cls):
for person in ("pending", "dc", "dc_ga", "dm", "dm_ga"):
cls._add_method(cls._test_success, person)
for person in ("dd_nu", "dd_u", "fd", "dam"):
cls._add_method(cls._test_is_dd, person)
def make_test_client(self, person):
"""
Override the default make_test_client to allow sso-logged-in people
with no corresponding Person record in the database
"""
if person and "@" in person:
return super(TestClaim, self).make_test_client(None, sso_username=person)
else:
return super(TestClaim, self).make_test_client(person)
def get_confirm_url(self, person):
"""
Set up a test case where person has an invalid username and
self.test_fingerprint as fingerprint, and request a claim url.
Returns the original username of the person, and the plaintext claim
url.
"""
person = self.persons[person]
orig_username = person.username
person.username = "invalid@example.org"
person.save(audit_skip=True)
fpr = Fingerprint.objects.create(fpr=self.test_fingerprint, user=person, is_active=True, audit_skip=True)
client = self.make_test_client(orig_username)
response = client.get(reverse("dm_claim"))
self.assertEquals(response.status_code, 200)
self.assertEquals(response.context["username"], orig_username)
response = client.post(reverse("dm_claim"), data={"fpr": self.test_fingerprint})
self.assertEquals(response.status_code, 200)
self.assertEquals(response.context["username"], orig_username)
self.assertEquals(response.context["fpr"].fpr, self.test_fingerprint)
self.assertIn("/dm/claim/confirm", response.context["plaintext"])
self.assertIn("-----BEGIN PGP MESSAGE-----", response.context["challenge"])
return orig_username, response.context["plaintext"].strip()
def _test_success(self, person):
orig_username, confirm_url = self.get_confirm_url(person)
client = self.make_test_client(orig_username)
response = client.get(confirm_url)
self.assertEquals(response.status_code, 200)
self.assertEquals(response.context["errors"], [])
person = Person.objects.get(pk=self.persons[person].pk)
# The username has now been set
self.assertEquals(person.username, orig_username)
def _test_is_dd(self, person):
orig_username, confirm_url = self.get_confirm_url(person)
client = self.make_test_client(orig_username)
response = client.get(confirm_url)
self.assertEquals(response.status_code, 200)
self.assertEquals(response.context["errors"], ["The GPG fingerprint corresponds to a Debian Developer."])
person = Person.objects.get(pk=self.persons[person].pk)
# The username has not been set
self.assertEquals(person.username, "invalid@example.org")
def test_anonymous(self):
client = self.make_test_client(None)
response = client.get(reverse("dm_claim"))
self.assertPermissionDenied(response)
response = client.get(reverse("dm_claim_confirm", kwargs={"token": "123456"}))
self.assertPermissionDenied(response)
...@@ -9,6 +9,7 @@ from django.views.generic.edit import FormView ...@@ -9,6 +9,7 @@ from django.views.generic.edit import FormView
from django.core import signing from django.core import signing
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import forms from django import forms
from django.core.exceptions import PermissionDenied
from backend.mixins import VisitorMixin from backend.mixins import VisitorMixin
import backend.models as bmodels import backend.models as bmodels
...@@ -70,6 +71,10 @@ class Claim(VisitorMixin, FormView): ...@@ -70,6 +71,10 @@ class Claim(VisitorMixin, FormView):
}) })
})) }))
plaintext += "\n" plaintext += "\n"
# Add to context: it will not be rendered, but it can be picked up
# by unit tests without the need to have access to the private key
# to decode it
ctx["plaintext"] = plaintext
ctx["challenge"] = key.encrypt(plaintext.encode("utf8")) ctx["challenge"] = key.encrypt(plaintext.encode("utf8"))
return ctx return ctx
...@@ -84,6 +89,12 @@ class ClaimConfirm(VisitorMixin, TemplateView): ...@@ -84,6 +89,12 @@ class ClaimConfirm(VisitorMixin, TemplateView):
""" """
template_name = "dm/claim_confirm.html" template_name = "dm/claim_confirm.html"
def pre_dispatch(self):
super(ClaimConfirm, self).pre_dispatch()
if self.request.sso_username is None: raise PermissionDenied
if not is_valid_username(self.request.sso_username): raise PermissionDenied
self.username = self.request.sso_username
def validate_token(self, token): def validate_token(self, token):
parsed = signing.loads(token) parsed = signing.loads(token)
self.errors = [] self.errors = []
...@@ -106,10 +117,12 @@ class ClaimConfirm(VisitorMixin, TemplateView): ...@@ -106,10 +117,12 @@ class ClaimConfirm(VisitorMixin, TemplateView):
if is_valid_username(self.fpr.user.username): if is_valid_username(self.fpr.user.username):
self.errors.append("The GPG fingerprint corresponds to a person that has a valid Single Sign-On username.") self.errors.append("The GPG fingerprint corresponds to a person that has a valid Single Sign-On username.")
if self.fpr.user.is_dd:
self.errors.append("The GPG fingerprint corresponds to a Debian Developer.")
# Validate username # Validate username
self.username = parsed["u"] if self.username != parsed["u"]:
if not is_valid_username(self.username): self.errors.append("The token was not generated by you")
self.errors.append("The username does not look like a valid SSO username")
try: try:
existing_person = bmodels.Person.objects.get(username=self.username) existing_person = bmodels.Person.objects.get(username=self.username)
...@@ -125,10 +138,10 @@ class ClaimConfirm(VisitorMixin, TemplateView): ...@@ -125,10 +138,10 @@ class ClaimConfirm(VisitorMixin, TemplateView):
if self.validate_token(self.kwargs["token"]): if self.validate_token(self.kwargs["token"]):
# Do the mapping # Do the mapping
self.fpr.person.username = self.username self.fpr.user.username = self.username
self.fpr.person.save() self.fpr.user.save(audit_author=self.fpr.user, audit_notes="claimed account via /dm/claim")
ctx["mapped"] = True ctx["mapped"] = True
ctx["person"] = self.fpr.person ctx["person"] = self.fpr.user
ctx["fpr"] = self.fpr ctx["fpr"] = self.fpr
ctx["username"] = self.username ctx["username"] = self.username
ctx["errors"] = self.errors ctx["errors"] = self.errors
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment