Projet

Général

Profil

0001-api-add-basic-auth-support-to-users-xxx-and-users-xx.patch

Lauréline Guérin, 14 septembre 2021 11:11

Télécharger (10,4 ko)

Voir les différences:

Subject: [PATCH] api: add basic auth support to users/xxx and users/xxx/forms
 (#56908)

 tests/api/test_user.py | 151 ++++++++++++++++++++++++++---------------
 wcs/api.py             |   9 ++-
 2 files changed, 100 insertions(+), 60 deletions(-)
tests/api/test_user.py
1 1
import datetime
2 2
import os
3
from functools import partial
3 4

  
4 5
import pytest
5 6
from quixote import get_publisher
......
77 78
    return user
78 79

  
79 80

  
81
def _get_url(url, app, auth, access, user, **kwargs):
82
    if auth == 'http-basic':
83
        app.set_authorization(('Basic', ('test', '12345')))
84
        return app.get(url, **kwargs)
85
    else:
86
        return app.get(
87
            sign_uri(url, user=user, orig=access.access_identifier, key=access.access_key), **kwargs
88
        )
89

  
90

  
91
@pytest.fixture
92
def access(pub):
93
    ApiAccess.wipe()
94
    access = ApiAccess()
95
    access.name = 'test'
96
    access.access_identifier = 'test'
97
    access.access_key = '12345'
98
    access.store()
99
    return access
100

  
101

  
80 102
def test_roles(pub, local_user):
81 103
    pub.role_class.wipe()
82 104
    role = pub.role_class(name='Hello World')
......
102 124
    assert resp.json['data'][0]['details'] == 'kouign amann'
103 125

  
104 126

  
127
def test_user_api_with_restricted_access(pub, access):
128
    role = pub.role_class(name='test')
129
    role.store()
130

  
131
    access.roles = [role]
132
    access.store()
133

  
134
    resp = get_app(pub).get(sign_uri('/api/user/', orig='test', key='12345'), status=403)
135
    assert resp.json['err'] == 1
136
    assert resp.json['err_desc'] == 'restricted API access'
137

  
138

  
139
def test_users_api_with_restricted_access(pub, local_user, access):
140
    role = pub.role_class(name='test')
141
    role.store()
142

  
143
    access.roles = [role]
144
    access.store()
145

  
146
    resp = get_app(pub).get(sign_uri('/api/users/', orig='test', key='12345'), status=403)
147
    assert resp.json['err'] == 1
148
    assert resp.json['err_desc'] == 'restricted API access'
149

  
150

  
105 151
def test_users(pub, local_user):
106 152
    resp = get_app(pub).get('/api/users/', status=403)
107 153

  
......
199 245
    )
200 246

  
201 247

  
202
def test_user_by_nameid(pub, local_user):
203
    resp = get_app(pub).get(sign_uri('/api/users/xyz/', user=local_user), status=404)
248
@pytest.mark.parametrize('auth', ['signature', 'http-basic'])
249
def test_user_by_nameid(pub, local_user, access, auth):
250
    app = get_app(pub)
251
    get_url = partial(_get_url, app=app, auth=auth, access=access, user=local_user)
252

  
253
    resp = get_url('/api/users/xyz/', status=404)
204 254
    local_user.name_identifiers = ['xyz']
205 255
    local_user.store()
206
    resp = get_app(pub).get(sign_uri('/api/users/xyz/', user=local_user))
256
    resp = get_url('/api/users/xyz/')
207 257
    assert str(resp.json['id']) == str(local_user.id)
208 258

  
209 259

  
210
def test_user_roles(pub, local_user):
211
    local_user.name_identifiers = ['xyz']
212
    local_user.store()
260
@pytest.mark.parametrize('auth', ['signature', 'http-basic'])
261
def test_user_roles(pub, local_user, access, auth):
213 262
    role = pub.role_class(name='Foo bar')
