Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests.py @ 38aff106

History | View | Annotate | Download (59.4 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 478ece6c Kostas Papadimitriou
from contextlib import contextmanager
34 d2633501 Kostas Papadimitriou
35 9d20fe23 Kostas Papadimitriou
import copy
36 d2633501 Kostas Papadimitriou
import datetime
37 478ece6c Kostas Papadimitriou
import functools
38 478ece6c Kostas Papadimitriou
39 d2b8ec7b Christos Stavrakakis
from snf_django.utils.testing import with_settings, override_settings
40 d2633501 Kostas Papadimitriou
41 d2633501 Kostas Papadimitriou
from django.test import TestCase, Client
42 d2633501 Kostas Papadimitriou
from django.core import mail
43 478ece6c Kostas Papadimitriou
from django.http import SimpleCookie, HttpRequest, QueryDict
44 478ece6c Kostas Papadimitriou
from django.utils.importlib import import_module
45 d2633501 Kostas Papadimitriou
46 9d20fe23 Kostas Papadimitriou
from astakos.im.activation_backends import *
47 d2633501 Kostas Papadimitriou
from astakos.im.target.shibboleth import Tokens as ShibbolethTokens
48 d2633501 Kostas Papadimitriou
from astakos.im.models import *
49 d2633501 Kostas Papadimitriou
from astakos.im import functions
50 d2633501 Kostas Papadimitriou
from astakos.im import settings as astakos_settings
51 e5966bd9 Kostas Papadimitriou
from astakos.im import forms
52 d2633501 Kostas Papadimitriou
53 d2633501 Kostas Papadimitriou
from urllib import quote
54 450c7fb0 Kostas Papadimitriou
from datetime import timedelta
55 d2633501 Kostas Papadimitriou
56 2e90e3ec Kostas Papadimitriou
from astakos.im import messages
57 9d20fe23 Kostas Papadimitriou
from astakos.im import auth_providers
58 450c7fb0 Kostas Papadimitriou
from astakos.im import quotas
59 450c7fb0 Kostas Papadimitriou
60 478ece6c Kostas Papadimitriou
from django.conf import settings
61 2e90e3ec Kostas Papadimitriou
62 34a76cdb Kostas Papadimitriou
63 478ece6c Kostas Papadimitriou
# set some common settings
64 34a76cdb Kostas Papadimitriou
astakos_settings.EMAILCHANGE_ENABLED = True
65 478ece6c Kostas Papadimitriou
astakos_settings.RECAPTCHA_ENABLED = False
66 478ece6c Kostas Papadimitriou
67 478ece6c Kostas Papadimitriou
settings.LOGGING_SETUP['disable_existing_loggers'] = False
68 34a76cdb Kostas Papadimitriou
69 0a7a4104 Kostas Papadimitriou
# shortcut decorators to override provider settings
70 0a7a4104 Kostas Papadimitriou
# e.g. shibboleth_settings(ENABLED=True) will set
71 0a7a4104 Kostas Papadimitriou
# ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_ENABLED = True in global synnefo settings
72 0a7a4104 Kostas Papadimitriou
prefixes = {'providers': 'AUTH_PROVIDER_',
73 0a7a4104 Kostas Papadimitriou
            'shibboleth': 'ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_',
74 0a7a4104 Kostas Papadimitriou
            'local': 'ASTAKOS_AUTH_PROVIDER_LOCAL_'}
75 450c7fb0 Kostas Papadimitriou
im_settings = functools.partial(with_settings, astakos_settings)
76 478ece6c Kostas Papadimitriou
shibboleth_settings = functools.partial(with_settings,
77 0a7a4104 Kostas Papadimitriou
                                        settings,
78 478ece6c Kostas Papadimitriou
                                        prefix=prefixes['shibboleth'])
79 0a7a4104 Kostas Papadimitriou
localauth_settings = functools.partial(with_settings, settings,
80 478ece6c Kostas Papadimitriou
                                       prefix=prefixes['local'])
81 478ece6c Kostas Papadimitriou
82 0a7a4104 Kostas Papadimitriou
83 478ece6c Kostas Papadimitriou
class AstakosTestClient(Client):
84 478ece6c Kostas Papadimitriou
    pass
85 478ece6c Kostas Papadimitriou
86 0a7a4104 Kostas Papadimitriou
87 478ece6c Kostas Papadimitriou
class ShibbolethClient(AstakosTestClient):
88 d2633501 Kostas Papadimitriou
    """
89 d2633501 Kostas Papadimitriou
    A shibboleth agnostic client.
90 d2633501 Kostas Papadimitriou
    """
91 9d20fe23 Kostas Papadimitriou
    VALID_TOKENS = filter(lambda x: not x.startswith("_"),
92 9d20fe23 Kostas Papadimitriou
                          dir(ShibbolethTokens))
93 d2633501 Kostas Papadimitriou
94 d2633501 Kostas Papadimitriou
    def __init__(self, *args, **kwargs):
95 d2633501 Kostas Papadimitriou
        self.tokens = kwargs.pop('tokens', {})
96 d2633501 Kostas Papadimitriou
        super(ShibbolethClient, self).__init__(*args, **kwargs)
97 d2633501 Kostas Papadimitriou
98 d2633501 Kostas Papadimitriou
    def set_tokens(self, **kwargs):
99 d2633501 Kostas Papadimitriou
        for key, value in kwargs.iteritems():
100 d2633501 Kostas Papadimitriou
            key = 'SHIB_%s' % key.upper()
101 d2633501 Kostas Papadimitriou
            if not key in self.VALID_TOKENS:
102 d2633501 Kostas Papadimitriou
                raise Exception('Invalid shibboleth token')
103 d2633501 Kostas Papadimitriou
104 d2633501 Kostas Papadimitriou
            self.tokens[key] = value
105 d2633501 Kostas Papadimitriou
106 d2633501 Kostas Papadimitriou
    def unset_tokens(self, *keys):
107 d2633501 Kostas Papadimitriou
        for key in keys:
108 d2633501 Kostas Papadimitriou
            key = 'SHIB_%s' % param.upper()
109 d2633501 Kostas Papadimitriou
            if key in self.tokens:
110 d2633501 Kostas Papadimitriou
                del self.tokens[key]
111 d2633501 Kostas Papadimitriou
112 d2633501 Kostas Papadimitriou
    def reset_tokens(self):
113 d2633501 Kostas Papadimitriou
        self.tokens = {}
114 d2633501 Kostas Papadimitriou
115 d2633501 Kostas Papadimitriou
    def get_http_token(self, key):
116 d2633501 Kostas Papadimitriou
        http_header = getattr(ShibbolethTokens, key)
117 d2633501 Kostas Papadimitriou
        return http_header
118 d2633501 Kostas Papadimitriou
119 d2633501 Kostas Papadimitriou
    def request(self, **request):
120 d2633501 Kostas Papadimitriou
        """
121 d2633501 Kostas Papadimitriou
        Transform valid shibboleth tokens to http headers
122 d2633501 Kostas Papadimitriou
        """
123 d2633501 Kostas Papadimitriou
        for token, value in self.tokens.iteritems():
124 d2633501 Kostas Papadimitriou
            request[self.get_http_token(token)] = value
125 d2633501 Kostas Papadimitriou
126 d2633501 Kostas Papadimitriou
        for param in request.keys():
127 d2633501 Kostas Papadimitriou
            key = 'SHIB_%s' % param.upper()
128 d2633501 Kostas Papadimitriou
            if key in self.VALID_TOKENS:
129 d2633501 Kostas Papadimitriou
                request[self.get_http_token(key)] = request[param]
130 d2633501 Kostas Papadimitriou
                del request[param]
131 d2633501 Kostas Papadimitriou
132 d2633501 Kostas Papadimitriou
        return super(ShibbolethClient, self).request(**request)
133 d2633501 Kostas Papadimitriou
134 d2633501 Kostas Papadimitriou
135 450c7fb0 Kostas Papadimitriou
def get_user_client(username, password="password"):
136 450c7fb0 Kostas Papadimitriou
    client = Client()
137 450c7fb0 Kostas Papadimitriou
    client.login(username=username, password=password)
138 450c7fb0 Kostas Papadimitriou
    return client
139 450c7fb0 Kostas Papadimitriou
140 450c7fb0 Kostas Papadimitriou
141 d2633501 Kostas Papadimitriou
def get_local_user(username, **kwargs):
142 d2633501 Kostas Papadimitriou
        try:
143 d2633501 Kostas Papadimitriou
            return AstakosUser.objects.get(email=username)
144 d2633501 Kostas Papadimitriou
        except:
145 d2633501 Kostas Papadimitriou
            user_params = {
146 d2633501 Kostas Papadimitriou
                'username': username,
147 d2633501 Kostas Papadimitriou
                'email': username,
148 d2633501 Kostas Papadimitriou
                'is_active': True,
149 d2633501 Kostas Papadimitriou
                'activation_sent': datetime.now(),
150 d2633501 Kostas Papadimitriou
                'email_verified': True,
151 d2633501 Kostas Papadimitriou
                'provider': 'local'
152 d2633501 Kostas Papadimitriou
            }
153 d2633501 Kostas Papadimitriou
            user_params.update(kwargs)
154 d2633501 Kostas Papadimitriou
            user = AstakosUser(**user_params)
155 d2633501 Kostas Papadimitriou
            user.set_password(kwargs.get('password', 'password'))
156 d2633501 Kostas Papadimitriou
            user.save()
157 d2633501 Kostas Papadimitriou
            user.add_auth_provider('local', auth_backend='astakos')
158 d2633501 Kostas Papadimitriou
            if kwargs.get('is_active', True):
159 d2633501 Kostas Papadimitriou
                user.is_active = True
160 d2633501 Kostas Papadimitriou
            else:
161 d2633501 Kostas Papadimitriou
                user.is_active = False
162 d2633501 Kostas Papadimitriou
            user.save()
163 d2633501 Kostas Papadimitriou
            return user
164 d2633501 Kostas Papadimitriou
165 d2633501 Kostas Papadimitriou
166 d2633501 Kostas Papadimitriou
def get_mailbox(email):
167 d2633501 Kostas Papadimitriou
    mails = []
168 d2633501 Kostas Papadimitriou
    for sent_email in mail.outbox:
169 d2633501 Kostas Papadimitriou
        for recipient in sent_email.recipients():
170 d2633501 Kostas Papadimitriou
            if email in recipient:
171 d2633501 Kostas Papadimitriou
                mails.append(sent_email)
172 d2633501 Kostas Papadimitriou
    return mails
173 d2633501 Kostas Papadimitriou
174 d2633501 Kostas Papadimitriou
175 d2633501 Kostas Papadimitriou
class ShibbolethTests(TestCase):
176 d2633501 Kostas Papadimitriou
    """
177 d2633501 Kostas Papadimitriou
    Testing shibboleth authentication.
178 d2633501 Kostas Papadimitriou
    """
179 d2633501 Kostas Papadimitriou
180 d2633501 Kostas Papadimitriou
    fixtures = ['groups']
181 d2633501 Kostas Papadimitriou
182 d2633501 Kostas Papadimitriou
    def setUp(self):
183 d2633501 Kostas Papadimitriou
        self.client = ShibbolethClient()
184 9d20fe23 Kostas Papadimitriou
        astakos_settings.IM_MODULES = ['local', 'shibboleth']
185 9d20fe23 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
186 d2633501 Kostas Papadimitriou
187 0a7a4104 Kostas Papadimitriou
    @im_settings(FORCE_PROFILE_UPDATE=False)
188 d2633501 Kostas Papadimitriou
    def test_create_account(self):
189 ba50648c Kostas Papadimitriou
190 d2633501 Kostas Papadimitriou
        client = ShibbolethClient()
191 d2633501 Kostas Papadimitriou
192 d2633501 Kostas Papadimitriou
        # shibboleth views validation
193 d2633501 Kostas Papadimitriou
        # eepn required
194 d2633501 Kostas Papadimitriou
        r = client.get('/im/login/shibboleth?', follow=True)
195 e24d0e0d Kostas Papadimitriou
        self.assertContains(r, messages.SHIBBOLETH_MISSING_EPPN % {
196 e24d0e0d Kostas Papadimitriou
            'domain': astakos_settings.BASEURL,
197 31bc3a62 Kostas Papadimitriou
            'contact_email': settings.CONTACT_EMAIL
198 e24d0e0d Kostas Papadimitriou
        })
199 d2633501 Kostas Papadimitriou
        client.set_tokens(eppn="kpapeppn")
200 ba50648c Kostas Papadimitriou
201 31fdafa8 Kostas Papadimitriou
        astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = True
202 d2633501 Kostas Papadimitriou
        # shibboleth user info required
203 d2633501 Kostas Papadimitriou
        r = client.get('/im/login/shibboleth?', follow=True)
204 2e90e3ec Kostas Papadimitriou
        self.assertContains(r, messages.SHIBBOLETH_MISSING_NAME)
205 31fdafa8 Kostas Papadimitriou
        astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = False
206 d2633501 Kostas Papadimitriou
207 d2633501 Kostas Papadimitriou
        # shibboleth logged us in
208 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn",
209 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou",
210 ba50648c Kostas Papadimitriou
                          ep_affiliation="Test Affiliation")
