Unification of requests and security contexts through Use

Unification of requests and security contexts: Use

Status: IsResolved

Authors

Steve Alexander and JimFulton

Introduction

The Zope 3 security enforcement system mediates access to object names (attribute and operation names). It assures that principals in the current context have the permission required for the access.

What is the context? It is an object that represents an interaction of external actors with the system. It's interesting to note that this is a lot like the request. When we describe views, we use a figure like the following:

        O
      /---/    -----------      --------      ----------
        |      | Request |--o<--| View |-->o--| Object |     
        ^      -----------      --------      ----------
       / \

The view provides access to an object for an actor (user). The request represents the user within the system.

Security contexts and requests provide similar functions, they represent an interaction with external actors. They provide information about the external actors and the way they are interacting with the system (e.g. protocols, addresses, etc.).

The parallel between security contexts and requests is so pronounced that it is compelling to use the same object for both purposes.

Problem

The existing security context, defined in zope.security is not well defined. It was developed early on and is based on the Zope 2 security context. As part of the current security refactoring effort, we seek to make the security architecture in Zope 3 clearer. The current poor definition of the security context is an impediment to clarity.

Proposal

It appears that security contexts and requests are either the same thing or different aspects of the same thing. Perhaps there should be a concept and object that encompasses both. We propose the introduction of the following concepts:

  • An "Interaction", which is an object that represents a use of the system by one or more principals. It represents a particular interaction between some principals and the system. This can be viewed as an instance of a use case.
  • A principal's "participation" in a interaction. This represents the way the principal participates in the interaction. This can be thought of as an instance of the edge connencting an actor to a use-case in a use-case diagram. We will usually use the name "request" to refer to "participation", both for the sake of brevity and familiarity:
               --------------- 1    * -----------------    1 -------------
               | Interaction |--------| Participation |----->| Principal |
               ---------------        -----------------      -------------
    

