1
# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Test maasserver preferences views."""
6
from __future__ import (
20
from apiclient.creds import convert_tuple_to_string
21
from django.contrib.auth.models import User
22
from django.core.urlresolvers import reverse
23
from lxml.html import fromstring
24
from maasserver.models import SSHKey
25
from maasserver.models.user import get_creds_tuple
26
from maasserver.testing import (
30
get_prefixed_form_data,
32
from maasserver.testing.factory import factory
33
from maasserver.testing.testcase import MAASServerTestCase
36
class UserPrefsViewTest(MAASServerTestCase):
38
def test_prefs_GET_profile(self):
39
# The preferences page displays a form with the user's personal
42
user = self.logged_in_user
43
user.last_name = 'Steve Bam'
45
response = self.client.get('/account/prefs/')
46
doc = fromstring(response.content)
47
self.assertSequenceEqual(
49
[elem.value for elem in
50
doc.cssselect('input#id_profile-last_name')])
52
def test_prefs_GET_api(self):
53
# The preferences page displays the API access tokens.
55
user = self.logged_in_user
56
# Create a few tokens.
58
user.get_profile().create_authorisation_token()
59
response = self.client.get('/account/prefs/')
60
doc = fromstring(response.content)
61
# The OAuth tokens are displayed.
62
for token in user.get_profile().get_authorisation_tokens():
63
# The token string is a compact representation of the keys.
64
self.assertSequenceEqual(
65
[convert_tuple_to_string(get_creds_tuple(token))],
66
[elem.value.strip() for elem in
67
doc.cssselect('input#%s' % token.key)])
69
def test_prefs_POST_profile(self):
70
# The preferences page allows the user the update its profile
74
'last_name': 'John Doe',
75
'email': 'jon@example.com',
77
response = self.client.post(
78
'/account/prefs/', get_prefixed_form_data('profile', params))
80
self.assertEqual(httplib.FOUND, response.status_code)
81
user = User.objects.get(id=self.logged_in_user.id)
82
self.assertAttributes(user, params)
84
def test_prefs_POST_password(self):
85
# The preferences page allows the user to change their password.
87
self.logged_in_user.set_password('password')
88
old_pw = self.logged_in_user.password
89
response = self.client.post(
91
get_prefixed_form_data(
94
'old_password': 'test',
95
'new_password1': 'new',
96
'new_password2': 'new',
99
self.assertEqual(httplib.FOUND, response.status_code)
100
user = User.objects.get(id=self.logged_in_user.id)
101
# The password is SHA1ized, we just make sure that it has changed.
102
self.assertNotEqual(old_pw, user.password)
104
def test_prefs_displays_message_when_no_public_keys_are_configured(self):
106
response = self.client.get('/account/prefs/')
107
self.assertIn("No SSH key configured.", response.content)
109
def test_prefs_displays_add_ssh_key_button(self):
111
response = self.client.get('/account/prefs/')
112
add_key_link = reverse('prefs-add-sshkey')
113
self.assertIn(add_key_link, get_content_links(response))
115
def test_prefs_displays_compact_representation_of_users_keys(self):
117
_, keys = factory.make_user_with_keys(user=self.logged_in_user)
118
response = self.client.get('/account/prefs/')
120
self.assertIn(key.display_html(), response.content)
122
def test_prefs_displays_link_to_delete_ssh_keys(self):
124
_, keys = factory.make_user_with_keys(user=self.logged_in_user)
125
response = self.client.get('/account/prefs/')
126
links = get_content_links(response)
128
del_key_link = reverse('prefs-delete-sshkey', args=[key.id])
129
self.assertIn(del_key_link, links)
132
class KeyManagementTest(MAASServerTestCase):
134
def test_add_key_GET(self):
135
# The 'Add key' page displays a form to add a key.
137
response = self.client.get(reverse('prefs-add-sshkey'))
138
doc = fromstring(response.content)
140
self.assertEqual(1, len(doc.cssselect('textarea#id_key')))
141
# The page features a form that submits to itself.
142
self.assertSequenceEqual(
144
[elem.get('action').strip() for elem in doc.cssselect(
147
def test_add_key_POST_adds_key(self):
149
key_string = get_data('data/test_rsa0.pub')
150
response = self.client.post(
151
reverse('prefs-add-sshkey'), {'key': key_string})
153
self.assertEqual(httplib.FOUND, response.status_code)
154
self.assertTrue(SSHKey.objects.filter(key=key_string).exists())
156
def test_add_key_POST_fails_if_key_already_exists_for_the_user(self):
158
key_string = get_data('data/test_rsa0.pub')
159
key = SSHKey(user=self.logged_in_user, key=key_string)
161
response = self.client.post(
162
reverse('prefs-add-sshkey'), {'key': key_string})
164
self.assertEqual(httplib.OK, response.status_code)
166
"This key has already been added for this user.",
168
self.assertItemsEqual([key], SSHKey.objects.filter(key=key_string))
170
def test_key_can_be_added_if_same_key_already_setup_for_other_user(self):
172
key_string = get_data('data/test_rsa0.pub')
173
key = SSHKey(user=factory.make_user(), key=key_string)
175
response = self.client.post(
176
reverse('prefs-add-sshkey'), {'key': key_string})
177
new_key = SSHKey.objects.get(key=key_string, user=self.logged_in_user)
179
self.assertEqual(httplib.FOUND, response.status_code)
180
self.assertItemsEqual(
181
[key, new_key], SSHKey.objects.filter(key=key_string))
183
def test_delete_key_GET(self):
184
# The 'Delete key' page displays a confirmation page with a form.
186
key = factory.make_sshkey(self.logged_in_user)
187
del_link = reverse('prefs-delete-sshkey', args=[key.id])
188
response = self.client.get(del_link)
189
doc = fromstring(response.content)
192
"Are you sure you want to delete the following key?",
194
# The page features a form that submits to itself.
195
self.assertSequenceEqual(
197
[elem.get('action').strip() for elem in doc.cssselect(
200
def test_delete_key_GET_cannot_access_someone_elses_key(self):
202
key = factory.make_sshkey(factory.make_user())
203
del_link = reverse('prefs-delete-sshkey', args=[key.id])
204
response = self.client.get(del_link)
206
self.assertEqual(httplib.FORBIDDEN, response.status_code)
208
def test_delete_key_GET_nonexistent_key_redirects_to_prefs(self):
209
# Deleting a nonexistent key requires no confirmation. It just
210
# "succeeds" instantaneously.
212
key = factory.make_sshkey(self.logged_in_user)
213
del_link = reverse('prefs-delete-sshkey', args=[key.id])
215
response = self.client.get(del_link)
216
self.assertEqual('/account/prefs/', extract_redirect(response))
218
def test_delete_key_POST(self):
219
# A POST request deletes the key, and redirects to the prefs.
221
key = factory.make_sshkey(self.logged_in_user)
222
del_link = reverse('prefs-delete-sshkey', args=[key.id])
223
response = self.client.post(del_link, {'post': 'yes'})
225
self.assertEqual('/account/prefs/', extract_redirect(response))
226
self.assertFalse(SSHKey.objects.filter(id=key.id).exists())
228
def test_delete_key_POST_ignores_nonexistent_key(self):
229
# Deleting a key that's already been deleted? Basically that's
232
key = factory.make_sshkey(self.logged_in_user)
233
del_link = reverse('prefs-delete-sshkey', args=[key.id])
235
response = self.client.post(del_link, {'post': 'yes'})
236
self.assertEqual('/account/prefs/', extract_redirect(response))