211 f47ecf6b Kostas Papadimitriou
        r = client.get('/im/login/shibboleth?', follow=True)
212 9d20fe23 Kostas Papadimitriou
        token = PendingThirdPartyUser.objects.get().token
213 9d20fe23 Kostas Papadimitriou
        self.assertRedirects(r, '/im/signup?third_party_token=%s' % token)
214 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
215 d2633501 Kostas Papadimitriou
216 d2633501 Kostas Papadimitriou
        # a new pending user created
217 d2633501 Kostas Papadimitriou
        pending_user = PendingThirdPartyUser.objects.get(
218 d2633501 Kostas Papadimitriou
            third_party_identifier="kpapeppn")
219 d2633501 Kostas Papadimitriou
        self.assertEqual(PendingThirdPartyUser.objects.count(), 1)
220 ba50648c Kostas Papadimitriou
        # keep the token for future use
221 d2633501 Kostas Papadimitriou
        token = pending_user.token
222 d2633501 Kostas Papadimitriou
        # from now on no shibboleth headers are sent to the server
223 d2633501 Kostas Papadimitriou
        client.reset_tokens()
224 d2633501 Kostas Papadimitriou
225 ba50648c Kostas Papadimitriou
        # this is the old way, it should fail, to avoid pending user take over
226 d2633501 Kostas Papadimitriou
        r = client.get('/im/shibboleth/signup/%s' % pending_user.username)
227 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 404)
228 d2633501 Kostas Papadimitriou
229 9d20fe23 Kostas Papadimitriou
        # this is the signup unique url associated with the pending user
230 9d20fe23 Kostas Papadimitriou
        # created
231 ba50648c Kostas Papadimitriou
        r = client.get('/im/signup/?third_party_token=%s' % token)
232 9d20fe23 Kostas Papadimitriou
        identifier = pending_user.third_party_identifier
233 9d20fe23 Kostas Papadimitriou
        post_data = {'third_party_identifier': identifier,
234 d2633501 Kostas Papadimitriou
                     'first_name': 'Kostas',
235 d2633501 Kostas Papadimitriou
                     'third_party_token': token,
236 d2633501 Kostas Papadimitriou
                     'last_name': 'Mitroglou',
237 9d20fe23 Kostas Papadimitriou
                     'provider': 'shibboleth'}
238 ba50648c Kostas Papadimitriou
239 0a7a4104 Kostas Papadimitriou
        signup_url = reverse('signup')
240 0a7a4104 Kostas Papadimitriou
241 ba50648c Kostas Papadimitriou
        # invlid email
242 ba50648c Kostas Papadimitriou
        post_data['email'] = 'kpap'
243 0a7a4104 Kostas Papadimitriou
        r = client.post(signup_url, post_data)
244 8ab484ea Kostas Papadimitriou
        self.assertContains(r, token)
245 ba50648c Kostas Papadimitriou
246 ba50648c Kostas Papadimitriou
        # existing email
247 ba50648c Kostas Papadimitriou
        existing_user = get_local_user('test@test.com')
248 ba50648c Kostas Papadimitriou
        post_data['email'] = 'test@test.com'
249 0a7a4104 Kostas Papadimitriou
        r = client.post(signup_url, post_data)
250 ba50648c Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_USED)
251 ba50648c Kostas Papadimitriou
        existing_user.delete()
252 ba50648c Kostas Papadimitriou
253 ba50648c Kostas Papadimitriou
        # and finally a valid signup
254 8ab484ea Kostas Papadimitriou
        post_data['email'] = 'kpap@grnet.gr'
255 0a7a4104 Kostas Papadimitriou
        r = client.post(signup_url, post_data, follow=True)
256 e5966bd9 Kostas Papadimitriou
        self.assertContains(r, messages.NOTIFICATION_SENT)
257 ba50648c Kostas Papadimitriou
258 ba50648c Kostas Papadimitriou
        # everything is ok in our db
259 d2633501 Kostas Papadimitriou
        self.assertEqual(AstakosUser.objects.count(), 1)
260 d2633501 Kostas Papadimitriou
        self.assertEqual(AstakosUserAuthProvider.objects.count(), 1)
261 ba50648c Kostas Papadimitriou
        self.assertEqual(PendingThirdPartyUser.objects.count(), 0)
262 d2633501 Kostas Papadimitriou
263 ba50648c Kostas Papadimitriou
        # provider info stored
264 ba50648c Kostas Papadimitriou
        provider = AstakosUserAuthProvider.objects.get(module="shibboleth")
265 ba50648c Kostas Papadimitriou
        self.assertEqual(provider.affiliation, 'Test Affiliation')
266 ba50648c Kostas Papadimitriou
        self.assertEqual(provider.info, {u'email': u'kpap@grnet.gr',
267 e5966bd9 Kostas Papadimitriou
                                         u'eppn': u'kpapeppn',
268 e5966bd9 Kostas Papadimitriou
                                         u'name': u'Kostas Papadimitriou'})
269 d2633501 Kostas Papadimitriou
270 ba50648c Kostas Papadimitriou
        # lets login (not activated yet)
271 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn",
272 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
273 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
274 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, 'is pending moderation')
275 d2633501 Kostas Papadimitriou
276 ba50648c Kostas Papadimitriou
        # admin activates our user
277 ba50648c Kostas Papadimitriou
        u = AstakosUser.objects.get(username="kpap@grnet.gr")
278 d2633501 Kostas Papadimitriou
        functions.activate(u)
279 d2633501 Kostas Papadimitriou
        self.assertEqual(u.is_active, True)
280 d2633501 Kostas Papadimitriou
281 ba50648c Kostas Papadimitriou
        # we see our profile
282 ba50648c Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
283 478ece6c Kostas Papadimitriou
        self.assertRedirects(r, '/im/landing')
284 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
285 d2633501 Kostas Papadimitriou
286 d2633501 Kostas Papadimitriou
    def test_existing(self):
287 ba50648c Kostas Papadimitriou
        """
288 ba50648c Kostas Papadimitriou
        Test adding of third party login to an existing account
289 ba50648c Kostas Papadimitriou
        """
290 ba50648c Kostas Papadimitriou
291 ba50648c Kostas Papadimitriou
        # this is our existing user
292 d2633501 Kostas Papadimitriou
        existing_user = get_local_user('kpap@grnet.gr')
293 478ece6c Kostas Papadimitriou
        existing_inactive = get_local_user('kpap-inactive@grnet.gr')
294 478ece6c Kostas Papadimitriou
        existing_inactive.is_active = False
295 478ece6c Kostas Papadimitriou
        existing_inactive.save()
296 478ece6c Kostas Papadimitriou
297 478ece6c Kostas Papadimitriou
        existing_unverified = get_local_user('kpap-unverified@grnet.gr')
298 478ece6c Kostas Papadimitriou
        existing_unverified.is_active = False
299 478ece6c Kostas Papadimitriou
        existing_unverified.activation_sent = None
300 478ece6c Kostas Papadimitriou
        existing_unverified.email_verified = False
301 478ece6c Kostas Papadimitriou
        existing_unverified.is_verified = False
302 478ece6c Kostas Papadimitriou
        existing_unverified.save()
303 d2633501 Kostas Papadimitriou
304 d2633501 Kostas Papadimitriou
        client = ShibbolethClient()
305 d2633501 Kostas Papadimitriou
        # shibboleth logged us in, notice that we use different email
306 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
307 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
308 9d20fe23 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
309 d2633501 Kostas Papadimitriou
310 d2633501 Kostas Papadimitriou
        # a new pending user created
311 d2633501 Kostas Papadimitriou
        pending_user = PendingThirdPartyUser.objects.get()
312 9d20fe23 Kostas Papadimitriou
        token = pending_user.token
313 d2633501 Kostas Papadimitriou
        self.assertEqual(PendingThirdPartyUser.objects.count(), 1)
314 d2633501 Kostas Papadimitriou
        pending_key = pending_user.token
315 d2633501 Kostas Papadimitriou
        client.reset_tokens()
316 9d20fe23 Kostas Papadimitriou
        self.assertRedirects(r, "/im/signup?third_party_token=%s" % token)
317 d2633501 Kostas Papadimitriou
318 2a88057d Christos Stavrakakis
        form = r.context['login_form']
319 9d20fe23 Kostas Papadimitriou
        signupdata = copy.copy(form.initial)
320 9d20fe23 Kostas Papadimitriou
        signupdata['email'] = 'kpap@grnet.gr'
321 9d20fe23 Kostas Papadimitriou
        signupdata['third_party_token'] = token
322 9d20fe23 Kostas Papadimitriou
        signupdata['provider'] = 'shibboleth'
323 2a88057d Christos Stavrakakis
        signupdata.pop('id', None)
324 d2633501 Kostas Papadimitriou
325 478ece6c Kostas Papadimitriou
        # the email exists to another user
326 478ece6c Kostas Papadimitriou
        r = client.post("/im/signup", signupdata)
327 478ece6c Kostas Papadimitriou
        self.assertContains(r, "There is already an account with this email "
328 478ece6c Kostas Papadimitriou
                               "address")
329 478ece6c Kostas Papadimitriou
        # change the case, still cannot create
330 478ece6c Kostas Papadimitriou
        signupdata['email'] = 'KPAP@grnet.GR'
331 478ece6c Kostas Papadimitriou
        r = client.post("/im/signup", signupdata)
332 478ece6c Kostas Papadimitriou
        self.assertContains(r, "There is already an account with this email "
333 478ece6c Kostas Papadimitriou
                               "address")
334 478ece6c Kostas Papadimitriou
        # inactive user
335 478ece6c Kostas Papadimitriou
        signupdata['email'] = 'KPAP-inactive@grnet.GR'
336 9d20fe23 Kostas Papadimitriou
        r = client.post("/im/signup", signupdata)
337 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, "There is already an account with this email "
338 9d20fe23 Kostas Papadimitriou
                               "address")
339 d2633501 Kostas Papadimitriou
340 478ece6c Kostas Papadimitriou
        # unverified user, this should pass, old entry will be deleted
341 478ece6c Kostas Papadimitriou
        signupdata['email'] = 'KAPAP-unverified@grnet.GR'
342 478ece6c Kostas Papadimitriou
        r = client.post("/im/signup", signupdata)
343 478ece6c Kostas Papadimitriou
344 d2633501 Kostas Papadimitriou
        post_data = {'password': 'password',
345 9d20fe23 Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
346 9d20fe23 Kostas Papadimitriou
        r = client.post('/im/local', post_data, follow=True)
347 9d20fe23 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
348 9d20fe23 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
349 9d20fe23 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
350 9d20fe23 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
351 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, "enabled for this account")
352 9d20fe23 Kostas Papadimitriou
        client.reset_tokens()
353 9d20fe23 Kostas Papadimitriou
354 9d20fe23 Kostas Papadimitriou
        user = existing_user
355 9d20fe23 Kostas Papadimitriou
        self.assertTrue(user.has_auth_provider('shibboleth'))
356 9d20fe23 Kostas Papadimitriou
        self.assertTrue(user.has_auth_provider('local',
357 9d20fe23 Kostas Papadimitriou
                                               auth_backend='astakos'))
358 d2633501 Kostas Papadimitriou
        client.logout()
359 d2633501 Kostas Papadimitriou
360 d2633501 Kostas Papadimitriou
        # look Ma, i can login with both my shibboleth and local account
361 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
362 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
363 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
364 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
365 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr")
366 478ece6c Kostas Papadimitriou
        self.assertRedirects(r, '/im/landing')
367 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
368 d2633501 Kostas Papadimitriou
        client.logout()
369 d2633501 Kostas Papadimitriou
        client.reset_tokens()
370 ba50648c Kostas Papadimitriou
371 ba50648c Kostas Papadimitriou
        # logged out
372 d2633501 Kostas Papadimitriou
        r = client.get("/im/profile", follow=True)
373 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
374 d2633501 Kostas Papadimitriou
375 ba50648c Kostas Papadimitriou
        # login with local account also works
376 d2633501 Kostas Papadimitriou
        post_data = {'password': 'password',
377 d2633501 Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
378 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
379 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
380 ba50648c Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr")
381 9d20fe23 Kostas Papadimitriou
        self.assertRedirects(r, '/im/landing')
382 ba50648c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
383 d2633501 Kostas Papadimitriou
384 ba50648c Kostas Papadimitriou
        # cannot add the same eppn
385 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn",
386 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", )
387 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
388 478ece6c Kostas Papadimitriou
        self.assertRedirects(r, '/im/landing')
389 ba50648c Kostas Papadimitriou
        self.assertTrue(r.status_code, 200)
390 ba50648c Kostas Papadimitriou
        self.assertEquals(existing_user.auth_providers.count(), 2)
391 d2633501 Kostas Papadimitriou
392 9d20fe23 Kostas Papadimitriou
        # only one allowed by default
393 ba50648c Kostas Papadimitriou
        client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn2",
394 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou", ep_affiliation="affil2")
395 9d20fe23 Kostas Papadimitriou
        prov = auth_providers.get_provider('shibboleth')
396 ba50648c Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
397 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, "Failed to add")
398 ba50648c Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
399 ba50648c Kostas Papadimitriou
        self.assertTrue(r.status_code, 200)
