宣告轉換規則語言

適用於: Windows Server 2022、Windows Server 2019、Windows Server 2016、Windows Server 2012 R2、Windows Server 2012

跨樹系宣告轉換功能可讓您在跨樹系信任上設定宣告轉換原則,以跨樹系界限橋接動態存取控制的宣告。 所有原則的主要元件都是以宣告轉換規則語言所撰寫的規則。 本主題提供此語言的詳細資料,並提供撰寫宣告轉換規則的指引。

跨樹系信任轉換原則的 Windows PowerShell Cmdlet 有一些選項可設定常見案例中所需的簡單原則。 這些 Cmdlet 會將使用者輸入轉譯為宣告轉換規則語言中的原則和規則,然後以指定的格式將其儲存在 Active Directory 中。 如需宣告轉換 Cmdlet 的詳細資訊,請參閱動態存取控制的 AD DS Cmdlet

根據 Active Directory 樹系中跨樹系信任的宣告設定和需求,您的宣告轉換原則可能必須比適用於 Active Directory 的 Windows PowerShell Cmdlet 所支援的原則更為複雜。 若要有效地撰寫這類原則,請務必了解宣告轉換規則語言語法和語意。 此宣告轉換規則語言 (以下總稱「語言」) 在 Active Directory 中是 Active Directory 同盟服務用於類似用途的語言子集,且具有非常類似的語法和語意。 不過,允許的作業較少,且會將其他語法限制放在語言的 Active Directory 版本中。

本主題簡述在 Active Directory 中宣告轉換規則語言的語法和語意,以及撰寫原則時所要考量的事項。 其提供多組範例規則來協助您開始使用,以及錯誤語法及其產生的訊息範例,協助您在撰寫規則時解密錯誤訊息。

撰寫宣告轉換原則的工具

適用於 Active Directory 的 Windows PowerShell Cmdlet:這是撰寫及設定宣告轉換原則的慣用和建議方式。 這些 Cmdlet 提供簡單原則的切換,並驗證針對更複雜原則所設定的規則。

LDAP:宣告轉換原則可透過輕量型目錄存取協定 (LDAP) 在 Active Directory 中編輯。 不過,不建議這麼做,因為原則有數個複雜的元件,且您在將原則寫入 Active Directory 之前,您所使用的工具可能無法驗證原則。 這在後續可能需要相當長的時間來診斷問題。

Active Directory 宣告轉換規則語言

語法概觀

以下是語言的語法和語意簡短概觀:

  • 宣告轉換規則集是由零個或多個規則所組成。 每個規則都有兩個作用中組件:[選取條件清單] 和 [規則動作]。 如果 [選取條件清單] 評估為 TRUE,則會執行對應的規則動作。

  • [選取條件清單] 有零個或多個 [選取條件]。 所有 [選取條件] 都必須評估為 TRUE,[選取條件清單] 才能評估為 TRUE。

  • 每個 [選取條件] 都有一組零個或多個 [比對條件]。 所有 [比對條件] 都必須評估為 TRUE,[選取條件] 才能評估為 TRUE。 這些條件全都會針對單一宣告進行評估。 符合 [選取條件] 的宣告可由 [識別碼] 標記,並在 [規則動作] 中加以參考。

  • 每個 [比對條件] 都會指定條件,以使用不同的 [條件運算子] 和 [字串常值] 來比對宣告的 TypeValueValueType

    • 當您指定 Value 的 [比對條件] 時,也必須指定特定 ValueType 的 [比對條件],反之亦然。 這些條件在語法中必須彼此相鄰。

    • ValueType 比對條件只能使用特定的 ValueType 常值。

  • [規則動作] 可以複製一個以 [識別碼] 標記的宣告,或根據以識別碼和/或指定字串常值標記的宣告發出一個宣告。

範例規則

此範例示範的規則可用來在兩個樹系之間轉譯宣告類型,前提是其使用相同的宣告 ValueTypes,並針對此類型的宣告值具有相同解譯。 規則有一個比對條件,以及使用 [字串常值] 和相符宣告參考的 Issue 陳述式。

C1: [TYPE=="EmployeeType"]
                 => ISSUE (TYPE= "EmpType", VALUE = C1.VALUE, VALUETYPE = C1.VALUETYPE);
[TYPE=="EmployeeType"] == Select Condition List with one Matching Condition for claims Type.
ISSUE (TYPE= "EmpType", VALUE = C1.VALUE, VALUETYPE = C1.VALUETYPE) == Rule Action that issues a claims using string literal and matching claim referred with the Identifier.

執行階段作業

