test_newnm.py 9.58 KB
Newer Older
1
from django.test import TestCase, override_settings
2
from django.urls import reverse
3
from django.core import mail
4
from backend.models import Person
Enrico Zini's avatar
Enrico Zini committed
5
6
from backend import const
from backend.unittest import PersonFixtureMixin
7
from signon import providers
Enrico Zini's avatar
Enrico Zini committed
8

9

10
11
12
13
@override_settings(SIGNON_PROVIDERS=[
    providers.DebssoProvider(name="debsso", label="sso.debian.org"),
    providers.BaseSessionProvider(name="salsa", label="Salsa", single_bind=True),
])
Enrico Zini's avatar
Enrico Zini committed
14
class TestNewnm(PersonFixtureMixin, TestCase):
15
16
17
    # Use an old, not yet revoked key of mine
    new_person_fingerprint = "66B4DFB68CB24EBBD8650BC4F4B4B0CC797EBFAB"

Enrico Zini's avatar
Enrico Zini committed
18
19
    @classmethod
    def __add_extra_tests__(cls):
20
        for person in ("pending", "dc", "dc_ga", "dm", "dm_ga"):
21
22
            cls._add_method(cls._test_non_dd, person, "debsso")
            cls._add_method(cls._test_non_dd, person, "salsa")
Enrico Zini's avatar
Enrico Zini committed
23
24

        for person in ("dd_nu", "dd_u", "fd", "dam"):
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
            cls._add_method(cls._test_dd, person, "debsso")
            cls._add_method(cls._test_dd, person, "salsa")

        cls._add_method(cls._test_no_person, "debsso")
        cls._add_method(cls._test_no_person, "salsa")

    def get_identity_for_issuer(self, person, issuer):
        if issuer == "debsso":
            person = self.persons[person]
            if person is None:
                uid = "new_person"
            else:
                uid = person.ldap_fields.uid
            return self.identities.create(
                    "debsso", issuer="debsso",
                    subject=f"{uid}@users.alioth.debian.org",
                    username=f"{uid}@users.alioth.debian.org", audit_skip=True)
        elif issuer == "salsa":
            person = self.persons[person]
            if person is None:
                subject = "1234567"
            else:
                subject = str(person.pk)

            return self.identities.create(
                    "salsa", issuer="salsa",
                    subject=subject, audit_skip=True)
Enrico Zini's avatar
Enrico Zini committed
52
        else:
53
            raise NotImplementedError("Issuer {issuer} not supported in test")
Enrico Zini's avatar
Enrico Zini committed
54

55
56
57
58
59
    def assertPostForbidden(self, person):
        person = self.persons[person]
        client = self.make_test_client(person)

        # Posting to newnm to create a new record is forbidden
Enrico Zini's avatar
Enrico Zini committed
60
        response = client.post(reverse("public_newnm"), data={
Enrico Zini's avatar
Enrico Zini committed
61
62
63
            "person-fpr": self.new_person_fingerprint,
            "person-sc_ok": "yes",
            "person-dmup_ok": "yes",
64
            "person-fullname": "test",
Enrico Zini's avatar
Enrico Zini committed
65
66
            "ldap_fields-cn": "test",
            "person-email": "new_person@example.org"})
67
68
69
70
        self.assertPermissionDenied(response)

        # Trying to resend newnm challenge is forbidden
        if person:
71
72
            response = client.get(reverse(
                "public_newnm_resend_challenge", kwargs={"key": person.lookup_key}))
73
        else:
74
75
            response = client.get(reverse(
                "public_newnm_resend_challenge", kwargs={"key": self.persons["pending"].lookup_key}))
76
77
78
79
80
81
82
83
84
        self.assertPermissionDenied(response)

        # Trying to confirm the account is forbidden
        if person:
            response = client.get(reverse("public_newnm_confirm", kwargs={"nonce": person.pending}))
        else:
            response = client.get(reverse("public_newnm_confirm", kwargs={"nonce": self.persons["pending"].pending}))
        self.assertPermissionDenied(response)