400 9d20fe23 Kostas Papadimitriou
        self.assertEquals(existing_user.auth_providers.count(), 2)
401 d2633501 Kostas Papadimitriou
        client.logout()
402 ba50648c Kostas Papadimitriou
        client.reset_tokens()
403 ba50648c Kostas Papadimitriou
404 ba50648c Kostas Papadimitriou
        # cannot login with another eppn
405 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppninvalid",
406 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
407 d2633501 Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
408 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
409 d2633501 Kostas Papadimitriou
410 478ece6c Kostas Papadimitriou
        # cannot
411 478ece6c Kostas Papadimitriou
412 f432088a Kostas Papadimitriou
        # lets remove local password
413 f432088a Kostas Papadimitriou
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
414 f432088a Kostas Papadimitriou
                                       email="kpap@grnet.gr")
415 9d20fe23 Kostas Papadimitriou
        remove_local_url = user.get_auth_provider('local').get_remove_url
416 9d20fe23 Kostas Papadimitriou
        remove_shibbo_url = user.get_auth_provider('shibboleth',
417 9d20fe23 Kostas Papadimitriou
                                                   'kpapeppn').get_remove_url
418 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
419 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimtriou")
420 f432088a Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
421 f432088a Kostas Papadimitriou
        client.reset_tokens()
422 ba50648c Kostas Papadimitriou
423 ba50648c Kostas Papadimitriou
        # TODO: this view should use POST
424 ba50648c Kostas Papadimitriou
        r = client.get(remove_local_url)
425 ba50648c Kostas Papadimitriou
        # 2 providers left
426 f432088a Kostas Papadimitriou
        self.assertEqual(user.auth_providers.count(), 1)
427 ba50648c Kostas Papadimitriou
        # cannot remove last provider
428 ba50648c Kostas Papadimitriou
        r = client.get(remove_shibbo_url)
429 f432088a Kostas Papadimitriou
        self.assertEqual(r.status_code, 403)
430 f432088a Kostas Papadimitriou
        self.client.logout()
431 ba50648c Kostas Papadimitriou
432 ba50648c Kostas Papadimitriou
        # cannot login using local credentials (notice we use another client)
433 f432088a Kostas Papadimitriou
        post_data = {'password': 'password',
434 f432088a Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
435 f432088a Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
436 f432088a Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
437 f432088a Kostas Papadimitriou
438 ba50648c Kostas Papadimitriou
        # we can reenable the local provider by setting a password
439 f432088a Kostas Papadimitriou
        r = client.get("/im/password_change", follow=True)
440 0a7a4104 Kostas Papadimitriou
        r = client.post("/im/password_change", {'new_password1': '111',
441 f432088a Kostas Papadimitriou
                                                'new_password2': '111'},
442 f432088a Kostas Papadimitriou
                        follow=True)
443 f432088a Kostas Papadimitriou
        user = r.context['request'].user
444 f432088a Kostas Papadimitriou
        self.assertTrue(user.has_auth_provider('local'))
445 f432088a Kostas Papadimitriou
        self.assertTrue(user.has_auth_provider('shibboleth'))
446 f432088a Kostas Papadimitriou
        self.assertTrue(user.check_password('111'))
447 f432088a Kostas Papadimitriou
        self.assertTrue(user.has_usable_password())
448 f432088a Kostas Papadimitriou
        self.client.logout()
449 ba50648c Kostas Papadimitriou
450 ba50648c Kostas Papadimitriou
        # now we can login
451 f432088a Kostas Papadimitriou
        post_data = {'password': '111',
452 f432088a Kostas Papadimitriou
                     'username': 'kpap@grnet.gr'}
453 f432088a Kostas Papadimitriou
        r = self.client.post('/im/local', post_data, follow=True)
454 f432088a Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
455 f432088a Kostas Papadimitriou
456 ba50648c Kostas Papadimitriou
        client.reset_tokens()
457 f432088a Kostas Papadimitriou
458 ba50648c Kostas Papadimitriou
        # we cannot take over another shibboleth identifier
459 f432088a Kostas Papadimitriou
        user2 = get_local_user('another@grnet.gr')
460 f432088a Kostas Papadimitriou
        user2.add_auth_provider('shibboleth', identifier='existingeppn')
461 ba50648c Kostas Papadimitriou
        # login
462 e5966bd9 Kostas Papadimitriou
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn",
463 e5966bd9 Kostas Papadimitriou
                          cn="Kostas Papadimitriou")
464 f432088a Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
465 ba50648c Kostas Papadimitriou
        # try to assign existing shibboleth identifier of another user
466 9d20fe23 Kostas Papadimitriou
        client.set_tokens(mail="kpap_second@shibboleth.gr",
467 9d20fe23 Kostas Papadimitriou
                          eppn="existingeppn", cn="Kostas Papadimitriou")
468 f432088a Kostas Papadimitriou
        r = client.get("/im/login/shibboleth?", follow=True)
469 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, "this account is already assigned")
470 2e90e3ec Kostas Papadimitriou
471 d2633501 Kostas Papadimitriou
472 478ece6c Kostas Papadimitriou
class TestLocal(TestCase):
473 d2633501 Kostas Papadimitriou
474 d2633501 Kostas Papadimitriou
    fixtures = ['groups']
475 d2633501 Kostas Papadimitriou
476 2e90e3ec Kostas Papadimitriou
    def setUp(self):
477 2e90e3ec Kostas Papadimitriou
        settings.ADMINS = (('admin', 'support@cloud.grnet.gr'),)
478 2e90e3ec Kostas Papadimitriou
        settings.SERVER_EMAIL = 'no-reply@grnet.gr'
479 9d20fe23 Kostas Papadimitriou
        self._orig_moderation = astakos_settings.MODERATION_ENABLED
480 9d20fe23 Kostas Papadimitriou
        settings.ASTAKOS_MODERATION_ENABLED = True
481 9d20fe23 Kostas Papadimitriou
482 9d20fe23 Kostas Papadimitriou
    def tearDown(self):
483 9d20fe23 Kostas Papadimitriou
        settings.ASTAKOS_MODERATION_ENABLED = self._orig_moderation
484 2e90e3ec Kostas Papadimitriou
485 7233d542 Kostas Papadimitriou
    def test_no_moderation(self):
486 ba50648c Kostas Papadimitriou
        # disable moderation
487 7233d542 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = False
488 ba50648c Kostas Papadimitriou
489 ba50648c Kostas Papadimitriou
        # create a new user
490 7233d542 Kostas Papadimitriou
        r = self.client.get("/im/signup")
491 7233d542 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
492 9d20fe23 Kostas Papadimitriou
        data = {'email': 'kpap@grnet.gr', 'password1': 'password',
493 9d20fe23 Kostas Papadimitriou
                'password2': 'password', 'first_name': 'Kostas',
494 7233d542 Kostas Papadimitriou
                'last_name': 'Mitroglou', 'provider': 'local'}
495 7233d542 Kostas Papadimitriou
        r = self.client.post("/im/signup", data)
496 ba50648c Kostas Papadimitriou
497 ba50648c Kostas Papadimitriou
        # user created
498 7233d542 Kostas Papadimitriou
        self.assertEqual(AstakosUser.objects.count(), 1)
499 7233d542 Kostas Papadimitriou
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
500 7233d542 Kostas Papadimitriou
                                       email="kpap@grnet.gr")
501 7233d542 Kostas Papadimitriou
        self.assertEqual(user.username, 'kpap@grnet.gr')
502 7233d542 Kostas Papadimitriou
        self.assertEqual(user.has_auth_provider('local'), True)
503 7233d542 Kostas Papadimitriou
        self.assertFalse(user.is_active)
504 7233d542 Kostas Papadimitriou
505 ba50648c Kostas Papadimitriou
        # user (but not admin) gets notified
506 7233d542 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('support@cloud.grnet.gr')), 0)
507 7233d542 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
508 7233d542 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
509 d2633501 Kostas Papadimitriou
510 e5966bd9 Kostas Papadimitriou
    def test_email_case(self):
511 e5966bd9 Kostas Papadimitriou
        data = {
512 9d20fe23 Kostas Papadimitriou
            'email': 'kPap@grnet.gr',
513 9d20fe23 Kostas Papadimitriou
            'password1': '1234',
514 9d20fe23 Kostas Papadimitriou
            'password2': '1234'
515 e5966bd9 Kostas Papadimitriou
        }
516 e5966bd9 Kostas Papadimitriou
517 e5966bd9 Kostas Papadimitriou
        form = forms.LocalUserCreationForm(data)
518 e5966bd9 Kostas Papadimitriou
        self.assertTrue(form.is_valid())
519 e5966bd9 Kostas Papadimitriou
        user = form.save()
520 e5966bd9 Kostas Papadimitriou
        form.store_user(user, {})
521 e5966bd9 Kostas Papadimitriou
522 9d20fe23 Kostas Papadimitriou
        u = AstakosUser.objects.get()
523 e5966bd9 Kostas Papadimitriou
        self.assertEqual(u.email, 'kPap@grnet.gr')
524 e5966bd9 Kostas Papadimitriou
        self.assertEqual(u.username, 'kpap@grnet.gr')
525 e5966bd9 Kostas Papadimitriou
        u.is_active = True
526 e5966bd9 Kostas Papadimitriou
        u.email_verified = True
527 e5966bd9 Kostas Papadimitriou
        u.save()
528 e5966bd9 Kostas Papadimitriou
529 e5966bd9 Kostas Papadimitriou
        data = {'username': 'kpap@grnet.gr', 'password': '1234'}
530 e5966bd9 Kostas Papadimitriou
        login = forms.LoginForm(data=data)
531 e5966bd9 Kostas Papadimitriou
        self.assertTrue(login.is_valid())
532 e5966bd9 Kostas Papadimitriou
533 e5966bd9 Kostas Papadimitriou
        data = {'username': 'KpaP@grnet.gr', 'password': '1234'}
534 e5966bd9 Kostas Papadimitriou
        login = forms.LoginForm(data=data)
535 e5966bd9 Kostas Papadimitriou
        self.assertTrue(login.is_valid())
536 e5966bd9 Kostas Papadimitriou
537 e5966bd9 Kostas Papadimitriou
        data = {
538 9d20fe23 Kostas Papadimitriou
            'email': 'kpap@grnet.gr',
539 9d20fe23 Kostas Papadimitriou
            'password1': '1234',
540 9d20fe23 Kostas Papadimitriou
            'password2': '1234'
541 e5966bd9 Kostas Papadimitriou
        }
542 e5966bd9 Kostas Papadimitriou
        form = forms.LocalUserCreationForm(data)
543 e5966bd9 Kostas Papadimitriou
        self.assertFalse(form.is_valid())
544 e5966bd9 Kostas Papadimitriou
545 0a7a4104 Kostas Papadimitriou
    @im_settings(HELPDESK=(('support', 'support@synnefo.org'),))
546 0a7a4104 Kostas Papadimitriou
    @im_settings(FORCE_PROFILE_UPDATE=False)
547 d2633501 Kostas Papadimitriou
    def test_local_provider(self):
548 19a992e3 Kostas Papadimitriou
        self.helpdesk_email = astakos_settings.HELPDESK[0][1]
549 ba50648c Kostas Papadimitriou
        # enable moderation
550 7233d542 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
551 ba50648c Kostas Papadimitriou
552 ba50648c Kostas Papadimitriou
        # create a user
553 d2633501 Kostas Papadimitriou
        r = self.client.get("/im/signup")
554 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
555 9d20fe23 Kostas Papadimitriou
        data = {'email': 'kpap@grnet.gr', 'password1': 'password',
556 9d20fe23 Kostas Papadimitriou
                'password2': 'password', 'first_name': 'Kostas',
557 d2633501 Kostas Papadimitriou
                'last_name': 'Mitroglou', 'provider': 'local'}
558 d2633501 Kostas Papadimitriou
        r = self.client.post("/im/signup", data)
559 ba50648c Kostas Papadimitriou
560 ba50648c Kostas Papadimitriou
        # user created
561 d2633501 Kostas Papadimitriou
        self.assertEqual(AstakosUser.objects.count(), 1)
562 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
563 d2633501 Kostas Papadimitriou
                                       email="kpap@grnet.gr")
564 d2633501 Kostas Papadimitriou
        self.assertEqual(user.username, 'kpap@grnet.gr')
565 d2633501 Kostas Papadimitriou
        self.assertEqual(user.has_auth_provider('local'), True)
566 9d20fe23 Kostas Papadimitriou
        self.assertFalse(user.is_active)  # not activated
567 9d20fe23 Kostas Papadimitriou
        self.assertFalse(user.email_verified)  # not verified
568 9d20fe23 Kostas Papadimitriou
        self.assertFalse(user.activation_sent)  # activation automatically sent
569 d2633501 Kostas Papadimitriou
570 ba50648c Kostas Papadimitriou
        # admin gets notified and activates the user from the command line
