def xsrf_protected(non_xsrf_protected_methods: List[str] = config.get_setting( 'NON_XSRF_PROTECTED_METHODS')): """ Decorator to validate XSRF tokens for any methods but GET, HEAD, OPTIONS. :param non_xsrf_protected_methods: List of methods (lowercase) defaults to list from settings (get, head, options) """ def decorated(func): @wraps(func) def decorator(*args, **kwargs): if flask.request.method.lower() in non_xsrf_protected_methods: # Generate XSRF token token = generate_xsrf_token() flask.current_app.jinja_env.globals['xsrf_token'] = token @flask.after_this_request def add_cookie(response): response.set_cookie('XSRF-TOKEN', token) return response return func(*args, **kwargs) else: # Validate XSRF token token = flask.request.form.get('xsrf') if not token: raise XSRFError("XSRF token required but not given.") validate_xsrf_token(token) return func(*args, **kwargs) return decorator return decorated
def add_report_to_headers(response): """ Generate the Report-To header to be added to a response. :param response: The response our app has generated which requires headers. :return: The response with the required headers. """ response.headers['Report-To'] = json.dumps( config.get_setting('REPORT_TO_HEADER')) return response
def get_base_task(self) -> dict: """ Generate the base task body. This method is provided as a convenient way of overriding the default body if it requires more complexity than updating a setting. The default assumes this is being run in App Engine. This body is supposed to be updated later with the task payload and URI. :return: The base task body. """ return config.get_setting("CLOUD_TASKS_BODY")
def setup_app_config(self, app: Flask) -> Flask: """ Setup the configuration for the Flask app. This method is meant to be overridden in the case that a Flask app needs extra configuration. By default it sets the app Secret Key. :param Flask app: The Flask app that requires configuring. :return: The configured Flask app. :rtype: Flask """ app.secret_key = config.get_setting('SECRET_KEY') return app
def get_task_queue(self): """ Generate a queue object to create tasks with. This is meant as an easy way to override the method for generating a queue object for which we make tasks with. """ try: queue_settings = config.get_setting(self.QUEUE_SETTINGS_NAME) except AttributeError: raise AttributeError( f"{self.QUEUE_SETTINGS_NAME} setting not defined. " f"For {self.__module__}.{self.__name__} to work the " f"{self.QUEUE_SETTINGS_NAME} setting must be defined.") return TASK_CLIENT.queue_path(**queue_settings)
def add_csp_headers(response): """ Generate CSP Headers to be added to a response. The CSP headers are generated by inspecting the CSP_CONFIG object in the settings module. :param response: The response our app has generated which requires headers. :return: The response with the required headers. """ csp_headers = '; '.join( f'{key} {value}' for key, value in config.get_setting('CSP_CONFIG').items()) response.headers['Content-Security-Policy'] = csp_headers return response
def validate_xsrf_token(token): """ Validate a token against the current session token :param token: Token to validate (should be serialized) :return True/False """ serializer = URLSafeTimedSerializer(flask.current_app.secret_key) try: token = serializer.loads(token, max_age=config.get_setting('XSRF_TIME_LIMIT')) except SignatureExpired: raise XSRFError("XSRF token has expired.") except BadData: raise XSRFError("XSRF token is invalid.") if not hmac.compare_digest(flask.session['xsrf_token'], token): raise XSRFError("XSRF token does not match server token.") return True
def login(): return render_template(template, nonce=get_setting('CSP_NONCE'), client_id=client_id)
def get_client_id(self) -> str: """ Overrideable method to make customising the client_id easier to do. """ return get_setting(self._CLIENT_ID_SETTING)
def get_template_folder(self) -> str: """ Overrideable method to make customising the template folder easier to do. """ return get_setting(self._AUTH_TEMPLATE_FOLDER_SETTING)
import inspect from importlib import import_module from secure_scaffold.config import get_setting try: _DATABASE_SETTINGS = get_setting('DATABASE_SETTINGS') except AttributeError: raise AttributeError('DATABASE_SETTINGS setting not defined. ' 'For the database system to work the ' 'DATABASE_SETTINGS setting must be defined.') _ENGINE_KEY = _DATABASE_SETTINGS.get('engine') if not _ENGINE_KEY: raise KeyError('DATABASE_SETTINGS improperly defined. ' 'Requires an engine value.') _ENGINE_MODULE = import_module(_DATABASE_SETTINGS['engine']) _ENGINE_SETTINGS = _DATABASE_SETTINGS.get('settings') if not _ENGINE_SETTINGS: raise KeyError('DATABASE_SETTINGS improperly defined. ' 'Requires a settings value.') ENGINE = _ENGINE_MODULE.Engine(**_DATABASE_SETTINGS['settings']) class NotUniqueError(Exception): pass