Enrico Zini's avatar
Enrico Zini committed
85
86
87
    def test_require_login(self):
        client = self.make_test_client(None)
        response = client.get(reverse("public_newnm"))
Enrico Zini's avatar
Enrico Zini committed
88
        self.assertEqual(response.status_code, 200)
89
        self.assertFalse(response.context["person"].is_authenticated)
Enrico Zini's avatar
Enrico Zini committed
90
91
        self.assertEqual(response.context["errors"], [])
        self.assertEqual(response.context["DAYS_VALID"], 3)
Enrico Zini's avatar
Enrico Zini committed
92
93
        self.assertContains(response, "Please login first")
        self.assertNotContains(response, "You already have an entry in the system")
94
        self.assertNotContains(response, "Not only do you already have an entry, but you are also")
Enrico Zini's avatar
Enrico Zini committed
95
        self.assertNotContains(response, "Apply for an entry in the system")
96
        self.assertNotContains(response, "Submit disabled because you already have an entry in the system")
97
        self.assertPostForbidden(None)
Enrico Zini's avatar
Enrico Zini committed
98

99
    def _test_no_person(self, issuer):
100
        self.maxDiff = None
101
102
        identity = self.get_identity_for_issuer(None, issuer)
        client = self.make_test_client(None, [identity])
Enrico Zini's avatar
Enrico Zini committed
103
        response = client.get(reverse("public_newnm"))
Enrico Zini's avatar
Enrico Zini committed
104
        self.assertEqual(response.status_code, 200)
Enrico Zini's avatar
Enrico Zini committed
105
        self.assertFalse(response.context["require_login"])
106
        self.assertFalse(response.context["person"].is_authenticated)
Enrico Zini's avatar
Enrico Zini committed
107
108
        self.assertEqual(response.context["errors"], [])
        self.assertEqual(response.context["DAYS_VALID"], 3)
Enrico Zini's avatar
Enrico Zini committed
109
110
        self.assertNotContains(response, "Please login first")
        self.assertNotContains(response, "You already have an entry in the system")
111
        self.assertNotContains(response, "Not only do you already have an entry, but you are also")
Enrico Zini's avatar
Enrico Zini committed
112
        self.assertContains(response, "Apply for an entry in the system")
113
        self.assertNotContains(response, "Submit disabled because you already have an entry in the system")
Enrico Zini's avatar
Enrico Zini committed
114

115
        # A new Person is created on POST
Enrico Zini's avatar
Enrico Zini committed
116
117
118
119
        response = client.post(reverse("public_newnm"), data={
            "person-fpr": self.new_person_fingerprint,
            "person-sc_ok": "yes",
            "person-dmup_ok": "yes",
120
            "person-fullname": "test",
Enrico Zini's avatar
Enrico Zini committed
121
122
123
124
            "ldap_fields-cn": "test",
            "person-email": "new_person@example.org"})
        self.assertRedirectMatches(
                response, reverse("public_newnm_resend_challenge", kwargs={"key": "new_person@example.org"}))
125
        new_person = Person.lookup("new_person@example.org")
Enrico Zini's avatar
Enrico Zini committed
126
        self.assertEqual(new_person.status, const.STATUS_DC)
127
128
129
130
        self.assertIsNotNone(new_person.expires)
        self.assertIsNotNone(new_person.pending)

        # The new person can resend the challenge email
131
        mail.outbox = []