571 19a992e3 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox(self.helpdesk_email)), 1)
572 31fdafa8 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
573 9d20fe23 Kostas Papadimitriou
                                           'password': 'password'})
574 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, messages.NOTIFICATION_SENT)
575 d2633501 Kostas Papadimitriou
        functions.send_activation(user)
576 d2633501 Kostas Papadimitriou
577 ba50648c Kostas Papadimitriou
        # user activation fields updated and user gets notified via email
578 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
579 d2633501 Kostas Papadimitriou
        self.assertTrue(user.activation_sent)
580 d2633501 Kostas Papadimitriou
        self.assertFalse(user.email_verified)
581 f47ecf6b Kostas Papadimitriou
        self.assertFalse(user.is_active)
582 d2633501 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
583 d2633501 Kostas Papadimitriou
584 d2633501 Kostas Papadimitriou
        # user forgot she got registered and tries to submit registration
585 d2633501 Kostas Papadimitriou
        # form. Notice the upper case in email
586 9d20fe23 Kostas Papadimitriou
        data = {'email': 'KPAP@grnet.gr', 'password1': 'password',
587 9d20fe23 Kostas Papadimitriou
                'password2': 'password', 'first_name': 'Kostas',
588 d2633501 Kostas Papadimitriou
                'last_name': 'Mitroglou', 'provider': 'local'}
589 564a2292 Kostas Papadimitriou
        r = self.client.post("/im/signup", data, follow=True)
590 564a2292 Kostas Papadimitriou
        self.assertRedirects(r, reverse('index'))
591 564a2292 Kostas Papadimitriou
        self.assertContains(r, messages.NOTIFICATION_SENT)
592 564a2292 Kostas Papadimitriou
593 9d20fe23 Kostas Papadimitriou
        user = AstakosUser.objects.get()
594 9d20fe23 Kostas Papadimitriou
        functions.send_activation(user)
595 9d20fe23 Kostas Papadimitriou
596 564a2292 Kostas Papadimitriou
        # previous user replaced
597 564a2292 Kostas Papadimitriou
        self.assertTrue(user.activation_sent)
598 564a2292 Kostas Papadimitriou
        self.assertFalse(user.email_verified)
599 564a2292 Kostas Papadimitriou
        self.assertFalse(user.is_active)
600 9d20fe23 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('KPAP@grnet.gr')), 1)
601 d2633501 Kostas Papadimitriou
602 f47ecf6b Kostas Papadimitriou
        # hmmm, email exists; lets request a password change
603 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/local/password_reset')
604 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
605 9d20fe23 Kostas Papadimitriou
        data = {'email': 'kpap@grnet.gr'}
606 9d20fe23 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', data, follow=True)
607 d2633501 Kostas Papadimitriou
        # she can't because account is not active yet
608 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, 'pending activation')
609 d2633501 Kostas Papadimitriou
610 9d20fe23 Kostas Papadimitriou
        # moderation is enabled and an activation email has already been sent
611 9d20fe23 Kostas Papadimitriou
        # so user can trigger resend of the activation email
612 9d20fe23 Kostas Papadimitriou
        r = self.client.get('/im/send/activation/%d' % user.pk, follow=True)
613 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, 'has been sent to your email address.')
614 9d20fe23 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('KPAP@grnet.gr')), 2)
615 ba50648c Kostas Papadimitriou
616 d2633501 Kostas Papadimitriou
        # also she cannot login
617 9d20fe23 Kostas Papadimitriou
        data = {'username': 'kpap@grnet.gr', 'password': 'password'}
618 9d20fe23 Kostas Papadimitriou
        r = self.client.post('/im/local', data, follow=True)
619 d2633501 Kostas Papadimitriou
        self.assertContains(r, 'Resend activation')
620 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
621 d2633501 Kostas Papadimitriou
        self.assertFalse('_pithos2_a' in self.client.cookies)
622 ba50648c Kostas Papadimitriou
623 d2633501 Kostas Papadimitriou
        # user sees the message and resends activation
624 9d20fe23 Kostas Papadimitriou
        r = self.client.get('/im/send/activation/%d' % user.pk, follow=True)
625 9d20fe23 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('KPAP@grnet.gr')), 3)
626 d2633501 Kostas Papadimitriou
627 d2633501 Kostas Papadimitriou
        # switch back moderation setting
628 d2633501 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
629 d2633501 Kostas Papadimitriou
        r = self.client.get(user.get_activation_url(), follow=True)
630 9d20fe23 Kostas Papadimitriou
        self.assertRedirects(r, "/im/landing")
631 9d20fe23 Kostas Papadimitriou
        r = self.client.get('/im/profile', follow=True)
632 9d20fe23 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
633 9d20fe23 Kostas Papadimitriou
        self.assertTrue('_pithos2_a' in self.client.cookies)
634 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, "KPAP@grnet.gr")
635 9d20fe23 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('KPAP@grnet.gr')), 4)
636 d2633501 Kostas Papadimitriou
637 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
638 d2633501 Kostas Papadimitriou
        # user activated and logged in, token cookie set
639 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
640 d2633501 Kostas Papadimitriou
        self.assertTrue('_pithos2_a' in self.client.cookies)
641 d2633501 Kostas Papadimitriou
        cookies = self.client.cookies
642 9d20fe23 Kostas Papadimitriou
        self.assertTrue(quote(user.auth_token) in
643 9d20fe23 Kostas Papadimitriou
                        cookies.get('_pithos2_a').value)
644 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/logout', follow=True)
645 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/')
646 d2633501 Kostas Papadimitriou
        # user logged out, token cookie removed
647 d2633501 Kostas Papadimitriou
        self.assertFalse(r.context['request'].user.is_authenticated())
648 d2633501 Kostas Papadimitriou
        self.assertFalse(self.client.cookies.get('_pithos2_a').value)
649 9d20fe23 Kostas Papadimitriou
650 9d20fe23 Kostas Papadimitriou
        #https://docs.djangoproject.com/en/dev/topics/testing/#persistent-state
651 d2633501 Kostas Papadimitriou
        del self.client.cookies['_pithos2_a']
652 d2633501 Kostas Papadimitriou
653 d2633501 Kostas Papadimitriou
        # user can login
654 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
655 d2633501 Kostas Papadimitriou
                                           'password': 'password'},
656 9d20fe23 Kostas Papadimitriou
                             follow=True)
657 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
658 d2633501 Kostas Papadimitriou
        self.assertTrue('_pithos2_a' in self.client.cookies)
659 d2633501 Kostas Papadimitriou
        cookies = self.client.cookies
660 9d20fe23 Kostas Papadimitriou
        self.assertTrue(quote(user.auth_token) in
661 9d20fe23 Kostas Papadimitriou
                        cookies.get('_pithos2_a').value)
662 d2633501 Kostas Papadimitriou
        self.client.get('/im/logout', follow=True)
663 d2633501 Kostas Papadimitriou
664 d2633501 Kostas Papadimitriou
        # user forgot password
665 d2633501 Kostas Papadimitriou
        old_pass = user.password
666 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/local/password_reset')
667 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
668 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', {'email':
669 d2633501 Kostas Papadimitriou
                                                          'kpap@grnet.gr'})
670 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 302)
671 d2633501 Kostas Papadimitriou
        # email sent
672 9d20fe23 Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('KPAP@grnet.gr')), 5)
673 d2633501 Kostas Papadimitriou
674 d2633501 Kostas Papadimitriou
        # user visits change password link
675 95150b7d Christos Stavrakakis
        # "Refresh" user because created url is based on last_login timestamp
676 126f6a55 Christos Stavrakakis
        user = AstakosUser.objects.get(pk=user.pk)
677 d2633501 Kostas Papadimitriou
        r = self.client.get(user.get_password_reset_url())
678 d2633501 Kostas Papadimitriou
        r = self.client.post(user.get_password_reset_url(),
679 9d20fe23 Kostas Papadimitriou
                             {'new_password1': 'newpass',
680 9d20fe23 Kostas Papadimitriou
                              'new_password2': 'newpass'})
681 d2633501 Kostas Papadimitriou
682 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
683 d2633501 Kostas Papadimitriou
        self.assertNotEqual(old_pass, user.password)
684 d2633501 Kostas Papadimitriou
685 d2633501 Kostas Papadimitriou
        # old pass is not usable
686 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
687 d2633501 Kostas Papadimitriou
                                           'password': 'password'})
688 31fdafa8 Kostas Papadimitriou
        self.assertContains(r, 'Please enter a correct username and password')
689 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
690 d2633501 Kostas Papadimitriou
                                           'password': 'newpass'},
691 478ece6c Kostas Papadimitriou
                             follow=True)
692 d2633501 Kostas Papadimitriou
        self.assertTrue(r.context['request'].user.is_authenticated())
693 d2633501 Kostas Papadimitriou
        self.client.logout()
694 d2633501 Kostas Papadimitriou
695 d2633501 Kostas Papadimitriou
        # tests of special local backends
696 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get(pk=user.pk)
697 d2633501 Kostas Papadimitriou
        user.auth_providers.filter(module='local').update(auth_backend='ldap')
698 d2633501 Kostas Papadimitriou
        user.save()
699 d2633501 Kostas Papadimitriou
700 d2633501 Kostas Papadimitriou
        # non astakos local backends do not support password reset
701 d2633501 Kostas Papadimitriou
        r = self.client.get('/im/local/password_reset')
702 d2633501 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
703 d2633501 Kostas Papadimitriou
        r = self.client.post('/im/local/password_reset', {'email':
704 d2633501 Kostas Papadimitriou
                                                          'kpap@grnet.gr'})
705 d2633501 Kostas Papadimitriou
        # she can't because account is not active yet
706 9d20fe23 Kostas Papadimitriou
        self.assertContains(r, "Changing password is not")
707 9d20fe23 Kostas Papadimitriou
708 9d20fe23 Kostas Papadimitriou
709 34a76cdb Kostas Papadimitriou
class UserActionsTests(TestCase):
710 34a76cdb Kostas Papadimitriou
711 34a76cdb Kostas Papadimitriou
    def test_email_change(self):
712 34a76cdb Kostas Papadimitriou
        # to test existing email validation
713 478ece6c Kostas Papadimitriou
        get_local_user('existing@grnet.gr')
714 34a76cdb Kostas Papadimitriou
715 34a76cdb Kostas Papadimitriou
        # local user
716 34a76cdb Kostas Papadimitriou
        user = get_local_user('kpap@grnet.gr')
717 34a76cdb Kostas Papadimitriou
718 34a76cdb Kostas Papadimitriou
        # login as kpap
719 34a76cdb Kostas Papadimitriou
        self.client.login(username='kpap@grnet.gr', password='password')
720 34a76cdb Kostas Papadimitriou
        r = self.client.get('/im/profile', follow=True)
721 34a76cdb Kostas Papadimitriou
        user = r.context['request'].user
722 34a76cdb Kostas Papadimitriou
        self.assertTrue(user.is_authenticated())
723 34a76cdb Kostas Papadimitriou
724 34a76cdb Kostas Papadimitriou
        # change email is enabled
725 34a76cdb Kostas Papadimitriou
        r = self.client.get('/im/email_change')
726 34a76cdb Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
727 34a76cdb Kostas Papadimitriou
        self.assertFalse(user.email_change_is_pending())
728 34a76cdb Kostas Papadimitriou
729 34a76cdb Kostas Papadimitriou
        # request email change to an existing email fails
730 34a76cdb Kostas Papadimitriou
        data = {'new_email_address': 'existing@grnet.gr'}
731 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/email_change', data)
732 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_USED)
733 34a76cdb Kostas Papadimitriou
734 34a76cdb Kostas Papadimitriou
        # proper email change
735 34a76cdb Kostas Papadimitriou
        data = {'new_email_address': 'kpap@gmail.com'}
736 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/email_change', data, follow=True)
737 34a76cdb Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
738 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_CHANGE_REGISTERED)
739 34a76cdb Kostas Papadimitriou
        change1 = EmailChange.objects.get()
740 34a76cdb Kostas Papadimitriou
741 34a76cdb Kostas Papadimitriou
        # user sees a warning
742 34a76cdb Kostas Papadimitriou
        r = self.client.get('/im/email_change')
743 34a76cdb Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
744 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.PENDING_EMAIL_CHANGE_REQUEST)
745 34a76cdb Kostas Papadimitriou
        self.assertTrue(user.email_change_is_pending())
746 34a76cdb Kostas Papadimitriou
747 34a76cdb Kostas Papadimitriou
        # link was sent
748 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 0)
749 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@gmail.com')), 1)
750 34a76cdb Kostas Papadimitriou
751 34a76cdb Kostas Papadimitriou
        # proper email change
752 34a76cdb Kostas Papadimitriou
        data = {'new_email_address': 'kpap@yahoo.com'}
753 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/email_change', data, follow=True)
754 34a76cdb Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
755 34a76cdb Kostas Papadimitriou
        self.assertContains(r, messages.EMAIL_CHANGE_REGISTERED)
756 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 0)
757 34a76cdb Kostas Papadimitriou
        self.assertEqual(len(get_mailbox('kpap@yahoo.com')), 1)
