Skip to content

Commit e7a3852

Browse files
committed
Implement finding users by email address.
1 parent 17c4db9 commit e7a3852

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

mig/services/coreapi/server.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
from mig.shared.tlsserver import hardened_ssl_context
7575
from mig.shared.url import urlparse, urlencode, parse_qsl
7676
from mig.shared.useradm import get_any_oid_user_dn, check_password_scramble, \
77-
check_hash
77+
check_hash, search_users as useradm_search_users
7878
from mig.shared.userdb import default_db_path
7979
from mig.shared.validstring import possible_user_id, is_valid_email_address
8080
from mig.server.createuser import _main as createuser
@@ -203,6 +203,13 @@ def _is_string_and_non_empty(value):
203203
))
204204

205205

206+
def search_users(configuration, search_filter):
207+
conf_path = configuration.config_file
208+
db_path = default_db_path(configuration)
209+
_, hits = useradm_search_users(search_filter, conf_path, db_path)
210+
return list((obj for _, obj in hits))
211+
212+
206213
def validate_payload(definition, payload):
207214
args = definition(*[payload.get(field, None) for field in definition._fields])
208215

@@ -228,6 +235,19 @@ def GET_user():
228235
def GET_user_username(username):
229236
return 'FOOBAR'
230237

238+
@app.get('/user/find')
239+
def GET_user_find():
240+
query_params = request.args
241+
242+
objects = search_users(configuration, {
243+
'email': query_params['email']
244+
})
245+
246+
if len(objects) != 1:
247+
raise http_error_from_status_code(404, None)
248+
249+
return dict(objects=objects)
250+
231251
@app.post('/user')
232252
def POST_user():
233253
payload = request.get_json()

tests/test_mig_services_coreapi.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616
from mig.services.coreapi import ThreadedApiHttpServer, \
1717
_create_and_expose_server
18+
from mig.server.createuser import _main as _createuser
1819
from mig.shared.conf import get_configuration_object
20+
from mig.shared.url import urlencode
1921
from mig.shared.useradm import _USERADM_CONFIG_DIR_KEYS
2022

2123
_PYTHON_MAJOR = '2' if PY2 else '3'
@@ -248,5 +250,111 @@ def _on_instance(server):
248250
return server_thread
249251

250252

253+
class MigServerGrid_openid__existing_user(MigTestCase, HtmlAssertMixin):
254+
def before_each(self):
255+
self.server_addr = None
256+
self.server_thread = None
257+
258+
for config_key in _USERADM_CONFIG_DIR_KEYS:
259+
dir_path = getattr(self.configuration, config_key)[0:-1]
260+
try:
261+
shutil.rmtree(dir_path)
262+
except OSError as exc:
263+
if exc.errno != errno.ENOENT: # FileNotFoundError
264+
pass
265+
266+
_createuser(self.configuration, [
267+
"Test User",
268+
"Test Org",
269+
"NA",
270+
"DK",
271+
"user@example.com",
272+
"This is the create comment",
273+
"password"
274+
], default_renew=True)
275+
pass
276+
277+
def _provide_configuration(self):
278+
return 'testconfig'
279+
280+
def after_each(self):
281+
if self.server_thread:
282+
self.server_thread.stop()
283+
284+
def issue_request(self, request_path):
285+
return self.issue_GET(request_path)
286+
287+
def issue_GET(self, request_path, query_dict=None, response_encoding='textual'):
288+
assert isinstance(request_path, str) and request_path.startswith('/'), "require http path starting with /"
289+
request_url = ''.join(('http://', self.server_addr[0], ':', str(self.server_addr[1]), request_path))
290+
291+
if query_dict is not None:
292+
query_string = urlencode(query_dict)
293+
request_url = ''.join((request_url, '?', query_string))
294+
295+
status = 0
296+
data = None
297+
298+
try:
299+
response = urlopen(request_url, None, timeout=2000)
300+
301+
status = response.getcode()
302+
data = response.read()
303+
except HTTPError as httpexc:
304+
status = httpexc.code
305+
data = None
306+
307+
content = attempt_to_decode_response_data(data, response_encoding)
308+
return (status, content)
309+
310+
@unittest.skipIf(PY2, "Python 3 only")
311+
def test_GET_openid_user_find(self):
312+
flask_app = None
313+
314+
self.server_addr = ('localhost', 4567)
315+
self.server_thread = self._make_server(self.configuration, self.logger, self.server_addr)
316+
self.server_thread.start_wait_until_ready()
317+
318+
status, content = self.issue_GET('/user/find', {
319+
'email': 'user@example.com'
320+
})
321+
322+
self.assertEqual(status, 200)
323+
324+
self.assertIsInstance(content, dict)
325+
self.assertIn('objects', content)
326+
self.assertIsInstance(content['objects'], list)
327+
328+
user = content['objects'][0]
329+
# check we received the correct user
330+
self.assertEqual(user['full_name'], 'Test User')
331+
332+
def _make_configuration(self, test_logger, server_addr, overrides=None):
333+
configuration = self.configuration
334+
_extend_configuration(
335+
configuration,
336+
server_addr[0],
337+
server_addr[1],
338+
logger=test_logger,
339+
expandusername=False,
340+
host_rsa_key='',
341+
nossl=True,
342+
show_address=False,
343+
show_port=False,
344+
)
345+
return configuration
346+
347+
@staticmethod
348+
def _make_server(configuration, logger=None, server_address=None):
349+
def _on_instance(server):
350+
server.server_app = _create_and_expose_server(
351+
server, server.configuration)
352+
353+
(host, port) = server_address
354+
server_thread = make_wrapped_server(ThreadedApiHttpServer, \
355+
configuration, logger, host, port, on_instance=_on_instance)
356+
return server_thread
357+
358+
251359
if __name__ == '__main__':
252360
testmain()

0 commit comments

Comments
 (0)