Let's look at a concrete example, the Zope web-application server. An interaction will correspond to a web request. When a request is handled by the system:

  • An interaction will be created
  • When we identify a principal, the principal is added to the interaction. Note that we often start with an unauthenticated principal and later replace it in the interaction with an authenticated principal.
  • When security checks are done, the security policy is passed the current interaction.
  • In the course of processing the request other actors might be created and added. For example, we might use some untrusted code. When the code begins executing, it creates actors for each of its authors and adds them to the interaction. When the code stops executing, it removes them. These actors have, as their participation, "authorship of x", where "x" is the code being executed. (We aren't doing this with untrusted code now. This is just a possible scenario.)
  • At the end of the request, we can discard the interaction.

This example provides just one possibility. One might, instead, associate an interaction with some sort of web session. One might even allow multiple participants in the interaction.

Another possibility is to model multi-request (keep-alive) web connections as a single interaction. We could even model the participation as the connection, rather than the individual requests.

Obviously, non-web applications provide many more possibilities.

We propose to make the following software changes:

  1. We will replace the concept of security contexts with interactions.
  2. Interactions will be managed as thread globals, in much the way we manage security managers now.
  3. We will change the existing security management API to deal with interactions directly.
  4. We will change ISecurityPolicy? so that it expects an interaction, rather than a context.
  5. We will need to revisit the way logged in users are displayed. This will probably be accomplished using views on actors.

Additional benefits (beyond solving problems)

  • Better support for untrusted code

    If one wanted to implement the policy that it was necessary to check access of owners of untrusted code, this could be implemented by having untrusted executable objects add participations for their owners before executing the code and then remove them afterwards.

    An important case of untrusted code is untrusted event subscriptions.

  • Support for multiple users

    This is a bit of a stretch, but one could imagine non-web applications that supported multiple users. This architecture could support such applications.

Implementation

Here are the proposed definitions for the new interfaces:

        class IInteraction(Interface):

            participations = Attribute("An iterable of participations")

            def add(participation):
                """Add a participation."""

            def remove(participation):
                """Remove a participation."""

        class IParticipation(Interface):

            interaction = Attribute("The interaction")
            principal = Attribute("The authenticated principal")

        class IInteractionManagement(Interface):

            def newInteraction(participation=None):
                """Start a new interaction.

                If participation is not None, it is added to the new interaction.
                """

            def getInteraction():
                """Return the current interaction or None if there isn't one."

            def endInteraction():
                """End the current interaction."""

Security contexts will be replaced with interactions. Security managers will disappear completely (rationale: once the security context and its executable stack go away, the security manager's API shrinks and the remaining methods simply delegate everything to the interaction). ISecurityManagementSetup? (newSecurityManager etc.) will be replaced with IInteractionManagement? which matches the problem domain more closely. Requests will implement IParticipation? (this implies renaming request.user to request.principal).


comments:

Notes from mailing list discussions --stevea, 2004/02/05 11:39 EST reply
- There was a general consensus that the word "Use" should be replaced with "Activity" or "Interaction", because the word "use" is common as both a noun and a verb in everyday English.

  • We can lose the "Actor" and just have:: [Use]?<>--[Participation]?<>--Principal
  • The implementation of the Activity/Interaction will typically belong with the implementation of the security policy. So, it will be possible and useful to create application-specific Activities/Interactions. Components that implement untrusted code will adapt the Activity/Interaction to some interface (ITellInteractionOrActivityAboutUntrustedCode? perhaps) that it can use to tell the Activity/Interaction about the principals who are responsible for the code. Some Activities/Interactions will simply ignore this (with a null adapter). Others will keep track of it because the security policy they are associated with needs it. The publication component will adapt the Activity/Interaction to an interface that allows it to say the request and principals that initiated the current publication process.

Note about isClientConnected method --stevea, 2004/02/24 09:34 EST reply
On the Zope 2 developers' mailing list, Chris McDonough? wrote:

Zope should have something like ASP's Response.IsClientConnected? method, which would allow app code to manually abort the processing of a request in strategic places if the connection has already been closed. I mentioned this a while back, but never did do anything about it.

I think code that is not presentaton code should be able to ask the Interaction whether the principals are still interacting.

Initial implementation --mgedmin, 2004/03/08 14:34 EST reply
I've just commited an implementation of this proposal as I understood to the mgedmin-events2-branch (Steve and I initially thought it was a prerequisite for the event service refactorings). The implementation is not polished yet.

... --jim, 2004/03/08 15:55 EST reply
I've updated this to reflect no-longer having proxies hold the interactions. We need to think more about the security api changes (or not).

Currently, the per-thread security manager has a reference to the context and the policy. We may want to keep this and simply replace the policy with the interaction.

Branch moved to subversion --mgedmin, 2004/05/12 17:46 EST reply
I almost finished merging the implementation to a new branch in subversion, called mgedmin-security. I haven't finished testing it yet. Also, at least the README and sandbox sample in zope.security need to be updated.

Implementation is finished --mgedmin, 2004/05/13 12:16 EST reply
The merge to a new branch in Subversion is finished. make test passes, Zope starts up just fine, and seems to work.

Remaining questions (some of them were answered by Jim on IRC):

  • Should endInteraction raise an error when there is no active interaction? Currently it does, but almost all places wrap the call in try: ... except: pass. I'm inclined to change it so that endInteraction never raises. Jim agrees.
  • Should getInteraction return None or raise an error when there is no active interaction? Currently it returns None. I think that's OK. Jim agrees and adds that "perhaps it should be renamed to queryInteraction".
  • What should ZopeSecurityPolicy? do when there are no principals in the interaction? Currently it raises AssertionError?. I think it should allow things protected with CheckerPublic? and disallow everything else.
  • Should ZopeSecurityPolicy? gracefully handle the case when getInteraction returns None? Currently it barfs with TypeError?. I think it should be changed to behave as if there were an interaction with no participations (see the item above).
  • What should ZopeSecurityPolicy? do when there are two or more principals in the interaction? Currently it raises AssertionError?. I think it should be changed to allow things only if they are allowed to ALL principals in the interaction.
  • What should stateful workflow (zope.app.workflow.stateful.instance.StatefulProcessInstance?._getContext) do when there are two or more principals in the interaction? Currently it raises AssertionError?. I don't know how to resolve this as I'm not familiar with workflow packages.
  • Should I merge the branch to the trunk? Perhaps after these questions are resolved? The only externally visible change should be the renaming of request.user to request.principal. Jim is for merging the changes.


( 97 subscribers )