758 34a76cdb Kostas Papadimitriou
        change2 = EmailChange.objects.get()
759 34a76cdb Kostas Papadimitriou
760 34a76cdb Kostas Papadimitriou
        r = self.client.get(change1.get_url())
761 34a76cdb Kostas Papadimitriou
        self.assertEquals(r.status_code, 302)
762 34a76cdb Kostas Papadimitriou
        self.client.logout()
763 34a76cdb Kostas Papadimitriou
764 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/local?next=' + change2.get_url(),
765 34a76cdb Kostas Papadimitriou
                             {'username': 'kpap@grnet.gr',
766 34a76cdb Kostas Papadimitriou
                              'password': 'password',
767 34a76cdb Kostas Papadimitriou
                              'next': change2.get_url()},
768 34a76cdb Kostas Papadimitriou
                             follow=True)
769 34a76cdb Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
770 34a76cdb Kostas Papadimitriou
        user = r.context['request'].user
771 34a76cdb Kostas Papadimitriou
        self.assertEquals(user.email, 'kpap@yahoo.com')
772 34a76cdb Kostas Papadimitriou
        self.assertEquals(user.username, 'kpap@yahoo.com')
773 34a76cdb Kostas Papadimitriou
774 34a76cdb Kostas Papadimitriou
        self.client.logout()
775 34a76cdb Kostas Papadimitriou
        r = self.client.post('/im/local?next=' + change2.get_url(),
776 34a76cdb Kostas Papadimitriou
                             {'username': 'kpap@grnet.gr',
777 34a76cdb Kostas Papadimitriou
                              'password': 'password',
778 34a76cdb Kostas Papadimitriou
                              'next': change2.get_url()},
779 34a76cdb Kostas Papadimitriou
                             follow=True)
780 34a76cdb Kostas Papadimitriou
        self.assertContains(r, "Please enter a correct username and password")
781 34a76cdb Kostas Papadimitriou
        self.assertEqual(user.emailchanges.count(), 0)
782 34a76cdb Kostas Papadimitriou
783 9d20fe23 Kostas Papadimitriou
784 478ece6c Kostas Papadimitriou
class TestAuthProviderViews(TestCase):
785 478ece6c Kostas Papadimitriou
786 478ece6c Kostas Papadimitriou
    @shibboleth_settings(CREATION_GROUPS_POLICY=['academic-login'])
787 478ece6c Kostas Papadimitriou
    @shibboleth_settings(AUTOMODERATE_POLICY=True)
788 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['shibboleth', 'local'])
789 478ece6c Kostas Papadimitriou
    @im_settings(MODERATION_ENABLED=True)
790 0a7a4104 Kostas Papadimitriou
    @im_settings(FORCE_PROFILE_UPDATE=False)
791 478ece6c Kostas Papadimitriou
    def test_user(self):
792 478ece6c Kostas Papadimitriou
        Profile = AuthProviderPolicyProfile
793 478ece6c Kostas Papadimitriou
        Pending = PendingThirdPartyUser
794 478ece6c Kostas Papadimitriou
        User = AstakosUser
795 478ece6c Kostas Papadimitriou
796 0a7a4104 Kostas Papadimitriou
        User.objects.create(email="newuser@grnet.gr")
797 0a7a4104 Kostas Papadimitriou
        get_local_user("olduser@grnet.gr")
798 478ece6c Kostas Papadimitriou
        cl_olduser = ShibbolethClient()
799 0a7a4104 Kostas Papadimitriou
        get_local_user("olduser2@grnet.gr")
800 0a7a4104 Kostas Papadimitriou
        ShibbolethClient()
801 478ece6c Kostas Papadimitriou
        cl_newuser = ShibbolethClient()
802 478ece6c Kostas Papadimitriou
        cl_newuser2 = Client()
803 478ece6c Kostas Papadimitriou
804 478ece6c Kostas Papadimitriou
        academic_group, created = Group.objects.get_or_create(
805 478ece6c Kostas Papadimitriou
            name='academic-login')
806 478ece6c Kostas Papadimitriou
        academic_users = academic_group.user_set
807 478ece6c Kostas Papadimitriou
        assert created
808 478ece6c Kostas Papadimitriou
        policy_only_academic = Profile.objects.add_policy('academic_strict',
809 478ece6c Kostas Papadimitriou
                                                          'shibboleth',
810 478ece6c Kostas Papadimitriou
                                                          academic_group,
811 478ece6c Kostas Papadimitriou
                                                          exclusive=True,
812 478ece6c Kostas Papadimitriou
                                                          login=False,
813 478ece6c Kostas Papadimitriou
                                                          add=False)
814 478ece6c Kostas Papadimitriou
815 478ece6c Kostas Papadimitriou
816 478ece6c Kostas Papadimitriou
        # new academic user
817 478ece6c Kostas Papadimitriou
        self.assertFalse(academic_users.filter(email='newuser@grnet.gr'))
818 478ece6c Kostas Papadimitriou
        cl_newuser.set_tokens(eppn="newusereppn")
819 478ece6c Kostas Papadimitriou
        r = cl_newuser.get('/im/login/shibboleth?', follow=True)
820 478ece6c Kostas Papadimitriou
        pending = Pending.objects.get()
821 478ece6c Kostas Papadimitriou
        identifier = pending.third_party_identifier
822 478ece6c Kostas Papadimitriou
        signup_data = {'third_party_identifier': identifier,
823 478ece6c Kostas Papadimitriou
                       'first_name': 'Academic',
824 478ece6c Kostas Papadimitriou
                       'third_party_token': pending.token,
825 478ece6c Kostas Papadimitriou
                       'last_name': 'New User',
826 478ece6c Kostas Papadimitriou
                       'provider': 'shibboleth'}
827 478ece6c Kostas Papadimitriou
        r = cl_newuser.post('/im/signup', signup_data)
828 478ece6c Kostas Papadimitriou
        self.assertContains(r, "This field is required", )
829 478ece6c Kostas Papadimitriou
        signup_data['email'] = 'olduser@grnet.gr'
830 478ece6c Kostas Papadimitriou
        r = cl_newuser.post('/im/signup', signup_data)
831 478ece6c Kostas Papadimitriou
        self.assertContains(r, "already an account with this email", )
832 478ece6c Kostas Papadimitriou
        signup_data['email'] = 'newuser@grnet.gr'
833 478ece6c Kostas Papadimitriou
        r = cl_newuser.post('/im/signup', signup_data, follow=True)
834 478ece6c Kostas Papadimitriou
        r = cl_newuser.post('/im/signup', signup_data, follow=True)
835 478ece6c Kostas Papadimitriou
        self.assertEqual(r.status_code, 404)
836 478ece6c Kostas Papadimitriou
        newuser = User.objects.get(email="newuser@grnet.gr")
837 478ece6c Kostas Papadimitriou
        activation_link = newuser.get_activation_url()
838 478ece6c Kostas Papadimitriou
        self.assertTrue(academic_users.get(email='newuser@grnet.gr'))
839 478ece6c Kostas Papadimitriou
840 478ece6c Kostas Papadimitriou
        # new non-academic user
841 478ece6c Kostas Papadimitriou
        signup_data = {'first_name': 'Non Academic',
842 478ece6c Kostas Papadimitriou
                       'last_name': 'New User',
843 478ece6c Kostas Papadimitriou
                       'provider': 'local',
844 478ece6c Kostas Papadimitriou
                       'password1': 'password',
845 478ece6c Kostas Papadimitriou
                       'password2': 'password'}
846 478ece6c Kostas Papadimitriou
        signup_data['email'] = 'olduser@grnet.gr'
847 478ece6c Kostas Papadimitriou
        r = cl_newuser2.post('/im/signup', signup_data)
848 478ece6c Kostas Papadimitriou
        self.assertContains(r, 'There is already an account with this '
849 478ece6c Kostas Papadimitriou
                               'email address')
850 478ece6c Kostas Papadimitriou
        signup_data['email'] = 'newuser@grnet.gr'
851 478ece6c Kostas Papadimitriou
        r = cl_newuser2.post('/im/signup/', signup_data)
852 478ece6c Kostas Papadimitriou
        self.assertFalse(academic_users.filter(email='newuser@grnet.gr'))
853 478ece6c Kostas Papadimitriou
        r = self.client.get(activation_link, follow=True)
854 478ece6c Kostas Papadimitriou
        self.assertEqual(r.status_code, 400)
855 478ece6c Kostas Papadimitriou
        newuser = User.objects.get(email="newuser@grnet.gr")
856 478ece6c Kostas Papadimitriou
        self.assertFalse(newuser.activation_sent)
857 478ece6c Kostas Papadimitriou
        r = self.client.get(newuser.get_activation_url(), follow=True)
858 478ece6c Kostas Papadimitriou
        self.assertContains(r, "pending moderation")
859 478ece6c Kostas Papadimitriou
860 478ece6c Kostas Papadimitriou
        self.assertFalse(academic_users.filter(email='newuser@grnet.gr'))
861 478ece6c Kostas Papadimitriou
        r = cl_newuser.get('/im/login/shibboleth?', follow=True)
862 478ece6c Kostas Papadimitriou
        pending = Pending.objects.get()
863 478ece6c Kostas Papadimitriou
        identifier = pending.third_party_identifier
864 478ece6c Kostas Papadimitriou
        signup_data = {'third_party_identifier': identifier,
865 478ece6c Kostas Papadimitriou
                       'first_name': 'Academic',
866 478ece6c Kostas Papadimitriou
                       'third_party_token': pending.token,
867 478ece6c Kostas Papadimitriou
                       'last_name': 'New User',
868 478ece6c Kostas Papadimitriou
                       'provider': 'shibboleth'}
869 478ece6c Kostas Papadimitriou
        signup_data['email'] = 'newuser@grnet.gr'
870 478ece6c Kostas Papadimitriou
        r = cl_newuser.post('/im/signup', signup_data)
871 478ece6c Kostas Papadimitriou
        newuser = User.objects.get(email="newuser@grnet.gr")
872 478ece6c Kostas Papadimitriou
        self.assertTrue(newuser.activation_sent)
873 478ece6c Kostas Papadimitriou
        activation_link = newuser.get_activation_url()
874 478ece6c Kostas Papadimitriou
        self.assertTrue(academic_users.get(email='newuser@grnet.gr'))
875 478ece6c Kostas Papadimitriou
        r = cl_newuser.get(newuser.get_activation_url(), follow=True)
876 478ece6c Kostas Papadimitriou
        self.assertRedirects(r, '/im/landing')
877 478ece6c Kostas Papadimitriou
        newuser = User.objects.get(email="newuser@grnet.gr")
878 478ece6c Kostas Papadimitriou
        self.assertEqual(newuser.is_active, True)
879 478ece6c Kostas Papadimitriou
        self.assertEqual(newuser.email_verified, True)
880 478ece6c Kostas Papadimitriou
        cl_newuser.logout()
881 478ece6c Kostas Papadimitriou
882 478ece6c Kostas Papadimitriou
        # cannot reactivate if suspended
883 478ece6c Kostas Papadimitriou
        newuser.is_active = False
884 478ece6c Kostas Papadimitriou
        newuser.save()
885 478ece6c Kostas Papadimitriou
        r = cl_newuser.get(newuser.get_activation_url())
886 478ece6c Kostas Papadimitriou
        newuser = User.objects.get(email="newuser@grnet.gr")
887 478ece6c Kostas Papadimitriou
        self.assertFalse(newuser.is_active)
888 478ece6c Kostas Papadimitriou
889 478ece6c Kostas Papadimitriou
        # release suspension
890 478ece6c Kostas Papadimitriou
        newuser.is_active = True
891 478ece6c Kostas Papadimitriou
        newuser.save()
892 478ece6c Kostas Papadimitriou
893 478ece6c Kostas Papadimitriou
        cl_newuser.get('/im/login/shibboleth?', follow=True)
894 478ece6c Kostas Papadimitriou
        local = auth.get_provider('local', newuser)
895 478ece6c Kostas Papadimitriou
        self.assertEqual(local.get_add_policy, False)
896 478ece6c Kostas Papadimitriou
        self.assertEqual(local.get_login_policy, False)
897 478ece6c Kostas Papadimitriou
        r = cl_newuser.get(local.get_add_url, follow=True)
898 478ece6c Kostas Papadimitriou
        self.assertRedirects(r, '/im/profile')
899 478ece6c Kostas Papadimitriou
        self.assertContains(r, 'disabled for your')
900 478ece6c Kostas Papadimitriou
901 478ece6c Kostas Papadimitriou
        cl_olduser.login(username='olduser@grnet.gr', password="password")
902 478ece6c Kostas Papadimitriou
        r = cl_olduser.get('/im/profile', follow=True)
903 478ece6c Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
904 478ece6c Kostas Papadimitriou
        r = cl_olduser.get('/im/login/shibboleth?', follow=True)
905 478ece6c Kostas Papadimitriou
        self.assertContains(r, 'Your request is missing a unique token')
906 478ece6c Kostas Papadimitriou
        cl_olduser.set_tokens(eppn="newusereppn")
