Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests.py @ 7deaaa5f

History | View | Annotate | Download (29.6 kB)

1 d2633501 Kostas Papadimitriou
# Copyright 2011 GRNET S.A. All rights reserved.
2 d2633501 Kostas Papadimitriou
#
3 d2633501 Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 d2633501 Kostas Papadimitriou
# without modification, are permitted provided that the following
5 d2633501 Kostas Papadimitriou
# conditions are met:
6 d2633501 Kostas Papadimitriou
#
7 d2633501 Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 d2633501 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 d2633501 Kostas Papadimitriou
#      disclaimer.
10 d2633501 Kostas Papadimitriou
#
11 d2633501 Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 d2633501 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 d2633501 Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 d2633501 Kostas Papadimitriou
#      provided with the distribution.
15 d2633501 Kostas Papadimitriou
#
16 d2633501 Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d2633501 Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d2633501 Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d2633501 Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d2633501 Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d2633501 Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d2633501 Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d2633501 Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d2633501 Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d2633501 Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d2633501 Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d2633501 Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 d2633501 Kostas Papadimitriou
#
29 d2633501 Kostas Papadimitriou
# The views and conclusions contained in the software and
30 d2633501 Kostas Papadimitriou
# documentation are those of the authors and should not be
31 d2633501 Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 d2633501 Kostas Papadimitriou
# or implied, of GRNET S.A.
33 d2633501 Kostas Papadimitriou
34 d2633501 Kostas Papadimitriou
import datetime
35 d2633501 Kostas Papadimitriou
36 d2633501 Kostas Papadimitriou
from django.test import TestCase, Client
37 d2633501 Kostas Papadimitriou
from django.conf import settings
38 d2633501 Kostas Papadimitriou
from django.core import mail
39 d2633501 Kostas Papadimitriou
40 d2633501 Kostas Papadimitriou
from astakos.im.target.shibboleth import Tokens as ShibbolethTokens
41 d2633501 Kostas Papadimitriou
from astakos.im.models import *
42 d2633501 Kostas Papadimitriou
from astakos.im import functions
43 d2633501 Kostas Papadimitriou
from astakos.im import settings as astakos_settings
44 e5966bd9 Kostas Papadimitriou
from astakos.im import forms
45 d2633501 Kostas Papadimitriou
46 d2633501 Kostas Papadimitriou
from urllib import quote
47 d2633501 Kostas Papadimitriou
48 2e90e3ec Kostas Papadimitriou
from astakos.im import messages
49 2e90e3ec Kostas Papadimitriou
50 34a76cdb Kostas Papadimitriou
51 34a76cdb Kostas Papadimitriou
astakos_settings.EMAILCHANGE_ENABLED = True
52 34a76cdb Kostas Papadimitriou
53 d2633501 Kostas Papadimitriou
class ShibbolethClient(Client):
54 d2633501 Kostas Papadimitriou
    """
55 d2633501 Kostas Papadimitriou
    A shibboleth agnostic client.
56 d2633501 Kostas Papadimitriou
    """
57 d2633501 Kostas Papadimitriou
    VALID_TOKENS = filter(lambda x: not x.startswith("_"), dir(ShibbolethTokens))
58 d2633501 Kostas Papadimitriou
59 d2633501 Kostas Papadimitriou
    def __init__(self, *args, **kwargs):
60 d2633501 Kostas Papadimitriou
        self.tokens = kwargs.pop('tokens', {})
61 d2633501 Kostas Papadimitriou
        super(ShibbolethClient, self).__init__(*args, **kwargs)
62 d2633501 Kostas Papadimitriou
63 d2633501 Kostas Papadimitriou
    def set_tokens(self, **kwargs):
64 d2633501 Kostas Papadimitriou
        for key, value in kwargs.iteritems():
65 d2633501 Kostas Papadimitriou
            key = 'SHIB_%s' % key.upper()
66 d2633501 Kostas Papadimitriou
            if not key in self.VALID_TOKENS:
67 d2633501 Kostas Papadimitriou
                raise Exception('Invalid shibboleth token')
68 d2633501 Kostas Papadimitriou
69 d2633501 Kostas Papadimitriou
            self.tokens[key] = value
70 d2633501 Kostas Papadimitriou
71 d2633501 Kostas Papadimitriou
    def unset_tokens(self, *keys):
72 d2633501 Kostas Papadimitriou
        for key in keys:
73 d2633501 Kostas Papadimitriou
            key = 'SHIB_%s' % param.upper()
74 d2633501 Kostas Papadimitriou
            if key in self.tokens:
75 d2633501 Kostas Papadimitriou
                del self.tokens[key]
76 d2633501 Kostas Papadimitriou
77 d2633501 Kostas Papadimitriou
    def reset_tokens(self):
78 d2633501 Kostas Papadimitriou
        self.tokens = {}
79 d2633501 Kostas Papadimitriou
80 d2633501 Kostas Papadimitriou
    def get_http_token(self, key):
81 d2633501 Kostas Papadimitriou
        http_header = getattr(ShibbolethTokens, key)
82 d2633501 Kostas Papadimitriou
        return http_header
83 d2633501 Kostas Papadimitriou
84 d2633501 Kostas Papadimitriou
    def request(self, **request):
85 d2633501 Kostas Papadimitriou
        """
86 d2633501 Kostas Papadimitriou
        Transform valid shibboleth tokens to http headers
87 d2633501 Kostas Papadimitriou
        """
88 d2633501 Kostas Papadimitriou
        for token, value in self.tokens.iteritems():
89 d2633501 Kostas Papadimitriou
            request[self.get_http_token(token)] = value
90 d2633501 Kostas Papadimitriou
91 d2633501 Kostas Papadimitriou
        for param in request.keys():
92 d2633501 Kostas Papadimitriou
            key = 'SHIB_%s' % param.upper()
93 d2633501 Kostas Papadimitriou
            if key in self.VALID_TOKENS:
94 d2633501 Kostas Papadimitriou
                request[self.get_http_token(key)] = request[param]
95 d2633501 Kostas Papadimitriou
                del request[param]
