Security and Workflow
預設的工作流程稱為 Simple Publication Workflow,從 /@@content-controlpanel 網址可以存取管理介面,針對各別型別指定適合的工作流程。常見的需求,是把公開網站改成內部網站。
新增使用者並指定權限
- Administrators (管理者) 具備系統最高權限
- Site Administrators (網站管理員) 具備編輯所有內容的權限
- Reviewers (審核者) 可以被指派負責特定目錄裡的內容發佈
Administrator 權限可能導致 reindex 啟動,造成效能議題,因此要考慮避免。有 collective.deligatesiteadmin 處理 Sharing 設定選項。
Permissions
Plone 的權限使用 Zope 的安全機制為基礎,組成元素包括 permission、role、group、workflow、state、transition 等,常見像 'Manage portal' 或 'View' 之類的設定值,被稱為 CMF Core Permission,完整定義在 Products/CMFCore/permissions.py 檔案裡。
Always ask for permission, never for role. If you ask for role, you may as well put app logic in TALES or just use PHP. Also, objects' methods are protected by permissions, not roles.
透過 permission 的 title 或 id 來查詢
plone.app.workflowmanager 搭配 Graphviz 視覺化管理 collective.wtf: spreadsheet
控制 Default View, Default Layout 的設定權限
zope2.View vs zope.View zope.Public
Delete Item in Folder Instead of Type
manage_pasteObjects protected with "Modify portal content"
permissions.zcml 從 plone.app.controlpanel 搬到 Products.CMFPlone
Show Toolbar http://community.plone.org/t/grant-permissions/7517 collective.impersonate
Roles
Add Portal Roles with Python Code 指定範例 manage_permission 自製角色 getRolesInContext
"Show as" Option for a View under a specific Role: collective.powertoken.view
Restrict Transition on Multiple Roles
pyramid_localroles zopyx.plone.cassandra
Sharing
Sharing Tab 提供角色權限的管理介面,可以勾選 Can add、Can edit、Can view、Can review 的設定值,它們分別對應到 Contributor、Editor、Reader、Reviewer 角色,比對模組裡的角色設定後,來決定使用者是否具備權限,當然,除了這些基本的角色外,我們也可以新增角色權限,利用 GenericSetup 的 sharing.xml 檔案來設定。
Reader可以看到 private 狀態的內容,但不能修改,如果想讓某人審核一篇尚未發佈的文章,就該指定 Reader 角色。Contributor可以新增文件、使用版本管理、檢視尚未發佈的文章,如果想讓某人可以建立文件,卻不會修改到別人的文章,就該指定 Contributor 角色。Editor能夠修改,但不能新增文件,同時可管理文件的屬性值,並執行提交動作。Reviewer和 Editor 互斥,可以執行發佈動作,或退回給原作者。Manager可以做所有事,包括進入 ZMI 介面。Owner不論何時,都可以修改自己的文章? 這個待確認
範例:採用 example.conference 的 workflow 時,未登入者無法檢示 draft 狀態的內容。
Custom Permissions Dexterity Advanced permissions
隱藏目錄裡的檔案和圖檔,預設沒有套用工作流程,顯示條件就由 Container View Permission 的 acquire 狀況來決定。
針對 4.2.4 分析 openlogic on collaboaration
Workflow UI Discussion Sharing: Removing Acquisition
在 Sharing 裡,Can Read 影響的是 Reader Role 的權限。
collective.subtractiveworkflow: two workflows for one content type
網頁方式建置工作流程的範例,使用工具包括 plone.app.workflowmanager、PloneFormGen、collective.pfg.dexterity。
Authentication from Multiple Sources
http://blog.keul.it/2011/09/plone-security-and-workflows-when-rely.html
http://blog.keul.it/2011/10/plone-security-and-workflows-learn-how.html
Workflow Policy Support (CMFPlacefulWorkflow) vs portal_controlpanel
AccessControl
self having no attribute 'access', Acquisition jumps back to the os module which has an attribute being osaccess
Custom Workflow is_allowed_state_change()
http://collective-docs.readthedocs.org/en/latest/sessions/login.html
Toolbar
http://www.it-spir.it/artikel/customize-plone-personal-tool-bar-style
collective.blog.portlets example
from Products.CMFCore.utils import getToolByName wftool = getToolByName(site, 'portal_workflow') wftool.doActionFor(obj, 'publish') obj.reindexObject()
Remove state menu from edit-bar
Reference Field for Another Type without Access Permission
<dtml-if expr="hasManagerPermission() !=1"> /*This hides the image option in the Add New menu if you are not a manager*/ a#image.contenttype-image span.subMenuTitle { display:none; } </dtml-if>
Acquire
Multiple Sites Effected by Acquisition
put setDefaultRoles in init.py outside of any function, so that it runs early during Zope startup
Workflow History
Multiple Workflows
Multiple Workflows for Different Groups: Workflow Stacked
利用 CMF Placeful Workflow 可以讓目錄擁有各自的工作流程,這個模組已內建安裝,只要啟用後,在工作狀態的下拉選單,可以看到「Policy...」選項。
讓 CMFWorkflow 針對 interface 客製化
Anonymous Adding Types
portal_action and workflow permission
Login with Username and Password
Role Drops to Anonymous When Adding Items with Custom Workflow
Masquerading As Another User In a Zope 3 Browser View
可能有兩層的設定:目錄要有 View, Add portal content, Access content information, MyPackage: Add MyType 型別要有 View, Modify portal content, Access content information
Workflow Script
Auto-Trigger
University of Wisconsin Oshkosh Workflow Training 範例: 申請表點選送出按鈕,狀態立即變成待審。
<transition transition_id="auto_to_private" title="Members only" new_state="private" trigger="AUTOMATIC" before_script="" after_script=""> <guard> <guard-expression>not:object/@@netimpact-utils/is_contact_publishable</guard-expression> </guard> </transition>
再搭配 Transition Trigger 程式碼
@grok.subscribe(IContact, IObjectModifiedEvent) def trigger_contact_workflow(contact, event): wtool = getToolByName(contact, 'portal_workflow') wtool.doActionFor(contact, 'autotrigger')
Cross Site Request Forgery
plone.protect: AJAX POST Requests _authenticator=<Some token>
取消保護: collective.dancing plone4.csrffixes buildout.cfg Workflow Script
# buildout.cfg environment-vars = PLONE_CSRF_DISABLED true
iframe 內容使用 https 或 http 會有不同影響。
Guard
當 private 到 pending 時,啟用 SimplePublicationWorkflow。
Miscellaneous
系統會信任來自檔案系統的程式碼,對於 Through The Web 的程式碼,會限制它們的功能或進行額外的權限檢查。
http://stackoverflow.com/questions/9667750/plone-4-restricting-published-content
cmf.ModifyPortalContent vs plone.app.iterate.permissions.CheckoutPermission
http://nathanvangheem.com/news/notes-on-a-more-secure-plone-deployment
像 intranet_workflow 並非使用 published 狀態名稱,或是沒有套用 workflow 的型別,可能造成模組無法正常運作。
hardcoded review state for anonymous users
Visitor Search Disabled, Only Member Can Search
Support for Site Administrator Role: Products.Poi
Member Basics
http://collective-docs.readthedocs.org/en/latest/members/member_basics.html
Read-only Public Site + Rewrite Login URLs
Basic Authentication
如果 Basic Auth Header 存在,就不會使用 Cookie 認證功能。
PAS
http://sharbas.blogspot.tw/2008/10/optional-auto-login-in-plone3.html auth_cookie_length
src_users = app.mysite.acl_users dict(src_users._user_passwords) {'jsmith': '{SSHA}jC/xX1xJ1eFn86HBdLGv)vciSNppMwWiRpCr'} dict(src_user._userid_to_login) {'jsmith': 'jsmith'}
plone.belowcontentbody.workflowhistory
http://stackoverflow.com/questions/14398585/how-to-cleanly-remove-a-plone-custom-permission
Image Folder 設定成 Intranet 狀態,但希望 Newsletter 若包含圖檔連結時,讀者是看得到內容的。可能方式之一,是把圖檔實際加進 Newsletter 來顯示,另外較麻煩的方式,是另為圖檔連結設定 View 來建立讀取權限。
Local Roles
Delegating Plone managing users and local roles on content
URL redirection after state or transition changed
Replace Local Roles on Users with Groups
http://plone.org/documentation/kb/adding-a-custom-permission-to-a-plone-2-5-product
想要取消 Local Role 的設定時,可在型別定義裡加上 flag 值:
class MyType(content.Container): """My content type """ implements(IMyType) __ac_local_roles_block__ = True
Adding a custom permission to a product
Using rolemap.xml to create new Roles is easy, you can add predefined permissions to your new roles. But what if you want to define a new permission for your product? Use setDefaultRoles.
Note for Plone 4
Please note that this instruction target Plone 2.5 and Plone 3. In Plone 4, you can add permissions from ZCML directives.
Purpose
Let's say you are developing a product called MyProduct, in which you want to create a new permission called "MyProduct: MyPermission".
Prerequisities
This how-to is targeted at product developers.
Step by step
#1. Add a file called permissions.py. from Products.CMFCore import permissions as CMFCorePermissions from AccessControl.SecurityInfo import ModuleSecurityInfo from Products.CMFCore.permissions import setDefaultRoles security = ModuleSecurityInfo('MyProduct') security.declarePublic('MyPermission') MyPermission = 'MyProduct: MyPermission' setDefaultRoles(MyPermission, ()) #2. Call this from your __init__.py. # Initial permissions setup. import permissions
The old way
There's been talk of Extensions/Install.py going away, so i'd advise against using this in your product.
Add this to your product's Extensions/Install.py:
from Products.CMFCore.permissions import setDefaultRoles def install(self, reinstall=False): setDefaultRoles('MyProduct: MyPermission', ())
Further information
Assigning permissions to a role using Generic Setup
If you also want to assign this permission to a role, 'Member' for example, the best way to go is to do it via Generic Setup in rolemap.xml:
<?xml version="1.0"?> <rolemap> <roles> <role name="Member"/> </roles> <permissions> <permission name="MyProduct: MyPermission" acquire="False"> <role name="Member"/> </permission> </permissions> </rolemap>
As 'Member' is a default role, there is no need to include it in <roles />. If you want a custom role 'MyCustomRole' in your product, you could replace 'Member' by 'MyCustomRole' and be done.
Assigning permissions to roles the OLD way
Before Generic Setup, people used to assign permissions to roles in this way:
In Install.py: from Products.CMFCore.permissions import setDefaultRoles def install(self, reinstall=False): MY_PERMISSION = 'MyProduct: MyPermission' setDefaultRoles(MY_PERMISSION, ()) PERMISSIONS = [ (MY_PERMISSION, ['Member',], 0), ] for p in PERMISSIONS: self.manage_permission( p[0], p[1], p[2],)
Assigning permissions to roles the OLD way, several files
To cleanly seperate the code from the rest of your installation code, some people also spread it out over several files:
In permissions.py: from Products.CMFCore.permissions import setDefaultRoles from AccessControl import ModuleSecurityInfo security = ModuleSecurityInfo('Products.MyProduct.permissions') security.declarePublic('MY_PERMISSION') MY_PERMISSION = 'MyProduct: MyPermission' setDefaultRoles(MY_PERMISSION, ()) In AppConfig.py: from Products.MyProduct.permissions import MY_PERMISSION PERMISSIONS = [ (MY_PERMISSION, 0, ['Member',]), ] In Extensions/AppInstall.py: from StringIO import StringIO from Products.MyProduct.AppConfig import PERMISSIONS def install(self): out = StringIO() for p in PERMISSIONS: self.manage_permission( p[0], p[1], p[2],) return out.getvalue() In Extensions/Install.py: from Products.ExternalMethod.ExternalMethod import ExternalMethod # try to call a custom install method # in 'AppInstall.py' method 'install' try: install = ExternalMethod('temp', 'temp', PROJECTNAME+'.AppInstall', 'install') except NotFound: install = None
* 內容型別通常會搭配一組「新增的權限設定值」,用來控制誰可以新增這個型別。 * 顯示方法 (包括表單) 也可能搭配特定權限。 * 個別欄位也可以