ERP5 手冊/魔法安全
不用說,安全在大多數專案中至關重要。設計一個既嚴格又靈活的許可權系統可能是開發人員的噩夢。
幸運的是,ERP5 帶有極其強大的安全機制。不幸的是,它不能開箱即用,需要進行自定義。
ERP5 的安全模型基於角色。角色是 Zope 的概念,在 Zope 文件(Zope 手冊)中進行了說明。一般來說,角色描述了使用者的身份(例如,會計,文員,官員),但不描述他們可以做什麼。這是由許可權定義的(例如,檢視許可權,修改許可權)。對於每個文件,都存在一個角色到許可權的對映。擁有會計角色的使用者可以被允許訪問某些文件,但不能被允許訪問其他文件。
ERP5 擴充套件了 Zope 的概念,引入了 5A 安全模型,它為業務安全提供了簡單一致的檢視。5A 代表 ERP5 的作者、審計員、分配者、被分配者和關聯者的角色。這些角色中的每一個都有一個特定的目的
作者 可以建立新文件。他不需要能夠檢視文件(他可能能夠檢視自己的文件,這得益於 Zope 的所有者角色)。
審計員 被允許檢視文件。
分配者 可以檢視、修改、刪除和建立文件,以及將其他使用者分配到指定的文件。
被分配者 只能處理模組中的某些文件。例如,他只能訪問與特定區域相關的文件。
關聯者 可以在某些條件下處理文件(例如,他可以檢視組織,前提是它們與他負責的發票文件相關)。
角色在:http://wiki.erp5.org/HowToDesignSecurity 中有描述
當用戶嘗試登入 ERP5 網站時,安全機制會嘗試找到一個人(在 person_module 中),該人具有引用屬性的值(在人員表單的詳細資訊選項卡上稱為“使用者名稱”)設定為使用者的登入名。如果存在這樣的人,擁有“內部”角色並且已透過驗證(參見關於工作流的章節),並且使用者提供的密碼與該人的密碼匹配,那麼允許使用者登入。
(重要——從修訂版 r15915 開始,人員不再需要擁有“內部”角色。相反,人員必須至少擁有一個開啟的分配。)
所以,要讓某人登入 ERP5 網站,你必須
- 定義一個人;
- 將引用屬性設定為使用者登入名;
- 設定密碼;
- 將人員的角色設定為內部(在 r15915 之後的修訂版中不再需要);
- 驗證一個人;
- 為該人員開啟一個分配(從修訂版 r15915 開始)。
安全分為兩部分——使用者端安全和物件端安全。
使用者端安全定義了使用者成功登入後擁有的安全設定。
物件端安全定義了使用者在給定物件上下文中獲得角色時應該滿足的條件。
在 ERP5 中,幾乎所有東西都是物件——模組、首選項、類別等等。每次使用者嘗試訪問物件時,ERP5 會執行以下操作
- 檢查使用者安全設定和物件安全設定是否允許在該物件上下文中授予使用者角色或多個角色;
- 查詢授予這些角色的許可權;
- 允許或拒絕訪問物件。
當用戶登入 ERP5 時,會為他計算安全類別。這些安全類別類似於一組鍵(“鍵”指的是一個小金屬物體,而不是密碼學中使用的鍵!)。回到程式設計,類別只是一列字串,例如: ['MA_CS','MA_CS_WA']
每個 ERP5 物件也具有其安全類別。這些類別可以被認為是鑰匙孔。每個類別都與角色相關聯。例如:[('HR','Assignor'),('SD','Assignee'),('MA_CS_WA','Auditor')]
當用戶擁有與給定鑰匙孔匹配的鑰匙時,他將獲得鑰匙孔後面的角色。在前面的示例中,使用者獲得了物件的審計員角色,因為他擁有(除其他外)MA_CS_WA 安全類別,並且物件與其關聯了審計員角色。
由於每個物件可以擁有不同的安全類別,因此使用者可以為不同的物件獲得不同的角色。如果另一個物件具有以下類別:[('HR','Assignor'),('SD','Assignee'),('MA_CS_LD','Auditor')],則第一個示例中的使用者將不會獲得任何角色,因此將無法訪問該物件。
現在主要的問題是——安全類別是如何計算的?好吧,這取決於我們是在談論使用者端安全設定還是物件端安全設定。
使用者端安全基於門戶類別(如果您不熟悉類別工具,請參見類別工具的說明)。正如我們之前提到的(參見上面的“ 如何成為使用者?”),每個登入的使用者都擁有與之關聯的人員物件,定義在人員模組中(這對像 Zope 這樣的特殊使用者來說並不適用,因此 ERP5 安全機制將無法為他們工作!)。這個人屬於一些類別(直接透過從包含的職業或分配中獲取,例如職位、組或站點)。
如果您檢視門戶類別,您會發現每個類別值都可能定義了一個編碼,即一個簡短的字串,用於識別該值。假設類別職位可以具有(除其他外)“經理”的值,它具有“MA”編碼。類別組可以具有“客戶服務”的值,它具有“CS”編碼。
如果使用者的職能是"經理",所屬組是"客戶服務",那麼該使用者的安全類別可以是"MA"("經理"的編碼)和"CS"("客戶服務"的編碼),用下劃線連線:MA_CS。對於另一個職能是"職員"(編碼"CL")且所屬組是"客戶服務"的使用者,其安全類別將是CL_CS。
關鍵問題是:哪些類別用於安全計算,以及它是如何工作的?
所以讓我們拿起螺絲刀,拆下 ERP5 安全機制的前面板,看看內部。
計算使用者安全設定的中心點是名為 ERP5Type_getSecurityCategoryMapping 的 Python 指令碼,它定義了哪些指令碼和哪些基本類別將用於安全計算。此指令碼應返回一個元組
((e1),(e2),...,(en))
該元組的每個元素也是一個元組:(script_name, cat_list),其中指令碼是用於計算安全類別的指令碼名稱,而 cat_list 是將作為引數之一傳遞給該指令碼的基本類別列表(其餘引數將在後面討論)。因此,如果 ERP5Type_getSecurityCategoryMapping 返回:(('script1', ['function']),('script2',['function','group'])),那麼首先將使用 ['function'] 呼叫 script1,然後將使用 ['function','group'] 呼叫 script2。
這些指令碼做什麼?它們檢查使用者的 Person 物件,獲取指定類別的值並將其作為字典列表返回。在前面的示例中,script1 應獲取 function 類別的值 ID,而 script2 應獲取 function 和 group 類別的值 ID。因此,對於在客戶服務中的經理角色的 Person,script1 可能返回: [{'function':'manager'}] ,而 script2 將返回: [{'function':'manager'},{'group','customer_service'}].
有一件事應該解釋清楚 - 為什麼指令碼返回字典列表而不是單個字典?這是因為某些類別可能在 Person 物件中包含的物件(例如分配)中定義,使用者可能有多個開放的分配,這會導致給定類別有多個值。
這些指令碼長什麼樣?它們應該接受以下引數
- base_category_list:之前已經討論過。
- user_name:已登入使用者的名稱(登入名),
- object:通常在此處不使用;
- portal_type:物件的入口型別(在此也不使用)。
ERP5Type_getSecurityCategoryMapping 應該由開發人員提供,並放置在門戶皮膚中的某個位置。如果沒有此指令碼,系統將按指令碼存在並返回以下元組的方式執行
(('ERP5Type_getSecurityCategoryFromAssignment',
self.getPortalAssignmentBaseCategoryList() ),)
這會導致使用從 getPortalAssignmentBaseCategoryList() 呼叫獲得的 base_category_list 引數呼叫 ERP5Type_getSecurityCategoryFromAssignment,該引數目前是: ('function', 'group', 'site')
ERP5Type_getSecurityCategoryFromAssignment 從已登入使用者 Person 物件的所有開放分配計算安全對映。
讓我們假設有一家跨多個地區經營的能源銷售公司。該公司有一個客戶服務部門。客戶服務的區域經理應該能夠訪問其各自區域的最終客戶的連線文件,但不能訪問其他區域的最終客戶的文件。區域儲存為 site 類別。
假設使用者 jacek 是一位經理。他有兩種開放的分配 - 華沙和普魯什科夫地區。第一個分配有以下設定
function: manager group: customer_service site: warsaw
而第二個分配有以下設定
function: manager group: customer_service site: pruszkow
注意:對於這類公司,擁有一個在兩個不同地區擁有兩種分配的經理可能不太常見。但是,我想表明,即使是這種不常見的需求也能夠在 ERP5 中輕鬆實現。
ERP5Type_getSecurityCategoryFromAssignment 將為使用者 jacek 返回以下字典列表
[{'function': 'manager', 'group': 'customer_service', 'site': 'warsaw'},
{'function': 'manager', 'group': 'customer_service', 'site': 'pruszkow'}]
使用者 bartek 是塞德爾策地區的經理。他擁有以下分配
function: manager group: customer_service site: siedlce
因此,指令碼為他返回
[{'function': 'manager', 'group': 'customer_service', 'site': 'siedlce'},]
但是,關於我在本章開頭提到的安全類別的字串表示呢?為此,使用了編碼。讓我們假設: function/manager 的編碼是 MA
group/production 的編碼是 CS
site/warsaw 的編碼是 WA
site/pruszkow 的編碼是 PRS
以及
site/siedlce 的編碼是 SL
在獲得字典列表後,每個字典的 ERP5 安全機制
- 按字母順序對鍵進行排序;
- 用其編碼替換類別值 ID;
- 將所有編碼連線到一個字串中,並用下劃線分隔;
因此,對於使用者 jacek 和第一個字典,編碼將是:MA_CS_WA,而第二個將是:MA_CS_PRS
最後,jacek 獲取以下對映:['MA_CS_WA','MA_CS_PRS']
使用者 bartek 獲取:['MA_CS_SL']
注意:如果未為給定類別定義編碼,則將使用該類別的 ID。但是,最好為安全中使用的類別定義編碼。
然後,這些安全設定將被 ERP5 用於控制對物件的訪問。這將在下一章中解釋。
物件安全設定(角色設定)是在門戶型別基礎上定義的(如果您不熟悉門戶型別,請閱讀此處)。這些設定是“鑰匙孔”,允許鑰匙所有者訪問指定的 roles。
角色可以是靜態計算也可以是動態計算。不幸的是,靜態和動態角色計算之間沒有明顯的區別,因為它們都定義在同一個表單中。稍後我們將討論這種差異。
要為門戶型別定義安全設定,您應該導航到其管理表單並點選“角色”選項卡。
<圖片待定 - 角色定義表單>
在 Name 欄位中,您可以輸入設定的名稱。(它不是角色名稱)。在實踐中,通常在此處輸入簡短的描述。這僅供參考。
在 Role 欄位中,您可以設定要授予使用者的角色名稱,該使用者的“鑰匙”與這個“鑰匙孔”匹配(也就是說,擁有正確安全類別的使用者)。
在 Description 欄位中,您可以設定設定的更詳細描述。這僅供參考。
在 Condition 欄位中,您可以設定一個條件,該條件應該滿足才能應用設定(例如,它可以是一個 Python 指令碼呼叫)。
在 Base Category 欄位中,您可以設定用於角色計算的基本類別名稱的空格分隔列表。
在 Base Category Script 欄位中,您可以設定如果使用動態角色計算方法,將呼叫的 Python 指令碼的名稱。如果使用靜態角色計算,則不會呼叫指令碼,並且欄位值沒有意義。
在 Category 文字區域中,您可以設定用於角色計算的類別值 ID 列表。每個類別值 ID 應放在單獨的行上。
如果對於在 Base Category 欄位中定義的每個基本類別名稱,在 Category 文字區域中都有一個匹配的定義,則計算是靜態的,也就是說,不會呼叫 Base Category Script。如果存在沒有在 Category 文字區域中匹配定義的基本類別名稱,則計算是動態的,也就是說,將呼叫指令碼,並且其返回值將用於缺失的定義。
靜態計算非常簡單 - 基於類別值建立對映。如果 Base Category 欄位包含 function group,而 Category 文字區域包含
function/sale_manager group/customer_service
那麼計算出的對映將是 MA_CS,前提是編碼與前面的示例相同。任何擁有 MA_CS 安全類別的使用者都將獲得該物件的 role。
但是,動態計算更困難。如果 Base Category 欄位中的條目多於 Category 文字區域中的類別值,則將為缺失的類別呼叫在 Base Category Script 欄位中定義的指令碼。
指令碼獲得以下引數
- base_category_list:在 Base Category 欄位中定義的類別列表。
- user_name:已登入使用者的名稱(登入名),
- object:計算角色設定的物件,
- portal_type:物件的入口型別。
指令碼應返回字典列表,就像使用者側安全計算指令碼一樣(事實上,在某些情況下,它們可能是相同的指令碼)。每個字典都包含來自 base_category_list 的類別名稱及其相應的 value ID。
這些指令碼應該做什麼?這取決於開發人員。
在我們的示例中,我們想要限制對客戶連線引數的訪問,只允許負責指定區域的經理訪問(即客戶居住的區域)。連線引數儲存在門戶型別為 Connection Parameters 的物件中。此物件透過 source 關係連結到 Person 物件(代表最終客戶)。Person 包含 Address 物件,而 Address 物件又具有 city 屬性。
讓我們導航到 Connection Parameters 管理表單,選擇 Role 選項卡並填寫表單
- 在 Name 欄位中,輸入簡短的描述,例如 Customer Service Management People。
- 在 Role 欄位中,輸入要授予使用者的角色名稱,例如 Assignor;
- 在“描述”欄位中輸入設定的描述,例如客戶管理人員應具有其區域內所有客戶的連線引數的分配者訪問許可權。
- 將“條件”欄位留空。
- 在“基本類別”欄位中輸入以空格分隔的基本類別名稱列表:“功能組站點”。
- 在“基本類別指令碼”欄位中輸入 Python 指令碼的名稱。我們將其命名為ConnectionParameters_getSecurityCategoryFromCustomerAddress,以遵循 ERP5 命名約定。
- 在“類別”文字區域中輸入類別值 ID 列表
function/manager group/customer_service
(您應該將每個類別值 ID 放在單獨的行中)可以很容易地看到,我們定義了三個基本類別,但只有兩個類別值 ID。因此,對於缺少的類別(站點),將使用ConnectionParameters_getSecurityCategoryFromCustomerAddress指令碼。
該指令碼應檢查連線引數物件,獲取連結的人員物件,獲取其預設地址城市,從城市名稱計算區域(它可以在類別中定義城市到區域的對映;或呼叫外部 GIS 系統;或使用水晶球),然後返回相應的字典列表。
該指令碼可能類似於以下指令碼
if portal_type != 'Connection Parameters':
raise RuntimeError, 'Error: Script called for invalid portal type'
customer = object.getSourceValue()
city = customer.getDefaultAddressCity()
region = context.ERP5Site_GetRegionFromCity() #guess the region somehow
category_dict = {}
for base_category in base_category_list:
if base_category == 'site':
category_dict[base_category]=region
對於居住在普魯什科夫地區的城市的客戶,該指令碼應返回:[{'site':'pruszkow'}]
其餘的對映將靜態計算 – 功能/經理對映到MA,組/客戶服務對映到CS,並且由於站點/普魯什科夫對映到PRS,最終對映將為MA_CS_PRS。任何具有此安全類別的使用者(即負責普魯什科夫地區的客戶服務經理)將被授予文件的分配者角色。
那麼,與多個客戶(可能居住在不同地區)相關的文件呢?沒問題,這隻需要稍作修改。該指令碼應檢查與文件相關的人員列表,並返回一個字典列表 – 一個客戶一個字典。因此,如果文件與兩個客戶相關 – 一個在普魯什科夫地區,一個在耶齊奧爾納地區,返回值將如下:[{'site':'pruszkow'},{'site':'jeziorna'}],最終文件將獲得以下對映'MA_CS_PRS','MA_CS_JEZ'
擴充套件預設值
[edit | edit source]假設有一類文件(例如連線標準,門戶型別連線標準)應提供給所有經理,無論他們負責哪個地區。如何實現這一點?第一個想法是為連線標準門戶型別編寫一個基本類別指令碼,以便它返回所有地區的所有可能對映:MA_CS_PRS,MA_CS_WA,MA_CS_SL,……等等。嗯,如果公司有 20 個地區,就會有 20 種不同的對映。很多吧?更糟糕的是,如果公司發展壯大,出現了新的地區,所有文件的安全設定都必須重新定義。
更好的想法是定義沒有地區程式碼的對映,即MA_CS。具有此對映的文件將可供所有客戶服務經理訪問……或者不?
嗯,不完全是,因為沒有經理會獲得MA_CS安全類別!因此,需要稍微修改一下預設的 ERP5 安全機制。
為此,您必須將ERP5Type_getSecurityCategoryMapping指令碼放在皮膚中。該指令碼應如下所示
return
(('ERP5Type_getSecurityCategoryFromAssignment', ['function','group','site']),
('ERP5Type_getSecurityCategoryFromAssignment', ['function','group']))
第一行看起來類似於系統預設值(我用顯式基本類別列表替換了 getPortalAssignmentBaseCategoryList()),第二行是新的。現在,當用戶登入時,ERP5Type_getSecurityCategoryFromAssignment 將被呼叫兩次 – 一次使用['function','group','site'],另一次僅使用['function','group']。此第二次呼叫為任何“客戶服務經理”(無論地區如何)產生MA_CS。
對於連線標準門戶型別,我們應該定義以下角色定義(僅顯示相關欄位)
- 在“角色”欄位中:分配者;
- 在“基本類別”欄位中:功能組。
- 在“類別”文字區域中
function/manager group/customer_service
這將產生對映MA_CS,因此所有具有MA_CS安全類別的使用者都將被授予分配者角色。
角色不是許可權
[edit | edit source]好吧,在這一點上,您可能會認為所有需要做的事情都已完成,但事實並非如此。您尚未定義角色到許可權的對映。
什麼到什麼的對映?——你可能會問。嗯,儘管有他們的名字,但角色並不能說明與他們相關的特權。在“審計員”或“分配者”這兩個詞中沒有任何神奇之處,ERP5 本身並不知道這些角色被允許做什麼。
(這甚至適用於 Zope 的經理角色!在許多系統中,經理(或者無論他被稱為什麼)都是一個強大的警長,可以做任何事情。但在 ERP5 中則不然。您決定每個角色擁有哪些許可權。如果您願意,甚至可以定義沒有任何許可權的經理,儘管這是一個很糟糕的想法。但是,您很容易錯誤地授予經理不足的許可權,在這種情況下,您會在開發過程中遇到很大的麻煩。)
如何定義角色的許可權?可以透過靜態方式或動態方式完成。
靜態許可權定義
[edit | edit source]這適用於在開發期間存在的物件。它們主要是模組。要為這樣的物件定義許可權,請導航到該物件的管理頁面,然後轉到“安全性”選項卡。閱讀 Zope 文件以瞭解詳細資訊。
動態許可權定義
[edit | edit source]這是工作流進入場景的時候。如您所知(如果您不知道,請閱讀有關工作流的部分),每個門戶型別都可以分配給一個或多個工作流。因此,此門戶型別的物件(例項)可以處於某些工作流狀態。每個工作流狀態定義單獨的角色到許可權對映。進入特定工作流狀態的物件將獲得為此工作流狀態定義的角色到許可權對映。
這允許非常靈活的特權操作。例如,新建立的連線引數文件應該只能由其建立者訪問,因此草稿狀態僅為所有者定義了檢視和修改許可權。文件完成後,可以提交。在這種狀態下,分配者和審計員可以閱讀,分配者可以讀寫。然後文件經過工作流的剩餘部分,最終進入存檔狀態,在此狀態下,任何人都無法更改它,但許多人可以閱讀。
要啟用基於工作流的安全性,請導航到工作流管理頁面,單擊“許可權”選項卡並新增所需的許可權。至少以下許可權應由工作流管理:檢視和訪問內容資訊(讀取)、修改門戶內容(寫入)和新增門戶內容(建立新物件)。
要為工作流狀態定義角色到許可權對映,請導航到工作流狀態管理頁面,然後單擊“許可權”選項卡。您將僅看到由此工作流管理的許可權。
更新安全設定
[edit | edit source]物件上的安全設定不會自動更新。這是開發人員在物件狀態更改後更新安全設定的責任。
一種方法是使用單獨的互動工作流,該工作流為參與安全計算的屬性的設定器定義了互動(在我們“幾乎真實的案例示例”中,人員的地址城市名稱是此類屬性的示例 – 城市名稱的更改會導致相關連線引數文件的安全設定更改,如果新城市與舊城市位於不同的地區)。互動應觸發一個檢查所有相關物件併為其重新計算安全設定的指令碼。
要重新計算物件上的安全設定,請在該物件的上下文中呼叫 updateLocalRolesOnSecurityGroups()。然後,重新索引該物件(這是必要的,因為物件許可權儲存在門戶目錄中 -> 請參閱目錄工具的說明)。
除錯安全性
[edit | edit source]<待撰寫>