96 d2633501 Kostas Papadimitriou
97 d2633501 Kostas Papadimitriou
        return super(ShibbolethClient, self).request(**request)
98 d2633501 Kostas Papadimitriou
99 d2633501 Kostas Papadimitriou
100 d2633501 Kostas Papadimitriou
def get_local_user(username, **kwargs):
101 d2633501 Kostas Papadimitriou
        try:
102 d2633501 Kostas Papadimitriou
            return AstakosUser.objects.get(email=username)
103 d2633501 Kostas Papadimitriou
        except:
104 d2633501 Kostas Papadimitriou
            user_params = {
105 d2633501 Kostas Papadimitriou
                'username': username,
106 d2633501 Kostas Papadimitriou
                'email': username,
107 d2633501 Kostas Papadimitriou
                'is_active': True,
108 d2633501 Kostas Papadimitriou
                'activation_sent': datetime.now(),
109 d2633501 Kostas Papadimitriou
                'email_verified': True,
110 d2633501 Kostas Papadimitriou
                'provider': 'local'
111 d2633501 Kostas Papadimitriou
            }
112 d2633501 Kostas Papadimitriou
            user_params.update(kwargs)
113 d2633501 Kostas Papadimitriou
            user = AstakosUser(**user_params)
114 d2633501 Kostas Papadimitriou
            user.set_password(kwargs.get('password', 'password'))
115 d2633501 Kostas Papadimitriou
            user.save()
116 d2633501 Kostas Papadimitriou
            user.add_auth_provider('local', auth_backend='astakos')
117 d2633501 Kostas Papadimitriou
            if kwargs.get('is_active', True):
118 d2633501 Kostas Papadimitriou
                user.is_active = True
119 d2633501 Kostas Papadimitriou
            else:
120 d2633501 Kostas Papadimitriou
                user.is_active = False
121 d2633501 Kostas Papadimitriou
            user.save()
122 d2633501 Kostas Papadimitriou
            return user
123 d2633501 Kostas Papadimitriou
124 d2633501 Kostas Papadimitriou
125 d2633501 Kostas Papadimitriou
def get_mailbox(email):
126 d2633501 Kostas Papadimitriou
    mails = []
127 d2633501 Kostas Papadimitriou
    for sent_email in mail.outbox:
128 d2633501 Kostas Papadimitriou
        for recipient in sent_email.recipients():
129 d2633501 Kostas Papadimitriou
            if email in recipient:
130 d2633501 Kostas Papadimitriou
                mails.append(sent_email)
131 d2633501 Kostas Papadimitriou
    return mails
132 d2633501 Kostas Papadimitriou
133 d2633501 Kostas Papadimitriou
134 d2633501 Kostas Papadimitriou
class ShibbolethTests(TestCase):
135 d2633501 Kostas Papadimitriou
    """
136 d2633501 Kostas Papadimitriou
    Testing shibboleth authentication.
137 d2633501 Kostas Papadimitriou
    """
138 d2633501 Kostas Papadimitriou
139 d2633501 Kostas Papadimitriou
    fixtures = ['groups']
140 d2633501 Kostas Papadimitriou
141 d2633501 Kostas Papadimitriou
    def setUp(self):
142 d2633501 Kostas Papadimitriou
        self.client = ShibbolethClient()
143 d2633501 Kostas Papadimitriou
        settings.ASTAKOS_IM_MODULES = ['local', 'shibboleth']
144 ba50648c Kostas Papadimitriou
        settings.ASTAKOS_MODERATION_ENABLED = True
145 d2633501 Kostas Papadimitriou
146 d2633501 Kostas Papadimitriou
    def test_create_account(self):
147 ba50648c Kostas Papadimitriou
148 d2633501 Kostas Papadimitriou
        client = ShibbolethClient()
149 d2633501 Kostas Papadimitriou
150 d2633501 Kostas Papadimitriou
        # shibboleth views validation
151 d2633501 Kostas Papadimitriou
        # eepn required
152 d2633501 Kostas Papadimitriou
        r = client.get('/im/login/shibboleth?', follow=True)
153 e24d0e0d Kostas Papadimitriou
        self.assertContains(r, messages.SHIBBOLETH_MISSING_EPPN % {
154 e24d0e0d Kostas Papadimitriou
            'domain': astakos_settings.BASEURL,
155 e24d0e0d Kostas Papadimitriou
            'contact_email': astakos_settings.DEFAULT_CONTACT_EMAIL
156 e24d0e0d Kostas Papadimitriou
        })
157 d2633501 Kostas Papadimitriou
        client.set_tokens(eppn="kpapeppn")
158 ba50648c Kostas Papadimitriou
159 31fdafa8 Kostas Papadimitriou
        astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = True
160 d2633501 Kostas Papadimitriou
        # shibboleth user info required
161 d2633501 Kostas Papadimitriou
        r = client.get('/im/login/shibboleth?', follow=True)
162 2e90e3ec Kostas Papadimitriou
        self.assertContains(r, messages.SHIBBOLETH_MISSING_NAME)
163 31fdafa8 Kostas Papadimitriou
        astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = False
164 d2633501 Kostas Papadimitriou
165 d2633501 Kostas Papadimitriou
        # shibboleth logged us in
166 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn",
167 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou",
168 ba50648c Kostas Papadimitriou
                          ep_affiliation="Test Affiliation")
169 f47ecf6b Kostas Papadimitriou
        r = client.get('/im/login/shibboleth?', follow=True)
170 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
171 d2633501 Kostas Papadimitriou
172 d2633501 Kostas Papadimitriou
        # astakos asks if we want to add shibboleth
173 d2633501 Kostas Papadimitriou
        self.assertContains(r, "Already have an account?")
174 d2633501 Kostas Papadimitriou
175 d2633501 Kostas Papadimitriou
        # a new pending user created
176 d2633501 Kostas Papadimitriou
        pending_user = PendingThirdPartyUser.objects.get(
177 d2633501 Kostas Papadimitriou
            third_party_identifier="kpapeppn")
178 d2633501 Kostas Papadimitriou
        self.assertEqual(PendingThirdPartyUser.objects.count(), 1)
