diff options
Diffstat (limited to 'docs/narr.rst')
-rw-r--r-- | docs/narr.rst | 543 |
1 files changed, 53 insertions, 490 deletions
diff --git a/docs/narr.rst b/docs/narr.rst index 4f19fe4..d746fc3 100644 --- a/docs/narr.rst +++ b/docs/narr.rst @@ -1,8 +1,8 @@ -Overview -======== +=========================== + Overview and Introduction +=========================== -Introduction ------------- +.. currentmodule:: zope.security.interfaces The Security framework provides a generic mechanism to implement security policies on Python objects. This introduction provides a tutorial of the @@ -10,22 +10,34 @@ framework explaining concepts, design, and going through sample usage from the perspective of a Python programmer using the framework outside of Zope. Definitions ------------ +=========== Principal -~~~~~~~~~ +--------- -A generalization of a concept of a user. +A generalization of a concept of a :class:`user <IPrincipal>`. Further +specializations include :class:`groups of users <IGroup>` and +principals that :class:`know what groups they belong to +<IGroupAwarePrincipal>`. All of these principals may interact with the system. Permission -~~~~~~~~~~ +---------- A kind of access, i.e. permission to READ vs. permission to WRITE. -Fundamentally the whole security framework is organized around checking -permissions on objects. +Fundamentally the whole security framework is organized around +checking permissions on objects. Permissions are represented (and +checked) as strings, with the exception of :data:`a constant +<zope.security.checker.CheckerPublic>` that has the special meaning of +"public", i.e., no checking needs to be done. + +There are :class:`permission objects <IPermission>` that can be +registered as zope.component utilities for validation, introspection, +and producing :func:`lists of available permissions +<zope.security.permission.PermissionVocabulary>` to help users assign +them to objects. Purpose -------- +======= The security framework's primary purpose is to guard and check access to Python objects. It does this by providing mechanisms for explicit and @@ -44,10 +56,10 @@ it can be substituted with one which doesn't care about principals or interactions at all. Framework Components --------------------- +==================== Low Level Components -~~~~~~~~~~~~~~~~~~~~ +-------------------- These components provide the infrastructure for guarding attribute access and providing hooks into the higher level security framework. @@ -55,9 +67,10 @@ providing hooks into the higher level security framework. Checkers ~~~~~~~~ -A checker is associated with an object kind, and provides the hooks that map -attribute checks onto permissions deferring to the security manager (which in -turn defers to the policy) to perform the check. +A :class:`checker <IChecker>` is associated +with an object kind, and provides the hooks that map attribute checks +onto permissions deferring to the security manager (which in turn +defers to the policy) to perform the check. Additionally, checkers provide for creating proxies of objects associated with the checker. @@ -68,491 +81,41 @@ grant access based on attribute names. Proxies ~~~~~~~ -Wrappers around Python objects that implicitly guard access to their wrapped -contents by delegating to their associated checker. Proxies are also viral in -nature, in that values returned by proxies are also proxied. +:class:`Wrappers around Python objects <zope.security.proxy.Proxy>` +that implicitly guard access to their wrapped contents by delegating +to their associated checker. Proxies are also viral in nature, in that +values returned by proxies are also proxied. High Level Components ---------------------- +===================== Security Management -~~~~~~~~~~~~~~~~~~~ - -Provides accessors for setting up interactions and the global security policy. +------------------- -Interaction -~~~~~~~~~~~ +Provides accessors for :class:`setting up interactions +<IInteractionManagement>` and the :class:`global security policy +<ISecurityManagement>`. -Stores transient information on the list of participations. - -Participation -~~~~~~~~~~~~~ +:class:`Interaction <zope.security.interfaces.IInteraction>` +------------------------------------------------------------ -Stores information about a principal participating in the interaction. +An :class:`interaction <IInteraction>` represents zero or more +principals manipulating or viewing (interacting with) the system. -Security Policy -~~~~~~~~~~~~~~~ - -Provides a single method that accepts the object, the permission, and the -interaction of the access being checked and is used to implement the +Interactions also provide :func:`a single method +<IInteraction.checkPermission>` that accepts the object and the +permission of the access being checked and is used to implement the application logic for the security framework. -Narrative (agent sandbox) -------------------------- - -As an example we take a look at constructing a multi-agent distributed system, -and then adding a security layer using the Zope security model onto it. - -Scenario -~~~~~~~~ - -Our agent simulation consists of autonomous agents that live in various agent -homes/sandboxes and perform actions that access services available at their -current home. Agents carry around authentication tokens which signify their -level of access within any given home. Additionally agents attempt to migrate -from home to home randomly. - -The agent simulation was constructed separately from any security aspects. -Now we want to define and integrate a security model into the simulation. The -full code for the simulation and the security model is available separately; -we present only relevant code snippets here for illustration as we go through -the implementation process. - -For the agent simulation we want to add a security model such that we group -agents into two authentication groups, "norse legends", including the -principals thor, odin, and loki, and "greek men", including prometheus, -archimedes, and thucydides. - -We associate permissions with access to services and homes. We differentiate -the homes such that certain authentication groups only have access to services -or the home itself based on the local settings of the home in which they -reside. - -We define the homes/sandboxes - - - origin - all agents start here, and have access to all - services here. - - - valhalla - only agents in the authentication group 'norse - legend' can reside here. - - - jail - all agents can come here, but only 'norse legend's - can leave or access services. - - -Process -~~~~~~~ - -Loosely we define a process for implementing this security model - - - mapping permissions onto actions - - - mapping authentication tokens onto permissions - - - implementing checkers and security policies that use our - authentication tokens and permissions. - - - binding checkers to our simulation classes - - - inserting the hooks into the original simulation code to add - proxy wrappers to automatically check security. - - - inserting hooks into the original simulation to register the - agents as the active principal in an interaction. - - -Defining a Permission Model -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We define the following permissions:: - - NotAllowed = 'Not Allowed' - Public = Checker.CheckerPublic - TransportAgent = 'Transport Agent' - AccessServices = 'Access Services' - AccessAgents = 'Access Agents' - AccessTimeService = 'Access Time Services' - AccessAgentService = 'Access Agent Service' - AccessHomeService = 'Access Home Service' - -and create a dictionary database mapping homes to authentication groups which -are linked to associated permissions. - - -Defining and Binding Checkers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Checkers are the foundational unit for the security framework. They define -what attributes can be accessed or set on a given instance. They can be used -implicitly via Proxy objects, to guard all attribute access automatically or -explicitly to check a given access for an operation. - -Checker construction expects two functions or dictionaries, one is used to map -attribute names to permissions for attribute access and another to do the same -for setting attributes. - -We use the following checker factory function:: - - def PermissionMapChecker(permissions_map={}, - setattr_permission_func=NoSetAttr): - res = {} - for k,v in permissions_map.items(): - for iv in v: - res[iv]=k - return checker.Checker(res.get, setattr_permission_func) - - time_service_checker = PermissionMapChecker( - # permission : [methods] - {'AccessTimeService':['getTime']} - ) - -with the NoSetAttr function defined as a lambda which always return the -permission `NotAllowed`. - -To bind the checkers to the simulation classes we register our checkers with -the security model's global checker registry:: - - import sandbox_simulation - from zope.security.checker import defineChecker - defineChecker(sandbox_simulation.TimeService, time_service_checker) - - -Defining a Security Policy -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We implement our security policy such that it checks the current agent's -authentication token against the given permission in the home of the object -being accessed:: - - @implementer(ISecurityPolicy) - class SimulationSecurityPolicy: - - createInteraction = staticmethod(simpleinteraction.createInteraction) - - def checkPermission(self, permission, object, interaction): - - home = object.getHome() - db = getattr(SimulationSecurityDatabase, home.getId(), None) - - if db is None: - return False - - allowed = db.get('any', ()) - if permission in allowed or ALL in allowed: - return True - - if interaction is None: - return False - if not interaction.participations: - return False - for participation in interaction.participations: - token = participation.principal.getAuthenticationToken() - allowed = db.get(token, ()) - if permission not in allowed: - return False - - return True - -There are no specific requirements for the interaction class, so we can just -use `zope.security.simpleinteraction.Interaction`. - -Since an interaction can have more than one principal, we check that *all* of -them are given the necessary permission. This is not really necessary since -we only create interactions with a single active principal. - -There is some additional code present to allow for shortcuts in defining the -permission database when defining permissions for all auth groups and all -permissions. - - -Integration -~~~~~~~~~~~ - -At this point we have implemented our security model, and we need to integrate -it with our simulation model. We do so in three separate steps. - -First we make it such that agents only access homes that are wrapped in a -security proxy. By doing this all access to homes and services (proxies have -proxied return values for their methods) is implicitly guarded by our security -policy. - -The second step is that we want to associate the active agent with the -security context so the security policy will know which agent's authentication -token to validate against. - -The third step is to set our security policy as the default policy for the -Zope security framework. It is possible to create custom security policies at -a finer grained than global, but such is left as an exercise for the reader. - - -Interaction Access -~~~~~~~~~~~~~~~~~~ - -The *default* implementation of the interaction management interfaces defines -interactions on a per thread basis with a function for an accessor. This -model is not appropriate for all systems, as it restricts one to a single -active interaction per thread at any given moment. Reimplementing the -interaction access methods though is easily doable and is noted here for -completeness. - - -Perspectives -~~~~~~~~~~~~ - -It's important to keep in mind that there is a lot more that is possible using -the security framework than what's been presented here. All of the -interactions are interface based, such that if you need to re-implement the -semantics to suite your application a new implementation of the interface will -be sufficient. Additional possibilities range from restricted interpreters -and dynamic loading of untrusted code to non Zope web application security -systems. Insert imagination here ;-). - - -Zope Perspective -~~~~~~~~~~~~~~~~ - -A Zope3 programmer will never commonly need to interact with the low level -security framework. Zope3 defines a second security package over top the low -level framework and authentication sources and checkers are handled via zcml -registration. Still those developing Zope3 will hopefully find this useful as -an introduction into the underpinnings of the security framework. - - -Code -~~~~ - -The complete code for this example is available. - -- sandbox.py - the agent framework - -- sandbox_security.py - the security implementation and binding to the agent - framework. - - -Authors -~~~~~~~ - -- Kapil Thangavelu <hazmat at objectrealms.net> -- Guido Wesdorp <guido at infrae.com> -- Marius Gedminas <marius at pov.lt> - - -Untrusted interpreters -====================== - -Untrusted programs are executed by untrusted interpreters. Untrusted -interpreters make use of security proxies to prevent un-mediated -access to assets. An untrusted interpreter defines an environment for -running untrusted programs. All objects within the environment are -either: - -- "safe" objects created internally by the environment or created in - the course of executing the untrusted program, or - -- "basic" objects - -- security-proxied non-basic objects - -The environment includes proxied functions for accessing objects -outside of the environment. These proxied functions provide the only -way to access information outside the environment. Because these -functions are proxied, as described below, any access to objects -outside the environment is mediated by the target security functions. - -Safe objects are objects whose operations, except for attribute -retrieval, and methods access only information stored within the -objects or passed as arguments. Safe objects contained within the -interpreter environment can contain only information that is already -in the environment or computed directly from information that is -included in the environment. For this reason, safe objects created -within the environment cannot be used to directly access information -outside the environment. - -Safe objects have some attributes that could (very) indirectly be used -to access assets. For this reason, an untrusted interpreter always -proxies the results of attribute accesses on a safe objects. - -Basic objects are safe objects that are used to represent elemental -data values such as strings and numbers. Basic objects require a -lower level of protection than non-basic objects, as will be described -detail in a later section. - -Security proxies mediate all object operations. Any operation -access is checked to see whether a subject is authorized to perform -the operation. All operation results other than basic objects are, in -turn, security proxied. Security proxies will be described in greater -detail in a later section. Any operation on a security proxy that -results in a non-basic object is also security proxied. - -All external resources needed to perform an operation are security -proxied. - -Let's consider the trusted interpreter for evaluating URLs. In -operation 1 of the example, the interpreter uses a proxied method for -getting the system root object. Because the method is proxied, the -result of calling the method and the operation is also proxied. - -The interpreter has a function for traversing objects. This function -is proxied. When traversing an object, the function is passed an -object and a name. In operation 2, the function is passed the result -of operation 1, which is the proxied root object and the name 'A'. We -may traverse an object by invoking an operation on it. For example, -we may use an operation to get a sub-object. Because any operation on a -proxied object returns a proxied object or a basic object, the result -is either a proxied object or a basic object. Traversal may also look -up a component. For example, in operation 1, we might look up a -presentation component named "A" for the root object. In this case, -the external object is not proxied, but, when it is returned from the -traversal function, it is proxied (unless it is a a basic object) -because the traversal function is proxied, and the result of calling a -proxied function is proxied (unless the result is a basic object). -Operation 3 proceeds in the same way. - -When we get to operation 4, we use a function for computing the -default presentation of the result of operation 3. As with traversal, -the result of getting the default presentation is either a proxied -object or a basic object because the function for getting the default -presentation is proxied. - -When we get to the last operation, we have either a proxied object or a -basic object. If the result of operation 4 is a basic object, we -simply convert it to a string and return it as the result page. If -the result of operation 4 is a non-basic object, we invoke a render -operation on it and return the result as a string. - -Note that an untrusted interpreter may or may not provide protection -against excessive resource usage. Different interpreters will provide -different levels of service with respect to limitations on resource -usage. - -If an untrusted interpreter performs an attribute access, the trusted -interpreter must proxy the result unless the result is a basic object. - -In summary, an untrusted interpreter assures that any access to assets -is mediated through security proxies by creating an environment to run -untrusted code and making sure that: - -- The only way to access anything from outside of the environment is - to call functions that are proxied in the environment. - -- Results of any attribute access in the environment are proxied - unless the results are basic objects. - -Security proxies ----------------- - -Security proxies are objects that wrap and mediate access to objects. - -The Python programming language used by Zope defines a set of specific -named low-level operations. In addition to operations, Python objects -can have attributes, used to represent data and methods. Attributes -are accessed using a dot notation. Applications can, and usually do, -define methods to provide extended object behaviors. Methods are -accessed as attributes through the low-level operation named -"__getattribute__". The Python code:: - - a.b() - -invokes 2 operations: - - 1. Use the low-level `__getattribute__` operation with the name "b". - - 2. Use the low-level '__call__' operation on the result of the first - operation. - -For all operations except the `__getattribute__` and -`__setattribute__` operations, security proxies have a permission -value defined by the permission-declaration subsystem. Two special -permission values indicate that access is either forbidden (never -allowed) or public (always allowed). For all other permission values, -the authorization subsystem is used to decide whether the subject has -the permission for the proxied object. If the subject has the -permission, then access to the operation is allowed. Otherwise, access -is denied. - -For getting or setting attributes, a proxy has permissions for getting -and a permission for setting attribute values for a given attribute -name. As described above, these permissions may be one of the two -special permission values indicating forbidden or public access, or -another permission value that must be checked with the authorization -system. - -For all objects, Zope defines the following operations to be always public: - - comparison - "__lt__", "__le__", "__eq__", "__gt__", "__ge__", "__ne__" - - hash - "__hash__" - - boolean value - "__nonzero__" - - class introspection - "__class__" - - interface introspection - "__providedBy__", "__implements__" - - adaptation - "__conform__" - - low-level string representation - "__repr__" - -The result of an operation on a proxied object is a security proxy -unless the result is a basic value. - -Basic objects +Participation ------------- -Basic objects are safe immutable objects that contain only immutable -subobjects. Examples of basic objects include: - -- Strings, - -- Integers (long and normal), - -- Floating-point objects, - -- Date-time objects, - -- Boolean objects (True and False), and +Stores information about a single principal :class:`participating +<zope.security.interfaces.IParticipation>` in the :class:`interaction +<zope.security.interfaces.IInteraction>`. -- The special (nil) object, None. - -Basic objects are safe, so, as described earlier, operations on basic -objects, other than attribute access, use only information contained -within the objects or information passed to them. For this reason, -basic objects cannot be used to access information outside of the -untrusted interpreter environment. - -The decision not to proxy basic objects is largely an optimization. -It allows low-level safe computation to be performed without -unnecessary overhead, - -Note that a basic object could contain sensitive information, but such -a basic object would need to be obtained by making a call on a proxied -object. Therefore, the access to the basic object in the first place -is mediated by the security functions. - -Rationale for mutable safe objects ----------------------------------- - -Some safe objects are not basic. For these objects, we proxy the -objects if they originate from outside of the environment. We do this -for two reasons: - -1. Non-basic objects from outside the environment need to be proxied - to prevent unauthorized access to information. - -2. We need to prevent un-mediated change of information from outside of - the environment. +Security Policy +--------------- -We don't proxy safe objects created within the environment. This is -safe to do because such safe objects can contain and provide access to -information already in the environment. Sometimes the interpreter or -the interpreted program needs to be able to create simple data -containers to hold information computed in the course of the program -execution. Several safe container types are provided for this -purpose. +A :class:`security policy <ISecurityPolicy>` is used to create the +interaction that will ultimately be responsible for security checking. |