policy(major): simplify PolicyEngine API, add flag to ignore cache for debug purposes
This commit is contained in:
parent
13f4ea0b8b
commit
d4cb1a98c7
|
@ -103,8 +103,9 @@ class PolicyTestView(AdminRequiredMixin, DetailView, FormView):
|
|||
def form_valid(self, form):
|
||||
policy = self.get_object()
|
||||
user = form.cleaned_data.get('user')
|
||||
policy_engine = PolicyEngine([policy])
|
||||
policy_engine.for_user(user).with_request(self.request).build()
|
||||
policy_engine = PolicyEngine([policy], user, self.request)
|
||||
policy_engine.use_cache = False
|
||||
policy_engine.build()
|
||||
result = policy_engine.passing
|
||||
if result:
|
||||
messages.success(self.request, _('User successfully passed policy.'))
|
||||
|
|
|
@ -17,8 +17,8 @@ def user_factors(context: RequestContext) -> List[UserSettings]:
|
|||
matching_factors: List[UserSettings] = []
|
||||
for factor in _all_factors:
|
||||
user_settings = factor.user_settings()
|
||||
policy_engine = PolicyEngine(factor.policies.all())
|
||||
policy_engine.for_user(user).with_request(context.get('request')).build()
|
||||
policy_engine = PolicyEngine(factor.policies.all(), user, context.get('request'))
|
||||
policy_engine.build()
|
||||
if policy_engine.passing and user_settings:
|
||||
matching_factors.append(user_settings)
|
||||
return matching_factors
|
||||
|
@ -31,8 +31,8 @@ def user_sources(context: RequestContext) -> List[UserSettings]:
|
|||
matching_sources: List[UserSettings] = []
|
||||
for factor in _all_sources:
|
||||
user_settings = factor.user_settings()
|
||||
policy_engine = PolicyEngine(factor.policies.all())
|
||||
policy_engine.for_user(user).with_request(context.get('request')).build()
|
||||
policy_engine = PolicyEngine(factor.policies.all(), user, context.get('request'))
|
||||
policy_engine.build()
|
||||
if policy_engine.passing and user_settings:
|
||||
matching_sources.append(user_settings)
|
||||
return matching_sources
|
||||
|
|
|
@ -31,6 +31,6 @@ class AccessMixin:
|
|||
def user_has_access(self, application: Application, user: User) -> Tuple[bool, List[str]]:
|
||||
"""Check if user has access to application."""
|
||||
LOGGER.debug("Checking permissions", user=user, application=application)
|
||||
policy_engine = PolicyEngine(application.policies.all())
|
||||
policy_engine.for_user(user).with_request(self.request).build()
|
||||
policy_engine = PolicyEngine(application.policies.all(), user, self.request)
|
||||
policy_engine.build()
|
||||
return policy_engine.result
|
||||
|
|
|
@ -16,8 +16,7 @@ class OverviewView(LoginRequiredMixin, TemplateView):
|
|||
def get_context_data(self, **kwargs):
|
||||
kwargs['applications'] = []
|
||||
for application in Application.objects.all():
|
||||
engine = PolicyEngine(application.policies.all())
|
||||
engine.for_user(self.request.user).with_request(self.request)
|
||||
engine = PolicyEngine(application.policies.all(), self.request.user, self.request)
|
||||
engine.build()
|
||||
if engine.passing:
|
||||
kwargs['applications'].append(application)
|
||||
|
|
|
@ -13,8 +13,8 @@ def password_policy_checker(sender, password, **_):
|
|||
setattr(sender, '__password__', password)
|
||||
_all_factors = PasswordFactor.objects.filter(enabled=True).order_by('order')
|
||||
for factor in _all_factors:
|
||||
policy_engine = PolicyEngine(factor.password_policies.all().select_subclasses())
|
||||
policy_engine.for_user(sender).build()
|
||||
policy_engine = PolicyEngine(factor.password_policies.all().select_subclasses(), sender)
|
||||
policy_engine.build()
|
||||
passing, messages = policy_engine.result
|
||||
if not passing:
|
||||
raise PasswordPolicyInvalid(*messages)
|
||||
|
|
|
@ -67,8 +67,8 @@ class AuthenticationView(UserPassesTestMixin, View):
|
|||
for factor in _all_factors:
|
||||
LOGGER.debug("Checking if factor applies to user",
|
||||
factor=factor, user=self.pending_user)
|
||||
policy_engine = PolicyEngine(factor.policies.all())
|
||||
policy_engine.for_user(self.pending_user).with_request(self.request).build()
|
||||
policy_engine = PolicyEngine(factor.policies.all(), self.pending_user, self.request)
|
||||
policy_engine.build()
|
||||
if policy_engine.passing:
|
||||
pending_factors.append((factor.uuid.hex, factor.type))
|
||||
LOGGER.debug("Factor applies", factor=factor, user=self.pending_user)
|
||||
|
|
|
@ -31,6 +31,7 @@ class PolicyProcessInfo:
|
|||
class PolicyEngine:
|
||||
"""Orchestrate policy checking, launch tasks and return result"""
|
||||
|
||||
use_cache: bool = True
|
||||
policies: List[Policy] = []
|
||||
__request: HttpRequest
|
||||
__user: User
|
||||
|
@ -43,16 +44,6 @@ class PolicyEngine:
|
|||
self.__user = user
|
||||
self.__processes = []
|
||||
|
||||
def for_user(self, user: User) -> 'PolicyEngine':
|
||||
"""Check policies for user"""
|
||||
self.__user = user
|
||||
return self
|
||||
|
||||
def with_request(self, request: HttpRequest) -> 'PolicyEngine':
|
||||
"""Set request"""
|
||||
self.__request = request
|
||||
return self
|
||||
|
||||
def _select_subclasses(self) -> List[Policy]:
|
||||
"""Make sure all Policies are their respective classes"""
|
||||
return Policy.objects \
|
||||
|
@ -69,14 +60,14 @@ class PolicyEngine:
|
|||
request.http_request = self.__request
|
||||
for policy in self._select_subclasses():
|
||||
cached_policy = cache.get(cache_key(policy, self.__user), None)
|
||||
if cached_policy:
|
||||
if cached_policy and self.use_cache:
|
||||
LOGGER.debug("Taking result from cache", policy=policy)
|
||||
cached_policies.append(cached_policy)
|
||||
else:
|
||||
LOGGER.debug("Evaluating policy", policy=policy)
|
||||
our_end, task_end = Pipe(False)
|
||||
task = PolicyProcess(policy, request, task_end)
|
||||
LOGGER.debug("Starting Process", for_policy=policy)
|
||||
LOGGER.debug("Starting Process", policy=policy)
|
||||
task.start()
|
||||
self.__processes.append(PolicyProcessInfo(process=task,
|
||||
connection=our_end, policy=policy))
|
||||
|
|
|
@ -42,7 +42,7 @@ class PolicyProcess(Process):
|
|||
if self.policy.negate:
|
||||
policy_result.passing = not policy_result.passing
|
||||
LOGGER.debug("Got result", policy=self.policy, result=policy_result,
|
||||
process="PolicyProcess")
|
||||
process="PolicyProcess", passing=policy_result.passing, user=self.request.user)
|
||||
key = cache_key(self.policy, self.request.user)
|
||||
cache.set(key, policy_result)
|
||||
LOGGER.debug("Cached policy evaluation", key=key)
|
||||
|
|
|
@ -18,8 +18,8 @@ def check_permissions(request, user, client):
|
|||
except Application.DoesNotExist:
|
||||
return redirect('passbook_providers_oauth:oauth2-permission-denied')
|
||||
LOGGER.debug("Checking permissions for application", user=user, application=application)
|
||||
policy_engine = PolicyEngine(application.policies.all())
|
||||
policy_engine.for_user(user).with_request(request).build()
|
||||
policy_engine = PolicyEngine(application.policies.all(), user, request)
|
||||
policy_engine.build()
|
||||
|
||||
# Check permissions
|
||||
passing, policy_messages = policy_engine.result
|
||||
|
|
|
@ -59,8 +59,9 @@ class AccessRequiredView(AccessMixin, View):
|
|||
|
||||
def _has_access(self):
|
||||
"""Check if user has access to application"""
|
||||
policy_engine = PolicyEngine(self.provider.application.policies.all())
|
||||
policy_engine.for_user(self.request.user).with_request(self.request).build()
|
||||
policy_engine = PolicyEngine(self.provider.application.policies.all(),
|
||||
self.request.user, self.request)
|
||||
policy_engine.build()
|
||||
return policy_engine.passing
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
|
|
Reference in a new issue