def portletManagerDirective( _context, name, title, for_=None, description=u'', class_=None, schema=None, layer=IDefaultBrowserLayer, provides=(), portlettype=IPortlet, **kw): # Build a new class ManagerClass = PortletManager( name, class_, provides, title, description, schema, portlettype, **kw) # Set up permission mapping for various accessible attributes required = {'__call__': CheckerPublic, 'browserDefault': CheckerPublic, 'publishTraverse': CheckerPublic} for iname in IPortletManager: required[iname] = CheckerPublic # security checker defineChecker(ManagerClass, Checker(required)) # security for schema fields for iface in (IPortletManagerConfiguration, schema): if iface is None: continue for f_id in iface: field = iface[f_id] if IField.providedBy(field) and not field.readonly: protectSetAttribute(ManagerClass, f_id, 'zojax.ManagePortlets') protectName(ManagerClass, f_id, 'zope.Public') # register the portlet manager adapter(_context, (ManagerClass,), IPortletManager, (for_, layer, None), name=name)
def ApplySecurity( ctx ): # setup security # for c in ctx.domain_model.__bases__: if c is object: continue protectLikeUnto( ctx.domain_model, c ) attributes = set([n for n,d in \ ctx.domain_interface.namesAndDescriptions(1)]) attributes = attributes.union( set( [ f.get('name') for f in ctx.descriptor.fields] ) ) descriptor = ctx.descriptor for n in attributes: model_field = descriptor.get(n) p = model_field and model_field.view_permission or 'zope.Public' protectName( ctx.domain_model, n, p ) for n in attributes: model_field = descriptor.get(n) p = model_field and model_field.edit_permission or 'zope.Public' # 'zope.ManageContent' protectSetAttribute( ctx.domain_model, n, p) for k, v in ctx.domain_model.__dict__.items(): if isinstance( v, ManagedContainerDescriptor ): protectName( ctx.domain_model, k, "zope.Public" )
def generate_container_class(ti): """Generate a zope3 container class for a domain model. """ type_key = naming.polymorphic_identity(ti.domain_model) container_name = naming.container_class_name(type_key) container_iname = naming.container_interface_name(type_key) base_interfaces = (IAlchemistContainer, ) # !+achetype.container_interface? # logging variables msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_name) # container class - if we already have one, exit if getattr(CONTAINER_MODULE, container_name, None): log.info( "generate_container_class [model=%s] found container %s.%s, skipping", *msg) ti.container_class = getattr(CONTAINER_MODULE, container_name) return container_class = type( container_name, (AlchemistContainer, ), dict(_class=ti.domain_model, __module__=CONTAINER_MODULE.__name__)) # set on CONTAINER_MODULE, register on type_info setattr(CONTAINER_MODULE, container_name, container_class) ti.container_class = container_class log.info("generate_container_class [model=%s] generated container %s.%s", *msg) # container interface - if we already have one, skip creation # !+ should always be newly created? container_iface = getattr(INTERFACE_MODULE, container_iname, None) msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_iname) if container_iface is not None: assert issubclass(container_iface, IAlchemistContainer) log.info( "generate_container_class [model=%s] skipping container interface %s.%s for", *msg) else: container_iface = interface.interface.InterfaceClass( container_iname, bases=base_interfaces, __module__=INTERFACE_MODULE.__name__) # set on INTERFACE_MODULE, register on type_info setattr(INTERFACE_MODULE, container_iname, container_iface) ti.container_interface = container_iface log.info( "generate_container_class [model=%s] generated container interface %s.%s", *msg) # setup security for n, d in container_iface.namesAndDescriptions(all=True): protectName(container_class, n, "zope.Public") # apply implementedBy if not container_iface.implementedBy(container_class): interface.classImplements(container_class, container_iface)
def generate_container_class(ti): """Generate a zope3 container class for a domain model. """ type_key = naming.polymorphic_identity(ti.domain_model) container_name = naming.container_class_name(type_key) container_iname = naming.container_interface_name(type_key) base_interfaces = (IAlchemistContainer,) # logging variables msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_name) # container class - if we already have one, exit if getattr(CONTAINER_MODULE, container_name, None): log.info("generate_container_class [model=%s] found container %s.%s, skipping" % msg) ti.container_class = getattr(CONTAINER_MODULE, container_name) return container_class = type(container_name, (AlchemistContainer,), dict(_class=ti.domain_model, __module__=CONTAINER_MODULE.__name__) ) # set on CONTAINER_MODULE, register on type_info setattr(CONTAINER_MODULE, container_name, container_class) ti.container_class = container_class log.info("generate_container_class [model=%s] generated container %s.%s" % msg) # container interface - if we already have one, skip creation # !+ should always be newly created? container_iface = getattr(INTERFACE_MODULE, container_iname, None) msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_iname) if container_iface is not None: assert issubclass(container_iface, IAlchemistContainer) log.info("generate_container_class [model=%s] skipping container interface %s.%s for" % msg) else: container_iface = interface.interface.InterfaceClass( container_iname, bases=base_interfaces, __module__=INTERFACE_MODULE.__name__ ) # set on INTERFACE_MODULE, register on type_info setattr(INTERFACE_MODULE, container_iname, container_iface) ti.container_interface = container_iface log.info("generate_container_class [model=%s] generated container interface %s.%s" % msg) # setup security for n, d in container_iface.namesAndDescriptions(all=True): protectName(container_class, n, "zope.Public") # apply implementedBy if not container_iface.implementedBy(container_class): interface.classImplements(container_class, container_iface)
def portletDirective( _context, name, title, for_=None, template=u'', description=u'', class_=None, provides=IPortlet, schema=None, type=IPortlet, manager=None, **kw): # Make sure that the template exists if template: template = os.path.abspath(str(_context.path(template))) if not os.path.isfile(template): raise ConfigurationError("No such file", template) # Build a new class. PortletClass = Portlet( name, class_, title, description, template, schema, **kw) if provides is not IPortlet: interface.classImplements(PortletClass, provides) # Set up permission mapping for various accessible attributes required = {'__call__': CheckerPublic, 'browserDefault': CheckerPublic, 'publishTraverse': CheckerPublic} for iface in (IPortlet, provides): for iname in iface: required[iname] = CheckerPublic # security checker defineChecker(PortletClass, Checker(required)) # portlet schema if schema is not None: # security for configuration for f_id in schema: field = schema[f_id] if IField.providedBy(field) and not field.readonly: protectSetAttribute(PortletClass, f_id, 'zojax.ManagePortlets') protectName(PortletClass, f_id, CheckerPublic) # register the portlet adapter(_context, (PortletClass,), type, (for_, None, manager, None), name=name)
def viewModelDirective( _context, name, title, for_=interface.Interface, description=u'', class_=None, schema=None, layer=IDefaultBrowserLayer, provides=(), **kw): # Build a new class ViewModelClass = ViewModelType( name, class_, provides, title, description, schema, **kw) # Set up permission mapping for various accessible attributes required = {'__call__': CheckerPublic, 'context': CheckerPublic, 'request': CheckerPublic} for iname in IViewModel: required[iname] = CheckerPublic # security checker defineChecker(ViewModelClass, Checker(required)) ifaces = list(provides) if schema is not None: ifaces.append(schema) # security for schema fields for iface in ifaces: for f_id in iface: field = iface[f_id] if IField.providedBy(field) and not field.readonly: protectSetAttribute(ViewModelClass, f_id, 'zojax.ManageViewModels') protectName(ViewModelClass, f_id, 'zope.Public') # register pagelet manager _context.action( discriminator = ('zojax:contentextensions.dynamic', name), callable = handler, args = ('registerAdapter', ViewModelClass, (for_, layer), IViewModel, name, _context.info))
def __new__(cls, name, klass, schema, fields, module): cname = 'ContentRevision<%s>'%name # generate bases if klass is None: klass = ContentRevision if issubclass(klass, ContentRevision): bases = (klass,) else: bases = (klass, ContentRevision) # generate fields attrs = {'__module__': module} for f_id in getFields(schema): if f_id in fields: attrs[f_id] = fields[f_id] else: attrs[f_id] = FieldProperty(schema[f_id]) # create type tp = type.__new__(cls, cname, bases, attrs) # set schema and implements tp.__schema__ = SchemaProperty(schema) component.getSiteManager().registerAdapter( getContentRevision, (tp,), schema) # set class to module setattr(sys.modules[module], cname, tp) # create security checker for n, d in schema.namesAndDescriptions(1): protectName(tp, n, 'zope.View') for n, d in IContentRevision.namesAndDescriptions(1): protectName(tp, n, 'zope.View') protectName(tp, '__schema__', 'zope.Public') for name, field in getFields(schema).items() + \ getFields(IContentRevision).items(): if not field.readonly: protectSetAttribute(tp, name, 'zojax.ModifyContent') return tp
def testInherited(self): class B1(object): def g(self): return 'B1.g' class B2(object): def h(self): return 'B2.h' class S(B1, B2): pass ztapi.provideUtility(IPermission, Permission('B1', ''), 'B1') ztapi.provideUtility(IPermission, Permission('S', ''), 'S') protectName(B1, 'g', 'B1') protectName(S, 'g', 'S') protectName(S, 'h', 'S') self.assertEqual(selectChecker(B1()).permission_id('g'), 'B1') self.assertEqual(selectChecker(B2()).permission_id('h'), None) self.assertEqual(selectChecker(S()).permission_id('g'), 'S') self.assertEqual(selectChecker(S()).permission_id('h'), 'S') self.assertEqual(S().g(), 'B1.g') self.assertEqual(S().h(), 'B2.h')
def apply_security(ti): domain_model, descriptor_model = ti.domain_model, ti.descriptor_model type_key = naming.polymorphic_identity(domain_model) log.debug("APPLY SECURITY: %s %s", type_key, domain_model) # first, "inherit" security settings of super classes i.e. equivalent of # something like <require like_class=".domain.Doc" /> for c in domain_model.__bases__: if c is object: continue log.debug(" LIKE_CLASS: %s", c) protectLikeUnto(domain_model, c) # !+DECL permissions here--for CUSTOM types only, and SINCE r9946--override # what is defined in domain.zcml, as opposed to vice-versa (probably # because CUSTOM types are setup at a later stage). # So (for CUSTOM types only?) we use the parametrized # bungeni.{type_key}.{Mode} as the view/edit permission: pv_type = "zope.Public" # view permission, for type pe_type = "zope.Public" # edit permission, for type if descriptor_model.scope == "custom": pv_type = "bungeni.%s.View" % (type_key) pe_type = "bungeni.%s.Edit" % (type_key) # !+SCHEMA_FIELDS(mr, oct-2012) all this seems superfluous anyway, as is # (always?) overwritten further down? Switch to base loop on superset of # names (dir(cls)?) and then decide ONCE on various criteria how to # protect the name. _view_protected = set() # remember names protected for view _edit_protected = set() # remember names protected for edit # sorted (for clearer logging) list of attr names that are BOTH defined # by the db mapped-table schema AND have a dedicated UI Field. dts_attrs = [ n for n in ti.derived_table_schema.names(all=True) ] df_attrs = [ f.get("name") for f in descriptor_model.fields ] attrs = sorted(set(dts_attrs).union(set(df_attrs))) log.debug(" DTS+Fields: %s, %s", ti.derived_table_schema.__name__, descriptor_model.__name__) for n in attrs: # !+DECL special cases, do not override domain.zcml... if n in ("response_text",): continue _view_protected.add(n); _edit_protected.add(n) pv = pv_type pe = pe_type model_field = descriptor_model.get(n) if model_field: if descriptor_model.scope != "custom": # !+DECL proceed as before for now pv = model_field.view_permission # always "zope.Public" pe = model_field.edit_permission # always "zope.ManageContent" # !+DECL parametrize all permissions by type AND mode, ensure to grant # to appropriate roles. What about non-workflows or non-catalyzed types? protectName(domain_model, n, pv) protectSetAttribute(domain_model, n, pe) DTS = n in dts_attrs and "dts" or " " DF = n in df_attrs and "df" or " " log.debug(" %s %s [%s] view:%s edit:%s %x", DTS, DF, n, pv, pe, id(model_field)) if n not in domain_model.__dict__: log.debug(" ---- [%s] !+SCHEMA_FIELDS not in %s.__dict__", n, domain_model) # container attributes (never a UI Field for these) log.debug(" __dict__: %s" % (domain_model)) for k in sorted(domain_model.__dict__.keys()): # !+ if IManagedContainer.providedBy(v): ? v = domain_model.__dict__[k] if isinstance(v, ManagedContainerDescriptor): if k in _view_protected: log.debug(" ---- %s RESETTING...", k) _view_protected.add(k) log.debug(" managed %s view:%s" % (k, "zope.Public")) elif isinstance(v, orm.attributes.InstrumentedAttribute): if k in _view_protected: log.debug(" ---- %s RESETTING...", k) _view_protected.add(k) log.debug(" instrumented [%s] view:%s", k, "zope.Public") else: log.debug(" ---- [%s] !+SCHEMA_FIELD IN __dict__ but NOT " "instrumented OR managed", k) continue if k not in attrs: log.debug(" ---- [%s] !+SCHEMA_FIELDS not in attrs", k) protectName(domain_model, k, "zope.Public") #!+pv_type # Dump permission_id required to getattr/setattr for "custom" types. # We only dump the security settings for "custom" types as it only these # are processed AFTER that domain.zcml has been executed (for other types, # loaded earlier during app startup, it is the settings in domain.zcml # (executed later during app startup) that ends up applying. if descriptor_model.scope == "custom": from zope.security import proxy, checker dmc = checker.getChecker(proxy.ProxyFactory(domain_model())) log.debug(" checker: %s", dmc) for n in sorted(_view_protected.union(["response_text"])): g = dmc.get_permissions.get(n) s = dmc.set_permissions.get(n) #dmc.setattr_permission_id(n) log.debug(" [%s] get:%s set:%s", n, getattr(g, "__name__", g), s)
def defineCheckers(): # define the appropriate checker for a FileResource for these tests from zope.app.security.protectclass import protectName from zope.app.publisher.browser.fileresource import FileResource protectName(FileResource, '__call__', 'zope.Public')
def GenerateContainer( ctx, container_name=None, container_iname=None, base_interfaces=() ): """ generate a zope3 container class for a domain model """ # create container container_name = container_name or \ ctx.domain_model.__name__ + 'Container' # allow passing in dotted python path if isinstance( ctx.container_module, (str, unicode) ): ctx.container_module = resolve( ctx.container_module ) # if not present use the domain class's module elif ctx.container_module is None: ctx.container_module = resolve( ctx.domain_model.__module__ ) # sanity check we have a module for the container assert isinstance(ctx.container_module, types.ModuleType ), "Invalid Container" # logging variables msg = ( ctx.domain_model.__name__, ctx.container_module.__name__, container_name ) # if we already have a container class, exit if getattr( ctx.container_module, container_name, None ): if ctx.echo: ctx.logger.debug("%s: found container %s.%s, skipping"%msg ) ctx.container_class = getattr( ctx.container_module, container_name ) return if ctx.echo: ctx.logger.debug("%s: generated container %s.%s"%msg ) # if we already have a container class, exit container_class = type( container_name, (AlchemistContainer,), dict(_class=ctx.domain_model, __module__=ctx.container_module.__name__ ) ) setattr( ctx.container_module, container_name, container_class) # save container class on catalyst context ctx.container_class = container_class # interface for container container_iname = container_iname or "I%s"%container_name # if the interface module is none, then use the nearest one to the domain class if ctx.interface_module is None: ispec = ctx.domain_model.__module__.rsplit('.',1)[0]+'.interfaces' ctx.interface_module = resolve( ispec ) msg = ( ctx.domain_model.__name__, ctx.container_module.__name__, container_iname ) # if we already have a container interface class, skip creation container_interface = getattr( ctx.interface_module, container_iname, None ) if container_interface is not None: assert issubclass( container_interface, IAlchemistContainer ) if ctx.echo: ctx.logger.debug("%s: skipping container interface %s.%s for"%msg ) else: if ctx.echo: ctx.logger.debug("%s: generated container interface %s.%s"%msg ) # ensure that our base interfaces include alchemist container if base_interfaces: assert isinstance( base_interfaces, tuple ) found = False for bi in base_interfaces: found = issubclass( bi, IAlchemistContainer ) if found: break if not found: base_interfaces = base_interfaces + ( IAlchemistContainer,) else: base_interfaces = ( IAlchemistContainer, ) # create interface container_interface = InterfaceClass( container_iname, bases = base_interfaces, __module__ = ctx.interface_module.__name__ ) # store container interface for catalyst ctx.container_interface = container_interface setattr( ctx.interface_module, container_iname, container_interface ) # setup security for n,d in container_interface.namesAndDescriptions(1): protectName( container_class, n, "zope.Public") if not container_interface.implementedBy(container_class): interface.classImplements(container_class, container_interface) ctx.container_interface = container_interface