Example #1
0
 def test02_logout_service_description(self):
     auth = IIIFAuthBasic()
     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' )
Example #2
0
 def test05_login_handler(self):
     """Test login_handler."""
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         response = auth.login_handler()
         self.assertEqual(response.status_code, 401)
         self.assertEqual(response.headers['Content-type'], 'text/html')
         html = response.get_data().decode('utf-8')  # data is bytes in python3
         self.assertEqual(html, '')
     # add good login params and check OK, window close
     h = Headers()
     h.add('Authorization', b'Basic ' +
           base64.b64encode(b'userpass:userpass'))
     with dummy_app.test_request_context('/a_request', headers=h):
         response = auth.login_handler()
         self.assertEqual(response.status_code, 200)
         html = response.get_data().decode('utf-8')
         self.assertTrue(
             re.search(
                 r'<script>window.close\(\);</script>',
                 html))
         set_cookie = response.headers['Set-Cookie']
         self.assertTrue(
             re.search(
                 auth.auth_cookie_name +
                 '=valid-http-basic-login',
                 set_cookie))
     # add bad login params and check fail
     h = Headers()
     h.add('Authorization', b'Basic ' +
           base64.b64encode(b'userpass:bad-pass'))
     with dummy_app.test_request_context('/a_request', headers=h):
         response = auth.login_handler()
         self.assertEqual(response.status_code, 401)
Example #3
0
 def test06_logout_handler(self):
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         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) )
Example #4
0
 def test02_logout_service_description(self):
     """Test logout_service_description."""
     auth = IIIFAuthBasic()
     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')
Example #5
0
 def test06_logout_handler(self):
     """Test logout_handler."""
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         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')  # get_data is bytes in python3
         self.assertTrue(
             re.search(r'<script>window.close\(\);</script>', html))
Example #6
0
 def test07_access_token_handler(self):
     """Test access_token_handler."""
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         response = auth.access_token_handler()
         self.assertEqual(response.status_code, 200)
         self.assertEqual(
             response.headers['Content-type'],
             'application/json')
         # get_data is bytes in python3
         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 Authorization header, check we get token
     h = Headers()
     h.add('Authorization', b'Basic ' +
           base64.b64encode(b'userpass:userpass'))
     with dummy_app.test_request_context('/a_request', headers=h):
         auth = IIIFAuthBasic()
         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'], "secret_token_here")  # FIXME
         self.assertEqual(j['token_type'], "Bearer")
         self.assertEqual(j['expires_in'], 3600)
     # add callback but no Authorization header
     with dummy_app.test_request_context('/a_request?callback=CB'):
         auth = IIIFAuthBasic()
         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")
Example #7
0
 def test07_access_token_handler(self):
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         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 Authorization header, check we get token
     h = Headers()
     h.add('Authorization', 'Basic ' + base64.b64encode('userpass:userpass'))
     with dummy_app.test_request_context('/a_request', headers=h):
         auth = IIIFAuthBasic()
         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'], "secret_token_here" ) #FIXME
         self.assertEqual( j['token_type'], "Bearer" )
         self.assertEqual( j['expires_in'], 3600 )
     # add callback but no Authorization header
     with dummy_app.test_request_context('/a_request?callback=CB'):
         auth = IIIFAuthBasic()
         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" )
Example #8
0
 def test26_IIIFHandler_image_information_response(self):
     """Test IIIFHandler.image_information_response()."""
     c = Config()
     c.api_version = '2.1'
     c.klass_name = 'dummy'
     c.image_dir = os.path.join(os.path.dirname(__file__), '../testimages')
     c.tile_height = 512
     c.tile_width = 512
     c.scale_factors = [1, 2]
     c.host = 'example.org'
     c.port = 80
     i = IIIFHandler(prefix='p',
                     identifier='starfish',
                     config=c,
                     klass=IIIFManipulator,
                     auth=IIIFAuthBasic())
     environ = WSGI_ENVIRON()
     with self.test_app.request_context(environ):
         resp = i.image_information_response()
         jsonb = resp.response[0]
         self.assertIn(b'default', jsonb)
         self.assertNotIn(b'native', jsonb)
         self.assertIn(b'starfish', jsonb)
         self.assertIn(b'scaleFactors', jsonb)
         self.assertIn(b'login', jsonb)
     # v1.1, auto scale factors
     c.api_version = '1.1'
     c.scale_factors = ['auto']
     i = IIIFHandler(prefix='p',
                     identifier='starfish',
                     config=c,
                     klass=IIIFManipulator,
                     auth=None)
     with self.test_app.request_context(environ):
         resp = i.image_information_response()
         jsonb = resp.response[0]
         self.assertNotIn(b'default', jsonb)
         self.assertIn(b'native', jsonb)
         self.assertIn(b'starfish', jsonb)
         self.assertNotIn(b'scaleFactors', jsonb)
     # degraded
     c.api_version = '2.1'
     i = IIIFHandler(prefix='p',
                     identifier='starfish-deg',
                     config=c,
                     klass=IIIFManipulator,
                     auth=None)
     with self.test_app.request_context(environ):
         resp = i.image_information_response()
         jsonb = resp.response[0]
         self.assertIn(b'starfish-deg', jsonb)
Example #9
0
 def test21_IIIFHandler_init(self):
     """Test IIIFHandler class init."""
     # No auth
     c = Config()
     c.api_version = '2.1'
     i = IIIFHandler(prefix='/p',
                     identifier='i',
                     config=c,
                     klass=IIIFManipulator,
                     auth=None)
     self.assertTrue(i.manipulator.api_version, '2.1')
     # Basic auth
     a = IIIFAuthBasic()
     c.host = 'example.org'
     c.port = 80
     c.prefix = '/p'
     i = IIIFHandler(prefix='/p',
                     identifier='i',
                     config=c,
                     klass=IIIFManipulator,
                     auth=a)
     self.assertTrue(i.manipulator.api_version, '2.1')
Example #10
0
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')
Example #11
0
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
Example #12
0
 def test04_image_authn(self):
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         ia = auth.image_authn()
         self.assertEqual( ia, '' )
Example #13
0
 def test03_info_authn(self):
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         ia = auth.info_authn()
         self.assertEqual( ia, False )
Example #14
0
 def test04_image_authn(self):
     """Test image_authn."""
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         ia = auth.image_authn()
         self.assertEqual(ia, '')
Example #15
0
 def test03_info_authn(self):
     """Test info_authn."""
     with dummy_app.test_request_context('/a_request'):
         auth = IIIFAuthBasic()
         ia = auth.info_authn()
         self.assertEqual(ia, False)
Example #16
0
 def test01_init(self):
     """Test inialization."""
     auth = IIIFAuthBasic()
     self.assertTrue(re.match(r'\d+_', auth.cookie_prefix))
     auth = IIIFAuthBasic(cookie_prefix='abc')
     self.assertEqual(auth.cookie_prefix, 'abc')