請務必了解宣告轉換的執行階段作業,以有效撰寫規則。 執行階段作業會使用三組宣告:

  1. 輸入宣告集:提供給宣告轉換作業的宣告輸入集。

  2. 工作宣告集:在宣告轉換期間讀取及寫入的中繼宣告。

  3. 輸出宣告集:宣告轉換作業的輸出。

以下是執行階段宣告轉換作業的簡短概觀:

  1. 宣告轉換的輸入宣告可用來初始化工作宣告集。

    1. 處理每個規則時,工作宣告集會用於輸入宣告。

    2. 規則中的 [選取條件清單] 會與工作宣告集中的所有可能宣告集合相符。

    3. 每組相符宣告都會用來執行該規則中的動作。

    4. 執行規則動作會產生一個宣告,這會附加至輸出宣告集和工作宣告集。 因此,規則的輸出會用來做為規則集中後續規則的輸入。

  2. 規則集中的規則會依循序處理,並從第一個規則開始。

  3. 處理整個規則集時,會處理輸出宣告集來移除重複的宣告,以及其他安全性問題。產生的宣告是宣告轉換程序的輸出。

您可以根據先前的執行階段行為來撰寫複雜的宣告轉換。

範例:執行階段作業

此範例示範使用兩個規則的宣告轉換執行階段作業。


     C1:[Type=="EmpType", Value=="FullTime",ValueType=="string"] =>
                Issue(Type=="EmployeeType", Value=="FullTime",ValueType=="string");
     [Type=="EmployeeType"] =>
               Issue(Type=="AccessType", Value=="Privileged", ValueType=="string");
Input claims and Initial Evaluation Context:
  {(Type= "EmpType"),(Value="FullTime"),(ValueType="String")}
{(Type= "Organization"),(Value="Marketing"),(ValueType="String")}
After Processing Rule 1:
 Evaluation Context:
  {(Type= "EmpType"),(Value="FullTime"),(ValueType="String")}
{(Type= "Organization"), (Value="Marketing"),(ValueType="String")}
  {(Type= "EmployeeType"),(Value="FullTime"),(ValueType="String")}
Output Context:
  {(Type= "EmployeeType"),(Value="FullTime"),(ValueType="String")}

After Processing Rule 2:
Evaluation Context:
  {(Type= "EmpType"),(Value="FullTime"),(ValueType="String")}
{(Type= "Organization"),(Value="Marketing"),(ValueType="String")}
  {(Type= "EmployeeType"),(Value="FullTime"),(ValueType="String")}
  {(Type= "AccessType"),(Value="Privileged"),(ValueType="String")}
Output Context:
  {(Type= "EmployeeType"),(Value="FullTime"),(ValueType="String")}
  {(Type= "AccessType"),(Value="Privileged"),(ValueType="String")}

Final Output:
  {(Type= "EmployeeType"),(Value="FullTime"),(ValueType="String")}
  {(Type= "AccessType"),(Value="Privileged"),(ValueType="String")}

特殊規則語意

以下是規則的特殊語法:

  1. 空白規則集 == 沒有輸出宣告

  2. 空白選取條件清單 == 每個宣告都符合選取條件清單

    範例:空白選取條件清單

    下列規則會比對工作集中的每個宣告。

    => Issue (Type = "UserType", Value = "External", ValueType = "string")
    
  3. 空白選取比對清單 == 每個宣告都符合選取條件清單

    範例:空白比對條件

    下列規則會比對工作集中的每個宣告。 如果單獨使用,則這是基本的「全部允許」規則。

    C1:[] => Issule (claim = C1);
    

安全性考量

進入樹系的宣告

傳入樹系的主體所提供的宣告必須經過徹底檢查,以確保我們只允許或發出正確的宣告。 不當的宣告可能會危害樹系安全性,在撰寫進入樹系的宣告轉換原則時,這應該是首要考量。

Active Directory 具有下列功能,可防止進入樹系的宣告設定錯誤:

  • 如果樹系信任沒有針對進入樹系的宣告設定宣告轉換原則,則 Active Directory 會卸載所有進入樹系的主體宣告。

  • 如果在進入樹系的宣告上執行規則集會造成樹系中未定義的宣告,則會從輸出宣告卸載未定義的宣告。

離開樹系的宣告

離開樹系的宣告比進入樹系的宣告少一些安全性考量。 即使沒有對應的宣告轉換原則,宣告仍可依原狀離開樹系。 您也可以發出未在樹系中定義的宣告,做為轉換離開樹系宣告的一部分。 這可讓您使用宣告輕鬆地設定跨樹系信任。 系統管理員可以判斷進入樹系的宣告是否需要轉換,並設定適當的原則。 例如,如果需要隱藏宣告以防止資訊揭露,系統管理員可以設定原則。