179 ba50648c Kostas Papadimitriou
        # keep the token for future use
180 d2633501 Kostas Papadimitriou
        token = pending_user.token
181 d2633501 Kostas Papadimitriou
        # from now on no shibboleth headers are sent to the server
182 d2633501 Kostas Papadimitriou
        client.reset_tokens()
183 d2633501 Kostas Papadimitriou
184 ba50648c Kostas Papadimitriou
        # this is the old way, it should fail, to avoid pending user take over
185 d2633501 Kostas Papadimitriou
        r = client.get('/im/shibboleth/signup/%s' % pending_user.username)
186 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 404)
187 d2633501 Kostas Papadimitriou
188 ba50648c Kostas Papadimitriou
        # this is the signup unique url associated with the pending user created
189 ba50648c Kostas Papadimitriou
        r = client.get('/im/signup/?third_party_token=%s' % token)
190 d2633501 Kostas Papadimitriou
        form = r.context['form']
191 ba50648c Kostas Papadimitriou
        post_data = {'third_party_identifier': pending_user.third_party_identifier,
192 d2633501 Kostas Papadimitriou
                     'first_name': 'Kostas',
193 d2633501 Kostas Papadimitriou
                     'third_party_token': token,
194 d2633501 Kostas Papadimitriou
                     'last_name': 'Mitroglou',
195 d2633501 Kostas Papadimitriou
                     'provider': 'shibboleth'
196 d2633501 Kostas Papadimitriou
                    }
197 ba50648c Kostas Papadimitriou
198 ba50648c Kostas Papadimitriou
        # invlid email
199 ba50648c Kostas Papadimitriou
        post_data['email'] = 'kpap'
200 d2633501 Kostas Papadimitriou
        r = client.post('/im/signup', post_data)
201 8ab484ea Kostas Papadimitriou
        self.assertContains(r, token)
202 ba50648c Kostas Papadimitriou
203 ba50648c Kostas Papadimitriou
        # existing email
204 ba50648c Kostas Papadimitriou
        existing_user = get_local_user('test@test.com')
205 ba50648c Kostas Papadimitriou
        post_data['email'] = 'test@test.com'
206 ba50648c Kostas Papadimitriou
        r = client.post('/im/signup', post_data)
207 ba50648c Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_USED)
208 ba50648c Kostas Papadimitriou
        existing_user.delete()
209 ba50648c Kostas Papadimitriou
210 ba50648c Kostas Papadimitriou
        # and finally a valid signup
211 8ab484ea Kostas Papadimitriou
        post_data['email'] = 'kpap@grnet.gr'
212 e5966bd9 Kostas Papadimitriou
        r = client.post('/im/signup', post_data, follow=True)
213 e5966bd9 Kostas Papadimitriou
        self.assertContains(r, messages.NOTIFICATION_SENT)
214 ba50648c Kostas Papadimitriou
215 ba50648c Kostas Papadimitriou
        # everything is ok in our db
216 d2633501 Kostas Papadimitriou
        self.assertEqual(AstakosUser.objects.count(), 1)
217 d2633501 Kostas Papadimitriou
        self.assertEqual(AstakosUserAuthProvider.objects.count(), 1)
218 ba50648c Kostas Papadimitriou
        self.assertEqual(PendingThirdPartyUser.objects.count(), 0)
219 d2633501 Kostas Papadimitriou
220 ba50648c Kostas Papadimitriou
        # provider info stored
221 ba50648c Kostas Papadimitriou
        provider = AstakosUserAuthProvider.objects.get(module="shibboleth")
222 ba50648c Kostas Papadimitriou
        self.assertEqual(provider.affiliation, 'Test Affiliation')
223 ba50648c Kostas Papadimitriou
        self.assertEqual(provider.info, {u'email': u'kpap@grnet.gr',
224 e5966bd9 Kostas Papadimitriou
                                         u'eppn': u'kpapeppn',
225 e5966bd9 Kostas Papadimitriou
                                         u'name': u'Kostas Papadimitriou'})
226 d2633501 Kostas Papadimitriou
227 ba50648c Kostas Papadimitriou
        # lets login (not activated yet)
228 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn",
229 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
230 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
231 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, messages.ACCOUNT_PENDING_MODERATION)
232 d2633501 Kostas Papadimitriou
        r = client.get("/im/profile", follow=True)
233 f47ecf6b Kostas Papadimitriou
        self.assertRedirects(r, 'http://testserver/im/?next=/im/profile')
234 d2633501 Kostas Papadimitriou
235 ba50648c Kostas Papadimitriou
        # admin activates our user
236 ba50648c Kostas Papadimitriou
        u = AstakosUser.objects.get(username="kpap@grnet.gr")
237 d2633501 Kostas Papadimitriou
        functions.activate(u)
238 d2633501 Kostas Papadimitriou
        self.assertEqual(u.is_active, True)
239 d2633501 Kostas Papadimitriou
240 ba50648c Kostas Papadimitriou
        # we see our profile
241 ba50648c Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
242 d2633501 Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
243 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
244 d2633501 Kostas Papadimitriou
245 d2633501 Kostas Papadimitriou
    def test_existing(self):
246 ba50648c Kostas Papadimitriou
        """
247 ba50648c Kostas Papadimitriou
        Test adding of third party login to an existing account
248 ba50648c Kostas Papadimitriou
        """
249 ba50648c Kostas Papadimitriou
250 ba50648c Kostas Papadimitriou
        # this is our existing user
251 d2633501 Kostas Papadimitriou
        existing_user = get_local_user('kpap@grnet.gr')
252 d2633501 Kostas Papadimitriou
253 d2633501 Kostas Papadimitriou
        client = ShibbolethClient()
254 d2633501 Kostas Papadimitriou
        # shibboleth logged us in, notice that we use different email
255 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
256 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
257 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?")
258 ba50648c Kostas Papadimitriou
259 d2633501 Kostas Papadimitriou
        # astakos asks if we want to switch a local account to shibboleth
260 d2633501 Kostas Papadimitriou
        self.assertContains(r, "Already have an account?")
261 d2633501 Kostas Papadimitriou
262 d2633501 Kostas Papadimitriou
        # a new pending user created