907 478ece6c Kostas Papadimitriou
        r = cl_olduser.get('/im/login/shibboleth?', follow=True)
908 478ece6c Kostas Papadimitriou
        self.assertContains(r, 'is already assigned to another user')
909 478ece6c Kostas Papadimitriou
        cl_olduser.set_tokens(eppn="oldusereppn")
910 478ece6c Kostas Papadimitriou
        r = cl_olduser.get('/im/login/shibboleth?', follow=True)
911 478ece6c Kostas Papadimitriou
        self.assertContains(r, 'Academic login enabled for this account')
912 478ece6c Kostas Papadimitriou
913 478ece6c Kostas Papadimitriou
        user = User.objects.get(email="olduser@grnet.gr")
914 478ece6c Kostas Papadimitriou
        shib_provider = user.get_auth_provider('shibboleth', 'oldusereppn')
915 478ece6c Kostas Papadimitriou
        local_provider = user.get_auth_provider('local')
916 478ece6c Kostas Papadimitriou
        self.assertEqual(shib_provider.get_remove_policy, True)
917 478ece6c Kostas Papadimitriou
        self.assertEqual(local_provider.get_remove_policy, True)
918 478ece6c Kostas Papadimitriou
919 478ece6c Kostas Papadimitriou
920 478ece6c Kostas Papadimitriou
        policy_only_academic = Profile.objects.add_policy('academic_strict2',
921 478ece6c Kostas Papadimitriou
                                                          'shibboleth',
922 478ece6c Kostas Papadimitriou
                                                          academic_group,
923 478ece6c Kostas Papadimitriou
                                                          remove=False)
924 478ece6c Kostas Papadimitriou
        user.groups.add(academic_group)
925 478ece6c Kostas Papadimitriou
        shib_provider = user.get_auth_provider('shibboleth', 'oldusereppn')
926 478ece6c Kostas Papadimitriou
        local_provider = user.get_auth_provider('local')
927 478ece6c Kostas Papadimitriou
        self.assertEqual(shib_provider.get_remove_policy, False)
928 478ece6c Kostas Papadimitriou
        self.assertEqual(local_provider.get_remove_policy, True)
929 478ece6c Kostas Papadimitriou
        self.assertEqual(local_provider.get_login_policy, False)
930 478ece6c Kostas Papadimitriou
931 478ece6c Kostas Papadimitriou
        cl_olduser.logout()
932 478ece6c Kostas Papadimitriou
        login_data = {'username': 'olduser@grnet.gr', 'password': 'password'}
933 478ece6c Kostas Papadimitriou
        r = cl_olduser.post('/im/local', login_data, follow=True)
934 478ece6c Kostas Papadimitriou
        self.assertContains(r, "href='/im/login/shibboleth'>Academic login")
935 9d20fe23 Kostas Papadimitriou
936 9d20fe23 Kostas Papadimitriou
937 478ece6c Kostas Papadimitriou
class TestAuthProvidersAPI(TestCase):
938 478ece6c Kostas Papadimitriou
    """
939 478ece6c Kostas Papadimitriou
    Test auth_providers module API
940 478ece6c Kostas Papadimitriou
    """
941 478ece6c Kostas Papadimitriou
942 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
943 9d20fe23 Kostas Papadimitriou
    def test_create(self):
944 9d20fe23 Kostas Papadimitriou
        user = AstakosUser.objects.create(email="kpap@grnet.gr")
945 9d20fe23 Kostas Papadimitriou
        user2 = AstakosUser.objects.create(email="kpap2@grnet.gr")
946 9d20fe23 Kostas Papadimitriou
947 9d20fe23 Kostas Papadimitriou
        module = 'shibboleth'
948 9d20fe23 Kostas Papadimitriou
        identifier = 'SHIB_UUID'
949 9d20fe23 Kostas Papadimitriou
        provider_params = {
950 9d20fe23 Kostas Papadimitriou
            'affiliation': 'UNIVERSITY',
951 9d20fe23 Kostas Papadimitriou
            'info': {'age': 27}
952 9d20fe23 Kostas Papadimitriou
        }
953 9d20fe23 Kostas Papadimitriou
        provider = auth.get_provider(module, user2, identifier,
954 9d20fe23 Kostas Papadimitriou
                                     **provider_params)
955 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
956 9d20fe23 Kostas Papadimitriou
        provider = auth.get_provider(module, user, identifier,
957 9d20fe23 Kostas Papadimitriou
                                     **provider_params)
958 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
959 9d20fe23 Kostas Papadimitriou
        user.email_verified = True
960 9d20fe23 Kostas Papadimitriou
        user.save()
961 9d20fe23 Kostas Papadimitriou
        self.assertRaises(Exception, provider.add_to_user)
962 9d20fe23 Kostas Papadimitriou
        provider = user.get_auth_provider(module, identifier)
963 9d20fe23 Kostas Papadimitriou
        self.assertEqual(user.get_auth_provider(
964 9d20fe23 Kostas Papadimitriou
            module, identifier)._instance.info.get('age'), 27)
965 9d20fe23 Kostas Papadimitriou
966 9d20fe23 Kostas Papadimitriou
        module = 'local'
967 9d20fe23 Kostas Papadimitriou
        identifier = None
968 9d20fe23 Kostas Papadimitriou
        provider_params = {'auth_backend': 'ldap', 'info':
969 9d20fe23 Kostas Papadimitriou
                          {'office': 'A1'}}
970 9d20fe23 Kostas Papadimitriou
        provider = auth.get_provider(module, user, identifier,
971 9d20fe23 Kostas Papadimitriou
                                     **provider_params)
972 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
973 9d20fe23 Kostas Papadimitriou
        self.assertFalse(provider.get_add_policy)
974 9d20fe23 Kostas Papadimitriou
        self.assertRaises(Exception, provider.add_to_user)
975 9d20fe23 Kostas Papadimitriou
976 9d20fe23 Kostas Papadimitriou
        shib = user.get_auth_provider('shibboleth',
977 9d20fe23 Kostas Papadimitriou
                                      'SHIB_UUID')
978 9d20fe23 Kostas Papadimitriou
        self.assertTrue(shib.get_remove_policy)
979 9d20fe23 Kostas Papadimitriou
980 9d20fe23 Kostas Papadimitriou
        local = user.get_auth_provider('local')
981 9d20fe23 Kostas Papadimitriou
        self.assertTrue(local.get_remove_policy)
982 9d20fe23 Kostas Papadimitriou
983 9d20fe23 Kostas Papadimitriou
        local.remove_from_user()
984 9d20fe23 Kostas Papadimitriou
        self.assertFalse(shib.get_remove_policy)
985 9d20fe23 Kostas Papadimitriou
        self.assertRaises(Exception, shib.remove_from_user)
986 9d20fe23 Kostas Papadimitriou
987 478ece6c Kostas Papadimitriou
        provider = user.get_auth_providers()[0]
988 478ece6c Kostas Papadimitriou
        self.assertRaises(Exception, provider.add_to_user)
989 478ece6c Kostas Papadimitriou
990 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
991 478ece6c Kostas Papadimitriou
    @shibboleth_settings(ADD_GROUPS_POLICY=['group1', 'group2'])
992 478ece6c Kostas Papadimitriou
    @shibboleth_settings(CREATION_GROUPS_POLICY=['group-create', 'group1',
993 478ece6c Kostas Papadimitriou
                                                 'group2'])
994 478ece6c Kostas Papadimitriou
    @localauth_settings(ADD_GROUPS_POLICY=['localgroup'])
995 478ece6c Kostas Papadimitriou
    @localauth_settings(CREATION_GROUPS_POLICY=['localgroup-create',
996 478ece6c Kostas Papadimitriou
                                                'group-create'])
997 478ece6c Kostas Papadimitriou
    def test_add_groups(self):
998 478ece6c Kostas Papadimitriou
        user = AstakosUser.objects.create(email="kpap@grnet.gr")
999 478ece6c Kostas Papadimitriou
        provider = auth.get_provider('shibboleth', user, 'test123')
1000 478ece6c Kostas Papadimitriou
        provider.add_to_user()
1001 478ece6c Kostas Papadimitriou
        user = AstakosUser.objects.get()
1002 2a88057d Christos Stavrakakis
        self.assertEqual(sorted(user.groups.values_list('name', flat=True)),
1003 2a88057d Christos Stavrakakis
                         sorted([u'group1', u'group2', u'group-create']))
1004 478ece6c Kostas Papadimitriou
1005 478ece6c Kostas Papadimitriou
        local = auth.get_provider('local', user)
1006 478ece6c Kostas Papadimitriou
        local.add_to_user()
1007 478ece6c Kostas Papadimitriou
        provider = user.get_auth_provider('shibboleth')
1008 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_add_groups_policy, ['group1', 'group2'])
1009 478ece6c Kostas Papadimitriou
        provider.remove_from_user()
1010 478ece6c Kostas Papadimitriou
        user = AstakosUser.objects.get()
1011 478ece6c Kostas Papadimitriou
        self.assertEqual(len(user.get_auth_providers()), 1)
1012 2a88057d Christos Stavrakakis
        self.assertEqual(sorted(user.groups.values_list('name', flat=True)),
1013 2a88057d Christos Stavrakakis
                         sorted([u'group-create', u'localgroup']))
1014 478ece6c Kostas Papadimitriou
1015 478ece6c Kostas Papadimitriou
        local = user.get_auth_provider('local')
1016 478ece6c Kostas Papadimitriou
        self.assertRaises(Exception, local.remove_from_user)
1017 478ece6c Kostas Papadimitriou
        provider = auth.get_provider('shibboleth', user, 'test123')
1018 478ece6c Kostas Papadimitriou
        provider.add_to_user()
1019 478ece6c Kostas Papadimitriou
        user = AstakosUser.objects.get()
1020 2a88057d Christos Stavrakakis
        self.assertEqual(sorted(user.groups.values_list('name', flat=True)),
1021 2a88057d Christos Stavrakakis
                         sorted([u'group-create', u'group1', u'group2',
1022 2a88057d Christos Stavrakakis
                                 u'localgroup']))
1023 478ece6c Kostas Papadimitriou
1024 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
1025 9d20fe23 Kostas Papadimitriou
    def test_policies(self):
1026 9d20fe23 Kostas Papadimitriou
        group_old, created = Group.objects.get_or_create(name='olduser')
1027 9d20fe23 Kostas Papadimitriou
1028 9d20fe23 Kostas Papadimitriou
        astakos_settings.MODERATION_ENABLED = True
1029 9d20fe23 Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_CREATION_GROUPS_POLICY = \
1030 9d20fe23 Kostas Papadimitriou
            ['academic-user']
1031 9d20fe23 Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_GOOGLE_ADD_GROUPS_POLICY = \
1032 9d20fe23 Kostas Papadimitriou
            ['google-user']
1033 9d20fe23 Kostas Papadimitriou
1034 9d20fe23 Kostas Papadimitriou
        user = AstakosUser.objects.create(email="kpap@grnet.gr")
1035 9d20fe23 Kostas Papadimitriou
        user.groups.add(group_old)
1036 9d20fe23 Kostas Papadimitriou
        user.add_auth_provider('local')
1037 9d20fe23 Kostas Papadimitriou
1038 9d20fe23 Kostas Papadimitriou
        user2 = AstakosUser.objects.create(email="kpap2@grnet.gr")
1039 9d20fe23 Kostas Papadimitriou
        user2.add_auth_provider('shibboleth', identifier='shibid')
1040 9d20fe23 Kostas Papadimitriou
1041 9d20fe23 Kostas Papadimitriou
        user3 = AstakosUser.objects.create(email="kpap3@grnet.gr")
1042 9d20fe23 Kostas Papadimitriou
        user3.groups.add(group_old)
1043 9d20fe23 Kostas Papadimitriou
        user3.add_auth_provider('local')
1044 9d20fe23 Kostas Papadimitriou
        user3.add_auth_provider('shibboleth', identifier='1234')
1045 9d20fe23 Kostas Papadimitriou
1046 9d20fe23 Kostas Papadimitriou
        self.assertTrue(user2.groups.get(name='academic-user'))
1047 9d20fe23 Kostas Papadimitriou
        self.assertFalse(user2.groups.filter(name='olduser').count())
1048 9d20fe23 Kostas Papadimitriou
1049 9d20fe23 Kostas Papadimitriou
        local = auth_providers.get_provider('local')
1050 9d20fe23 Kostas Papadimitriou
        self.assertTrue(local.get_add_policy)
1051 9d20fe23 Kostas Papadimitriou
1052 9d20fe23 Kostas Papadimitriou
        academic_group = Group.objects.get(name='academic-user')
1053 9d20fe23 Kostas Papadimitriou
        AuthProviderPolicyProfile.objects.add_policy('academic', 'shibboleth',
1054 9d20fe23 Kostas Papadimitriou
                                                     academic_group,
1055 9d20fe23 Kostas Papadimitriou
                                                     exclusive=True,
1056 9d20fe23 Kostas Papadimitriou
                                                     add=False,
1057 9d20fe23 Kostas Papadimitriou
                                                     login=False)