214 263
    role.store()
264
    local_user.name_identifiers = ['xyz']
215 265
    local_user.roles = [role.id]
216 266
    local_user.store()
217
    resp = get_app(pub).get(sign_uri('/api/users/xyz/', user=local_user))
267

  
268
    app = get_app(pub)
269
    get_url = partial(_get_url, app=app, auth=auth, access=access, user=local_user)
270

  
271
    resp = get_url('/api/users/xyz/')
218 272
    assert len(resp.json['user_roles']) == 1
219 273
    assert resp.json['user_roles'][0]['name'] == 'Foo bar'
220 274

  
221 275

  
222
def test_user_forms(pub, local_user):
276
def test_user_forms(pub, local_user, access):
223 277
    Workflow.wipe()
224 278
    workflow = Workflow.get_default_workflow()
225 279
    workflow.id = '2'
......
339 393
    role = pub.role_class(name='test')
340 394
    role.store()
341 395

  
342
    access = ApiAccess()
343
    access.name = 'test'
344
    access.access_identifier = 'test'
345
    access.access_key = '12345'
346 396
    access.roles = [role]
347 397
    access.store()
348 398

  
......
351 401
    assert resp.json['err_desc'] == 'restricted API access'
352 402

  
353 403

  
354
def test_user_api_with_restricted_access(pub):
355
    role = pub.role_class(name='test')
356
    role.store()
357

  
358
    access = ApiAccess()
359
    access.name = 'test'
360
    access.access_identifier = 'test'
361
    access.access_key = '12345'
362
    access.roles = [role]
363
    access.store()
364

  
365
    resp = get_app(pub).get(sign_uri('/api/user/', orig='test', key='12345'), status=403)
366
    assert resp.json['err'] == 1
367
    assert resp.json['err_desc'] == 'restricted API access'
368

  
369

  
370
def test_users_api_with_restricted_access(pub, local_user):
371
    role = pub.role_class(name='test')
372
    role.store()
373

  
374
    access = ApiAccess()
375
    access.name = 'test'
376
    access.access_identifier = 'test'
377
    access.access_key = '12345'
378
    access.roles = [role]
379
    access.store()
380

  
381
    resp = get_app(pub).get(sign_uri('/api/users/', orig='test', key='12345'), status=403)
382
    assert resp.json['err'] == 1
383
    assert resp.json['err_desc'] == 'restricted API access'
384

  
385
    resp = get_app(pub).get(sign_uri('/api/users/%s/' % local_user.id, orig='test', key='12345'), status=403)
386
    assert resp.json['err'] == 1
387
    assert resp.json['err_desc'] == 'restricted API access'
388

  
389

  
390 404
def test_user_forms_limit_offset(pub, local_user):
391 405
    if not pub.is_using_postgresql():
392 406
        pytest.skip('this requires SQL')
......
496 510
    assert len(resp.json['data']) == 5
497 511

  
498 512

  
499
def test_user_forms_from_agent(pub, local_user):
513
@pytest.mark.parametrize('auth', ['signature', 'http-basic'])
514
def test_user_forms_from_agent(pub, local_user, access, auth):
500 515
    pub.role_class.wipe()
501 516
    role = pub.role_class(name='Foo bar')
502 517
    role.store()
......
525 540
    formdata.jump_status('new')
526 541
    formdata.store()
527 542

  
528
    resp = get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id, user=agent_user))
543
    if auth == 'http-basic':
544
        access.roles = [role]
545
        access.store()
546

  
547
    app = get_app(pub)
548
    get_url = partial(_get_url, app=app, auth=auth, access=access, user=agent_user)
549

  
550
    resp = get_url('/api/users/%s/forms' % local_user.id)
529 551
    assert resp.json['err'] == 0
530 552
    assert len(resp.json['data']) == 1
531 553
    assert resp.json['data'][0]['form_name'] == 'test'
......
536 558
    formdef.skip_from_360_view = True
