class

FlaskAuthTagger

Inherits PythonGuardDefinitions < FrameworkTagger < FileHelper < Tagger < Reference < Object

Constants

ALLOWS_INSTANCE = /^([A-Za-z_]\w*)[ \t]*(?::[^=\n]+)?=[ \t]*([A-Za-z_][\w.]*)[ \t]*\(/m

flask-allows: @allows.requires(IsAdmin, ...) on an allows = Allows(...) instance, @fa.requires(...) on the module, or a bare @requires(...) bound to flask_allows' (or its flask_allows2 fork, FlaskBB's) by this file's imports, aliases included, refuses (403, or the on_fail handler) a caller whose identity fails the requirements: an authorization check. A project's own requires decides nothing here, nor do requirements that only negate (requires(Not(...))); Not negates only its own argument.

ALLOWS_MODULE = /\Aflask_allows2?(?:\.|\z)/
AUTHZ_CALL = /\b(?:has_\w*perm\w*|check_access|CheckAccess)\b/

What an authorization check decides on, as opposed to a feature flag or a quota: a permission-check call, or a role / permission / ownership field tested in a condition. Only the condition counts for a field: Dify's token decorators query TenantAccountJoin.role == "owner" to find the tenant owner, which checks nothing about the caller.

AUTHZ_CONDITION = /(?m)^[ \t]*(?:if|elif|while|assert|case)\b.*(?:\.(?:roles?|permissions?|is_superuser|is_staff|is_admin\w*|is_owner\w*|owner_id)\b|\bowner(?:_id)?\s*[!=]=)/
BODY_REFUSAL = /\A(?:return|raise|abort)\b.*(?:#{LOGIN_REDIRECT.source}|\bredirect_to_(?:log_?in|sign_?in)\b|\b40[13]\b|Unauthori[sz]ed|Forbidden|\.response_40[13]\s*\()/i
CLASS_DECORATOR_ATTRS = ["decorators", "method_decorators"] of ::String
CLASS_DECORATORS = /^\s+(method_decorators|decorators)\s*(?::[^=]+)?=([^=].*)/

flask-restx Resource.method_decorators, Flask View.decorators.

CLASS_DEF = /^class\s+(\w+)\s*(?:\((.*)\))?\s*:/
DECORATOR_PATTERNS = [{/\@login_required/, "flask-login login_required"}, {/\@roles_required\s*\(/, "flask-security roles_required"}, {/\@roles_accepted\s*\(/, "flask-security roles_accepted"}, {/\@jwt_required\b/, "flask-jwt-extended jwt_required"}, {/\@jwt_optional\s*\(/, "flask-jwt-extended jwt_optional"}, {/\@fresh_jwt_required\s*\(/, "flask-jwt-extended fresh_jwt_required"}, {/\@auth_required\s*\(/, "flask-security auth_required"}, {/\@http_auth_required\b/, "flask-security http_auth_required"}, {/\@token_auth_required\b/, "flask-security token_auth_required"}, {/\@permission_required\s*\(/, "flask-security/principal permission_required"}, {/\@auth\.login_required/, "flask-httpauth login_required"}, {/\@auth\.verify_password/, "flask-httpauth verify_password"}, {/\@token_auth\.login_required/, "flask-httpauth token_auth"}, {/\@multi_auth\.login_required/, "flask-httpauth multi_auth"}, {/\@protect\s*\(/, "flask-appbuilder protect (a setting can make it public)"}, {/\@has_access\b/, "flask-appbuilder has_access (a setting can make it public)"}, {/\@has_access_api\b/, "flask-appbuilder has_access_api (a setting can make it public)"}, {/\@requires_auth/, "requires_auth"}, {/\@authenticated/, "authenticated"}]
FROM_IMPORT_LINE = /^[ \t]*from[ \t]+([\w.]+)[ \t]+import[ \t]+([^\n]+)/m
IMPORT_PARENS = /(\bimport[ \t]*)\(([^)]*)\)/
METHOD_TEST = /\Arequest\.method\s*(==|!=|in|not\s+in)\s*(.+)\z/
METHOD_VERBS = /['"]([A-Za-z]+)['"]/
PLAIN_IMPORT_LINE = /^[ \t]*import[ \t]+([^\n]+)/m
PY_STRING = /"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/
ROUTE_DECORATOR = /^@[\w.]+\.(?:route|get|post|put|patch|delete)\s*\(/
TOP_LEVEL_REQUIRES = /^(?:async[ \t]+)?def[ \t]+requires\b/m

Constructors

new(options : Hash(String, YAML::Any))
Source

Class methods

target_techs
Source