263 d2633501 Kostas Papadimitriou
        pending_user = PendingThirdPartyUser.objects.get()
264 d2633501 Kostas Papadimitriou
        self.assertEqual(PendingThirdPartyUser.objects.count(), 1)
265 d2633501 Kostas Papadimitriou
        pending_key = pending_user.token
266 d2633501 Kostas Papadimitriou
        client.reset_tokens()
267 d2633501 Kostas Papadimitriou
268 d2633501 Kostas Papadimitriou
        # we choose to add shibboleth to an our existing account
269 d2633501 Kostas Papadimitriou
        # we get redirected to login page with the pending token set
270 d2633501 Kostas Papadimitriou
        r = client.get('/im/login?key=%s' % pending_key)
271 d2633501 Kostas Papadimitriou
        post_data = {'password': 'password',
272 d2633501 Kostas Papadimitriou
                     'username': 'kpap@grnet.gr',
273 d2633501 Kostas Papadimitriou
                     'key': pending_key}
274 d2633501 Kostas Papadimitriou
        r = client.post('/im/local', post_data, follow=True)
275 ba50648c Kostas Papadimitriou
        self.assertRedirects(r, "/im/profile")
276 e5966bd9 Kostas Papadimitriou
        self.assertContains(r, messages.AUTH_PROVIDER_ADDED)
277 d2633501 Kostas Papadimitriou
278 ba50648c Kostas Papadimitriou
        self.assertTrue(existing_user.has_auth_provider('shibboleth'))
279 ba50648c Kostas Papadimitriou
        self.assertTrue(existing_user.has_auth_provider('local',
280 ba50648c Kostas Papadimitriou
                                                        auth_backend='astakos'))
281 d2633501 Kostas Papadimitriou
        client.logout()
282 d2633501 Kostas Papadimitriou
283 ba50648c Kostas Papadimitriou
        # check that we cannot assign same third party provide twice
284 d2633501 Kostas Papadimitriou
        r = client.get('/im/login?key=%s' % pending_key)
285 d2633501 Kostas Papadimitriou
        post_data = {'password': 'password',
286 d2633501 Kostas Papadimitriou
                     'username': 'kpap@grnet.gr',
287 d2633501 Kostas Papadimitriou
                     'key': pending_key}
288 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
289 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, messages.AUTH_PROVIDER_ADD_FAILED)
290 d2633501 Kostas Papadimitriou
        self.client.logout()
291 d2633501 Kostas Papadimitriou
        client.logout()
292 d2633501 Kostas Papadimitriou
293 d2633501 Kostas Papadimitriou
        # look Ma, i can login with both my shibboleth and local account
294 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
295 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
296 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
297 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
298 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr")
299 ba50648c Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
300 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
301 d2633501 Kostas Papadimitriou
        client.logout()
302 d2633501 Kostas Papadimitriou
        client.reset_tokens()
303 ba50648c Kostas Papadimitriou
304 ba50648c Kostas Papadimitriou
        # logged out
305 d2633501 Kostas Papadimitriou
        r = client.get("/im/profile", follow=True)
306 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
307 d2633501 Kostas Papadimitriou
308 ba50648c Kostas Papadimitriou
        # login with local account also works
309 d2633501 Kostas Papadimitriou
        post_data = {'password': 'password',
310 d2633501 Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
311 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
312 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
313 ba50648c Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr")
314 ba50648c Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
315 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
316 d2633501 Kostas Papadimitriou
317 ba50648c Kostas Papadimitriou
        # cannot add the same eppn
318 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn",
319 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
320 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
321 ba50648c Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
322 ba50648c Kostas Papadimitriou
        self.assertTrue(r.status_code, 200)
323 ba50648c Kostas Papadimitriou
        self.assertEquals(existing_user.auth_providers.count(), 2)
324 d2633501 Kostas Papadimitriou
325 ba50648c Kostas Papadimitriou
        # but can add additional eppn
326 ba50648c Kostas Papadimitriou
        client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn2",
327 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", ep_affiliation="affil2")
328 ba50648c Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
329 ba50648c Kostas Papadimitriou
        new_provider = existing_user.auth_providers.get(identifier="kpapeppn2")
330 ba50648c Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
331 ba50648c Kostas Papadimitriou
        self.assertTrue(r.status_code, 200)
332 ba50648c Kostas Papadimitriou
        self.assertEquals(existing_user.auth_providers.count(), 3)
333 ba50648c Kostas Papadimitriou
        self.assertEqual(new_provider.affiliation, 'affil2')
334 d2633501 Kostas Papadimitriou
        client.logout()
335 ba50648c Kostas Papadimitriou
        client.reset_tokens()
336 ba50648c Kostas Papadimitriou
337 ba50648c Kostas Papadimitriou
        # cannot login with another eppn
338 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppninvalid",
339 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
340 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
341 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
342 d2633501 Kostas Papadimitriou
343 f432088a Kostas Papadimitriou
        # lets remove local password
344 f432088a Kostas Papadimitriou
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
345 f432088a Kostas Papadimitriou
                                       email="kpap@grnet.gr")
346 ba50648c Kostas Papadimitriou
        remove_local_url = user.get_provider_remove_url('local')
347 ba50648c Kostas Papadimitriou
        remove_shibbo_url = user.get_provider_remove_url('shibboleth',
348 ba50648c Kostas Papadimitriou
                                                         identifier='kpapeppn')
349 ba50648c Kostas Papadimitriou
        remove_shibbo2_url = user.get_provider_remove_url('shibboleth',
350 ba50648c Kostas Papadimitriou
                                                         identifier='kpapeppn2')
351 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
352 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimtriou")
353 f432088a Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
354 f432088a Kostas Papadimitriou
        client.reset_tokens()
355 ba50648c Kostas Papadimitriou
356 ba50648c Kostas Papadimitriou
        # TODO: this view should use POST
357 ba50648c Kostas Papadimitriou
        r = client.get(remove_local_url)
358 ba50648c Kostas Papadimitriou
        # 2 providers left
359 ba50648c Kostas Papadimitriou
        self.assertEqual(user.auth_providers.count(), 2)