537 559
    formdef.store()
538 560

  
539
    resp = get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id, user=agent_user))
561
    resp = get_url('/api/users/%s/forms' % local_user.id)
540 562
    assert len(resp.json['data']) == 0
541 563

  
542 564
    formdef.workflow_roles = {'_receiver': str(role.id)}
543 565
    formdef.store()
544 566
    formdef.data_class().rebuild_security()
545
    resp = get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id, user=agent_user))
567
    resp = get_url('/api/users/%s/forms' % local_user.id)
546 568
    assert len(resp.json['data']) == 1
547 569

  
548 570
    agent_user.roles = []
549 571
    agent_user.store()
550
    get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id, user=agent_user), status=403)
572
    if auth == 'http-basic':
573
        access.roles = []
574
        access.store()
575
        resp = get_url('/api/users/%s/forms' % local_user.id)
576
        assert len(resp.json['data']) == 0
577
    else:
578
        get_url('/api/users/%s/forms' % local_user.id, status=403)
551 579

  
552 580

  
553
def test_user_forms_include_accessible(pub, local_user):
581
def test_user_forms_include_accessible(pub, local_user, access):
554 582
    if not pub.is_using_postgresql():
555 583
        pytest.skip('this requires SQL')
556 584
        return
......
611 639
    formdata4.jump_status('new')
612 640
    formdata4.store()
613 641

  
642
    app = get_app(pub)
643

  
614 644
    def get_ids(url):
615
        resp = get_app(pub).get(url)
645
        resp = app.get(url)
616 646
        return {int(x['form_number_raw']) for x in resp.json['data']}
617 647

  
618 648
    resp = get_ids(sign_uri('/api/user/forms', user=local_user))
......
628 658
    resp = get_ids(sign_uri('/api/users/%s/forms?include-accessible=on' % local_user.id, user=agent_user))
629 659
    assert resp == {formdata1.id, formdata3.id}
630 660

  
661
    # an api access gets the same results
662
    access.roles = [role]
663
    access.store()
664
    app.set_authorization(('Basic', ('test', '12345')))
665

  
666
    resp = get_ids('/api/users/%s/forms' % local_user.id)
667
    assert resp == {formdata1.id}
668

  
669
    resp = get_ids('/api/users/%s/forms?include-accessible=on' % local_user.id)
670
    assert resp == {formdata1.id, formdata3.id}
671

  
631 672

  
632 673
def test_user_drafts(pub, local_user):
633 674
    FormDef.wipe()
wcs/api.py
976 976
            # (from query string or session).
977 977
            query_user = get_user_from_api_query_string() or get_request().user
978 978
            if query_user and query_user.id != self.user.id:
979
                if not query_user.can_go_in_backoffice():
979
                if not query_user.is_api_user and not query_user.can_go_in_backoffice():
980 980
                    raise AccessForbiddenError('user not allowed to query data from others')
981 981
                # mark forms that are readable by querying user
982 982
                user_roles = set(query_user.get_roles())
......
1081 1081
        return json.dumps({'data': data, 'err': 0}, cls=misc.JSONEncoder)
1082 1082

  
1083 1083
    def _q_lookup(self, component):
1084
        if not (is_url_signed() or (get_request().user and get_request().user.can_go_in_admin())):
1085
            raise AccessForbiddenError('unsigned request or user has no access to backoffice')
1086

  
1087 1084
        api_user = get_user_from_api_query_string()
1088 1085
        if api_user and api_user.is_api_user:
1089
            raise AccessForbiddenError('restricted API access')
1086
            pass  # API users are ok
1087
        elif not (is_url_signed() or (get_request().user and get_request().user.can_go_in_admin())):
1088
            raise AccessForbiddenError('unsigned request or user has no access to backoffice')
1090 1089

  
1091 1090
        user_class = get_publisher().user_class
1092 1091
        try:
1093
-