2222"""
2323
2424import pytest
25- from omeroweb .testlib import IWebTest , get_json , _response , post
25+ from omeroweb .testlib import IWebTest , get_json
2626from django .urls import reverse , NoReverseMatch
2727from omeroweb .api import api_settings
2828from django .test import Client
29+ from django .test .client import MULTIPART_CONTENT
2930from omero_marshal import OME_SCHEMA_URL
30- import json
3131
3232
3333class TestLogin (IWebTest ):
3434 """
3535 Tests login workflow: getting url, csfv tokens etc.
3636 """
3737
38+ def get_login_url (self ):
39+ # test the most recent version
40+ version = api_settings .API_VERSIONS [- 1 ]
41+ return reverse ('api_login' , kwargs = {'api_version' : version })
42+
3843 def test_versions (self ):
3944 """
4045 Start at the base url, get versions
@@ -52,7 +57,6 @@ def test_base_url(self):
5257 Tests that the base url for a given version provides other urls
5358 """
5459 django_client = self .django_root_client
55- # test the most recent version
5660 version = api_settings .API_VERSIONS [- 1 ]
5761 request_url = reverse ('api_base' , kwargs = {'api_version' : version })
5862 rsp = get_json (django_client , request_url )
@@ -79,29 +83,61 @@ def test_login_get(self):
7983 Tests that we get a suitable message if we try to GET login_url
8084 """
8185 django_client = self .django_root_client
82- version = api_settings .API_VERSIONS [- 1 ]
83- request_url = reverse ('api_login' , kwargs = {'api_version' : version })
84- rsp = get_json (django_client , request_url , status_code = 405 )
86+ rsp = get_json (django_client , self .get_login_url (), status_code = 405 )
8587 assert (rsp ['message' ] ==
8688 "POST only with username, password, server and csrftoken" )
8789
88- def test_login_csrf (self ):
90+ def test_login_csrf_cookie_not_set (self ):
91+ """
92+ Test POST with missing CSRF cookie
93+
8994 """
90- Tests that we can only login with CSRF
95+ django_client = Client (enforce_csrf_checks = True )
96+ rsp = django_client .post (self .get_login_url ())
97+ assert rsp .status_code == 403
98+ assert rsp .json ()['message' ] == (
99+ "CSRF Failed: CSRF cookie not set." )
100+
101+ def test_login_missing_csrf_token (self ):
91102 """
92- django_client = self .django_root_client
93- # test the most recent version
94- version = api_settings .API_VERSIONS [- 1 ]
95- request_url = reverse ('api_login' , kwargs = {'api_version' : version })
96- # POST without adding CSRF token
97- rsp = _response (django_client , request_url , method = 'post' ,
98- status_code = 403 )
99- rsp = json .loads (rsp .content )
100- assert (rsp ['message' ] ==
101- ("CSRF Error. You need to include valid CSRF tokens for any"
102- " POST, PUT, PATCH or DELETE operations."
103- " You have to include CSRF token in the POST data or"
104- " add the token to the HTTP header." ))
103+ Test POST with missing CSRF token
104+
105+ """
106+ django_client = Client (enforce_csrf_checks = True )
107+ django_client .get (reverse ("weblogin" ))
108+ rsp = django_client .post (self .get_login_url ())
109+ assert rsp .status_code == 403
110+ assert rsp .json ()['message' ] == (
111+ "CSRF Failed: CSRF token missing." )
112+
113+ def test_login_empty_csrf_token (self ):
114+ """
115+ Test POST with empty CSRF token
116+ """
117+ django_client = Client (enforce_csrf_checks = True )
118+ django_client .get (reverse ("weblogin" ))
119+ data = {'username' : 'root' , 'password' : 'omero' , 'server' : 1 }
120+ rsp = django_client .post (
121+ self .get_login_url (), data , headers = {"X-CSRFToken" : "" })
122+ assert rsp .status_code == 403
123+ assert rsp .json ()['message' ] == (
124+ "CSRF Failed: "
125+ "CSRF token from the 'X-Csrftoken' HTTP header has incorrect "
126+ "length." )
127+
128+ def test_login_invalid_csrf_token (self ):
129+ """
130+ Test POST with invalid CSRF token
131+ """
132+ django_client = Client (enforce_csrf_checks = True )
133+ django_client .get (reverse ("weblogin" ))
134+ data = {'username' : 'root' , 'password' : 'omero' , 'server' : 1 }
135+ rsp = django_client .post (
136+ self .get_login_url (), data , headers = {"X-CSRFToken" : "0" * 64 })
137+ assert rsp .status_code == 403
138+ assert rsp .json ()['message' ] == (
139+ "CSRF Failed: "
140+ "CSRF token from the 'X-Csrftoken' HTTP header incorrect." )
105141
106142 @pytest .mark .parametrize ("credentials" , [
107143 [{'username' : 'guest' , 'password' : 'fake' , 'server' : 1 },
@@ -114,24 +150,35 @@ def test_login_csrf(self):
114150 "Server: This field is required." )],
115151 [{'username' : 'nobody' , 'password' : 'fake' , 'server' : 1 },
116152 ("Connection not available, "
117- "please check your user name and password." )]
153+ "please check your user name and password." )],
154+ [{'user' : 1 },
155+ ("Username: This field is required. "
156+ "Password: This field is required. "
157+ "Server: This field is required." )]
118158 ])
119- def test_login_errors (self , credentials ):
159+ @pytest .mark .parametrize ("content_type" , (
160+ MULTIPART_CONTENT , "application/json" ))
161+ def test_login_errors (self , credentials , content_type ):
120162 """
121163 Tests that we get expected form validation errors if try to login
122164 without required fields, as 'guest' or with invalid username/password.
123165 """
124- django_client = self .django_root_client
125- # test the most recent version
126- version = api_settings .API_VERSIONS [- 1 ]
127- request_url = reverse ('api_login' , kwargs = {'api_version' : version })
166+ client = Client (enforce_csrf_checks = True )
167+ client .get (reverse ("weblogin" ))
168+ csrf_token = client .cookies ["csrftoken" ].value
128169 data = credentials [0 ]
129170 message = credentials [1 ]
130- rsp = post (django_client , request_url , data , status_code = 403 )
131- rsp = json .loads (rsp .content )
132- assert rsp ['message' ] == message
171+ rsp = client .post (
172+ self .get_login_url (),
173+ data ,
174+ headers = {"X-CSRFToken" : csrf_token },
175+ content_type = content_type )
176+ assert rsp .status_code == 403
177+ assert rsp .json ()['message' ] == message
133178
134- def test_login_example (self ):
179+ @pytest .mark .parametrize ("content_type" , (
180+ MULTIPART_CONTENT , "application/json" ))
181+ def test_login_example (self , content_type ):
135182 """
136183 Example of successful login as user would do for real,
137184 starting at base url and getting all other urls and info from there.
@@ -179,10 +226,13 @@ def test_login_example(self):
179226 'server' : server_id ,
180227 # 'csrfmiddlewaretoken': token,
181228 }
182- login_rsp = django_client .post (login_url , data )
183- login_json = json .loads (login_rsp .content )
184- assert login_json ['success' ]
185- event_context = login_json ['eventContext' ]
229+ login_rsp = django_client .post (
230+ login_url ,
231+ data ,
232+ content_type = content_type )
233+ assert login_rsp .status_code == 200
234+ assert login_rsp .json ()['success' ]
235+ event_context = login_rsp .json ()['eventContext' ]
186236 # eventContext gives a bunch of info
187237 member_of_groups = event_context ['memberOfGroups' ]
188238 current_group = event_context ['groupId' ]
0 commit comments