360 ba50648c Kostas Papadimitriou
        r = client.get(remove_shibbo2_url)
361 ba50648c Kostas Papadimitriou
        # 1 provider left
362 f432088a Kostas Papadimitriou
        self.assertEqual(user.auth_providers.count(), 1)
363 ba50648c Kostas Papadimitriou
        # cannot remove last provider
364 ba50648c Kostas Papadimitriou
        r = client.get(remove_shibbo_url)
365 f432088a Kostas Papadimitriou
        self.assertEqual(r.status_code, 403)
366 f432088a Kostas Papadimitriou
        self.client.logout()
367 ba50648c Kostas Papadimitriou
368 ba50648c Kostas Papadimitriou
        # cannot login using local credentials (notice we use another client)
369 f432088a Kostas Papadimitriou
        post_data = {'password': 'password',
370 f432088a Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
371 f432088a Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
372 f432088a Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
373 f432088a Kostas Papadimitriou
374 ba50648c Kostas Papadimitriou
        # we can reenable the local provider by setting a password
375 f432088a Kostas Papadimitriou
        r = client.get("/im/password_change", follow=True)
376 f432088a Kostas Papadimitriou
        r = client.post("/im/password_change", {'new_password1':'111',
377 f432088a Kostas Papadimitriou
                                                'new_password2': '111'},
378 f432088a Kostas Papadimitriou
                        follow=True)
379 f432088a Kostas Papadimitriou
        user = r.context['request'].user
380 f432088a Kostas Papadimitriou
        self.assertTrue(user.has_auth_provider('local'))
381 f432088a Kostas Papadimitriou
        self.assertTrue(user.has_auth_provider('shibboleth'))
382 f432088a Kostas Papadimitriou
        self.assertTrue(user.check_password('111'))
383 f432088a Kostas Papadimitriou
        self.assertTrue(user.has_usable_password())
384 f432088a Kostas Papadimitriou
        self.client.logout()
385 ba50648c Kostas Papadimitriou
386 ba50648c Kostas Papadimitriou
        # now we can login
387 f432088a Kostas Papadimitriou
        post_data = {'password': '111',
388 f432088a Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
389 f432088a Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
390 f432088a Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
391 f432088a Kostas Papadimitriou
392 ba50648c Kostas Papadimitriou
        client.reset_tokens()
393 f432088a Kostas Papadimitriou
394 ba50648c Kostas Papadimitriou
        # we cannot take over another shibboleth identifier
395 f432088a Kostas Papadimitriou
        user2 = get_local_user('another@grnet.gr')
396 f432088a Kostas Papadimitriou
        user2.add_auth_provider('shibboleth', identifier='existingeppn')
397 ba50648c Kostas Papadimitriou
        # login
398 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
399 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
400 f432088a Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
401 ba50648c Kostas Papadimitriou
        # try to assign existing shibboleth identifier of another user
402 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="existingeppn",
403 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
404 f432088a Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
405 e5966bd9 Kostas Papadimitriou
        self.assertContains(r, messages.AUTH_PROVIDER_ADD_FAILED)
406 e5966bd9 Kostas Papadimitriou
        self.assertContains(r, messages.AUTH_PROVIDER_ADD_EXISTS)
407 2e90e3ec Kostas Papadimitriou
408 d2633501 Kostas Papadimitriou
409 d2633501 Kostas Papadimitriou
class LocalUserTests(TestCase):
410 d2633501 Kostas Papadimitriou
411 d2633501 Kostas Papadimitriou
    fixtures = ['groups']
412 d2633501 Kostas Papadimitriou
413 2e90e3ec Kostas Papadimitriou
    def setUp(self):
414 2e90e3ec Kostas Papadimitriou
        from django.conf import settings
415 2e90e3ec Kostas Papadimitriou
        settings.ADMINS = (('admin', 'support@cloud.grnet.gr'),)
416 2e90e3ec Kostas Papadimitriou
        settings.SERVER_EMAIL = 'no-reply@grnet.gr'
417 2e90e3ec Kostas Papadimitriou
418 7233d542 Kostas Papadimitriou
    def test_no_moderation(self):
419 ba50648c Kostas Papadimitriou
        # disable moderation
420 7233d542 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = False
421 ba50648c Kostas Papadimitriou
422 ba50648c Kostas Papadimitriou
        # create a new user
423 7233d542 Kostas Papadimitriou
        r = self.client.get("/im/signup")
424 7233d542 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
425 7233d542 Kostas Papadimitriou
        data = {'email':'kpap@grnet.gr', 'password1':'password',
426 7233d542 Kostas Papadimitriou
                'password2':'password', 'first_name': 'Kostas',
427 7233d542 Kostas Papadimitriou
                'last_name': 'Mitroglou', 'provider': 'local'}
428 7233d542 Kostas Papadimitriou
        r = self.client.post("/im/signup", data)
429 ba50648c Kostas Papadimitriou
430 ba50648c Kostas Papadimitriou
        # user created
431 7233d542 Kostas Papadimitriou
        self.assertEqual(AstakosUser.objects.count(), 1)
432 7233d542 Kostas Papadimitriou
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
433 7233d542 Kostas Papadimitriou
                                       email="kpap@grnet.gr")
434 7233d542 Kostas Papadimitriou
        self.assertEqual(user.username, 'kpap@grnet.gr')
435 7233d542 Kostas Papadimitriou
        self.assertEqual(user.has_auth_provider('local'), True)
436 7233d542 Kostas Papadimitriou
        self.assertFalse(user.is_active)
437 7233d542 Kostas Papadimitriou
438 ba50648c Kostas Papadimitriou
        # user (but not admin) gets notified
439 7233d542 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('support@cloud.grnet.gr')), 0)
440 7233d542 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
441 7233d542 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
442 d2633501 Kostas Papadimitriou
443 e5966bd9 Kostas Papadimitriou
    def test_email_case(self):
444 e5966bd9 Kostas Papadimitriou
        data = {
445 e5966bd9 Kostas Papadimitriou
          'email': 'kPap@grnet.gr',
446 e5966bd9 Kostas Papadimitriou
          'password1': '1234',
447 e5966bd9 Kostas Papadimitriou
          'password2': '1234'
448 e5966bd9 Kostas Papadimitriou
        }
