def check_set_namespace_publicly_mappable(pub_value, log_collector): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set([AuthsourceID('asone')]), storage) handlers.get_user.return_value = (User(AuthsourceID('asone'), Username('u')), False) storage.get_namespace.return_value = Namespace(NamespaceID('n'), False, set([ User(AuthsourceID('astwo'), Username('u2')), User(AuthsourceID('asone'), Username('u')), User(AuthsourceID('asthree'), Username('u'))])) idm.set_namespace_publicly_mappable( AuthsourceID('asone'), Token('t'), NamespaceID('n'), pub_value) assert handlers.get_user.call_args_list == [((AuthsourceID('asone'), Token('t'),), {})] assert storage.get_namespace.call_args_list == [((NamespaceID('n'),), {})] assert storage.set_namespace_publicly_mappable.call_args_list == \ [((NamespaceID('n'), pub_value), {})] print(log_collector) assert_logs_correct(log_collector, 'User asone/u set namespace n public map property to ' + str(pub_value))
def check_set_get_user_handler_ttl(epoch, rel, timervals): handler = create_autospec(UserLookup, spec_set=True, instance=True) timer = create_autospec(time.time, spec_set=True) handler.get_authsource_id.return_value = AuthsourceID('as') hset = UserLookupSet(set([handler]), timer) handler.get_user.return_value = (User(AuthsourceID('as'), Username('u1')), False, epoch, rel) timer.return_value = timervals[0] # cache user for X secs assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u1')), False) # force an error if the handler is called handler.get_user.return_value = None timer.return_value = timervals[1] assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u1')), False) # expect handler call at Y sec handler.get_user.return_value = (User(AuthsourceID('as'), Username('u1')), True, epoch, rel) timer.return_value = timervals[2] assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u1')), True) # check correct number of calls to get_user assert handler.get_user.call_args_list == [((Token('t'), ), {}), ((Token('t'), ), {})]
def test_create_and_get_namespace(service_port, mongo): storage = get_storage_instance(mongo) t = Token('foobar') # fail to create a namespace r = requests.put('http://localhost:' + service_port + '/api/v1/namespace/myns', headers={'Authorization': 'local ' + t.token}) assert_json_error_correct( r.json(), { 'error': { 'httpcode': 401, 'httpstatus': 'Unauthorized', 'appcode': 10020, 'apperror': 'Invalid token', 'message': '10020 Invalid token' } }) assert r.status_code == 401 # succeed at creating a namespace storage.create_local_user(Username('user1'), t.get_hashed_token()) storage.set_local_user_as_admin(Username('user1'), True) r = requests.put('http://localhost:' + service_port + '/api/v1/namespace/myns', headers={'Authorization': 'local ' + t.token}) assert r.status_code == 204 # get the namespace with a populated user list r = requests.get('http://localhost:' + service_port + '/api/v1/namespace/myns', headers={'Authorization': 'local ' + t.token}) assert r.json() == { 'namespace': 'myns', 'publicly_mappable': False, 'users': [] } assert r.status_code == 200 # fail getting a namespace r = requests.get('http://localhost:' + service_port + '/api/v1/namespace/myns1') assert_json_error_correct( r.json(), { 'error': { 'httpcode': 404, 'httpstatus': 'Not Found', 'appcode': 50010, 'apperror': 'No such namespace', 'message': '50010 No such namespace: myns1' } }) assert r.status_code == 404
def test_get_user_fail_invalid_token_token(): with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, status_code=401, json={'error': {'apperror': 'Invalid token', 'message': '10020 Invalid token'}}) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'admin') fail_get_user(kbuh, Token('bar'), InvalidTokenError( 'KBase auth server reported token is invalid.'))
def test_get_user_fail_auth_returned_other_error_token(): with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, status_code=401, json={'error': {'apperror': 'Authentication failed', 'message': '10000 Authentication failed: crap'}}) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'admin') fail_get_user(kbuh, Token('bar'), IOError('Error from KBase auth server: 10000 Authentication failed: crap'))
def test_set_get_user_cache_max_count(): # testing the default of 10k is just silly, not going to bother. handler = create_autospec(UserLookup, spec_set=True, instance=True) timer = create_autospec(time.time, spec_set=True) handler.get_authsource_id.return_value = AuthsourceID('as') hset = UserLookupSet(set([handler]), timer, cache_max_size=2) # add user 1 handler.get_user.return_value = (User(AuthsourceID('as'), Username('u1')), False, None, None) timer.return_value = 0 assert hset.get_user(AuthsourceID('as'), Token('t1')) == \ (User(AuthsourceID('as'), Username('u1')), False) # add user 2 handler.get_user.return_value = (User(AuthsourceID('as'), Username('u2')), True, None, None) timer.return_value = 1 assert hset.get_user(AuthsourceID('as'), Token('t2')) == \ (User(AuthsourceID('as'), Username('u2')), True) # add user 3, user 1 should now be evicted from the cache handler.get_user.return_value = (User(AuthsourceID('as'), Username('u3')), False, None, None) timer.return_value = 2 assert hset.get_user(AuthsourceID('as'), Token('t3')) == \ (User(AuthsourceID('as'), Username('u3')), False) # should only need a handler call for user 1 at this point handler.get_user.return_value = (User(AuthsourceID('as'), Username('u1')), True, None, None) timer.return_value = 3 # get the 3 users. Get user 1 last otherwise it'll evict user 2 from the cache assert hset.get_user(AuthsourceID('as'), Token('t2')) == \ (User(AuthsourceID('as'), Username('u2')), True) assert hset.get_user(AuthsourceID('as'), Token('t3')) == \ (User(AuthsourceID('as'), Username('u3')), False) assert hset.get_user(AuthsourceID('as'), Token('t1')) == \ (User(AuthsourceID('as'), Username('u1')), True) # check that the calls to get_user are as expected: assert handler.get_user.call_args_list == [((Token('t1'), ), {}), ((Token('t2'), ), {}), ((Token('t3'), ), {}), ((Token('t1'), ), {})]
def test_create_namespace(log_collector): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set([AuthsourceID('as')]), storage) handlers.get_user.return_value = (User(AuthsourceID('as'), Username('foo')), True) idm.create_namespace(AuthsourceID('as'), Token('bar'), NamespaceID('baz')) assert handlers.get_user.call_args_list == [((AuthsourceID('as'), Token('bar'),), {})] assert storage.create_namespace.call_args_list == [((NamespaceID('baz'),), {})] assert_logs_correct(log_collector, 'Admin as/foo created namespace baz')
def check_get_user(isadmin, customroles): with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, json={'user': '******', 'expires': 4800, 'cachefor': 5600}) m.get('http://my1stauthservice.com/api/api/V2/me', request_headers={'Authorization': 'bar'}, json={'customroles': customroles}) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'mapping_admin') assert kbuh.get_user(Token('bar')) == \ (User(AuthsourceID('kbase'), Username('u1')), isadmin, 4, 5)
def test_get_namespace_not_admin(): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set(), storage) storage.get_namespace.return_value = Namespace(NamespaceID('n'), True, set([ User(AuthsourceID('a'), Username('u')), User(AuthsourceID('a'), Username('u1'))])) handlers.get_user.return_value = (User(AuthsourceID('b'), Username('u2')), False) assert idm.get_namespace(NamespaceID('n'), AuthsourceID('b'), Token('t')) == Namespace( NamespaceID('n'), True, None) assert storage.get_namespace.call_args_list == [((NamespaceID('n'), ), {})] assert handlers.get_user.call_args_list == [((AuthsourceID('b'), Token('t')), {})]
def test_set_public_and_list_namespaces(service_port, mongo): storage = get_storage_instance(mongo) lut = Token('foobar') u = Username('lu') storage.create_local_user(u, lut.get_hashed_token()) priv = NamespaceID('priv') storage.create_namespace(priv) storage.add_user_to_namespace(priv, User(AuthsourceID('local'), u)) storage.set_namespace_publicly_mappable(priv, True) pub = NamespaceID('pub') storage.create_namespace(pub) storage.add_user_to_namespace(pub, User(AuthsourceID('local'), u)) r = requests.put('http://localhost:' + service_port + '/api/v1/namespace/priv/set?publicly_mappable=false', headers={'Authorization': 'local ' + lut.token}) assert r.status_code == 204 r = requests.put('http://localhost:' + service_port + '/api/v1/namespace/pub/set?publicly_mappable=true', headers={'Authorization': 'local ' + lut.token}) assert r.status_code == 204 r = requests.get('http://localhost:' + service_port + '/api/v1/namespace') assert r.json() == { 'publicly_mappable': ['pub'], 'privately_mappable': ['priv'] } r = requests.put('http://localhost:' + service_port + '/api/v1/namespace/missing/set?publicly_mappable=false', headers={'Authorization': 'local ' + lut.token}) assert_json_error_correct( r.json(), { 'error': { 'httpcode': 404, 'httpstatus': 'Not Found', 'appcode': 50010, 'apperror': 'No such namespace', 'message': '50010 No such namespace: missing' } }) assert r.status_code == 404
def test_init(): with requests_mock.Mocker() as m: m.get('http://whee.com/', request_headers={'Accept': 'application/json'}, json={'version': '0.1.2', 'gitcommithash': 'hashyhash', 'servertime': 3}) kbuh = KBaseUserLookup('http://whee.com', Token('foo'), 'admin') assert kbuh.auth_url == 'http://whee.com/'
def test_get_user_fail_invalid_token_me(): # this should basically be impossible, but it doesn't hurt to test it with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, json={'user': '******', 'expires': 2000, 'cachefor': 3000}) m.get('http://my1stauthservice.com/api/api/V2/me', request_headers={'Authorization': 'bar'}, status_code=401, json={'error': {'apperror': 'Invalid token', 'message': '10020 Invalid token'}}) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'admin') fail_get_user(kbuh, Token('bar'), InvalidTokenError( 'KBase auth server reported token is invalid.'))
def test_get_user_fail_not_json_token(log_collector): html = '<html><body>Sorry gopsasquatchpron.com has been shut down</body></html>' with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, status_code=404, text=html) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'admin') fail_get_user(kbuh, Token('bar'), IOError('Non-JSON response from KBase auth server, status code: 404')) assert_logs_correct( log_collector, 'Non-JSON response from KBase auth server, status code: 404, response:\n' + html)
def test_get_user_fail_auth_returned_other_error_me(): # this should basically be impossible, but it doesn't hurt to test it with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, json={'user': '******', 'expires': 2000, 'cachefor': 3000}) m.get('http://my1stauthservice.com/api/api/V2/me', request_headers={'Authorization': 'bar'}, status_code=401, json={'error': {'apperror': 'Authentication failed', 'message': '10000 Authentication failed: crap'}}) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'admin') fail_get_user(kbuh, Token('bar'), IOError('Error from KBase auth server: 10000 Authentication failed: crap'))
def test_create_namespace_fail_no_admin_authsource_provider(): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set([AuthsourceID('bs')]), storage) fail_create_namespace(idm, AuthsourceID('as'), Token('t'), NamespaceID('n'), UnauthorizedError( 'Auth source as is not configured as a provider of system administration status'))
def check_is_valid_user(json, result): with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/users/?list=imauser', request_headers={'Authorization': 'foo'}, json=json) kbuh = get_user_handler('http://my1stauthservice.com/api/', Token('foo'), 'admin') assert kbuh.is_valid_user(Username('imauser')) == (result, None, 3600)
def check_missing_keys(json, missing_keys): with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/', request_headers={'Accept': 'application/json'}, json=json) fail_init('http://my1stauthservice.com', Token('foo'), 'admin', IOError( 'http://my1stauthservice.com/ does not appear to be the KBase auth server. ' + 'The root JSON response does not contain the expected keys ' + missing_keys))
def check_local_get_user_admin(isadmin): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) storage.get_user.return_value = (Username('bar'), isadmin) assert LocalUserLookup(storage).get_user(Token('foo')) == \ (User(AuthsourceID('local'), Username('bar')), isadmin, None, 300) thash = '2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae' assert storage.get_user.call_args_list == [((HashedToken(thash), ), {})]
def test_create_namespace_fail_not_admin(): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set([AuthsourceID('as')]), storage) handlers.get_user.return_value = (User(AuthsourceID('as'), Username('foo')), False) fail_create_namespace(idm, AuthsourceID('as'), Token('t'), NamespaceID('n'), UnauthorizedError('User as/foo is not a system administrator'))
def test_remove_user_from_namespace(log_collector): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set([AuthsourceID('astwo')]), storage) handlers.get_user.return_value = (User(AuthsourceID('astwo'), Username('foo')), True) idm.remove_user_from_namespace( AuthsourceID('astwo'), Token('t'), NamespaceID('ns1'), User(AuthsourceID('asone'), Username('u1'))) assert handlers.get_user.call_args_list == [((AuthsourceID('astwo'), Token('t'),), {})] assert storage.remove_user_from_namespace.call_args_list == \ [((NamespaceID('ns1'), User(AuthsourceID('asone'), Username('u1'))), {})] assert_logs_correct(log_collector, 'Admin astwo/foo removed user asone/u1 from namespace ns1')
def test_get_user_fail_not_json_me(log_collector): html = '<html><body>Sorry notthensa.com has been shut down</body></html>' with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/token', request_headers={'Authorization': 'bar'}, json={'user': '******', 'expires': 2000, 'cachefor': 3000}) m.get('http://my1stauthservice.com/api/api/V2/me', request_headers={'Authorization': 'bar'}, status_code=404, text=html) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('foo'), 'mapping_admin') fail_get_user(kbuh, Token('bar'), IOError('Non-JSON response from KBase auth server, status code: 404')) assert_logs_correct( log_collector, 'Non-JSON response from KBase auth server, status code: 404, response:\n' + html)
def test_init_with_builder(): with requests_mock.Mocker() as m: m.get('http://whee.com/', request_headers={'Accept': 'application/json'}, json={'version': '0.1.2', 'gitcommithash': 'hashyhash', 'servertime': 3}) kbuh = build_lookup({'url': 'http://whee.com', 'token': 'foo', 'admin-role': 'admin'}) assert kbuh.auth_url == 'http://whee.com/' # reach into the implementation here to avoid running all tests twice, one for constructor, # one for builder. Outweights the bad practice here assert kbuh._token == Token('foo') assert kbuh._kbase_system_admin == 'admin'
def test_create_namespace_fail_None_input(): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set(), storage) as_ = AuthsourceID('foo') t = Token('t') n = NamespaceID('n') # authsource id is checked by the handler set fail_create_namespace(idm, as_, None, n, TypeError('token cannot be None')) fail_create_namespace(idm, as_, t, None, TypeError('namespace_id cannot be None'))
def test_init_fail_auth_returned_error(): # there isn't really a believable error the auth service could generate at the root, so # we just use any old error with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/', request_headers={'Accept': 'application/json'}, status_code=401, json={'error': {'apperror': 'Authentication failed', 'message': '10000 Authentication failed: crap'}}) fail_init('http://my1stauthservice.com', Token('foo'), 'admin', IOError('Error from KBase auth server: 10000 Authentication failed: crap'))
def test_is_valid_user_fail_auth_returned_other_error(): with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/api/api/V2/users/?list=supausah2', request_headers={'Authorization': 'baz'}, status_code=400, json={'error': {'apperror': 'Authentication failed', 'message': '10000 Authentication failed: crap'}}) kbuh = get_user_handler('http://my1stauthservice.com/api', Token('baz'), 'admin') fail_is_valid_user(kbuh, Username('supausah2'), IOError( 'Error from KBase auth server: 10000 Authentication failed: crap'))
def test_add_user_to_namespace_fail_no_such_user(): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set([AuthsourceID('asone')]), storage) handlers.get_user.return_value = (User(AuthsourceID('asone'), Username('bar')), True) handlers.is_valid_user.return_value = False fail_add_user_to_namespace(idm, AuthsourceID('asone'), Token('t'), NamespaceID('n'), User(AuthsourceID('asone'), Username('u')), NoSuchUserError('asone/u'))
def check_set_get_user_default_cache_ttl(hset, handler, timer, timervals): handler.get_user.return_value = (User(AuthsourceID('as'), Username('u')), False, None, None) timer.return_value = timervals[0] # user will not be in cache assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u')), False) # user is now cached handler.get_user.return_value = None # should cause error if called from now on timer.return_value = timervals[1] # just below default cache time assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u')), False) # now expire the user handler.get_user.return_value = (User(AuthsourceID('as'), Username('u')), True, None, None) timer.return_value = timervals[2] assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u')), True) # get the user again, should be cached. handler.get_user.return_value = None # should cause error if called from now on timer.return_value = timervals[3] assert hset.get_user(AuthsourceID('as'), Token('t')) == \ (User(AuthsourceID('as'), Username('u')), True) assert handler.get_user.call_args_list == [((Token('t'), ), {}), ((Token('t'), ), {})]
def test_token_hash(): # string hashes will change from instance to instance of the python interpreter, and therefore # tests can't be written that directly test the hash value. See # https://docs.python.org/3/reference/datamodel.html#object.__hash__ assert hash(Token('foo')) == hash(Token('foo')) assert hash(Token('bar')) == hash(Token('bar')) assert hash(Token('foo')) != hash(Token('bar'))
def test_set_namespace_publicly_mappable_fail_None_input(): storage = create_autospec(IDMappingStorage, spec_set=True, instance=True) handlers = create_autospec(UserLookupSet, spec_set=True, instance=True) idm = IDMapper(handlers, set(), storage) aid = AuthsourceID('asone') t = Token('t') n = NamespaceID('id') e = ' cannot be None' # handler set checks the authsource id fail_set_namespace_publicly_mappable(idm, aid, None, n, TypeError('token' + e)) fail_set_namespace_publicly_mappable(idm, aid, t, None, TypeError('namespace_id' + e))
def test_init_fail_not_json(log_collector): html = '<html><body>Sorry mylittleponypron.com has been shut down</body></html>' with requests_mock.Mocker() as m: m.get('http://my1stauthservice.com/', request_headers={'Accept': 'application/json'}, status_code=404, text=html) fail_init('http://my1stauthservice.com/', Token('foo'), 'admin', IOError('Non-JSON response from KBase auth server, status code: 404')) assert_logs_correct( log_collector, 'Non-JSON response from KBase auth server, status code: 404, response:\n' + html)