def test08_google_get_token(self): with dummy_app.test_request_context('/a_request'): with mock.patch('urllib2.urlopen', return_value=Readable('{"a":"b"}')): auth = IIIFAuthGoogle(client_secret_file=csf) config = Struct(host='a_host',port=None) j = auth.google_get_token(config,'prefix') self.assertEqual( j, {'a':'b'} )
def test02_logout_service_description(self): auth = IIIFAuthGoogle(client_secret_file=csf) auth.logout_uri = 'xyz' lsd = auth.logout_service_description() self.assertEqual( lsd['profile'], 'http://iiif.io/api/auth/0/logout' ) self.assertEqual( lsd['@id'], 'xyz' ) self.assertEqual( lsd['label'], 'Logout from image server' )
def test09_google_get_data(self): with dummy_app.test_request_context('/a_request'): with mock.patch('urllib2.urlopen', return_value=Readable('{"c":"d"}')): auth = IIIFAuthGoogle(client_secret_file=csf) config = Struct(host='a_host',port=None) j = auth.google_get_data(config,{'access_token':'TOKEN'}) self.assertEqual( j, {'c':'d'} )
def test06_logout_handler(self): with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.logout_handler() self.assertEqual( response.status_code, 200 ) self.assertEqual( response.headers['Content-type'], 'text/html' ) html = response.get_data() self.assertTrue( re.search(r'<script>window.close\(\);</script>',html) )
def test02_logout_service_description(self): """Test logout_service_description method.""" auth = IIIFAuthGoogle(client_secret_file=csf) auth.logout_uri = 'xyz' lsd = auth.logout_service_description() self.assertEqual(lsd['profile'], 'http://iiif.io/api/auth/0/logout') self.assertEqual(lsd['@id'], 'xyz') self.assertEqual(lsd['label'], 'Logout from image server')
def test10_google_get_data(self): """Test google_get_data method.""" with dummy_app.test_request_context('/a_request'): with mock.patch(self.urlopen_name(), return_value=Readable(b'{"c":"d"}')): auth = IIIFAuthGoogle(client_secret_file=csf) config = Struct(host='a_host', port=None) j = auth.google_get_data(config, {'access_token': 'TOKEN'}) self.assertEqual(j, {'c': 'd'})
def test09_google_get_token(self): """Test google_get_token method.""" with dummy_app.test_request_context('/a_request'): with mock.patch(self.urlopen_name(), return_value=Readable(b'{"a":"b"}')): auth = IIIFAuthGoogle(client_secret_file=csf) config = Struct(host='a_host', port=None) j = auth.google_get_token(config, 'prefix') self.assertEqual(j, {'a': 'b'})
def test05_login_handler(self): with dummy_app.test_request_context('/a_request'): config = Struct(host='a_host',port=None) auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.login_handler(config=config,prefix='wxy') self.assertEqual( response.status_code, 302 ) self.assertEqual( response.headers['Content-type'], 'text/html; charset=utf-8' ) self.assertTrue( re.match(r'https://accounts.google.com/o/oauth2/auth', response.headers['Location']) ) html = response.get_data() self.assertTrue( re.search('<h1>Redirecting...</h1>',html) )
def test06_logout_handler(self): """Test logout_handler method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.logout_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'text/html') html = response.get_data().decode('utf-8') self.assertTrue( re.search(r'<script>window.close\(\);</script>', html))
def test01_init(self): """Test initialize.""" auth = IIIFAuthGoogle(client_secret_file=csf) self.assertTrue(re.match(r'\d+_', auth.cookie_prefix)) auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='abc') self.assertEqual(auth.cookie_prefix, 'abc') self.assertEqual(auth.google_api_client_id, 'SECRET_CODE_537') auth = IIIFAuthGoogle(client_secret_file='/does_not_exist', cookie_prefix='abcd') self.assertEqual(auth.cookie_prefix, 'abcd') self.assertEqual(auth.google_api_client_id, 'oops_missing_client_id')
def test07_home_handler(self): with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) # Avoid actual calls to Google by mocking methods used by home_handler() auth.google_get_token = mock.Mock(return_value='ignored') auth.google_get_data = mock.Mock(return_value={'email':'e@mail','name':'a name'}) response = auth.home_handler() self.assertEqual( response.status_code, 200 ) self.assertEqual( response.headers['Content-type'], 'text/html' ) html = response.get_data() self.assertTrue( re.search(r'<script>window.close\(\);</script>',html) )
def test05_login_handler(self): """Test login_handler method.""" with dummy_app.test_request_context('/a_request'): config = Struct(host='a_host', port=None) auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.login_handler(config=config, prefix='wxy') self.assertEqual(response.status_code, 302) self.assertEqual(response.headers['Content-type'], 'text/html; charset=utf-8') self.assertTrue( re.match(r'https://accounts.google.com/o/oauth2/auth', response.headers['Location'])) html = response.get_data().decode('utf-8') self.assertTrue(re.search('<h1>Redirecting...</h1>', html))
def test08_home_handler(self): """Test home_handler method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) # Avoid actual calls to Google by mocking methods used by # home_handler() auth.google_get_token = mock.Mock(return_value='ignored') auth.google_get_data = mock.Mock(return_value={ 'email': 'e@mail', 'name': 'a name' }) response = auth.home_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'text/html') html = response.get_data().decode('utf-8') self.assertTrue( re.search(r'<script>window.close\(\);</script>', html))
def test07_access_token_handler(self): with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual( response.status_code, 200 ) self.assertEqual( response.headers['Content-type'], 'application/json' ) j = json.loads(response.get_data()) self.assertEqual( j['error_description'], "No login details received" ) self.assertEqual( j['error'], "client_unauthorized" ) # add callback but no account cookie with dummy_app.test_request_context('/a_request?callback=CB'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual( response.status_code, 200 ) self.assertEqual( response.headers['Content-type'], 'application/javascript' ) # strip JavaScript wrapper and then check JSON js = response.get_data() self.assertTrue( re.match('CB\(.*\);',js) ) j = json.loads(js.lstrip('CB(').rstrip(');')) self.assertEqual( j['error_description'], "No login details received" ) self.assertEqual( j['error'], "client_unauthorized" ) # add an account cookie h = Headers() h.add('Cookie', 'lol_account=ACCOUNT_TOKEN') with dummy_app.test_request_context('/a_request', headers=h): auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='lol_') response = auth.access_token_handler() self.assertEqual( response.status_code, 200 ) self.assertEqual( response.headers['Content-type'], 'application/json' ) j = json.loads(response.get_data()) self.assertEqual( j['access_token'], "ACCOUNT_TOKEN" ) self.assertEqual( j['token_type'], "Bearer" )
def test07_access_token_handler(self): """Test access_token_handler method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'application/json') j = json.loads(response.get_data().decode('utf-8')) self.assertEqual(j['error_description'], "No login details received") self.assertEqual(j['error'], "client_unauthorized") # add callback but no account cookie with dummy_app.test_request_context('/a_request?callback=CB'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'application/javascript') # strip JavaScript wrapper and then check JSON js = response.get_data().decode('utf-8') self.assertTrue(re.match('CB\(.*\);', js)) j = json.loads(js.lstrip('CB(').rstrip(');')) self.assertEqual(j['error_description'], "No login details received") self.assertEqual(j['error'], "client_unauthorized") # add an account cookie h = Headers() h.add('Cookie', 'lol_account=ACCOUNT_TOKEN') with dummy_app.test_request_context('/a_request', headers=h): auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='lol_') response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'application/json') j = json.loads(response.get_data().decode('utf-8')) self.assertEqual(j['access_token'], "ACCOUNT_TOKEN") self.assertEqual(j['token_type'], "Bearer")
def add_handler(app, config): """Add a single handler to the app. Adds one IIIF Image API handler to app, with config from config. Arguments: app - Flask app config - Configuration object in which: config.prefix - String path prefix for this handler config.client_prefix - String path prefix seen by client (which may be different because of reverse proxy or such config.klass_name - Manipulator class, e.g. 'pil' config.api_version - e.g. '2.1' config.include_osd - True or False to include OSD config.gauth_client_secret_file - filename if auth_type='gauth' config.access_cookie_lifetime - number of seconds config.access_token_lifetime - number of seconds config.auth_type - Auth type string or 'none' Returns True on success, nothing otherwise. """ auth = None if (config.auth_type is None or config.auth_type == 'none'): pass elif (config.auth_type == 'gauth'): from iiif.auth_google import IIIFAuthGoogle auth = IIIFAuthGoogle(client_secret_file=config.gauth_client_secret_file) elif (config.auth_type == 'basic'): from iiif.auth_basic import IIIFAuthBasic auth = IIIFAuthBasic() elif (config.auth_type == 'clickthrough'): from iiif.auth_clickthrough import IIIFAuthClickthrough auth = IIIFAuthClickthrough() elif (config.auth_type == 'kiosk'): from iiif.auth_kiosk import IIIFAuthKiosk auth = IIIFAuthKiosk() elif (config.auth_type == 'external'): from iiif.auth_external import IIIFAuthExternal auth = IIIFAuthExternal() else: logging.error("Unknown auth type %s, ignoring" % (config.auth_type)) return if (auth is not None): auth.access_cookie_lifetime = config.access_cookie_lifetime auth.access_token_lifetime = config.access_token_lifetime klass = None if (config.klass_name == 'pil'): from iiif.manipulator_pil import IIIFManipulatorPIL klass = IIIFManipulatorPIL elif (config.klass_name == 'netpbm'): from iiif.manipulator_netpbm import IIIFManipulatorNetpbm klass = IIIFManipulatorNetpbm elif (config.klass_name == 'dummy'): from iiif.manipulator import IIIFManipulator klass = IIIFManipulator elif (config.klass_name == 'gen'): from iiif.manipulator_gen import IIIFManipulatorGen klass = IIIFManipulatorGen else: logging.error("Unknown manipulator type %s, ignoring" % (config.klass_name)) return base = urljoin('/', config.prefix + '/') # ensure has trailing slash client_base = urljoin('/', config.client_prefix + '/') # ensure has trailing slash logging.warning("Installing %s IIIFManipulator at %s v%s %s" % (config.klass_name, base, config.api_version, config.auth_type)) params = dict(config=config, klass=klass, auth=auth, prefix=config.client_prefix) app.add_url_rule(base.rstrip('/'), 'prefix_index_page', prefix_index_page, defaults={'config': config}) app.add_url_rule(base, 'prefix_index_page', prefix_index_page, defaults={'config': config}) app.add_url_rule(base + '<string(minlength=1):identifier>/info.json', 'options_handler', options_handler, methods=['OPTIONS']) app.add_url_rule(base + '<string(minlength=1):identifier>/info.json', 'iiif_info_handler', iiif_info_handler, methods=['GET'], defaults=params) if (config.include_osd): app.add_url_rule(base + '<string(minlength=1):identifier>/osd.html', 'osd_page_handler', osd_page_handler, methods=['GET'], defaults=params) app.add_url_rule(base + '<string(minlength=1):identifier>/<path:path>', 'iiif_image_handler', iiif_image_handler, methods=['GET'], defaults=params) if (auth): setup_auth_paths(app, auth, config.client_prefix, params) # redirects to info.json must come after auth app.add_url_rule(base + '<string(minlength=1):identifier>', 'iiif_info_handler', redirect_to=client_base + '<identifier>/info.json') app.add_url_rule(base + '<string(minlength=1):identifier>/', 'iiif_info_handler', redirect_to=client_base + '<identifier>/info.json') return True
def test04_image_authn(self): """Test image_authn method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) ia = auth.image_authn() self.assertEqual(ia, False)
def test07_access_token_handler(self): """Test access_token_handler method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'application/json') j = json.loads(response.get_data().decode('utf-8')) self.assertEqual(j['description'], "No authorization details received") self.assertEqual(j['error'], "client_unauthorized") # add callback but no account cookie with dummy_app.test_request_context('/a_request?messageId=1234'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'text/html') # Check HTML is postMessage, includes an error html = response.get_data().decode('utf-8') self.assertTrue(re.search(r'postMessage\(', html)) self.assertTrue(re.search(r'"error"', html)) # add an account cookie h = Headers() h.add('Cookie', 'lol_account=ACCOUNT_TOKEN') with dummy_app.test_request_context('/a_request', headers=h): auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='lol_') # stub token gen: auth._generate_random_string = lambda x: 'lkjhg' response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'application/json') j = json.loads(response.get_data().decode('utf-8')) self.assertEqual(j['accessToken'], 'lkjhg') # add an account cookie and a messageId h = Headers() h.add('Cookie', 'lol_account=ACCOUNT_TOKEN') with dummy_app.test_request_context('/a_request?messageId=2345', headers=h): auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='lol_') response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual(response.headers['Content-type'], 'text/html') # Check HTML is postMessage, includes messageId, # does not include an error html = response.get_data().decode('utf-8') self.assertTrue(re.search(r'postMessage\(', html)) self.assertTrue(re.search(r'"messageId":\s*"2345"', html)) self.assertFalse(re.search(r'"error"', html))
def test04_image_authn(self): with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) ia = auth.image_authn() self.assertEqual( ia, '' )
def test07_access_token_handler(self): """Test access_token_handler method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual( response.headers['Content-type'], 'application/json') j = json.loads(response.get_data().decode('utf-8')) self.assertEqual( j['description'], "No authorization details received") self.assertEqual(j['error'], "client_unauthorized") # add callback but no account cookie with dummy_app.test_request_context('/a_request?messageId=1234'): auth = IIIFAuthGoogle(client_secret_file=csf) response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual( response.headers['Content-type'], 'text/html') # Check HTML is postMessage, includes an error html = response.get_data().decode('utf-8') self.assertTrue(re.search( r'postMessage\(', html)) self.assertTrue(re.search( r'"error"', html)) # add an account cookie h = Headers() h.add('Cookie', 'lol_account=ACCOUNT_TOKEN') with dummy_app.test_request_context('/a_request', headers=h): auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='lol_') # stub token gen: auth._generate_random_string = lambda x: 'lkjhg' response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual( response.headers['Content-type'], 'application/json') j = json.loads(response.get_data().decode('utf-8')) self.assertEqual(j['accessToken'], 'lkjhg') # add an account cookie and a messageId h = Headers() h.add('Cookie', 'lol_account=ACCOUNT_TOKEN') with dummy_app.test_request_context('/a_request?messageId=2345', headers=h): auth = IIIFAuthGoogle(client_secret_file=csf, cookie_prefix='lol_') response = auth.access_token_handler() self.assertEqual(response.status_code, 200) self.assertEqual( response.headers['Content-type'], 'text/html') # Check HTML is postMessage, includes messageId, # does not include an error html = response.get_data().decode('utf-8') self.assertTrue(re.search( r'postMessage\(', html)) self.assertTrue(re.search( r'"messageId":\s*"2345"', html)) self.assertFalse(re.search( r'"error"', html))
def add_handler(app, config): """Add a single handler to the app. Adds one IIIF Image API handler to app, with config from config. Arguments: app - Flask app config - Configuration object in which: config.prefix - String path prefix for this handler config.client_prefix - String path prefix seen by client (which may be different because of reverse proxy or such config.klass_name - Manipulator class, e.g. 'pil' config.api_version - e.g. '2.1' config.include_osd - True or False to include OSD config.gauth_client_secret_file - filename if auth_type='gauth' config.access_cookie_lifetime - number of seconds config.access_token_lifetime - number of seconds config.auth_type - Auth type string or 'none' Returns True on success, nothing otherwise. """ auth = None if (config.auth_type is None or config.auth_type == 'none'): pass elif (config.auth_type == 'gauth'): from iiif.auth_google import IIIFAuthGoogle auth = IIIFAuthGoogle( client_secret_file=config.gauth_client_secret_file) elif (config.auth_type == 'basic'): from iiif.auth_basic import IIIFAuthBasic auth = IIIFAuthBasic() elif (config.auth_type == 'clickthrough'): from iiif.auth_clickthrough import IIIFAuthClickthrough auth = IIIFAuthClickthrough() elif (config.auth_type == 'kiosk'): from iiif.auth_kiosk import IIIFAuthKiosk auth = IIIFAuthKiosk() elif (config.auth_type == 'external'): from iiif.auth_external import IIIFAuthExternal auth = IIIFAuthExternal() else: logging.error("Unknown auth type %s, ignoring" % (config.auth_type)) return if (auth is not None): auth.access_cookie_lifetime = config.access_cookie_lifetime auth.access_token_lifetime = config.access_token_lifetime klass = None if (config.klass_name == 'pil'): from iiif.manipulator_pil import IIIFManipulatorPIL klass = IIIFManipulatorPIL elif (config.klass_name == 'netpbm'): from iiif.manipulator_netpbm import IIIFManipulatorNetpbm klass = IIIFManipulatorNetpbm elif (config.klass_name == 'dummy'): from iiif.manipulator import IIIFManipulator klass = IIIFManipulator elif (config.klass_name == 'gen'): from iiif.manipulator_gen import IIIFManipulatorGen klass = IIIFManipulatorGen else: logging.error("Unknown manipulator type %s, ignoring" % (config.klass_name)) return base = urljoin('/', config.prefix + '/') # ensure has trailing slash client_base = urljoin('/', config.client_prefix + '/') # ensure has trailing slash logging.warning( "Installing %s IIIFManipulator at %s v%s %s" % (config.klass_name, base, config.api_version, config.auth_type)) params = dict(config=config, klass=klass, auth=auth, prefix=config.client_prefix) app.add_url_rule(base.rstrip('/'), 'prefix_index_page', prefix_index_page, defaults={'config': config}) app.add_url_rule(base, 'prefix_index_page', prefix_index_page, defaults={'config': config}) app.add_url_rule(base + '<string(minlength=1):identifier>/info.json', 'options_handler', options_handler, methods=['OPTIONS']) app.add_url_rule(base + '<string(minlength=1):identifier>/info.json', 'iiif_info_handler', iiif_info_handler, methods=['GET'], defaults=params) if (config.include_osd): app.add_url_rule(base + '<string(minlength=1):identifier>/osd.html', 'osd_page_handler', osd_page_handler, methods=['GET'], defaults=params) app.add_url_rule(base + '<string(minlength=1):identifier>/<path:path>', 'iiif_image_handler', iiif_image_handler, methods=['GET'], defaults=params) if (auth): setup_auth_paths(app, auth, config.client_prefix, params) # redirects to info.json must come after auth app.add_url_rule(base + '<string(minlength=1):identifier>', 'iiif_info_handler', redirect_to=client_base + '<identifier>/info.json') app.add_url_rule(base + '<string(minlength=1):identifier>/', 'iiif_info_handler', redirect_to=client_base + '<identifier>/info.json') return True
def add_handler(app, config, prefixes): """Add a single handler to the app. Adds handlers to app, with config from config. Add prefix to list in prefixes. """ wsgi_prefix = make_prefix(config.api_version, config.klass_name, config.auth_type) prefix = wsgi_prefix if (config.container_prefix): prefix = os.path.join(config.container_prefix, wsgi_prefix) prefixes.append(prefix) auth = None if (config.auth_type is None or config.auth_type == 'none'): pass elif (config.auth_type == 'gauth'): from iiif.auth_google import IIIFAuthGoogle auth = IIIFAuthGoogle( client_secret_file=config.gauth_client_secret_file) elif (config.auth_type == 'basic'): from iiif.auth_basic import IIIFAuthBasic auth = IIIFAuthBasic() elif (config.auth_type == 'clickthrough'): from iiif.auth_clickthrough import IIIFAuthClickthrough auth = IIIFAuthClickthrough() elif (config.auth_type == 'kiosk'): from iiif.auth_kiosk import IIIFAuthKiosk auth = IIIFAuthKiosk() else: print("Unknown auth type %s, ignoring" % (config.auth_type)) return if (auth is not None): auth.access_cookie_lifetime = opt.access_cookie_lifetime auth.access_token_lifetime = opt.access_token_lifetime klass = None if (config.klass_name == 'pil'): from iiif.manipulator_pil import IIIFManipulatorPIL klass = IIIFManipulatorPIL elif (config.klass_name == 'netpbm'): from iiif.manipulator_netpbm import IIIFManipulatorNetpbm klass = IIIFManipulatorNetpbm elif (config.klass_name == 'dummy'): from iiif.manipulator import IIIFManipulator klass = IIIFManipulator elif (config.klass_name == 'gen'): from iiif.manipulator_gen import IIIFManipulatorGen klass = IIIFManipulatorGen else: print("Unknown manipulator type %s, ignoring" % (config.klass_name)) return print("Installing %s IIIFManipulator at /%s/ v%s %s" % (config.klass_name, prefix, config.api_version, config.auth_type)) params = dict(config=config, klass=klass, auth=auth, prefix=prefix) app.add_url_rule('/' + wsgi_prefix, 'prefix_index_page', prefix_index_page, defaults={ 'config': config, 'prefix': prefix }) app.add_url_rule('/' + wsgi_prefix + '/<string(minlength=1):identifier>/info.json', 'options_handler', options_handler, methods=['OPTIONS']) app.add_url_rule('/' + wsgi_prefix + '/<string(minlength=1):identifier>/info.json', 'iiif_info_handler', iiif_info_handler, methods=['GET'], defaults=params) if (config.include_osd): app.add_url_rule('/' + wsgi_prefix + '/<string(minlength=1):identifier>/osd.html', 'osd_page_handler', osd_page_handler, methods=['GET'], defaults=params) app.add_url_rule('/' + wsgi_prefix + '/<string(minlength=1):identifier>/<path:path>', 'iiif_image_handler', iiif_image_handler, methods=['GET'], defaults=params) if (auth): setup_auth_paths(app, auth, wsgi_prefix, params) # redirects to info.json must come after auth app.add_url_rule('/' + wsgi_prefix + '/<string(minlength=1):identifier>', 'iiif_info_handler', redirect_to='/' + prefix + '/<identifier>/info.json') app.add_url_rule('/' + wsgi_prefix + '/<string(minlength=1):identifier>/', 'iiif_info_handler', redirect_to='/' + prefix + '/<identifier>/info.json')
def test03_info_authn(self): """Test info_authn method.""" with dummy_app.test_request_context('/a_request'): auth = IIIFAuthGoogle(client_secret_file=csf) ia = auth.info_authn() self.assertEqual(ia, False)