449 e5966bd9 Kostas Papadimitriou
450 e5966bd9 Kostas Papadimitriou
        form = forms.LocalUserCreationForm(data)
451 e5966bd9 Kostas Papadimitriou
        self.assertTrue(form.is_valid())
452 e5966bd9 Kostas Papadimitriou
        user = form.save()
453 e5966bd9 Kostas Papadimitriou
        form.store_user(user, {})
454 e5966bd9 Kostas Papadimitriou
455 e5966bd9 Kostas Papadimitriou
        u = AstakosUser.objects.get(pk=1)
456 e5966bd9 Kostas Papadimitriou
        self.assertEqual(u.email, 'kPap@grnet.gr')
457 e5966bd9 Kostas Papadimitriou
        self.assertEqual(u.username, 'kpap@grnet.gr')
458 e5966bd9 Kostas Papadimitriou
        u.is_active = True
459 e5966bd9 Kostas Papadimitriou
        u.email_verified = True
460 e5966bd9 Kostas Papadimitriou
        u.save()
461 e5966bd9 Kostas Papadimitriou
462 e5966bd9 Kostas Papadimitriou
        data = {'username': 'kpap@grnet.gr', 'password': '1234'}
463 e5966bd9 Kostas Papadimitriou
        login = forms.LoginForm(data=data)
464 e5966bd9 Kostas Papadimitriou
        self.assertTrue(login.is_valid())
465 e5966bd9 Kostas Papadimitriou
466 e5966bd9 Kostas Papadimitriou
        data = {'username': 'KpaP@grnet.gr', 'password': '1234'}
467 e5966bd9 Kostas Papadimitriou
        login = forms.LoginForm(data=data)
468 e5966bd9 Kostas Papadimitriou
        self.assertTrue(login.is_valid())
469 e5966bd9 Kostas Papadimitriou
470 e5966bd9 Kostas Papadimitriou
        data = {
471 e5966bd9 Kostas Papadimitriou
          'email': 'kpap@grnet.gr',
472 e5966bd9 Kostas Papadimitriou
          'password1': '1234',
473 e5966bd9 Kostas Papadimitriou
          'password2': '1234'
474 e5966bd9 Kostas Papadimitriou
        }
475 e5966bd9 Kostas Papadimitriou
        form = forms.LocalUserCreationForm(data)
476 e5966bd9 Kostas Papadimitriou
        self.assertFalse(form.is_valid())
477 e5966bd9 Kostas Papadimitriou
478 d2633501 Kostas Papadimitriou
    def test_local_provider(self):
479 ba50648c Kostas Papadimitriou
        # enable moderation
480 7233d542 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
481 ba50648c Kostas Papadimitriou
482 ba50648c Kostas Papadimitriou
        # create a user
483 d2633501 Kostas Papadimitriou
        r = self.client.get("/im/signup")
484 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
485 d2633501 Kostas Papadimitriou
        data = {'email':'kpap@grnet.gr', 'password1':'password',
486 d2633501 Kostas Papadimitriou
                'password2':'password', 'first_name': 'Kostas',
487 d2633501 Kostas Papadimitriou
                'last_name': 'Mitroglou', 'provider': 'local'}
488 d2633501 Kostas Papadimitriou
        r = self.client.post("/im/signup", data)
489 ba50648c Kostas Papadimitriou
490 ba50648c Kostas Papadimitriou
        # user created
491 d2633501 Kostas Papadimitriou
        self.assertEqual(AstakosUser.objects.count(), 1)
492 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
493 d2633501 Kostas Papadimitriou
                                       email="kpap@grnet.gr")
494 d2633501 Kostas Papadimitriou
        self.assertEqual(user.username, 'kpap@grnet.gr')
495 d2633501 Kostas Papadimitriou
        self.assertEqual(user.has_auth_provider('local'), True)
496 ba50648c Kostas Papadimitriou
        self.assertFalse(user.is_active) # not activated
497 ba50648c Kostas Papadimitriou
        self.assertFalse(user.email_verified) # not verified
498 ba50648c Kostas Papadimitriou
        self.assertFalse(user.activation_sent) # activation automatically sent
499 d2633501 Kostas Papadimitriou
500 ba50648c Kostas Papadimitriou
        # admin gets notified and activates the user from the command line
501 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('support@cloud.grnet.gr')), 1)
502 31fdafa8 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
503 31fdafa8 Kostas Papadimitriou
                                                 'password': 'password'})
504 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, messages.ACCOUNT_PENDING_MODERATION)
505 d2633501 Kostas Papadimitriou
        functions.send_activation(user)
506 d2633501 Kostas Papadimitriou
507 ba50648c Kostas Papadimitriou
        # user activation fields updated and user gets notified via email
508 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
509 d2633501 Kostas Papadimitriou
        self.assertTrue(user.activation_sent)
510 d2633501 Kostas Papadimitriou
        self.assertFalse(user.email_verified)
511 f47ecf6b Kostas Papadimitriou
        self.assertFalse(user.is_active)
512 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
513 d2633501 Kostas Papadimitriou
514 d2633501 Kostas Papadimitriou
        # user forgot she got registered and tries to submit registration
515 d2633501 Kostas Papadimitriou
        # form. Notice the upper case in email
516 d2633501 Kostas Papadimitriou
        data = {'email':'KPAP@grnet.gr', 'password1':'password',
517 d2633501 Kostas Papadimitriou
                'password2':'password', 'first_name': 'Kostas',
518 d2633501 Kostas Papadimitriou
                'last_name': 'Mitroglou', 'provider': 'local'}
519 564a2292 Kostas Papadimitriou
        r = self.client.post("/im/signup", data, follow=True)
520 564a2292 Kostas Papadimitriou
        self.assertRedirects(r, reverse('index'))
521 564a2292 Kostas Papadimitriou
        self.assertContains(r, messages.NOTIFICATION_SENT)
522 564a2292 Kostas Papadimitriou
523 564a2292 Kostas Papadimitriou
        # previous user replaced
