def test_create_record_check_acl_priority(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: with db.session.begin_nested(): acl1 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='get') actor1 = SystemRoleActor(name='auth', system_role='any_user', acl=acl1, originator=test_users.u1) acl2 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=1, originator=test_users.u1, operation='get') actor2 = SystemRoleActor(name='auth', system_role='authenticated_user', acl=acl2, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) db.session.add(acl2) db.session.add(actor2) login(client, test_users.u1) response = client.post(records_url(), data=json.dumps({ 'title': 'blah', 'contributors': [] }), content_type='application/json') assert response.status_code == 201 rest_metadata = get_json(response)['metadata'] assert 'control_number' in rest_metadata index, doctype = schema_to_index(RECORD_SCHEMA) rec_md = current_search_client.get( index=index, doc_type=doctype, id=str( PersistentIdentifier.get( 'recid', rest_metadata['control_number']).object_uuid)) clear_timestamp(rec_md) assert rec_md['_source']['_invenio_explicit_acls'] == [{ 'operation': 'get', 'id': acl2.id, 'timestamp': 'cleared', 'system_role': ['authenticated_user'] }]
def test_filter_schemas(app, db, es, es_acl_prepare, test_users): if db.engine.dialect.name != 'postgresql': return assert DefaultACL.query.filter(DefaultACL.schemas.any('aaa')).count() == 0 with db.session.begin_nested(): acl = DefaultACL(name='test', schemas=['aaa', RECORD_SCHEMA], operation='get', originator=test_users.u1) db.session.add(acl) assert DefaultACL.query.filter(DefaultACL.schemas.any('aaa')).count() == 1 assert DefaultACL.query.filter( DefaultACL.schemas.any(RECORD_SCHEMA)).count() == 1 with db.session.begin_nested(): acl1 = DefaultACL(name='test1', schemas=[RECORD_SCHEMA], operation='get', originator=test_users.u1) db.session.add(acl1) assert DefaultACL.query.filter(DefaultACL.schemas.any('aaa')).count() == 1 assert DefaultACL.query.filter( DefaultACL.schemas.any(RECORD_SCHEMA)).count() == 2 with db.session.begin_nested(): acl1.schemas = ['aaa'] db.session.add(acl1) assert DefaultACL.query.filter(DefaultACL.schemas.any('aaa')).count() == 2 assert DefaultACL.query.filter( DefaultACL.schemas.any(RECORD_SCHEMA)).count() == 1
def test_get_record_no_acls_anonymous(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): # create an empty ACL in order to get the _invenio_explicit_acls filled acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) actor = UserActor(name='test', acl=acl, users=[], originator=test_users.u1) db.session.add(actor) pid, record = create_record({}, clz=SchemaEnforcingRecord) RecordIndexer().index(record) # make sure it is flushed current_search_client.indices.flush() # try to get it ... with app.test_client() as client: res = client.get(record_url(pid)) assert res.status_code == 401 # unauthorized # get it directly from ES res = get_from_es(pid)['_source'] assert res['control_number'] == pid.pid_value assert res['$schema'] == 'https://localhost/schemas/' + RECORD_SCHEMA assert '_invenio_explicit_acls' in res
def test_rest_delete_record(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: with db.session.begin_nested(): acl = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='update') actor = UserActor(name='u1', users=[test_users.u1], acl=acl, originator=test_users.u1) db.session.add(acl) db.session.add(actor) pid, record = create_record({'keywords': ['blah']}, clz=SchemaEnforcingRecord) RecordIndexer().index(record) current_search_client.indices.refresh() current_search_client.indices.flush() login(client, test_users.u2) response = client.delete(record_url(pid)) assert response.status_code == 403 login(client, test_users.u1) response = client.delete(record_url(pid)) assert response.status_code == 204 with pytest.raises(NoResultFound): Record.get_record(pid.object_uuid)
def test_default_acl_delete(app, db, es, es_acl_prepare, test_users): # should pass as it does nothing with db.session.begin_nested(): acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) acl.delete()
def test_default_acl_repr(app, db, es, es_acl_prepare, test_users): # should pass as it does nothing with db.session.begin_nested(): acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) assert repr(acl) == "Default ACL on ['records/record-v1.0.0.json']"
def test_existing_acls_database_queries(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): acl = DefaultACL(name='test', schemas=['aaa', RECORD_SCHEMA], operation='get', originator=test_users.u1) db.session.add(acl) assert set(current_explicit_acls.enabled_schemas) == {'aaa', RECORD_SCHEMA} with db.session.begin_nested(): acl = DefaultACL(name='test1', schemas=[RECORD_SCHEMA], operation='get', originator=test_users.u1) db.session.add(acl) assert DefaultACL.query.count() == 2 assert set(current_explicit_acls.enabled_schemas) == {'aaa', RECORD_SCHEMA} assert len(list(current_explicit_acls.enabled_schemas)) == 2
def test_default_acl_get_record_acl(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) acl2 = DefaultACL(name='test 2', schemas=[ANOTHER_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl2) pid, record = create_record({'$schema': RECORD_SCHEMA}, clz=SchemaEnforcingRecord) acls = list(DefaultACL.get_record_acls(record)) assert len(acls) == 1 assert isinstance(acls[0], DefaultACL) assert acls[0].id == acl.id
def test_aclserializer(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): acl1 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='get') actor1 = UserActor(name='auth', users=[test_users.u1], acl=acl1, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) pid, rec = create_record({'title': 'blah'}, clz=SchemaEnforcingRecord) RecordIndexer().index(rec) current_search_client.indices.flush() assert current_jsonschemas.url_to_path( rec['$schema']) in current_explicit_acls.enabled_schemas assert list(DefaultACL.get_record_acls(rec)) != [] index, doc_type = schema_to_index(RECORD_SCHEMA) data = current_search_client.get(index=index, doc_type=doc_type, id=str(pid.object_uuid))['_source'] assert '_invenio_explicit_acls' in data assert len(data['_invenio_explicit_acls']) == 1 with app.test_request_context(): login_user(test_users.u1) set_identity(test_users.u1) acljson_serializer = ACLJSONSerializer(RecordSchemaV1, acl_rest_endpoint='recid', replace_refs=True) serialized = json.loads(acljson_serializer.serialize(pid, rec)) assert serialized['invenio_explicit_acls'] == ["get"] with app.test_client() as client: login(client, test_users.u1) search_results = client.get(url_for('invenio_records_rest.recid_list')) search_results = get_json(search_results) hits = search_results['hits']['hits'] assert len(hits) == 1 assert hits[0]['invenio_explicit_acls'] == ["get"]
def test_default_acl_get_matching_resources(app, db, es, es_acl_prepare, test_users): pid, record = create_record({'$schema': RECORD_SCHEMA}, clz=SchemaEnforcingRecord) RecordIndexer().index(record) current_search_client.indices.flush() with db.session.begin_nested(): acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) ids = list(acl.get_matching_resources()) assert len(ids) == 1 assert ids[0] == str(pid.object_uuid)
def test_get_enabled_schema(app, db, test_users): with db.session.begin_nested(): # add ACL for the record schema acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) assert 'records/record-v1.0.0.json' == get_record_acl_enabled_schema( {'$schema': 'records/record-v1.0.0.json'}) assert 'records/record-v1.0.0.json' == get_record_acl_enabled_schema( {'$schema': 'https://localhost/schemas/records/record-v1.0.0.json'}) assert get_record_acl_enabled_schema( {'$schema': 'https://localhost/schemas/unknown/unknown-v1.0.0.json' }) is None
def test_create_record_no_acls_authenticated(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: with db.session.begin_nested(): # create an empty ACL in order to get the _invenio_explicit_acls filled acl = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) db.session.add(acl) actor = UserActor(name='test', acl=acl, users=[], originator=test_users.u1) db.session.add(actor) login(client, test_users.u1) response = client.post(records_url(), data=json.dumps({ 'title': 'blah', 'contributors': [] }), content_type='application/json') # print("Response", response.get_data(as_text=True)) assert response.status_code == 201 created_record_metadata = get_json(response)['metadata'] # check that ACLs are not leaking assert 'invenio_explicit_acls' not in created_record_metadata pid = PersistentIdentifier.get( 'recid', created_record_metadata['control_number']) res = get_from_es(pid)['_source'] assert res['control_number'] == pid.pid_value assert res['$schema'] == 'https://localhost/schemas/' + RECORD_SCHEMA assert '_invenio_explicit_acls' in res # still can not get it res = client.get(record_url(pid)) assert res.status_code == 403 # Forbidden
def test_aclrecordsearch_explicit_user(app, db, es, es_acl_prepare, test_users): current_explicit_acls.prepare(RECORD_SCHEMA) with db.session.begin_nested(): acl1 = DefaultACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) actor1 = UserActor(name='auth', acl=acl1, users=[test_users.u1], originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) current_explicit_acls.reindex_acl(acl1, delayed=False) record_uuid = uuid.uuid4() data = {'title': 'blah', 'contributors': [], 'keywords': ['blah']} recid_minter(record_uuid, data) rec = SchemaEnforcingRecord.create(data, id_=record_uuid) RecordIndexer().index(rec) current_search_client.indices.refresh() current_search_client.indices.flush() rs = ACLRecordsSearch(user=test_users.u1, context={ 'system_roles': ['authenticated_user'] }) rec_id = str(rec.id) print(json.dumps(rs.query(Ids(values=[rec_id])).query.to_dict(), indent=4)) assert rs.query(Ids(values=[rec_id])).query.to_dict() == { "bool": { "minimum_should_match": "100%", "filter": [ { "bool": { "should": [ { "nested": { "path": "_invenio_explicit_acls", "_name": "invenio_explicit_acls_match_get", "query": { "bool": { "must": [ { "term": { "_invenio_explicit_acls.operation": "get" } }, { "bool": { "minimum_should_match": 1, "should": [ { "terms": { "_invenio_explicit_acls.role": [ 1 ] } }, { "term": { "_invenio_explicit_acls.user": 1 } }, { "terms": { "_invenio_explicit_acls.role": [ 1 ] } }, { "terms": { "_invenio_explicit_acls.system_role": [ "authenticated_user" ] } }, { "term": { "_invenio_explicit_acls.user": 1 } } ] } } ] } } } } ], "minimum_should_match": 1 } } ], "must": [ { "ids": { "values": [ rec_id ] } } ] } } hits = list(ACLRecordsSearch(user=test_users.u1, context={ 'system_roles': [authenticated_user] }).get_record(rec.id).execute()) assert len(hits) == 1 assert hits[0].meta.id == rec_id print(hits) hits = list(ACLRecordsSearch(user=test_users.u2, context={ 'system_roles': [authenticated_user] }).get_record(rec.id).execute()) assert hits == []
def test_rest_update_record(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: with db.session.begin_nested(): acl = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='update') actor = UserActor(name='u1', users=[test_users.u1], acl=acl, originator=test_users.u1) db.session.add(acl) db.session.add(actor) pid, record = create_record({'keywords': ['blah']}, clz=SchemaEnforcingRecord) RecordIndexer().index(record) current_search_client.indices.refresh() current_search_client.indices.flush() login(client, test_users.u1) response = client.put(record_url(pid), data=json.dumps({ 'keywords': ['test'], 'title': 'blah', 'contributors': [] }), content_type='application/json') assert response.status_code == 200 # put valid but relative schema response = client.put(record_url(pid), data=json.dumps({ 'keywords': ['test'], 'title': 'blah', 'contributors': [], '$schema': 'records/record-v1.0.0.json' }), content_type='application/json') assert response.status_code == 200 rec1 = Record.get_record(pid.object_uuid) assert rec1['keywords'] == ['test'] assert rec1['$schema'] == 'https://localhost/schemas/' + RECORD_SCHEMA login(client, test_users.u2) response = client.put(record_url(pid), data=json.dumps({ 'keywords': ['test1'], 'title': 'blah', 'contributors': [], }), content_type='application/json') assert response.status_code == 403 rec1 = Record.get_record(pid.object_uuid) assert rec1['keywords'] == ['test'] # check value not overwritten # try to pu invalid schema login(client, test_users.u1) response = client.put(record_url(pid), data=json.dumps({ 'keywords': ['test-invalid'], 'title': 'blah-invalid', 'contributors': [], '$schema': 'https://localhost/invalid-schema' }), content_type='application/json') assert response.status_code == 400
def test_create_acl_after_record(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: login(client, test_users.u1) response = client.post(records_url(), data=json.dumps({ 'title': 'blah', 'contributors': [] }), content_type='application/json') assert response.status_code == 201 rest_metadata = get_json(response)['metadata'] assert 'control_number' in rest_metadata current_search_client.indices.refresh() current_search_client.indices.flush() with db.session.begin_nested(): acl1 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='get') actor1 = SystemRoleActor(name='auth', system_role='any_user', acl=acl1, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) # reindex all resources that might be affected by the ACL change current_explicit_acls.reindex_acl(acl1, delayed=False) index, doctype = schema_to_index(RECORD_SCHEMA) rec_md = current_search_client.get( index=index, doc_type=doctype, id=str( PersistentIdentifier.get( 'recid', rest_metadata['control_number']).object_uuid)) clear_timestamp(rec_md) assert rec_md['_source']['_invenio_explicit_acls'] == [{ 'operation': 'get', 'id': acl1.id, 'timestamp': 'cleared', 'system_role': ['any_user'] }] # remove the ACL from the database with db.session.begin_nested(): db.session.delete(acl1) # reindex records affected by the removal of ACL current_explicit_acls.reindex_acl_removed(acl1, delayed=False) # make sure all changes had time to propagate and test current_search_client.indices.refresh() current_search_client.indices.flush() rec_md = current_search_client.get( index=index, doc_type=doctype, id=str( PersistentIdentifier.get( 'recid', rest_metadata['control_number']).object_uuid)) # there is no ACL in the database => no acls are defined nor enforced on the record print(json.dumps(rec_md, indent=4)) assert '_invenio_explicit_acls' not in rec_md['_source']