132
133
        response = client.get(reverse("public_newnm_resend_challenge", kwargs={"key": "new_person@example.org"}))
        self.assertRedirectMatches(response, new_person.get_absolute_url())
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
        self.assertEqual(len(mail.outbox), 1)
        m = mail.outbox[0]
        self.assertEqual(m.from_email, "nm@debian.org")
        self.assertEqual(m.to, [f"test <new_person@example.org>"])
        self.assertEqual(m.cc, [])
        self.assertEqual(m.bcc, [])
        self.assertEqual(m.extra_headers, {'Reply-To': 'nm@debian.org'})
        head = """Hello test,

to confirm your new entry at https://nm.debian.org/person/new_person@example.org/
you need to decrypt the following text. The result will be a URL, which you
then visit to make your entry confirmed.

-----BEGIN PGP MESSAGE-----
""".splitlines()
        tail = """-----END PGP MESSAGE-----


You should not need instructions to decrypt this. If you do not know how to do
it, you can consider it a challenge. In that case, you can start from here:
154
https://www.gnupg.org/howtos/en/GPGMiniHowto.html
155
156
157
158
159
160
161
162
163
164

For any problem, feel free to contact Front Desk at nm@debian.org.


Regards,

the nm.debian.org robotic minion for Front Desk""".splitlines()
        lines = m.body.splitlines()
        self.assertEqual(lines[:len(head)], head)
        self.assertEqual(lines[-len(tail):], tail)
165
166
167

        # The new person has a page in the system
        response = client.get(new_person.get_absolute_url())
Enrico Zini's avatar
Enrico Zini committed
168
        self.assertEqual(response.status_code, 200)
169
170
171
172
173

        # The new person can confirm its record
        response = client.get(reverse("public_newnm_confirm", kwargs={"nonce": new_person.pending}))
        self.assertRedirectMatches(response, new_person.get_absolute_url())
        new_person = Person.objects.get(pk=new_person.pk)
Enrico Zini's avatar
Enrico Zini committed
174
        self.assertEqual(new_person.status, const.STATUS_DC)
175
        self.assertIsNotNone(new_person.expires)
Enrico Zini's avatar
Enrico Zini committed
176
        self.assertEqual(new_person.pending, "")
177

178
179
180
    def _test_non_dd(self, person, issuer):
        identity = self.get_identity_for_issuer(person, issuer)
        client = self.make_test_client(person, [identity])
Enrico Zini's avatar
Enrico Zini committed
181
        response = client.get(reverse("public_newnm"))
Enrico Zini's avatar
Enrico Zini committed
182
183
184
185
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context["person"], self.persons[person])
        self.assertEqual(response.context["errors"], [])
        self.assertEqual(response.context["DAYS_VALID"], 3)
Enrico Zini's avatar
Enrico Zini committed
186
187
        self.assertNotContains(response, "Please login first")
        self.assertContains(response, "You already have an entry in the system")
188
        self.assertNotContains(response, "Not only do you already have an entry, but you are also")
Enrico Zini's avatar
Enrico Zini committed
189
        self.assertNotContains(response, "Apply for an entry in the system")
190
        self.assertNotContains(response, "Submit disabled because you already have an entry in the system")
191
        self.assertPostForbidden(None)
Enrico Zini's avatar
Enrico Zini committed
192

193
194
195
    def _test_dd(self, person, issuer):
        identity = self.get_identity_for_issuer(person, issuer)
        client = self.make_test_client(person, [identity])
Enrico Zini's avatar
Enrico Zini committed
196
        response = client.get(reverse("public_newnm"))
Enrico Zini's avatar
Enrico Zini committed
197
198
199
200
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context["person"], self.persons[person])
        self.assertEqual(response.context["errors"], [])
        self.assertEqual(response.context["DAYS_VALID"], 3)
Enrico Zini's avatar
Enrico Zini committed
201
202
        self.assertNotContains(response, "Please login first")
        self.assertContains(response, "You already have an entry in the system")
203
        self.assertContains(response, "Not only do you already have an entry, but you are also")
Enrico Zini's avatar
Enrico Zini committed
204
        self.assertContains(response, "Apply for an entry in the system")
205
        self.assertContains(response, "Submit disabled because you already have an entry in the system")
206
        self.assertPostForbidden(None)