def __init__(self, threshold=500, default_timeout=300, ignore_errors=False): BaseCache.__init__(self, default_timeout=default_timeout) CachelibSimpleCache.__init__(self, threshold=threshold, default_timeout=default_timeout) self.ignore_errors = ignore_errors
def __init__(self, app=None, *, base_url=None, client_id=None, client_secret=None, cache=None, scope='openid', url_prefix='/oauth2', session_key='flask-auth0-cookie'): # :param app: Flask app # :param base_url: your identity provider's base url # :param client_id: CLIENT_ID # :param client_secret: CLIENT_SECRET # :param cache: a cache object that implements `werkzeug.contrib.cache.BaseCache` to store the tokens in # :param scope: oauth2 scopes # :param url_prefix: what should be the prefix of all the routes needed for oauth2. default = /oauth2 # :param session_key: name of the key used in the session to store the uid self.app = app self.user_agent = f"{__name__}/{__version__} python-requests/{requests.__version__}" self.base_url = base_url self.client_id = client_id self.client_secret = client_secret self.scope = scope self.url_prefix = url_prefix self.session_key = session_key # User actions self._after_login_handler = None self._after_logout_handler = None self._after_refresh_handler = None self._logger = None # Setup backend cache if cache is None: self.cache = SimpleCache() elif isinstance(cache, BaseCache): self.cache = cache else: raise ValueError( f'your backend cache must implement `cachelib.BaseCache`. {cache} is {type(cache)}' ) # Utilities self.signer = None self.hasher = None self.openid_config = None if app is not None: self.init_app(app)
def __init__(self, app=None, route=None, blueprint=None, stream_cache=None, path='templates.yaml'): self.app = app self._route = route self._intent_view_funcs = {} self._intent_converts = {} self._intent_defaults = {} self._intent_mappings = {} self._launch_view_func = None self._session_ended_view_func = None self._on_session_started_callback = None self._default_intent_view_func = None self._player_request_view_funcs = {} self._player_mappings = {} self._player_converts = {} if app is not None: self.init_app(app, path) elif blueprint is not None: self.init_blueprint(blueprint, path) if stream_cache is None: self.stream_cache = SimpleCache() else: self.stream_cache = stream_cache
def _simple(self, **kwargs): """Returns a :class:`SimpleCache` instance .. warning:: This cache system might not be thread safe. Use with caution. """ kwargs.update(dict(threshold=self._config('threshold', 500))) return SimpleCache(**kwargs)
def test_dynamic_permission_needs_cache_invalidation(app, dynamic_permission): """Testing DynamicPermission refreshes needs. This is important when protecting a view with @permission.require(http_exception=403) If cache does not get invalidated, the needs will only be refreshed when the Python process restarts. """ cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): user_can_all = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_open) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.flush() permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.needs == set([Need(method='id', value=1)]) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.flush() assert permission_open.needs == set( [Need(method='id', value=1), Need(method='id', value=2)] )
def test_invenio_access_permission_cache(app, dynamic_permission): """Caching the user using memory caching.""" cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): user_can_all = User(email='*****@*****.**') user_can_open = User(email='*****@*****.**') user_can_open_1 = User(email='*****@*****.**') db.session.add(user_can_all) db.session.add(user_can_open) db.session.add(user_can_open_1) db.session.add(ActionUsers(action='open', user=user_can_all)) db.session.flush() permission_open = dynamic_permission(ActionNeed('open')) identity_open = FakeIdentity(UserNeed(user_can_open.id)) assert not permission_open.allows(identity_open) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) db.session.add(ActionUsers(action='open', user=user_can_open)) db.session.flush() permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_open) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) db.session.add(ActionUsers(action='open', argument=1, user=user_can_open_1)) db.session.flush() identity_open_1 = FakeIdentity(UserNeed(user_can_open_1.id)) permission_open_1 = dynamic_permission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_open_1) assert permission_open_1.allows(identity_open_1) assert current_access.get_action_cache('open::1') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=3)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) )
def init_app (self, app): app.config.from_object (Config) for layer in app.config['TILE_LAYERS']: if 'map_style' in layer: renderers[layer['id']] = Render (app, layer) app.tile_cache = SimpleCache ( threshold = TILE_CACHE_SIZE, default_timeout = TILE_CACHE_TIMEOUT )
def decorator(func): @wraps(func) def decorated(*args, **kwargs): cache_id = key(*args, **kwargs) return_value = decorated.cache.get(cache_id) if return_value is None: return_value = func(*args, **kwargs) decorated.cache.set( cache_id, return_value if return_value is not None else NO_DATA, timeout=timeout) elif return_value == NO_DATA: return_value = None return return_value decorated.cache = SimpleCache() return decorated
def simple(config, *args, **kwargs): defaults = dict(gen_defaults('threshold', **config)) defaults.update(kwargs) return SimpleCache(*args, **defaults)
def _factory(self, *args, **kwargs): return SimpleCache(*args, **kwargs)
"postgresql": "postgresql+psycopg2", "mysql": "mysql", "sqllite": "sqllite" } METADATA_DB_DEFAULT_PORTS = {"postgresql": 5432, "mysql": 3306} BROKER_PREFIXES = {"redis": "redis", "rabbitmq": "pyamqp"} BROKER_DEFAULT_PORTS = {"redis": 6379, "rabbitmq": 5672} SUPERSET_RESULTS_BACKENDS = { "simple": lambda: SimpleCache(threshold=get_env( "SUPERSET_SIMPLE_RESULTS_BACKEND_THRESHOLD", default=10, cast=int), default_timeout=get_env( "SUPERSET_SIMPLE_RESULTS_BACKEND_DEFAULT_TIMEOUT", default=300, cast=float)), "redis": lambda: RedisCache( host=get_env("SUPERSET_REDIS_RESULTS_BACKEND_HOST"), port=get_env( "SUPERSET_REDIS_RESULTS_BACKEND_PORT", default=6379, cast=int), password=get_env("SUPERSET_REDIS_RESULTS_BACKEND_PASSWORD"), key_prefix=get_env("SUPERSET_REDIS_RESULTS_BACKEND_KEY_PREFIX", default="superset_results"), db=get_env("SUPERSET_REDIS_RESULTS_BACKEND_DB", default=0, cast=int), default_timeout=get_env( "SUPERSET_REDIS_RESULTS_BACKEND_DEFAULT_TIMEOUT", default=300, cast=float)),
def simple(app, config, args, kwargs): kwargs.update(dict(threshold=config['CACHE_THRESHOLD'])) return SimpleCache(*args, **kwargs)
class JwtManager: # pylint: disable=too-many-instance-attributes """Manages the JWT verification and JWKS key lookup.""" ALGORITHMS = 'RS256' def __init__(self, app=None): """Initialize the JWTManager instance.""" # These are all set in the init_app function, but are listed here for easy reference self.app = app self.well_known_config = None self.well_known_obj_cache = None self.algorithms = JwtManager.ALGORITHMS self.jwks_uri = None self.issuer = None self.audience = None self.client_secret = None self.cache = None self.caching_enabled = False self.jwt_oidc_test_mode = False self.jwt_oidc_test_keys = None if app is not None: self.init_app(app) def init_app(self, app): """Initialize this extension. if the config['JWT_OIDC_WELL_KNOWN_CONFIG'] is set, then try to load the JWKS_URI & ISSUER from that If it is not set attempt to load the JWKS_URI and ISSUE from the application config Required settings to function: WELL_KNOWN_CONFIG (optional) is this is set, the JWKS_URI & ISSUER will be loaded from there JWKS_URI: the endpoint defined for the jwks_keys ISSUER: the endpoint for the issuer of the tokens ALGORITHMS: only RS256 is supported AUDIENCE: the oidc audience (or API_IDENTIFIER) CLIENT_SECRET: the shared secret / key assigned to the client (audience) """ self.app = app self.jwt_oidc_test_mode = app.config.get('JWT_OIDC_TEST_MODE', None) # # CHECK IF WE"RE RUNNING IN TEST_MODE!! # if self.jwt_oidc_test_mode: app.logger.debug( 'JWT MANAGER running in test mode, using locally defined certs & tokens' ) self.issuer = app.config.get('JWT_OIDC_TEST_ISSUER', 'localhost.localdomain') self.jwt_oidc_test_keys = app.config.get('JWT_OIDC_TEST_KEYS', None) self.audience = app.config.get('JWT_OIDC_TEST_AUDIENCE', None) self.client_secret = app.config.get('JWT_OIDC_TEST_CLIENT_SECRET', None) self.jwt_oidc_test_private_key_pem = app.config.get( 'JWT_OIDC_TEST_PRIVATE_KEY_PEM', None) if self.jwt_oidc_test_keys: app.logger.debug('local key being used: {}'.format( self.jwt_oidc_test_keys)) else: app.logger.error( 'Attempting to run JWT Manager with no local key assigned') raise Exception( 'Attempting to run JWT Manager with no local key assigned') else: self.algorithms = app.config.get( 'JWT_OIDC_ALGORITHMS', JwtManager.ALGORITHMS).replace(' ', '')\ .split(',') # If the WELL_KNOWN_CONFIG is set, then go fetch the JWKS & ISSUER self.well_known_config = app.config.get( 'JWT_OIDC_WELL_KNOWN_CONFIG', None) if self.well_known_config: # try to get the jwks & issuer from the well known config # jurl = urlopen(url=self.well_known_config, context=ssl.SSLContext()) # for gangster testing jurl = urlopen(url=self.well_known_config) self.well_known_obj_cache = json.loads( jurl.read().decode('utf-8')) self.jwks_uri = self.well_known_obj_cache['jwks_uri'] self.issuer = self.well_known_obj_cache['issuer'] else: self.jwks_uri = app.config.get('JWT_OIDC_JWKS_URI', None) self.issuer = app.config.get('JWT_OIDC_ISSUER', None) # Setup JWKS caching self.caching_enabled = app.config.get('JWT_OIDC_CACHING_ENABLED', False) if self.caching_enabled: self.cache = SimpleCache(default_timeout=app.config.get( 'JWT_OIDC_JWKS_CACHE_TIMEOUT', 300)) self.audience = app.config.get('JWT_OIDC_AUDIENCE', None) self.client_secret = app.config.get('JWT_OIDC_CLIENT_SECRET', None) app.logger.debug('JWKS_URI: {}'.format(self.jwks_uri)) app.logger.debug('ISSUER: {}'.format(self.issuer)) app.logger.debug('ALGORITHMS: {}'.format(self.algorithms)) app.logger.debug('AUDIENCE: {}'.format(self.audience)) app.logger.debug('CLIENT_SECRET: {}'.format(self.client_secret)) app.logger.debug('JWT_OIDC_TEST_MODE: {}'.format( self.jwt_oidc_test_mode)) app.logger.debug('JWT_OIDC_TEST_KEYS: {}'.format( self.jwt_oidc_test_keys)) # set the auth error handler auth_err_handler = app.config.get('JWT_OIDC_AUTH_ERROR_HANDLER', JwtManager.handle_auth_error) app.register_error_handler(AuthError, auth_err_handler) app.teardown_appcontext(self.teardown) def teardown(self, exception): """Remove any module items. This is a flask extension lifecycle hook. """ # ctx = _app_ctx_stack.top # if hasattr(ctx, 'cached object'): @staticmethod def handle_auth_error(ex): """Error handler.""" response = jsonify(ex.error) response.status_code = ex.status_code return response @staticmethod def get_token_auth_header(): """Obtain the access token from the Authorization Header.""" auth = request.headers.get('Authorization', None) if not auth: raise AuthError( { 'code': 'authorization_header_missing', 'description': 'Authorization header is expected' }, 401) parts = auth.split() if parts[0].lower() != 'bearer': raise AuthError( { 'code': 'invalid_header', 'description': 'Authorization header must start with Bearer' }, 401) if len(parts) < 2: raise AuthError( { 'code': 'invalid_header', 'description': 'Token not found after Bearer' }, 401) if len(parts) > 2: raise AuthError( { 'code': 'invalid_header', 'description': 'Authorization header is an invalid token structure' }, 401) return parts[1] @staticmethod def _get_token_auth_cookie(): """Obtain the access token from the cookie.""" cookie_name = current_app.config.get('JWT_OIDC_AUTH_COOKIE_NAME', 'oidc-jwt') cookie = request.cookies.get(cookie_name, None) if not cookie: raise AuthError( { 'code': 'authorization_cookie_missing', 'description': 'Authorization cookie is expected' }, 401) return cookie def contains_role(self, roles): """Check that the listed roles are in the token using the registered callback. Args: roles [str,]: Comma separated list of valid roles JWT_ROLE_CALLBACK (fn): The callback added to the Flask configuration """ token = self.get_token_auth_header() unverified_claims = jwt.get_unverified_claims(token) roles_in_token = current_app.config['JWT_ROLE_CALLBACK']( unverified_claims) if any(elem in roles_in_token for elem in roles): return True return False def has_one_of_roles(self, roles): """Check that at least one of the roles are in the token using the registered callback. Args: roles [str,]: Comma separated list of valid roles JWT_ROLE_CALLBACK (fn): The callback added to the Flask configuration """ def decorated(f): @wraps(f) def wrapper(*args, **kwargs): self._require_auth_validation(*args, **kwargs) if self.contains_role(roles): return f(*args, **kwargs) raise AuthError( { 'code': 'missing_a_valid_role', 'description': 'Missing a role required to access this endpoint' }, 401) return wrapper return decorated def validate_roles(self, required_roles): """Check that the listed roles are in the token using the registered callback. Args: required_roles [str,]: Comma separated list of required roles JWT_ROLE_CALLBACK (fn): The callback added to the Flask configuration """ token = self.get_token_auth_header() unverified_claims = jwt.get_unverified_claims(token) roles_in_token = current_app.config['JWT_ROLE_CALLBACK']( unverified_claims) if all(elem in roles_in_token for elem in required_roles): return True return False def requires_roles(self, required_roles): """Check that the listed roles are in the token using the registered callback. Args: required_roles [str,]: Comma separated list of required roles JWT_ROLE_CALLBACK (fn): The callback added to the Flask configuration """ def decorated(f): @wraps(f) def wrapper(*args, **kwargs): self._require_auth_validation(*args, **kwargs) if self.validate_roles(required_roles): return f(*args, **kwargs) raise AuthError( { 'code': 'missing_required_roles', 'description': 'Missing the role(s) required to access this endpoint' }, 401) return wrapper return decorated def requires_auth(self, f): """Validate the Bearer Token.""" @wraps(f) def decorated(*args, **kwargs): self._require_auth_validation(*args, **kwargs) return f(*args, **kwargs) return decorated def requires_auth_cookie(self, f): """Validate the Cookie.""" @wraps(f) def decorated(*args, **kwargs): self._require_auth_cookie_validation(*args, **kwargs) return f(*args, **kwargs) return decorated def _require_auth_validation(self, *args, **kwargs): # pylint: disable=unused-argument token = self.get_token_auth_header() self._validate_token(token) def _require_auth_cookie_validation(self, *args, **kwargs): # pylint: disable=unused-argument token = self._get_token_auth_cookie() self._validate_token(token) def _validate_token(self, token): try: unverified_header = jwt.get_unverified_header(token) except jwt.JWTError as jerr: raise AuthError( { 'code': 'invalid_header', 'description': 'Invalid header. ' 'Use an RS256 signed JWT Access Token' }, 401) from jerr if unverified_header['alg'] == 'HS256': raise AuthError( { 'code': 'invalid_header', 'description': 'Invalid header. ' 'Use an RS256 signed JWT Access Token' }, 401) if 'kid' not in unverified_header: raise AuthError( { 'code': 'invalid_header', 'description': 'Invalid header. ' 'No KID in token header' }, 401) rsa_key = self.get_rsa_key(self.get_jwks(), unverified_header['kid']) if not rsa_key and self.caching_enabled: # Could be key rotation, invalidate the cache and try again self.cache.delete('jwks') rsa_key = self.get_rsa_key(self.get_jwks(), unverified_header['kid']) if not rsa_key: raise AuthError( { 'code': 'invalid_header', 'description': 'Unable to find jwks key referenced in token' }, 401) try: payload = jwt.decode(token, rsa_key, algorithms=self.algorithms, audience=self.audience, issuer=self.issuer) _request_ctx_stack.top.current_user = g.jwt_oidc_token_info = payload except jwt.ExpiredSignatureError as sig: raise AuthError( { 'code': 'token_expired', 'description': 'token has expired' }, 401) from sig except jwt.JWTClaimsError as jwe: raise AuthError( { 'code': 'invalid_claims', 'description': 'incorrect claims,' ' please check the audience and issuer' }, 401) from jwe except Exception as exc: raise AuthError( { 'code': 'invalid_header', 'description': 'Unable to parse authentication' ' token.' }, 401) from exc def get_jwks(self): """Return the test, cached or fetched JWKS for the KID provided.""" if self.jwt_oidc_test_mode: return self.jwt_oidc_test_keys if self.caching_enabled: return self._get_jwks_from_cache() return self._fetch_jwks_from_url() def _get_jwks_from_cache(self): jwks = self.cache.get('jwks') if jwks is None: jwks = self._fetch_jwks_from_url() self.cache.set('jwks', jwks) return jwks def _fetch_jwks_from_url(self): jsonurl = urlopen(self.jwks_uri) return json.loads(jsonurl.read().decode('utf-8')) def create_jwt(self, claims, header): """Create a token for the client and JWKS kid provided.""" token = jwt.encode(claims, self.jwt_oidc_test_private_key_pem, headers=header, algorithm='RS256') return token @staticmethod def get_rsa_key(jwks, kid): """Return the matching RSA key for kid, from the jwks array.""" rsa_key = {} for key in jwks['keys']: if key['kid'] == kid: rsa_key = { 'kty': key['kty'], 'kid': key['kid'], 'use': key['use'], 'n': key['n'], 'e': key['e'] } return rsa_key
def test_invenio_access_permission_cache_users_updates( app, dynamic_permission ): """Testing ActionUsers cache with inserts/updates/deletes.""" cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): # Creation of some data to test. user_1 = User(email='*****@*****.**') user_2 = User(email='*****@*****.**') user_3 = User(email='*****@*****.**') user_4 = User(email='*****@*****.**') user_5 = User(email='*****@*****.**') user_6 = User(email='*****@*****.**') db.session.add(user_1) db.session.add(user_2) db.session.add(user_3) db.session.add(user_4) db.session.add(user_5) db.session.add(user_6) db.session.add(ActionUsers(action='open', user=user_1)) db.session.add(ActionUsers(action='write', user=user_4)) db.session.flush() # Creation identities to test. identity_user_1 = FakeIdentity(UserNeed(user_1.id)) identity_user_2 = FakeIdentity(UserNeed(user_2.id)) identity_user_3 = FakeIdentity(UserNeed(user_3.id)) identity_user_4 = FakeIdentity(UserNeed(user_4.id)) identity_user_5 = FakeIdentity(UserNeed(user_5.id)) identity_user_6 = FakeIdentity(UserNeed(user_6.id)) # Test if user 1 can open. In this case, the cache should store only # this object. permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_user_1) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) # Test if user 4 can write. In this case, the cache should have this # new object and the previous one (Open is allowed to user_1) permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_user_4) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1)]), set([]) ) # If we add a new user to the action open, the open action in cache # should be removed but it should still containing the write entry. db.session.add(ActionUsers(action='open', user=user_2)) db.session.flush() assert current_access.get_action_cache('open') is None permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_user_2) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) # Test if the new user is added to the action 'open' permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_user_4) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) # If we update an action swapping a user, the cache containing the # action, should be removed. user_4_action_write = ActionUsers.query.filter( ActionUsers.action == 'write' and ActionUsers.user == user_4).first() user_4_action_write.user = user_3 db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) # Test if the user_3 can now write. permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_user_4) permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_user_3) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=3)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) # If we remove a user from an action, the cache should clear the # action item. user_3_action_write = ActionUsers.query.filter( ActionUsers.action == 'write' and ActionUsers.user == user_3).first() db.session.delete(user_3_action_write) db.session.flush() assert current_access.get_action_cache('write') is None # If no one is allowed to perform an action then everybody is allowed. permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_user_3) assert current_access.get_action_cache('write') == ( set([]), set([]) ) db.session.add(ActionUsers(action='write', user=user_5)) db.session.flush() permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_user_5) permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_user_3) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=5)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) # If you update the name of an existing action, the previous action # and the new action should be remove from cache. permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_user_5) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=5)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2)]), set([]) ) user_5_action_write = ActionUsers.query.filter( ActionUsers.action == 'write' and ActionUsers.user == user_5).first() user_5_action_write.action = 'open' db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is None permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_user_1) assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5)]), set([]) ) db.session.add(ActionUsers(action='write', user=user_4)) permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_user_5) assert current_access.get_action_cache('write') == ( set([Need(method='id', value=4)]), set([]) ) db.session.add(ActionUsers(action='open', argument='1', user=user_6)) db.session.flush() permission_open_1 = dynamic_permission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_user_6) assert permission_open_1.allows(identity_user_6) assert current_access.get_action_cache('open::1') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5), Need(method='id', value=6)]), set([]) ) user_6_action_open_1 = ActionUsers.query.filter_by( action='open', argument='1', user_id=user_6.id).first() user_6_action_open_1.argument = '2' db.session.flush() assert current_access.get_action_cache('open::1') is None assert current_access.get_action_cache('open::2') is None permission_open_2 = dynamic_permission( ParameterizedActionNeed('open', '2')) assert permission_open_2.allows(identity_user_6) assert current_access.get_action_cache('open::2') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5), Need(method='id', value=6)]), set([]) ) # open action cache should remain as before assert current_access.get_action_cache('open') == ( set([Need(method='id', value=1), Need(method='id', value=2), Need(method='id', value=5)]), set([]) )
CACHE : Cache """ CACHE_DEFAULT_TIMEOUT = 60 * 24 * 7 """ Cache responses timeout. CACHE_DEFAULT_TIMEOUT : int """ CACHE.init_app(APP) APP.config.update( COMPRESS_LEVEL=3, COMPRESS_CACHE_KEY=lambda x: x.full_path, COMPRESS_CACHE_BACKEND=lambda: SimpleCache(default_timeout= # noqa CACHE_DEFAULT_TIMEOUT), ) Compress(APP) IMAGES_DIRECTORY = os.path.join(os.getcwd(), 'static', 'images') """ Images directory. IMAGES_DIRECTORY : unicode """ def _null_to_None(data): """ Converts *Javascript* originated *null* and *undefined* strings
def test_invenio_access_permission_cache_system_roles_updates( app, dynamic_permission ): """Testing ActionSystemRoles cache with inserts/updates/deletes.""" # This test case is doing the same of user test case but using # system roles. cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): system_role_1 = SystemRoleNeed('system_role_1') system_role_2 = SystemRoleNeed('system_role_2') system_role_3 = SystemRoleNeed('system_role_3') system_role_4 = SystemRoleNeed('system_role_4') system_role_5 = SystemRoleNeed('system_role_5') system_role_6 = SystemRoleNeed('system_role_6') current_access.system_roles = { 'system_role_1': system_role_1, 'system_role_2': system_role_2, 'system_role_3': system_role_3, 'system_role_4': system_role_4, 'system_role_5': system_role_5, 'system_role_6': system_role_6, } # Creation of some data to test. db.session.add(ActionSystemRoles(action='open', role_name=system_role_1.value)) db.session.add(ActionSystemRoles(action='write', role_name=system_role_4.value)) db.session.flush() # Creation of identities to test. identity_fake_1 = FakeIdentity(system_role_1) identity_fake_2 = FakeIdentity(system_role_2) identity_fake_3 = FakeIdentity(system_role_3) identity_fake_4 = FakeIdentity(system_role_4) identity_fake_5 = FakeIdentity(system_role_5) identity_fake_6 = FakeIdentity(system_role_6) # Test if system_role_1 can open. In this case, the cache should store # only this object. permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_fake_1) assert current_access.get_action_cache('open') == ( set([system_role_1]), set([]) ) # Test if system_role_2 can write. In this case, the cache should # have this new object and the previous one (Open is allowed to # system_role_1) permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_4) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1]), set([]) ) # If we add a new system role to the action open, the open action in # cache should be removed but it should still containing the write # entry. db.session.add(ActionSystemRoles(action='open', role_name=system_role_2.value)) db.session.flush() assert current_access.get_action_cache('open') is None permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_fake_2) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) # Test if the new role is added to the action 'open' permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_4) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) # If we update an action swapping a role, the cache containing the # action, should be removed. role_4_action_write = ActionSystemRoles.query.filter( ActionSystemRoles.action == 'write' and ActionSystemRoles.role_name == system_role_4.value).first() role_4_action_write.role_name = system_role_3.value db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is not None assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) # Test if the system_role_3 can write now. permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_fake_4) permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_3) assert current_access.get_action_cache('write') == ( set([system_role_3]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) # If we remove a role from an action, the cache should clear the # action item. cust_action_write = ActionSystemRoles.query.filter( ActionSystemRoles.action == 'write' and ActionSystemRoles.role_name == system_role_3).first() db.session.delete(cust_action_write) db.session.flush() assert current_access.get_action_cache('write') is None # If no one is allowed to perform an action then everybody is allowed. permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_3) assert current_access.get_action_cache('write') == ( set([]), set([]) ) db.session.add(ActionSystemRoles(action='write', role_name=system_role_5.value)) db.session.flush() permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_5) permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_fake_3) assert current_access.get_action_cache('write') == ( set([system_role_5]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) # If you update the name of an existing action, the previous action # and the new action should be remove from cache. permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_5) assert current_access.get_action_cache('write') == ( set([system_role_5]), set([]) ) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2]), set([]) ) role_5_action_write = ActionSystemRoles.query.filter( ActionSystemRoles.action == 'write' and ActionSystemRoles.role_name == system_role_5.value).first() role_5_action_write.action = 'open' db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is None permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_fake_1) assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2, system_role_5]), set([]) ) db.session.add(ActionSystemRoles(action='write', role_name=system_role_4.value)) permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_fake_5) assert current_access.get_action_cache('write') == ( set([system_role_4]), set([]) ) db.session.add(ActionSystemRoles(action='open', argument='1', role_name=system_role_6.value)) db.session.flush() permission_open_1 = dynamic_permission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_fake_6) assert permission_open_1.allows(identity_fake_6) assert current_access.get_action_cache('open::1') == ( set([system_role_1, system_role_2, system_role_5, system_role_6]), set([]) ) user_6_action_open_1 = ActionSystemRoles.query.filter_by( action='open', argument='1', role_name=system_role_6.value).first() user_6_action_open_1.argument = '2' db.session.flush() assert current_access.get_action_cache('open::1') is None assert current_access.get_action_cache('open::2') is None permission_open_2 = dynamic_permission( ParameterizedActionNeed('open', '2')) assert permission_open_2.allows(identity_fake_6) assert current_access.get_action_cache('open::2') == ( set([system_role_1, system_role_2, system_role_5, system_role_6]), set([]) ) # open action cache should remain as before assert current_access.get_action_cache('open') == ( set([system_role_1, system_role_2, system_role_5]), set([]) )
def test_invenio_access_permission_cache_roles_updates( app, dynamic_permission ): """Testing ActionRoles cache with inserts/updates/deletes.""" # This test case is doing the same of user test case but using roles. cache = SimpleCache() InvenioAccess(app, cache=cache) with app.test_request_context(): # Creation of some data to test. role_1 = Role(name='role_1') role_2 = Role(name='role_2') role_3 = Role(name='role_3') role_4 = Role(name='role_4') role_5 = Role(name='role_5') role_6 = Role(name='role_6') db.session.add(role_1) db.session.add(role_2) db.session.add(role_3) db.session.add(role_4) db.session.add(role_5) db.session.add(role_6) db.session.add(ActionRoles(action='open', role=role_1)) db.session.add(ActionRoles(action='write', role=role_4)) db.session.flush() # Creation of identities to test. identity_fake_role_1 = FakeIdentity(RoleNeed(role_1.name)) identity_fake_role_2 = FakeIdentity(RoleNeed(role_2.name)) identity_fake_role_3 = FakeIdentity(RoleNeed(role_3.name)) identity_fake_role_4 = FakeIdentity(RoleNeed(role_4.name)) identity_fake_role_5 = FakeIdentity(RoleNeed(role_5.name)) identity_fake_role_6 = FakeIdentity(RoleNeed(role_6.name)) # Test if role 1 can open. In this case, the cache should store only # this object. permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_fake_role_1) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name)]), set([]) ) # Test if role 4 can write. In this case, the cache should have this # new object and the previous one (Open is allowed to role_1) permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_4) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name)]), set([]) ) # If we add a new role to the action open, the open action in cache # should be removed but it should still containing the write entry. db.session.add(ActionRoles(action='open', role=role_2)) db.session.flush() assert current_access.get_action_cache('open') is None permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_fake_role_2) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) # Test if the new role is added to the action 'open' permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_4) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) # If we update an action swapping a role, the cache containing the # action, should be removed. role_4_action_write = ActionRoles.query.filter( ActionRoles.action == 'write' and ActionRoles.role == role_4).first() role_4_action_write.role = role_3 db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is not None assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) # Test if the role_3 can write now. permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_fake_role_4) permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_3) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_3.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) # If we remove a role from an action, the cache should clear the # action item. role_3_action_write = ActionRoles.query.filter( ActionRoles.action == 'write' and ActionRoles.role == role_3).first() db.session.delete(role_3_action_write) db.session.flush() assert current_access.get_action_cache('write') is None # If no one is allowed to perform an action then everybody is allowed. permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_3) assert current_access.get_action_cache('write') == ( set([]), set([]) ) db.session.add(ActionRoles(action='write', role=role_5)) db.session.flush() permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_5) permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_fake_role_3) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_5.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) # If you update the name of an existing action, the previous action # and the new action should be remove from cache. permission_write = dynamic_permission(ActionNeed('write')) assert permission_write.allows(identity_fake_role_5) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_5.name)]), set([]) ) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name)]), set([]) ) role_5_action_write = ActionRoles.query.filter( ActionRoles.action == 'write' and ActionRoles.role == role_5).first() role_5_action_write.action = 'open' db.session.flush() assert current_access.get_action_cache('write') is None assert current_access.get_action_cache('open') is None permission_open = dynamic_permission(ActionNeed('open')) assert permission_open.allows(identity_fake_role_1) assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name)]), set([]) ) db.session.add(ActionRoles(action='write', role=role_4)) permission_write = dynamic_permission(ActionNeed('write')) assert not permission_write.allows(identity_fake_role_5) assert current_access.get_action_cache('write') == ( set([Need(method='role', value=role_4.name)]), set([]) ) db.session.add(ActionRoles(action='open', argument='1', role=role_6)) db.session.flush() permission_open_1 = dynamic_permission( ParameterizedActionNeed('open', '1')) assert not permission_open.allows(identity_fake_role_6) assert permission_open_1.allows(identity_fake_role_6) assert current_access.get_action_cache('open::1') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name), Need(method='role', value=role_6.name)]), set([]) ) user_6_action_open_1 = ActionRoles.query.filter_by( action='open', argument='1', role_id=role_6.id).first() user_6_action_open_1.argument = '2' db.session.flush() assert current_access.get_action_cache('open::1') is None assert current_access.get_action_cache('open::2') is None permission_open_2 = dynamic_permission( ParameterizedActionNeed('open', '2')) assert permission_open_2.allows(identity_fake_role_6) assert current_access.get_action_cache('open::2') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name), Need(method='role', value=role_6.name)]), set([]) ) # open action cache should remain as before assert current_access.get_action_cache('open') == ( set([Need(method='role', value=role_1.name), Need(method='role', value=role_2.name), Need(method='role', value=role_5.name)]), set([]) )
if "WEBFAF_ENVIRON_PRODUCTION" in os.environ: app.config.from_object("webfaf.config.ProductionConfig") elif "WEBFAF_ENVIRON_TEST" in os.environ: app.config.from_object("webfaf.config.TestingConfig") else: app.config.from_object("webfaf.config.DevelopmentConfig") db = SQLAlchemy(app) if app.config["CACHE_TYPE"].lower() == "memcached": flask_cache = MemcachedCache(['{0}:{1}'.format( app.config["MEMCACHED_HOST"], app.config["MEMCACHED_PORT"])], key_prefix=app.config["MEMCACHED_KEY_PREFIX"]) elif app.config["CACHE_TYPE"].lower() == "simple": flask_cache = SimpleCache() else: flask_cache = NullCache() if app.config["PROXY_SETUP"]: app.wsgi_app = ProxyFix(app.wsgi_app) if app.config["OPENID_ENABLED"]: from flask_openid import OpenID from openid_teams import teams oid = OpenID(app, safe_roots=[], extension_responses=[teams.TeamsResponse]) from webfaf.login import login # pylint: disable=cyclic-import app.register_blueprint(login) from webfaf.user import user # pylint: disable=cyclic-import app.register_blueprint(user)
def werkzeug_subscriber(): subscriber = Subscriber(SQLite3SubscriberStorage('subscriber.db'), WerkzeugCacheTempSubscriberStorage(SimpleCache())) yield from subscriber_app(subscriber)
def test_intenio_access_cache_performance(app, dynamic_permission): """Performance test simulating 1000 users.""" InvenioAccess(app, cache=None) with app.test_request_context(): # CDS has (2015-11-19) 74 actions with 414 possible arguments with # 49259 users and 307 roles. In this test we are going to divide # into 50 and use the next prime number. users_number = 991 actions_users_number = 11 actions_roles_number = 7 roles = [] actions = [] for i in range(actions_roles_number): role = Role(name='role{0}'.format(i)) roles.append(role) db.session.add(role) db.session.flush() action_role = ActionRoles( action='action{0}'.format( str(i % actions_roles_number)), role=role) actions.append(action_role) db.session.add(action_role) db.session.flush() users = [] for i in range(users_number): user = User( email='invenio{0}@inveniosoftware.org'.format(str(i)), roles=[roles[i % actions_roles_number]]) users.append(user) db.session.add(user) db.session.flush() action_user = ActionUsers(action='action{0}'.format( str((i % actions_users_number) + actions_roles_number)), user=user) actions.append(action_user) db.session.add(action_user) db.session.flush() def test_permissions(): """Iterates over all users checking its permissions.""" for i in range(users_number): identity = FakeIdentity(UserNeed(users[i].id)) # Allowed permission permission_allowed_both = dynamic_permission( ActionNeed('action{0}'.format( (i % actions_users_number) + actions_roles_number)), ActionNeed('action{0}'.format(i % actions_roles_number)) ) assert permission_allowed_both.allows(identity) # Not allowed action user permission_not_allowed_user = dynamic_permission( ActionNeed('action{0}'.format( (i + 1) % actions_users_number + actions_roles_number)) ) assert not permission_not_allowed_user.allows(identity) # Not allowed action role permission_not_allowed_role = dynamic_permission( ActionNeed('action{0}'.format( (i + 1) % actions_roles_number)) ) assert not permission_not_allowed_role.allows(identity) app.extensions['invenio-access'].cache = None start_time_wo_cache = time.time() test_permissions() end_time_wo_cache = time.time() time_wo_cache = end_time_wo_cache - start_time_wo_cache app.extensions['invenio-access'].cache = SimpleCache() start_time_w_cache = time.time() test_permissions() end_time_w_cache = time.time() time_w_cache = end_time_w_cache - start_time_w_cache assert time_wo_cache / time_w_cache > 10
import datetime from cachelib import SimpleCache from app.clients.sms import PollableSMSClient from app.clients.sms.utils import timed from saplivelink365 import Configuration, ApiClient, AuthorizationApi, SMSV20Api # See https://livelink.sapmobileservices.com/documentation/guides/sms-channel/delivery_statuses/#body-description sap_response_map = { 'SENT': 'sending', 'DELIVERED': 'delivered', 'RECEIVED': 'delivered', 'ERROR': 'failed', } auth_cache = SimpleCache() def get_sap_responses(status): return sap_response_map[status] class SAPSMSClient(PollableSMSClient): def __init__(self, client_id=None, client_secret=None, *args, **kwargs): super(SAPSMSClient, self).__init__(*args, **kwargs) self._client_id = client_id self._client_secret = client_secret def init_app(self, logger, notify_host, *args, **kwargs): self.logger = logger self.notify_host = notify_host
class AuthorizationCodeFlow(object): def __init__(self, app=None, *, base_url=None, client_id=None, client_secret=None, cache=None, scope='openid', url_prefix='/oauth2', session_key='flask-auth0-cookie'): # :param app: Flask app # :param base_url: your identity provider's base url # :param client_id: CLIENT_ID # :param client_secret: CLIENT_SECRET # :param cache: a cache object that implements `werkzeug.contrib.cache.BaseCache` to store the tokens in # :param scope: oauth2 scopes # :param url_prefix: what should be the prefix of all the routes needed for oauth2. default = /oauth2 # :param session_key: name of the key used in the session to store the uid self.app = app self.user_agent = f"{__name__}/{__version__} python-requests/{requests.__version__}" self.base_url = base_url self.client_id = client_id self.client_secret = client_secret self.scope = scope self.url_prefix = url_prefix self.session_key = session_key # User actions self._after_login_handler = None self._after_logout_handler = None self._after_refresh_handler = None self._logger = None # Setup backend cache if cache is None: self.cache = SimpleCache() elif isinstance(cache, BaseCache): self.cache = cache else: raise ValueError( f'your backend cache must implement `cachelib.BaseCache`. {cache} is {type(cache)}' ) # Utilities self.signer = None self.hasher = None self.openid_config = None if app is not None: self.init_app(app) def init_app(self, app): # Config of the extension self.client_id = app.config.setdefault('AUTH0_CLIENT_ID', self.client_id) self.client_secret = app.config.setdefault('AUTH0_CLIENT_SECRET', self.client_secret) self.base_url = app.config.setdefault('AUTH0_BASE_URL', self.base_url) self.scope = app.config.setdefault('AUTH0_SCOPE', self.scope) if self.client_id is None or self.client_secret is None or self.base_url is None: raise ValueError('Missing config variables ') self.session_key = app.config.setdefault('AUTH0_SESSION_KEY', self.session_key) self.url_prefix = app.config.setdefault('AUTH0_URL_PREFIX', self.url_prefix) # Setup some crypto stuff. # I am not a cryptographer and might do this wrong. For prod use, tweak appropriately. # If you don't know why or what into you should change these values, # google for "Key Derivation Function" or ask someone with a Security background key_material = scrypt(password=app.secret_key.encode(), salt=b'flask-auth0', dklen=32, n=256, r=8, p=1) # Utils self.signer = URLSafeSerializer(key_material[:16]) self.hasher = lru_cache( maxsize=256 )( # Because this is non-trivial, we cache already computes values lambda value, uid: blake2b( value, key=key_material[16:], person=uid, digest_size=32). digest()) self._logger = app.logger self.openid_config = OpenIDConfig(self.base_url) # Routes blueprint = Blueprint('flask-auth0', __name__) blueprint.add_url_rule('/login', 'login', self.login) blueprint.add_url_rule('/logout', 'logout', self.logout) blueprint.add_url_rule('/callback', 'callback', self.callback) app.register_blueprint(blueprint=blueprint, url_prefix=self.url_prefix) def protected(self, enforce=False): """ This decorator indicates that the auth info needs to be available in the decorated route :param enforce: returns 401 if the auth info is not available :return: """ def actual_decorator(func): @wraps(func) def decorated_function(*args, **kwargs): if enforce: if self.is_authenticated: return func(*args, **kwargs) raise Unauthorized() return func(*args, **kwargs) return decorated_function return actual_decorator # Three decorators to make it easy for actions to trigger after login, logout, refresh def after_login(self, func): self._after_login_handler = func return func def after_logout(self, func): self._after_logout_handler = func return func def after_refresh(self, func): self._after_refresh_handler = func return func # Bunch of useful properties @property def is_authenticated(self): # If there's an access token, we consider the user logged in return self.access_token is not None @property def is_refreshable(self): # Checks whether there is a refresh token return session.get(self.session_key) is not None and self.cache.has( self._make_key('refresh_token')) @property def access_token(self): return self.cache.get(self._make_key('access_token')) @property def token_type(self): return self.cache.get(self._make_key('token_type')) @property def authorization_header(self): # Returns the value that should go in the Authorization header # when you want to use the access_token # This is a convenience function return f'{self.token_type} {self.access_token}' @property def id_token(self): return self.cache.get(self._make_key('id_token')) @property def refresh_token(self): return self.cache.get(self._make_key('refresh_token')) @lru_cache(maxsize=1024) def get_verified_claims(self, id_token): # Converts the jwt id_token into verified claims try: # We can get the info in the id_token, but it needs to be verified u_header, u_claims = jwt.get_unverified_header( id_token), jwt.get_unverified_claims(id_token) # Get the key which was used to sign this id_token kid, alg = u_header['kid'], u_header['alg'] except JWTError: self._logger.warn('Tried to verify claims of a broken id_token') return {} else: # Obtain JWT and the keys to validate the signature try: jwks_response = requests.get( self.openid_config.jwks_uri, headers={ 'User-Agent': self.user_agent, }, ) except requests.HTTPError: return {} else: jwks_data = jwks_response.json() try: for key in jwks_data['keys']: if key['kid'] == kid: payload = jwt.decode( token=id_token, key=key, audience=self.client_id, issuer=self.openid_config.issuer) return payload except ExpiredSignatureError: self._logger.warn( 'Tried to verify claims of an expired id_token') return {} # Retrieves the OpenID userinfo_endpoint def get_user_info(self): self._logger.debug('get_user_info() was called') try: result = requests.get(self.openid_config.userinfo_url, headers={ 'Authorization': self.authorization_header, 'Content-Type': 'application/json' }) result.raise_for_status() except requests.HTTPError: return {} else: return result.json() def logout_url(self, return_to=None): if return_to is None: return_to = request.args.get( 'return_to') or request.referrer or '/' # Redirect to auth0 logout params = { 'returnTo': return_to or url_for('index', _external=True), 'client_id': self.client_id } return f'{self.openid_config.issuer}v2/logout?{urlencode(params)}' # Route definitions def logout(self, return_to=None): """ Handler for logging out a user. This clears the server-side session entry and redirects to the index endpoint :return: redirect() """ self._logger.debug('logout() was called') self.cache.delete_many( self._make_key('token_data'), self._make_key('refresh_token'), ) session.clear() if callable(self._after_logout_handler): self._after_logout_handler() self._logger.debug('after_logout_handler() was called') return redirect(self.logout_url(return_to=return_to)) def login_url(self, return_to=None, prompt='login', response_type='code', redirect_uri=None): # Returns the full url for doing a login if prompt not in {'none', 'login', 'consent', 'select_account'}: raise ValueError('Invalid prompt') if response_type not in {'code', 'token'}: raise ValueError('Invalid response_type') if return_to is None: return_to = request.args.get( 'return_to') or request.referrer or '/' if redirect_uri is None: redirect_uri = url_for('flask-auth0.callback', _external=True) query_parameters = { 'response_type': response_type, 'scope': self.scope, 'state': self.signer.dumps({'return_to': return_to}), 'client_id': self.client_id, 'prompt': prompt, # Not strictly necessary to include redirect_uri, but avoids potential issues 'redirect_uri': redirect_uri, } return f'{self.openid_config.authorization_url}?{urlencode(query_parameters)}' def login(self, return_to=None, prompt='login', response_type='code', redirect_uri=None): """ Handler for logging in a user. This provides a redirect to the authorization url :return: redirect() """ self._logger.debug('login() was called') return redirect( self.login_url(return_to=return_to, prompt=prompt, response_type=response_type, redirect_uri=redirect_uri)) def callback(self): """ Handler for the OAuth2 callback This gets the code and turns it into tokens :return: redirect() """ self._logger.debug('callback() was called') try: # to get the state state = self.signer.loads(request.args.get('state')) except BadSignature: # State has been tampered with return BadRequest(description="State could not be validated") except TypeError: # state is None, not in the url state = {} # Handle callback errors error = request.args.get('error') error_description = request.args.get('error_description') error_uri = request.args.get('error_uri') if error is not None: return self.callback_error_handler( error=error, error_description=error_description, error_uri=error_uri, state=state) code = request.args.get('code') if code is not None: # try to login using the code in the url arg # Get the tokens using the code token_result = requests.post(self.openid_config.token_url, data={ 'code': request.args.get('code'), 'grant_type': 'authorization_code', 'client_id': self.client_id, 'client_secret': self.client_secret, 'redirect_uri': url_for('flask-auth0.callback', _external=True) }) try: token_data = token_result.json() # Handle errors in access token request error = token_data.get('error') error_description = token_data.get('error_description') error_uri = token_data.get('error_uri') if error is not None: return self.access_token_request_error_handler( error=error, error_description=error_description, error_uri=error_uri) # Raise for other HTTP trouble token_result.raise_for_status() except requests.HTTPError as e: self._logger.error( f'Could not exchange code for access_token: {e}') raise InternalServerError( description=f"Could not obtain access_token with code") else: session[self.session_key] = uuid.uuid4() self._update_tokens(**token_data) # Execute user actions if callable(self._after_login_handler): self._logger.debug('after_login_handler() was called') self._after_login_handler() # Get return url from the state return_to = state.get('return_to') if return_to: self._logger.debug(f'Returning to {return_to}') return redirect(return_to) # Fall back on a default return Response('Login Successful', status=200) else: # No code in url, return an error return Unauthorized(description="Unauthorized") def verify_email(self): email = request.args.get('email') message = request.args.get('message') success = request.args.get('success') # Convenience functions def refresh(self): """ Handler for the OAuth2 token refresh This exchanges the refresh_token for a new access_token :return: None """ self._logger.debug('refresh() was called') token_result = requests.post( self.openid_config.token_url, data={ 'grant_type': 'refresh_token', 'scope': self.scope, 'client_id': self.client_id, 'client_secret': self.client_secret, 'refresh_token': self.refresh_token, }, ) # TODO: better error handling (see callback) token_result.raise_for_status() token_data = token_result.json() self._update_tokens(**token_data) if callable(self._after_refresh_handler): self._after_refresh_handler() self._logger.debug('after_refresh_handler() was called') # Logic for updating the cache with new token info def _update_tokens(self, *, access_token, token_type='Bearer', refresh_token=None, id_token=None, expires_in=3600, **kwargs): self._logger.debug('update_tokens() was called') if kwargs: self._logger.debug(f'got extra token data: {kwargs.keys()}') if id_token is not None: self.cache.set(self._make_key('id_token'), id_token, timeout=expires_in) # Update the cache for the next request self.cache.set(self._make_key('access_token'), access_token, timeout=expires_in) self.cache.set(self._make_key('token_type'), token_type, timeout=expires_in) # Handle the refresh_token if present # it doesn't have a timeout since the refresh token shouldn't expire if refresh_token is not None: self.cache.set( self._make_key('refresh_token'), refresh_token, ) # To further obfuscate the relation between the cache key and the session id, # the token itself is cryptographically hashed, and that hash is used as the key in the backend cache # Is this strictly necessary to make it work? No, but it seemed like a cool thing to do :) def _make_key(self, value: str): uid = session.setdefault(self.session_key, uuid.uuid4()) return self.hasher(value=value.encode(), uid=uid.bytes) @property def session_id(self): return session.get(self.session_key) def callback_error_handler(self, error, error_description=None, error_uri=None, state=None): self._logger.error(f'{error}: {error_description} {error_uri} {state}') error_mapping = { 'invalid_request': BadRequest, # 400 'unauthorized': Unauthorized, # 401 'unauthorized_client': Unauthorized, # 401 'access_denied': Forbidden, # 403 'unsupported_response_type': Forbidden, # 403 'invalid_scope': Forbidden, # 403 'server_error': InternalServerError, # 500 'temporarily_unavailable': ServiceUnavailable, # 503 } HTTPError = error_mapping.get(error, BadRequest) # 400 raise HTTPError(description=error_description) def access_token_request_error_handler(self, error, error_description=None, error_uri=None): self._logger.error(f'{error}: {error_description} {error_uri}') if error == 'invalid_scope': pass if error == 'unsupported_grant_type': pass if error == 'unauthorized_client': pass if error == 'invalid_grant': pass if error == 'invalid_client': pass if error == 'invalid_request': pass raise InternalServerError( description="error trying to obtain access_token")
# (c) 2009 Haoyu Bai (http://gaedav.google.com/). """ Implement cache mechanism. """ import logging import threading from builtins import object from cachelib import MemcachedCache, RedisCache, SimpleCache try: memcache3 = MemcachedCache() # memcache3 = RedisCache() except Exception as e: logging.info(e) memcache3 = SimpleCache() memcache3._stats = { "byte_hits": 0, "bytes": 0, "hits": 0, "items": 0, "misses": 0, "oldest_item_age": 0, # keep track of operations other than get (= hits + misses) "set": 0, "set_multi": 0, "delete": 0, "get_list": 0, "set_list": 0, "del_list": 0,
from . import filters from .db import db, db_reload BACKCOMPAT_SERIES_ALIASES = { 'brno': 'brno-pyvo', 'praha': 'praha-pyvo', 'ostrava': 'ostrava-pyvo', 'olomouc': 'olomouc-pyvo', 'plzen': 'plzen-pyvo', 'liberec': 'liberec-pyvo', } # Be careful when using SimpleCache! # See: http://werkzeug.pocoo.org/docs/contrib/cache/ # #werkzeug.contrib.cache.SimpleCache cache = SimpleCache(threshold=500, default_timeout=300) routes = [] def route(url, methods=['GET'], translate=True, **kwargs): def decorator(func): assert url.startswith('/') options = dict(kwargs, methods=methods) if translate: routes.append(( url, func, dict(options, defaults={'lang_code': 'cs'}), )) routes.append((
def init_app(self, app): """Initialize this extension. if the config['JWT_OIDC_WELL_KNOWN_CONFIG'] is set, then try to load the JWKS_URI & ISSUER from that If it is not set attempt to load the JWKS_URI and ISSUE from the application config Required settings to function: WELL_KNOWN_CONFIG (optional) is this is set, the JWKS_URI & ISSUER will be loaded from there JWKS_URI: the endpoint defined for the jwks_keys ISSUER: the endpoint for the issuer of the tokens ALGORITHMS: only RS256 is supported AUDIENCE: the oidc audience (or API_IDENTIFIER) CLIENT_SECRET: the shared secret / key assigned to the client (audience) """ self.app = app self.jwt_oidc_test_mode = app.config.get('JWT_OIDC_TEST_MODE', None) # # CHECK IF WE"RE RUNNING IN TEST_MODE!! # if self.jwt_oidc_test_mode: app.logger.debug( 'JWT MANAGER running in test mode, using locally defined certs & tokens' ) self.issuer = app.config.get('JWT_OIDC_TEST_ISSUER', 'localhost.localdomain') self.jwt_oidc_test_keys = app.config.get('JWT_OIDC_TEST_KEYS', None) self.audience = app.config.get('JWT_OIDC_TEST_AUDIENCE', None) self.client_secret = app.config.get('JWT_OIDC_TEST_CLIENT_SECRET', None) self.jwt_oidc_test_private_key_pem = app.config.get( 'JWT_OIDC_TEST_PRIVATE_KEY_PEM', None) if self.jwt_oidc_test_keys: app.logger.debug('local key being used: {}'.format( self.jwt_oidc_test_keys)) else: app.logger.error( 'Attempting to run JWT Manager with no local key assigned') raise Exception( 'Attempting to run JWT Manager with no local key assigned') else: self.algorithms = app.config.get( 'JWT_OIDC_ALGORITHMS', JwtManager.ALGORITHMS).replace(' ', '')\ .split(',') # If the WELL_KNOWN_CONFIG is set, then go fetch the JWKS & ISSUER self.well_known_config = app.config.get( 'JWT_OIDC_WELL_KNOWN_CONFIG', None) if self.well_known_config: # try to get the jwks & issuer from the well known config # jurl = urlopen(url=self.well_known_config, context=ssl.SSLContext()) # for gangster testing jurl = urlopen(url=self.well_known_config) self.well_known_obj_cache = json.loads( jurl.read().decode('utf-8')) self.jwks_uri = self.well_known_obj_cache['jwks_uri'] self.issuer = self.well_known_obj_cache['issuer'] else: self.jwks_uri = app.config.get('JWT_OIDC_JWKS_URI', None) self.issuer = app.config.get('JWT_OIDC_ISSUER', None) # Setup JWKS caching self.caching_enabled = app.config.get('JWT_OIDC_CACHING_ENABLED', False) if self.caching_enabled: self.cache = SimpleCache(default_timeout=app.config.get( 'JWT_OIDC_JWKS_CACHE_TIMEOUT', 300)) self.audience = app.config.get('JWT_OIDC_AUDIENCE', None) self.client_secret = app.config.get('JWT_OIDC_CLIENT_SECRET', None) app.logger.debug('JWKS_URI: {}'.format(self.jwks_uri)) app.logger.debug('ISSUER: {}'.format(self.issuer)) app.logger.debug('ALGORITHMS: {}'.format(self.algorithms)) app.logger.debug('AUDIENCE: {}'.format(self.audience)) app.logger.debug('CLIENT_SECRET: {}'.format(self.client_secret)) app.logger.debug('JWT_OIDC_TEST_MODE: {}'.format( self.jwt_oidc_test_mode)) app.logger.debug('JWT_OIDC_TEST_KEYS: {}'.format( self.jwt_oidc_test_keys)) # set the auth error handler auth_err_handler = app.config.get('JWT_OIDC_AUTH_ERROR_HANDLER', JwtManager.handle_auth_error) app.register_error_handler(AuthError, auth_err_handler) app.teardown_appcontext(self.teardown)
def create_cache_list(request, tmpdir): mc = MemcachedCache() mc._client.flush_all() rc = RedisCache(port=6360) rc._client.flushdb() request.cls.cache_list = [FileSystemCache(tmpdir), mc, rc, SimpleCache()]
UnsubscribeConfirmation = 'UnsubscribeConfirmation' class InvalidMessageTypeException(Exception): pass def verify_message_type(message_type: str): try: SNSMessageType(message_type) except ValueError: raise InvalidMessageTypeException( f'{message_type} is not a valid message type.') certificate_cache = SimpleCache() def get_certificate(url): res = certificate_cache.get(url) if res is not None: return res res = requests.get(url).content certificate_cache.set(url, res, timeout=60 * 60) # 60 minutes return res # 400 counts as a permanent failure so SNS will not retry. # 500 counts as a failed delivery attempt so SNS will retry. # See https://docs.aws.amazon.com/sns/latest/dg/DeliveryPolicies.html#DeliveryPolicies @ses_callback_blueprint.route('/notifications/email/ses', methods=['POST'])
from cachelib import SimpleCache from werkzeug.urls import url_encode from discodop import treebank from discodop.tree import (Tree, DrawTree, DrawDependencies, writediscbrackettree) from discodop.parser import Parser, readparam, readgrammars, probstr from discodop.util import tokenize logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=logging.DEBUG) APP = Flask(__name__) LOG = APP.logger LIMIT = 40 # maximum sentence length CACHE = SimpleCache() PARSERS = {} SHOWFUNC = True # show function tags in results SHOWMORPH = True # show morphological features in results # POS tagged input is tokenized, and every token is of the form "word/POS" # POS may be empty. POSTAGS = re.compile(r'^\s*(?:\S+/\S*)(?:\s+\S+/\S*)*\s*$') @APP.route('/') def main(): """Redirect to main page.""" return redirect(url_for('index')) @APP.route('/parser/')
import os import sys import json import time import copy import uuid import threading import requests import docopt from flask import Flask, render_template, request, send_from_directory, make_response from cachelib import SimpleCache from htmlmin.minify import html_minify cache = SimpleCache() app = Flask(__name__, static_url_path="/static") def update_data(): try: print("==> Updating team data ...") try: r = requests.get("https://slack.com/api/team.info", params={"token": app.config["token"]}) j = r.json() assert j["ok"] except: print(" !!! Failed to update team data.") else: team = j["team"]
COLOURSPACE_MODEL : unicode **{'CAM02LCD', 'CAM02SCD', 'CAM02UCS', 'CAM16LCD', 'CAM16SCD', 'CAM16UCS', 'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW', 'DIN 99', 'Hunter Lab', 'Hunter Rdab', 'ICTCP', 'IGPGTG', 'IPT', 'JzAzBz', 'OSA UCS', 'hdr-CIELAB', 'hdr-IPT'}** """ DATA_POINTER_GAMUT = Lab_to_XYZ(LCHab_to_Lab(DATA_POINTER_GAMUT_VOLUME), CCS_ILLUMINANT_POINTER_GAMUT) """ Pointer's Gamut data converted to *CIE XYZ* tristimulus values. DATA_POINTER_GAMUT : ndarray """ IMAGE_CACHE = SimpleCache(default_timeout=60 * 24 * 7) """ Server side cache for images. IMAGE_CACHE : SimpleCache """ def load_image(path, decoding_cctf='sRGB'): """ Loads the image at given path and caches it in `IMAGE_CACHE` cache. If the image is already cached, it is returned directly. Parameters ---------- path : unicode