524 564a2292 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
525 564a2292 Kostas Papadimitriou
        self.assertTrue(user.activation_sent)
526 564a2292 Kostas Papadimitriou
        self.assertFalse(user.email_verified)
527 564a2292 Kostas Papadimitriou
        self.assertFalse(user.is_active)
528 564a2292 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 2)
529 d2633501 Kostas Papadimitriou
530 f47ecf6b Kostas Papadimitriou
        # hmmm, email exists; lets request a password change
531 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/local/password_reset')
532 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
533 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', {'email':
534 f47ecf6b Kostas Papadimitriou
                                                          'kpap@grnet.gr'},
535 f47ecf6b Kostas Papadimitriou
                            follow=True)
536 d2633501 Kostas Papadimitriou
        # she can't because account is not active yet
537 d2633501 Kostas Papadimitriou
        self.assertContains(r, "doesn't have an associated user account")
538 d2633501 Kostas Papadimitriou
539 d2633501 Kostas Papadimitriou
        # moderation is enabled so no automatic activation can be send
540 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/send/activation/%d' % user.pk)
541 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 403)
542 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
543 ba50648c Kostas Papadimitriou
544 d2633501 Kostas Papadimitriou
        # also she cannot login
545 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
546 d2633501 Kostas Papadimitriou
                                                 'password': 'password'})
547 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION_HELP)
548 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION)
549 d2633501 Kostas Papadimitriou
        self.assertNotContains(r, 'Resend activation')
550 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
551 d2633501 Kostas Papadimitriou
        self.assertFalse('_pithos2_a' in self.client.cookies)
552 d2633501 Kostas Papadimitriou
553 ba50648c Kostas Papadimitriou
        # same with disabled moderation
554 d2633501 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = False
555 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', {'email':
556 d2633501 Kostas Papadimitriou
                                                          'kpap@grnet.gr'})
557 d2633501 Kostas Papadimitriou
        self.assertContains(r, "doesn't have an associated user account")
558 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
559 d2633501 Kostas Papadimitriou
                                                 'password': 'password'})
560 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION)
561 d2633501 Kostas Papadimitriou
        self.assertContains(r, 'Resend activation')
562 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
563 d2633501 Kostas Papadimitriou
        self.assertFalse('_pithos2_a' in self.client.cookies)
564 ba50648c Kostas Papadimitriou
565 d2633501 Kostas Papadimitriou
        # user sees the message and resends activation
566 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/send/activation/%d' % user.pk)
567 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 2)
568 d2633501 Kostas Papadimitriou
569 d2633501 Kostas Papadimitriou
        # switch back moderation setting
570 d2633501 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
571 d2633501 Kostas Papadimitriou
        r = self.client.get(user.get_activation_url(), follow=True)
572 d2633501 Kostas Papadimitriou
        self.assertRedirects(r, "/im/profile")
573 d2633501 Kostas Papadimitriou
        self.assertContains(r, "kpap@grnet.gr")
574 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 3)
575 d2633501 Kostas Papadimitriou
576 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
577 d2633501 Kostas Papadimitriou
        # user activated and logged in, token cookie set
578 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
579 d2633501 Kostas Papadimitriou
        self.assertTrue('_pithos2_a' in self.client.cookies)
580 d2633501 Kostas Papadimitriou
        cookies = self.client.cookies
581 d2633501 Kostas Papadimitriou
        self.assertTrue(quote(user.auth_token) in cookies.get('_pithos2_a').value)
582 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/logout', follow=True)
583 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/')
584 d2633501 Kostas Papadimitriou
        # user logged out, token cookie removed
585 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
586 d2633501 Kostas Papadimitriou
        self.assertFalse(self.client.cookies.get('_pithos2_a').value)
587 d2633501 Kostas Papadimitriou
        # https://docs.djangoproject.com/en/dev/topics/testing/#persistent-state
588 d2633501 Kostas Papadimitriou
        del self.client.cookies['_pithos2_a']
589 d2633501 Kostas Papadimitriou
590 d2633501 Kostas Papadimitriou
        # user can login
591 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
592 d2633501 Kostas Papadimitriou
                                           'password': 'password'},
593 d2633501 Kostas Papadimitriou
                                          follow=True)
594 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
595 d2633501 Kostas Papadimitriou
        self.assertTrue('_pithos2_a' in self.client.cookies)
596 d2633501 Kostas Papadimitriou
        cookies = self.client.cookies
597 d2633501 Kostas Papadimitriou
        self.assertTrue(quote(user.auth_token) in cookies.get('_pithos2_a').value)
598 d2633501 Kostas Papadimitriou
        self.client.get('/im/logout', follow=True)
599 d2633501 Kostas Papadimitriou
600 d2633501 Kostas Papadimitriou
        # user forgot password
601 d2633501 Kostas Papadimitriou
        old_pass = user.password
602 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/local/password_reset')
603 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
604 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', {'email':
605 d2633501 Kostas Papadimitriou
                                                          'kpap@grnet.gr'})
606 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 302)
607 d2633501 Kostas Papadimitriou
        # email sent
608 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 4)
609 d2633501 Kostas Papadimitriou
610 d2633501 Kostas Papadimitriou
        # user visits change password link
611 d2633501 Kostas Papadimitriou
        r = self.client.get(user.get_password_reset_url())
612 d2633501 Kostas Papadimitriou
        r = self.client.post(user.get_password_reset_url(),
613 d2633501 Kostas Papadimitriou
                            {'new_password1':'newpass',
614 d2633501 Kostas Papadimitriou
                             'new_password2':'newpass'})
615 d2633501 Kostas Papadimitriou
616 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
617 d2633501 Kostas Papadimitriou
        self.assertNotEqual(old_pass, user.password)
618 d2633501 Kostas Papadimitriou
619 d2633501 Kostas Papadimitriou
        # old pass is not usable
620 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
621 d2633501 Kostas Papadimitriou
                                           'password': 'password'})
622 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, 'Please enter a correct username and password')
623 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
624 d2633501 Kostas Papadimitriou
                                           'password': 'newpass'},