1058 9d20fe23 Kostas Papadimitriou
        AuthProviderPolicyProfile.objects.add_policy('academic', 'shibboleth',
1059 9d20fe23 Kostas Papadimitriou
                                                     academic_group,
1060 9d20fe23 Kostas Papadimitriou
                                                     exclusive=True,
1061 9d20fe23 Kostas Papadimitriou
                                                     login=False,
1062 9d20fe23 Kostas Papadimitriou
                                                     add=False)
1063 9d20fe23 Kostas Papadimitriou
        # no duplicate entry gets created
1064 9d20fe23 Kostas Papadimitriou
        self.assertEqual(academic_group.authpolicy_profiles.count(), 1)
1065 9d20fe23 Kostas Papadimitriou
1066 9d20fe23 Kostas Papadimitriou
        self.assertEqual(user2.authpolicy_profiles.count(), 0)
1067 9d20fe23 Kostas Papadimitriou
        AuthProviderPolicyProfile.objects.add_policy('academic', 'shibboleth',
1068 9d20fe23 Kostas Papadimitriou
                                                     user2,
1069 9d20fe23 Kostas Papadimitriou
                                                     remove=False)
1070 9d20fe23 Kostas Papadimitriou
        self.assertEqual(user2.authpolicy_profiles.count(), 1)
1071 9d20fe23 Kostas Papadimitriou
1072 9d20fe23 Kostas Papadimitriou
        local = auth_providers.get_provider('local', user2)
1073 9d20fe23 Kostas Papadimitriou
        google = auth_providers.get_provider('google', user2)
1074 9d20fe23 Kostas Papadimitriou
        shibboleth = auth_providers.get_provider('shibboleth', user2)
1075 9d20fe23 Kostas Papadimitriou
        self.assertTrue(shibboleth.get_login_policy)
1076 9d20fe23 Kostas Papadimitriou
        self.assertFalse(shibboleth.get_remove_policy)
1077 9d20fe23 Kostas Papadimitriou
        self.assertFalse(local.get_add_policy)
1078 9d20fe23 Kostas Papadimitriou
        self.assertFalse(local.get_add_policy)
1079 9d20fe23 Kostas Papadimitriou
        self.assertFalse(google.get_add_policy)
1080 9d20fe23 Kostas Papadimitriou
1081 9d20fe23 Kostas Papadimitriou
        user2.groups.remove(Group.objects.get(name='academic-user'))
1082 9d20fe23 Kostas Papadimitriou
        self.assertTrue(local.get_add_policy)
1083 9d20fe23 Kostas Papadimitriou
        self.assertTrue(google.get_add_policy)
1084 9d20fe23 Kostas Papadimitriou
        user2.groups.add(Group.objects.get(name='academic-user'))
1085 9d20fe23 Kostas Papadimitriou
1086 9d20fe23 Kostas Papadimitriou
        AuthProviderPolicyProfile.objects.add_policy('academic', 'shibboleth',
1087 9d20fe23 Kostas Papadimitriou
                                                     user2,
1088 9d20fe23 Kostas Papadimitriou
                                                     exclusive=True,
1089 9d20fe23 Kostas Papadimitriou
                                                     add=True)
1090 9d20fe23 Kostas Papadimitriou
        self.assertTrue(local.get_add_policy)
1091 9d20fe23 Kostas Papadimitriou
        self.assertTrue(google.get_add_policy)
1092 9d20fe23 Kostas Papadimitriou
1093 9d20fe23 Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_AUTOMODERATE_POLICY = True
1094 9d20fe23 Kostas Papadimitriou
        self.assertFalse(local.get_automoderate_policy)
1095 9d20fe23 Kostas Papadimitriou
        self.assertFalse(google.get_automoderate_policy)
1096 9d20fe23 Kostas Papadimitriou
        self.assertTrue(shibboleth.get_automoderate_policy)
1097 9d20fe23 Kostas Papadimitriou
1098 9d20fe23 Kostas Papadimitriou
        for s in ['SHIBBOLETH_CREATION_GROUPS_POLICY',
1099 9d20fe23 Kostas Papadimitriou
                  'GOOGLE_ADD_GROUPS_POLICY']:
1100 9d20fe23 Kostas Papadimitriou
            delattr(settings, 'ASTAKOS_AUTH_PROVIDER_%s' % s)
1101 478ece6c Kostas Papadimitriou
1102 478ece6c Kostas Papadimitriou
1103 478ece6c Kostas Papadimitriou
    @shibboleth_settings(CREATE_POLICY=True)
1104 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
1105 478ece6c Kostas Papadimitriou
    def test_create_http(self):
1106 478ece6c Kostas Papadimitriou
        # this should be wrapped inside a transaction
1107 478ece6c Kostas Papadimitriou
        user = AstakosUser(email="test@test.com")
1108 478ece6c Kostas Papadimitriou
        user.save()
1109 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth', user,
1110 478ece6c Kostas Papadimitriou
                                               'test@academia.test')
1111 478ece6c Kostas Papadimitriou
        provider.add_to_user()
1112 478ece6c Kostas Papadimitriou
        user.get_auth_provider('shibboleth', 'test@academia.test')
1113 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('local', user)
1114 478ece6c Kostas Papadimitriou
        provider.add_to_user()
1115 478ece6c Kostas Papadimitriou
        user.get_auth_provider('local')
1116 478ece6c Kostas Papadimitriou
1117 478ece6c Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_CREATE_POLICY = False
1118 478ece6c Kostas Papadimitriou
        user = AstakosUser(email="test2@test.com")
1119 478ece6c Kostas Papadimitriou
        user.save()
1120 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth', user,
1121 478ece6c Kostas Papadimitriou
                                               'test@shibboleth.com',
1122 478ece6c Kostas Papadimitriou
                                               **{'info': {'name':
1123 478ece6c Kostas Papadimitriou
                                                                'User Test'}})
1124 478ece6c Kostas Papadimitriou
        self.assertFalse(provider.get_create_policy)
1125 478ece6c Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_CREATE_POLICY = True
1126 478ece6c Kostas Papadimitriou
        self.assertTrue(provider.get_create_policy)
1127 478ece6c Kostas Papadimitriou
        academic = provider.add_to_user()
1128 478ece6c Kostas Papadimitriou
1129 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
1130 478ece6c Kostas Papadimitriou
    @shibboleth_settings(LIMIT_POLICY=2)
1131 478ece6c Kostas Papadimitriou
    def test_policies(self):
1132 478ece6c Kostas Papadimitriou
        user = get_local_user('kpap@grnet.gr')
1133 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='1234')
1134 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='12345')
1135 478ece6c Kostas Papadimitriou
1136 478ece6c Kostas Papadimitriou
        # default limit is 1
1137 478ece6c Kostas Papadimitriou
        local = user.get_auth_provider('local')
1138 478ece6c Kostas Papadimitriou
        self.assertEqual(local.get_add_policy, False)
1139 478ece6c Kostas Papadimitriou
1140 478ece6c Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_LIMIT_POLICY = 3
1141 478ece6c Kostas Papadimitriou
        academic = user.get_auth_provider('shibboleth',
1142 478ece6c Kostas Papadimitriou
                                          identifier='1234')
1143 478ece6c Kostas Papadimitriou
        self.assertEqual(academic.get_add_policy, False)
1144 478ece6c Kostas Papadimitriou
        newacademic = auth_providers.get_provider('shibboleth', user,
1145 478ece6c Kostas Papadimitriou
                                                  identifier='123456')
1146 478ece6c Kostas Papadimitriou
        self.assertEqual(newacademic.get_add_policy, True)
1147 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='123456')
1148 478ece6c Kostas Papadimitriou
        self.assertEqual(academic.get_add_policy, False)
1149 478ece6c Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_LIMIT_POLICY = 1
1150 478ece6c Kostas Papadimitriou
1151 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
1152 478ece6c Kostas Papadimitriou
    @shibboleth_settings(LIMIT_POLICY=2)
1153 478ece6c Kostas Papadimitriou
    def test_messages(self):
1154 478ece6c Kostas Papadimitriou
        user = get_local_user('kpap@grnet.gr')
1155 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='1234')
1156 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='12345')
1157 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth')
1158 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_message('title'), 'Academic')
1159 478ece6c Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_TITLE = 'New title'
1160 478ece6c Kostas Papadimitriou
        # regenerate messages cache
1161 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth')
1162 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_message('title'), 'New title')
1163 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_message('login_title'),
1164 478ece6c Kostas Papadimitriou
                         'New title LOGIN')
1165 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_login_title_msg, 'New title LOGIN')
1166 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_module_icon,
1167 478ece6c Kostas Papadimitriou
                         settings.MEDIA_URL + 'im/auth/icons/shibboleth.png')
1168 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_module_medium_icon,
1169 478ece6c Kostas Papadimitriou
                         settings.MEDIA_URL +
1170 478ece6c Kostas Papadimitriou
                         'im/auth/icons-medium/shibboleth.png')
1171 478ece6c Kostas Papadimitriou
1172 478ece6c Kostas Papadimitriou
        settings.ASTAKOS_AUTH_PROVIDER_SHIBBOLETH_TITLE = None
1173 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth', user, '12345')
1174 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_method_details_msg,
1175 478ece6c Kostas Papadimitriou
                         'Account: 12345')
1176 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth', user, '1234')
1177 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_method_details_msg,
1178 478ece6c Kostas Papadimitriou
                         'Account: 1234')
1179 478ece6c Kostas Papadimitriou
1180 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth', user, '1234')
1181 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_not_active_msg,
1182 478ece6c Kostas Papadimitriou
                         "'Academic login' is disabled.")
1183 478ece6c Kostas Papadimitriou
1184 478ece6c Kostas Papadimitriou
    @im_settings(IM_MODULES=['local', 'shibboleth'])
1185 478ece6c Kostas Papadimitriou
    @shibboleth_settings(LIMIT_POLICY=2)
1186 478ece6c Kostas Papadimitriou
    def test_templates(self):
1187 478ece6c Kostas Papadimitriou
        user = get_local_user('kpap@grnet.gr')
1188 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='1234')
1189 478ece6c Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier='12345')
1190 478ece6c Kostas Papadimitriou
1191 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth')
1192 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_template('login'),
1193 478ece6c Kostas Papadimitriou
                         'im/auth/shibboleth_login.html')
1194 478ece6c Kostas Papadimitriou
        provider = auth_providers.get_provider('google')
1195 478ece6c Kostas Papadimitriou
        self.assertEqual(provider.get_template('login'),
1196 478ece6c Kostas Papadimitriou
                         'im/auth/generic_login.html')
1197 478ece6c Kostas Papadimitriou
1198 478ece6c Kostas Papadimitriou
1199 450c7fb0 Kostas Papadimitriou
class TestProjects(TestCase):
1200 450c7fb0 Kostas Papadimitriou
    """
1201 450c7fb0 Kostas Papadimitriou
    Test projects.
1202 450c7fb0 Kostas Papadimitriou
    """
1203 450c7fb0 Kostas Papadimitriou
    def setUp(self):
1204 ba886e03 Kostas Papadimitriou
        # astakos resources
1205 ba886e03 Kostas Papadimitriou
        self.astakos_service = Service.objects.create(name="astakos",
1206 ba886e03 Kostas Papadimitriou
                                                      api_url="/astakos/api/")
1207 ba886e03 Kostas Papadimitriou
        self.resource = Resource.objects.create(name="astakos.pending_app",
1208 ba886e03 Kostas Papadimitriou
                                                uplimit=0,
1209 37d59b27 Kostas Papadimitriou
                                                allow_in_projects=False,
1210 ba886e03 Kostas Papadimitriou
                                                service=self.astakos_service)
1211 ba886e03 Kostas Papadimitriou
1212 ba886e03 Kostas Papadimitriou
        # custom service resources
1213 450c7fb0 Kostas Papadimitriou
        self.service = Service.objects.create(name="service1",
1214 450c7fb0 Kostas Papadimitriou
                                              api_url="http://service.api")
1215 450c7fb0 Kostas Papadimitriou
        self.resource = Resource.objects.create(name="service1.resource",
1216 0a7a4104 Kostas Papadimitriou
                                                uplimit=100,
1217 0a7a4104 Kostas Papadimitriou
                                                service=self.service)
1218 450c7fb0 Kostas Papadimitriou
        self.admin = get_local_user("projects-admin@synnefo.org")
1219 450c7fb0 Kostas Papadimitriou
        self.admin.uuid = 'uuid1'
1220 450c7fb0 Kostas Papadimitriou
        self.admin.save()
1221 450c7fb0 Kostas Papadimitriou
1222 450c7fb0 Kostas Papadimitriou
        self.user = get_local_user("user@synnefo.org")
1223 450c7fb0 Kostas Papadimitriou
        self.member = get_local_user("member@synnefo.org")
1224 450c7fb0 Kostas Papadimitriou
        self.member2 = get_local_user("member2@synnefo.org")
1225 450c7fb0 Kostas Papadimitriou
1226 450c7fb0 Kostas Papadimitriou
        self.admin_client = get_user_client("projects-admin@synnefo.org")
1227 450c7fb0 Kostas Papadimitriou
        self.user_client = get_user_client("user@synnefo.org")