宣告轉換規則中的語法錯誤

如果指定的宣告轉換原則有一個規則集的語法不正確或有其他語法或儲存體問題,則原則會被視為無效。 這與先前所述的預設條件處理方式不同。

Active Directory 無法判斷此案例中的意圖,並進入保全模式,在該信任+周遊方向上不會產生任何輸出宣告。 需要系統管理員介入才能更正問題。 如果使用 LDAP 來編輯宣告轉換原則,就會發生這種情況。 適用於 Active Directory 的 Windows PowerShell Cmdlet 已就地進行驗證,以防止撰寫的原則發生語法問題。

其他語言考量

  1. 此語言有數個特別的關鍵字或字元 (稱為終端機)。 這些稍後都會呈現在本主題的語言終端機表格中。 錯誤訊息會使用這些終端機的標籤來釐清。

  2. 終端機有時可以當做字串常值使用。 不過,這類使用方式可能會與語言定義發生衝突,或產生非預期的結果。 不建議使用這種用法。

  3. 規則動作無法在宣告值上執行任何類型轉換,且包含這類規則動作的規則集會視為無效。 這會導致執行階段錯誤,且不會產生任何輸出宣告。

  4. 如果規則動作參照規則的 [選取條件清單] 部分未使用到的識別碼,則這是不正確的使用方式。 這會導致語法錯誤。

    範例:不正確的識別碼參考下列規則說明規則動作中使用到的不正確識別碼。

    C1:[] => Issue (claim = C2);
    

範例轉換規則

  • 允許特定類型的所有宣告

    精確類型

    C1:[type=="XYZ"] => Issue (claim = C1);
    

    使用 Regex

    C1: [type =~ "XYZ*"] => Issue (claim = C1);
    
  • 不允許特定宣告類型 Exact 類型

    C1:[type != "XYZ"] => Issue (claim=C1);
    

    使用 Regex

    C1:[Type !~ "XYZ?"] => Issue (claim=C1);
    

規則剖析器錯誤的範例

宣告轉換規則是由自訂剖析器進行剖析,以檢查語法錯誤。 在 Active Directory 中儲存規則之前,此剖析器是由相關的 Windows PowerShell Cmdlet 執行。 剖析規則時的任何錯誤 (包括語法錯誤) 都會列印在主控台上。 網域控制站也會先執行剖析器後,再使用轉換宣告的規則,並在事件記錄檔中記錄錯誤 (新增事件記錄號碼)。

本節說明一些以不正確語法撰寫的規則範例,以及剖析器所產生的對應語法錯誤。

  1. 範例:

    c1;[]=>Issue(claim=c1);
    

    此範例使用了錯誤的分號來取代冒號。 錯誤訊息:POLICY0002:無法剖析原則資料。行號:1,欄號:2,錯誤標記:;。行:'c1;[]=>Issue(claim=c1);'。剖析器錯誤:'POLICY0030: Syntax error, unexpected ';', expecting one of the following: ':' .'

  2. 範例:

    c1:[]=>Issue(claim=c2);
    

    在此範例中,未定義複製發行陳述式中的識別碼標記。 錯誤訊息POLICY0011:宣告規則中沒有條件符合 CopyIssuanceStatement: 'c2' 中指定的條件標記。

  3. 範例:

    c1:[type=="x1", value=="1", valuetype=="bool"]=>Issue(claim=c1)
    

    「bool」不是語言中的終端機,且不是有效的 ValueType。 有效的終端機會列在下列錯誤訊息中。 錯誤訊息:POLICY0002:無法剖析原則資料。行號:1,欄號:39,錯誤標記:「bool」。 行:'c1:[type=="x1", value=="1",valuetype=="bool"]=>Issue(claim=c1);'。 剖析器錯誤:'POLICY0030:語法錯誤,非預期的 'STRING',預期為下列其中一項:'INT64_TYPE' 'UINT64_TYPE' 'STRING_TYPE' 'BOOLEAN_TYPE' 'IDENTIFIER'

  4. 範例:

    c1:[type=="x1", value==1, valuetype=="boolean"]=>Issue(claim=c1);
    

    此範例中的數字 1 不是語言中的有效權杖,因此在比對條件中不允許使用這類用法。 其必須以雙引號括住,使其成為字串。 錯誤訊息:POLICY0002:無法剖析原則資料。行號:1,欄號:23,錯誤標記:1。行:'c1:[type=="x1", value==1, valuetype=="bool"]=>Issue(claim=c1);'.剖析器錯誤:'POLICY0029:非預期的輸入。

  5. 範例:

    c1:[type == "x1", value == "1", valuetype == "boolean"] =>
    
         Issue(type = c1.type, value="0", valuetype == "boolean");
    

    此範例使用雙等號 (==) 而不是單等號 (=)。 錯誤訊息:POLICY0002:無法剖析原則資料。行號:1,欄號:91,錯誤標記:==。行:'c1:[type=="x1", value=="1",valuetype=="boolean"]=>Issue(type=c1.type, value="0", valuetype=="boolean");'。剖析器錯誤:'POLICY0030:語法錯誤,非預期的 '==',預期為下列其中一項:'='

  6. 範例:

    c1:[type=="x1", value=="boolean", valuetype=="string"] =>
    
          Issue(type=c1.type, value=c1.value, valuetype = "string");
    

    此範例在語法和語意上是正確的。 不過,使用「boolean」做為字串值必然會造成混淆,因此應該避免。 如先前所述,應盡可能避免使用語言終端機做為宣告值。