625 d2633501 Kostas Papadimitriou
                                           follow=True)
626 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
627 d2633501 Kostas Papadimitriou
        self.client.logout()
628 d2633501 Kostas Papadimitriou
629 d2633501 Kostas Papadimitriou
        # tests of special local backends
630 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
631 d2633501 Kostas Papadimitriou
        user.auth_providers.filter(module='local').update(auth_backend='ldap')
632 d2633501 Kostas Papadimitriou
        user.save()
633 d2633501 Kostas Papadimitriou
634 d2633501 Kostas Papadimitriou
        # non astakos local backends do not support password reset
635 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/local/password_reset')
636 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
637 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', {'email':
638 d2633501 Kostas Papadimitriou
                                                          'kpap@grnet.gr'})
639 d2633501 Kostas Papadimitriou
        # she can't because account is not active yet
640 f47ecf6b Kostas Papadimitriou
        self.assertContains(r, messages.AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD)
641 d2633501 Kostas Papadimitriou
642 34a76cdb Kostas Papadimitriou
class UserActionsTests(TestCase):
643 34a76cdb Kostas Papadimitriou
644 34a76cdb Kostas Papadimitriou
    def test_email_change(self):
645 34a76cdb Kostas Papadimitriou
        # to test existing email validation
646 34a76cdb Kostas Papadimitriou
        existing_user = get_local_user('existing@grnet.gr')
647 34a76cdb Kostas Papadimitriou
648 34a76cdb Kostas Papadimitriou
        # local user
649 34a76cdb Kostas Papadimitriou
        user = get_local_user('kpap@grnet.gr')
650 34a76cdb Kostas Papadimitriou
651 34a76cdb Kostas Papadimitriou
        # login as kpap
652 34a76cdb Kostas Papadimitriou
        self.client.login(username='kpap@grnet.gr', password='password')
653 34a76cdb Kostas Papadimitriou
        r = self.client.get('/im/profile', follow=True)
654 34a76cdb Kostas Papadimitriou
        user = r.context['request'].user
655 34a76cdb Kostas Papadimitriou
        self.assertTrue(user.is_authenticated())
656 34a76cdb Kostas Papadimitriou
657 34a76cdb Kostas Papadimitriou
        # change email is enabled
658 34a76cdb Kostas Papadimitriou
        r = self.client.get('/im/email_change')
659 34a76cdb Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
660 34a76cdb Kostas Papadimitriou
        self.assertFalse(user.email_change_is_pending())
661 34a76cdb Kostas Papadimitriou
662 34a76cdb Kostas Papadimitriou
        # request email change to an existing email fails
663 34a76cdb Kostas Papadimitriou
        data = {'new_email_address': 'existing@grnet.gr'}
664 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/email_change', data)
665 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_USED)
666 34a76cdb Kostas Papadimitriou
667 34a76cdb Kostas Papadimitriou
        # proper email change
668 34a76cdb Kostas Papadimitriou
        data = {'new_email_address': 'kpap@gmail.com'}
669 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/email_change', data, follow=True)
670 34a76cdb Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
671 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_CHANGE_REGISTERED)
672 34a76cdb Kostas Papadimitriou
        change1 = EmailChange.objects.get()
673 34a76cdb Kostas Papadimitriou
674 34a76cdb Kostas Papadimitriou
        # user sees a warning
675 34a76cdb Kostas Papadimitriou
        r = self.client.get('/im/email_change')
676 34a76cdb Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
677 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.PENDING_EMAIL_CHANGE_REQUEST)
678 34a76cdb Kostas Papadimitriou
        self.assertTrue(user.email_change_is_pending())
679 34a76cdb Kostas Papadimitriou
680 34a76cdb Kostas Papadimitriou
        # link was sent
681 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 0)
682 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@gmail.com')), 1)
683 34a76cdb Kostas Papadimitriou
684 34a76cdb Kostas Papadimitriou
        # proper email change
685 34a76cdb Kostas Papadimitriou
        data = {'new_email_address': 'kpap@yahoo.com'}
686 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/email_change', data, follow=True)
687 34a76cdb Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
688 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_CHANGE_REGISTERED)
689 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 0)
690 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@yahoo.com')), 1)
691 34a76cdb Kostas Papadimitriou
        change2 = EmailChange.objects.get()
692 34a76cdb Kostas Papadimitriou
693 34a76cdb Kostas Papadimitriou
        r = self.client.get(change1.get_url())
694 34a76cdb Kostas Papadimitriou
        self.assertEquals(r.status_code, 302)
695 34a76cdb Kostas Papadimitriou
        self.client.logout()
696 34a76cdb Kostas Papadimitriou
697 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/local?next=' + change2.get_url(),
698 34a76cdb Kostas Papadimitriou
                             {'username': 'kpap@grnet.gr',
699 34a76cdb Kostas Papadimitriou
                              'password': 'password',
700 34a76cdb Kostas Papadimitriou
                              'next': change2.get_url()},
701 34a76cdb Kostas Papadimitriou
                             follow=True)
702 34a76cdb Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
703 34a76cdb Kostas Papadimitriou
        user = r.context['request'].user
704 34a76cdb Kostas Papadimitriou
        self.assertEquals(user.email, 'kpap@yahoo.com')
705 34a76cdb Kostas Papadimitriou
        self.assertEquals(user.username, 'kpap@yahoo.com')
706 34a76cdb Kostas Papadimitriou
707 34a76cdb Kostas Papadimitriou
708 34a76cdb Kostas Papadimitriou
        self.client.logout()
709 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/local?next=' + change2.get_url(),
710 34a76cdb Kostas Papadimitriou
                             {'username': 'kpap@grnet.gr',
711 34a76cdb Kostas Papadimitriou
                              'password': 'password',
712 34a76cdb Kostas Papadimitriou
                              'next': change2.get_url()},
713 34a76cdb Kostas Papadimitriou
                             follow=True)
714 34a76cdb Kostas Papadimitriou
        self.assertContains(r, "Please enter a correct username and password")
715 34a76cdb Kostas Papadimitriou
        self.assertEqual(user.emailchanges.count(), 0)