1228 450c7fb0 Kostas Papadimitriou
        self.member_client = get_user_client("member@synnefo.org")
1229 450c7fb0 Kostas Papadimitriou
        self.member2_client = get_user_client("member2@synnefo.org")
1230 450c7fb0 Kostas Papadimitriou
1231 ba886e03 Kostas Papadimitriou
        quotas.qh_sync_users(AstakosUser.objects.all())
1232 ba886e03 Kostas Papadimitriou
1233 ba886e03 Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
1234 450c7fb0 Kostas Papadimitriou
    def test_application_limit(self):
1235 450c7fb0 Kostas Papadimitriou
        # user cannot create a project
1236 450c7fb0 Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
1237 450c7fb0 Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
1238 450c7fb0 Kostas Papadimitriou
        self.assertContains(r, "You are not allowed to create a new project")
1239 450c7fb0 Kostas Papadimitriou
1240 450c7fb0 Kostas Papadimitriou
        # but admin can
1241 450c7fb0 Kostas Papadimitriou
        r = self.admin_client.get(reverse('project_add'), follow=True)
1242 450c7fb0 Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_add'))
1243 450c7fb0 Kostas Papadimitriou
1244 ba886e03 Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
1245 37d59b27 Kostas Papadimitriou
    def test_allow_in_project(self):
1246 37d59b27 Kostas Papadimitriou
        dfrom = datetime.now()
1247 37d59b27 Kostas Papadimitriou
        dto = datetime.now() + timedelta(days=30)
1248 37d59b27 Kostas Papadimitriou
1249 37d59b27 Kostas Papadimitriou
        # astakos.pending_uplimit allow_in_project flag is False
1250 37d59b27 Kostas Papadimitriou
        # we shouldn't be able to create a project application using this
1251 37d59b27 Kostas Papadimitriou
        # resource.
1252 37d59b27 Kostas Papadimitriou
        application_data = {
1253 37d59b27 Kostas Papadimitriou
            'name': 'project.synnefo.org',
1254 37d59b27 Kostas Papadimitriou
            'homepage': 'https://www.synnefo.org',
1255 37d59b27 Kostas Papadimitriou
            'start_date': dfrom.strftime("%Y-%m-%d"),
1256 37d59b27 Kostas Papadimitriou
            'end_date': dto.strftime("%Y-%m-%d"),
1257 37d59b27 Kostas Papadimitriou
            'member_join_policy': 2,
1258 37d59b27 Kostas Papadimitriou
            'member_leave_policy': 1,
1259 37d59b27 Kostas Papadimitriou
            'service1.resource_uplimit': 100,
1260 37d59b27 Kostas Papadimitriou
            'is_selected_service1.resource': "1",
1261 37d59b27 Kostas Papadimitriou
            'astakos.pending_app_uplimit': 100,
1262 37d59b27 Kostas Papadimitriou
            'is_selected_accounts': "1",
1263 37d59b27 Kostas Papadimitriou
            'user': self.user.pk
1264 37d59b27 Kostas Papadimitriou
        }
1265 37d59b27 Kostas Papadimitriou
        form = forms.ProjectApplicationForm(data=application_data)
1266 37d59b27 Kostas Papadimitriou
        # form is invalid
1267 37d59b27 Kostas Papadimitriou
        self.assertEqual(form.is_valid(), False)
1268 37d59b27 Kostas Papadimitriou
1269 37d59b27 Kostas Papadimitriou
        del application_data['astakos.pending_app_uplimit']
1270 37d59b27 Kostas Papadimitriou
        del application_data['is_selected_accounts']
1271 37d59b27 Kostas Papadimitriou
        form = forms.ProjectApplicationForm(data=application_data)
1272 37d59b27 Kostas Papadimitriou
        self.assertEqual(form.is_valid(), True)
1273 37d59b27 Kostas Papadimitriou
1274 37d59b27 Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
1275 450c7fb0 Kostas Papadimitriou
    def test_applications(self):
1276 ba886e03 Kostas Papadimitriou
        # let user have 2 pending applications
1277 ba886e03 Kostas Papadimitriou
        self.user.add_resource_policy('astakos.pending_app', 2)
1278 ba886e03 Kostas Papadimitriou
        quotas.qh_sync_users(AstakosUser.objects.all())
1279 ba886e03 Kostas Papadimitriou
1280 450c7fb0 Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
1281 450c7fb0 Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_add'))
1282 450c7fb0 Kostas Papadimitriou
1283 450c7fb0 Kostas Papadimitriou
        # user fills the project application form
1284 450c7fb0 Kostas Papadimitriou
        post_url = reverse('project_add') + '?verify=1'
1285 450c7fb0 Kostas Papadimitriou
        dfrom = datetime.now()
1286 450c7fb0 Kostas Papadimitriou
        dto = datetime.now() + timedelta(days=30)
1287 450c7fb0 Kostas Papadimitriou
        application_data = {
1288 450c7fb0 Kostas Papadimitriou
            'name': 'project.synnefo.org',
1289 450c7fb0 Kostas Papadimitriou
            'homepage': 'https://www.synnefo.org',
1290 450c7fb0 Kostas Papadimitriou
            'start_date': dfrom.strftime("%Y-%m-%d"),
1291 450c7fb0 Kostas Papadimitriou
            'end_date': dto.strftime("%Y-%m-%d"),
1292 450c7fb0 Kostas Papadimitriou
            'member_join_policy': 2,
1293 450c7fb0 Kostas Papadimitriou
            'member_leave_policy': 1,
1294 450c7fb0 Kostas Papadimitriou
            'service1.resource_uplimit': 100,
1295 37d59b27 Kostas Papadimitriou
            'is_selected_service1.resource': "1",
1296 450c7fb0 Kostas Papadimitriou
            'user': self.user.pk
1297 450c7fb0 Kostas Papadimitriou
        }
1298 450c7fb0 Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
1299 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
1300 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.context['form'].is_valid(), True)
1301 450c7fb0 Kostas Papadimitriou
1302 450c7fb0 Kostas Papadimitriou
        # confirm request
1303 450c7fb0 Kostas Papadimitriou
        post_url = reverse('project_add') + '?verify=0&edit=0'
1304 450c7fb0 Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
1305 450c7fb0 Kostas Papadimitriou
        self.assertContains(r, "The project application has been received")
1306 450c7fb0 Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
1307 450c7fb0 Kostas Papadimitriou
        self.assertEqual(ProjectApplication.objects.count(), 1)
1308 450c7fb0 Kostas Papadimitriou
        app1_id = ProjectApplication.objects.filter().order_by('pk')[0].pk
1309 450c7fb0 Kostas Papadimitriou
1310 450c7fb0 Kostas Papadimitriou
        # create another one
1311 450c7fb0 Kostas Papadimitriou
        application_data['name'] = 'project2.synnefo.org'
1312 450c7fb0 Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
1313 450c7fb0 Kostas Papadimitriou
        app2_id = ProjectApplication.objects.filter().order_by('pk')[1].pk
1314 450c7fb0 Kostas Papadimitriou
1315 450c7fb0 Kostas Papadimitriou
        # no more applications (LIMIT is 2)
1316 450c7fb0 Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
1317 450c7fb0 Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
1318 450c7fb0 Kostas Papadimitriou
        self.assertContains(r, "You are not allowed to create a new project")
1319 450c7fb0 Kostas Papadimitriou
1320 450c7fb0 Kostas Papadimitriou
        # login
1321 450c7fb0 Kostas Papadimitriou
        self.admin_client.get(reverse("edit_profile"))
1322 450c7fb0 Kostas Papadimitriou
        # admin approves
1323 450c7fb0 Kostas Papadimitriou
        r = self.admin_client.post(reverse('project_app_approve',
1324 450c7fb0 Kostas Papadimitriou
                                           kwargs={'application_id': app1_id}),
1325 450c7fb0 Kostas Papadimitriou
                                   follow=True)
1326 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
1327 450c7fb0 Kostas Papadimitriou
1328 450c7fb0 Kostas Papadimitriou
        # project created
1329 450c7fb0 Kostas Papadimitriou
        self.assertEqual(Project.objects.count(), 1)
1330 450c7fb0 Kostas Papadimitriou
1331 450c7fb0 Kostas Papadimitriou
        # login
1332 450c7fb0 Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
1333 450c7fb0 Kostas Papadimitriou
        # cannot join app2 (not approved yet)
1334 450c7fb0 Kostas Papadimitriou
        join_url = reverse("project_join", kwargs={'chain_id': app2_id})
1335 450c7fb0 Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
1336 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 403)
1337 450c7fb0 Kostas Papadimitriou
1338 450c7fb0 Kostas Papadimitriou
        # can join app1
1339 450c7fb0 Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
1340 450c7fb0 Kostas Papadimitriou
        join_url = reverse("project_join", kwargs={'chain_id': app1_id})
1341 450c7fb0 Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
1342 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
1343 450c7fb0 Kostas Papadimitriou
1344 5dcf6618 Giorgos Korfiatis
        memberships = ProjectMembership.objects.all()
1345 5dcf6618 Giorgos Korfiatis
        self.assertEqual(len(memberships), 1)
1346 5dcf6618 Giorgos Korfiatis
        memb_id = memberships[0].id
1347 450c7fb0 Kostas Papadimitriou
1348 450c7fb0 Kostas Papadimitriou
        reject_member_url = reverse('project_reject_member',
1349 2a88057d Christos Stavrakakis
                                    kwargs={'chain_id': app1_id, 'memb_id':
1350 5dcf6618 Giorgos Korfiatis
                                            memb_id})
1351 450c7fb0 Kostas Papadimitriou
        accept_member_url = reverse('project_accept_member',
1352 2a88057d Christos Stavrakakis
                                    kwargs={'chain_id': app1_id, 'memb_id':
1353 5dcf6618 Giorgos Korfiatis
                                            memb_id})
1354 450c7fb0 Kostas Papadimitriou
1355 450c7fb0 Kostas Papadimitriou
        # only project owner is allowed to reject
1356 450c7fb0 Kostas Papadimitriou
        r = self.member_client.post(reject_member_url, follow=True)
1357 450c7fb0 Kostas Papadimitriou
        self.assertContains(r, "You do not have the permissions")
1358 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
1359 450c7fb0 Kostas Papadimitriou
1360 450c7fb0 Kostas Papadimitriou
        # user (owns project) rejects membership
1361 450c7fb0 Kostas Papadimitriou
        r = self.user_client.post(reject_member_url, follow=True)
1362 450c7fb0 Kostas Papadimitriou
        self.assertEqual(ProjectMembership.objects.count(), 0)
1363 450c7fb0 Kostas Papadimitriou
1364 450c7fb0 Kostas Papadimitriou
        # user rejoins
1365 450c7fb0 Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
1366 450c7fb0 Kostas Papadimitriou
        join_url = reverse("project_join", kwargs={'chain_id': app1_id})
1367 450c7fb0 Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
1368 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
1369 450c7fb0 Kostas Papadimitriou
        self.assertEqual(ProjectMembership.objects.count(), 1)
1370 450c7fb0 Kostas Papadimitriou
1371 450c7fb0 Kostas Papadimitriou
        # user (owns project) accepts membership
1372 450c7fb0 Kostas Papadimitriou
        r = self.user_client.post(accept_member_url, follow=True)
1373 450c7fb0 Kostas Papadimitriou
        self.assertEqual(ProjectMembership.objects.count(), 1)
1374 450c7fb0 Kostas Papadimitriou
        membership = ProjectMembership.objects.get()
1375 450c7fb0 Kostas Papadimitriou
        self.assertEqual(membership.state, ProjectMembership.ACCEPTED)
1376 450c7fb0 Kostas Papadimitriou
1377 450c7fb0 Kostas Papadimitriou
        user_quotas = quotas.get_users_quotas([self.member])
1378 450c7fb0 Kostas Papadimitriou
        resource = 'service1.resource'
1379 450c7fb0 Kostas Papadimitriou
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
1380 450c7fb0 Kostas Papadimitriou
        # 100 from initial uplimit + 100 from project
1381 450c7fb0 Kostas Papadimitriou
        self.assertEqual(newlimit, 200)
1382 450c7fb0 Kostas Papadimitriou
1383 450c7fb0 Kostas Papadimitriou
        remove_member_url = reverse('project_remove_member',
1384 2a88057d Christos Stavrakakis
                                    kwargs={'chain_id': app1_id, 'memb_id':
1385 5dcf6618 Giorgos Korfiatis
                                            membership.id})
1386 450c7fb0 Kostas Papadimitriou
        r = self.user_client.post(remove_member_url, follow=True)
1387 450c7fb0 Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
1388 450c7fb0 Kostas Papadimitriou
1389 450c7fb0 Kostas Papadimitriou
        user_quotas = quotas.get_users_quotas([self.member])
1390 450c7fb0 Kostas Papadimitriou
        resource = 'service1.resource'
1391 450c7fb0 Kostas Papadimitriou
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
1392 450c7fb0 Kostas Papadimitriou
        # 200 - 100 from project
1393 450c7fb0 Kostas Papadimitriou
        self.assertEqual(newlimit, 100)