語言終端機

下表列出宣告轉換規則語言中所使用一組完整的終端機字串和相關聯的語言終端機。 這些定義是使用不區分大小寫的 UTF-16 字串。

String 終端
"=>" IMPLY
";" SEMICOLON
":" COLON
"," COMMA
"." DOT
"[" O_SQ_BRACKET
"]" C_SQ_BRACKET
"(" O_BRACKET
")" C_BRACKET
"==" EQ
"!=" NEQ
"=~" REGEXP_MATCH
"!~" REGEXP_NOT_MATCH
"=" ASSIGN
"&&"
"issue" 問題
"type" TYPE
"value"
"valuetype" VALUE_TYPE
"claim" CLAIM
"[_A-Za-z][_A-Za-z0-9]*" IDENTIFIER
"\"[^\"\n]*\"" 字串
"uint64" UINT64_TYPE
"int64" INT64_TYPE
"string" STRING_TYPE
"boolean" BOOLEAN_TYPE

語言語法

下列宣告轉換規則語言是以 ABNF 形式進行指定。 此定義會使用上表中所指定的終端機,以及此處定義的 ABNF 生產環境。 規則必須以 UTF-16 進行編碼,且字串比較必須視為不區分大小寫。

Rule_set        = ;/*Empty*/
             / Rules
Rules         = Rule
             / Rule Rules
Rule          = Rule_body
Rule_body       = (Conditions IMPLY Rule_action SEMICOLON)
Conditions       = ;/*Empty*/
             / Sel_condition_list
Sel_condition_list   = Sel_condition
             / (Sel_condition_list AND Sel_condition)
Sel_condition     = Sel_condition_body
             / (IDENTIFIER COLON Sel_condition_body)
Sel_condition_body   = O_SQ_BRACKET Opt_cond_list C_SQ_BRACKET
Opt_cond_list     = /*Empty*/
             / Cond_list
Cond_list       = Cond
             / (Cond_list COMMA Cond)
Cond          = Value_cond
             / Type_cond
Type_cond       = TYPE Cond_oper Literal_expr
Value_cond       = (Val_cond COMMA Val_type_cond)
             /(Val_type_cond COMMA Val_cond)
Val_cond        = VALUE Cond_oper Literal_expr
Val_type_cond     = VALUE_TYPE Cond_oper Value_type_literal
claim_prop       = TYPE
             / VALUE
Cond_oper       = EQ
             / NEQ
             / REGEXP_MATCH
             / REGEXP_NOT_MATCH
Literal_expr      = Literal
             / Value_type_literal

Expr          = Literal
             / Value_type_expr
             / (IDENTIFIER DOT claim_prop)
Value_type_expr    = Value_type_literal
             /(IDENTIFIER DOT VALUE_TYPE)
Value_type_literal   = INT64_TYPE
             / UINT64_TYPE
             / STRING_TYPE
             / BOOLEAN_TYPE
Literal        = STRING
Rule_action      = ISSUE O_BRACKET Issue_params C_BRACKET
Issue_params      = claim_copy
             / claim_new
claim_copy       = CLAIM ASSIGN IDENTIFIER
claim_new       = claim_prop_assign_list
claim_prop_assign_list = (claim_value_assign COMMA claim_type_assign)
             /(claim_type_assign COMMA claim_value_assign)
claim_value_assign   = (claim_val_assign COMMA claim_val_type_assign)
             /(claim_val_type_assign COMMA claim_val_assign)
claim_val_assign    = VALUE ASSIGN Expr
claim_val_type_assign = VALUE_TYPE ASSIGN Value_type_expr
Claim_type_assign   = TYPE ASSIGN Expr