コード例 #1
0
ファイル: access.py プロジェクト: pontiflex/trustme
	def __perform(self, action, capability, vetted=False, value=None):
		# Don't perform the access again
		if self.__performed:
			raise HTTPForbidden('Cannot perform access again')
		allowed = True

		try:

			if capability is None:
				at = ENTER
			else:
				at = capability.access_type
				# Verify that the action is allowed by the capability
				if not vetted:
					cons = capability.constraint
					if cons is not None and not cons.allows(action, self):
						raise HTTPForbidden('Invoked capability does not allow this access')

			if at in EXIT:
				# Make sure that the action has been filtered before making any attempt to
				# process its execution
				if not vetted and not self.filtered(action):
					raise HTTPForbidden('Action not available for processing')
				# If the access is an approval for processing, check that the action has not
				# been processed before, then perform it
				if at == EXIT[0]:
					if self.processed(action, None):
						raise HTTPForbidden('Action not available for processing')
					return action.perform(self.request)
				# Otherwise, if this action has already been approved, this is a revocation
				if self.processed(action):
					return action.revoke(self.request)
				# Otherwise, logging this access is enough to mark the action as denied
				return HTTPForbidden(FILTER_DENY) if vetted else 'Request marked as denied'
			elif at in FILTER:
				# Filtering is only done automatically
				if not vetted:
					raise RuntimeError('Request filtering must be automatic')
				if at == FILTER[0]:
					# If this access is letting the action through the filter, failure to
					# take further automatic action should simply stop execution. Possible
					# automatic accesses are drawn from the EXIT list
					types = EXIT
					filters = []
					# If this is an authenticated request, try proceeding with the requestor's
					# positive access capabilities. If none exist, then move on to auto-filters
					if self.user is not None:
						filters = self.own_processes(action)
					if not filters:
						filters = self.processes(action, True)
					def fail(msg): return value
				else:
					# Otherwise, logging this access is enough to mark the action as rejected
					return HTTPForbidden(FILTER_REJECT)
			elif at == ENTER:
				# If this access is a new request, failure should raise an unauthorized
				# exception and store the failed access. Possible automatic accesses are
				# drawn from the FILTER list
				types = FILTER
				filters = []
				# If this is an authenticated request, try proceeding with the requestor's
				# positive access capabilities. If none exist, then move on to auto-filters
				if self.user is not None:
					filters = self.own_filters(action)
				if not filters:
					filters = self.filters(action, True)
				value = HTTPAccepted(action.serial)
				def fail(msg): raise HTTPForbidden(msg)
			else: raise RuntimeError('%s is not a valid access type' % str(at))

			# If no filters actually match the action, then the attempt at automatic
			# access should fail closed immediately (lack of a no does not mean yes)
			if not filters: return fail(NO_FILTERS)

			pos = [cap for cap in filters if cap.access_type == types[0]]
			neg = [cap for cap in filters if cap.access_type == types[1]]
			if neg:
				# If any negative filters were triggered, perform a negative access
				value = self.__perform(action, neg[0], True, value)
				DBSession.add_all((self.__record(action, cap, True) for cap in neg[1:]))
				DBSession.add_all((self.__record(action, cap, False) for cap in pos))
			else:
				# Otherwise, perform a positive access
				value = self.__perform(action, pos[0], True, value)
				DBSession.add_all((self.__record(action, cap, True) for cap in pos[1:]))

		except:
			allowed = False
			raise
		finally:
			self.__save(action, capability, allowed)

		if value is None:
			raise RuntimeException('Illegal return state')
		return value