Gerade in grösseren Umgebungen kann es schnell mal vorkommen, dass ein Account in mehr als 150 (SAML Limit) bzw. 200 (JWT Limit) Gruppen Mitglied ist. Aufgrund des HTTP Header Limits wird der Groups Claim von Microsoft Entra ID speziell behandelt: Configure group claims for applications by using Azure Active Directory – Microsoft Entra | Microsoft Learn. Wenn das Limit überschritten wird, schickt Microsoft Entra ID anstelle der Liste einen Link zum Graph API über den, mit den entsprechenden Berechtigungen, die Gruppenmitgliedschaften abgefragt werden können. Nun hat nicht jede Applikation die Möglichkeit diesen API Aufruf durchzuführen.

Lange Zeit war es nur bei SAML Assertions möglich die Gruppen, welche im Claim erscheinen sollen, zu filtern. Dies hat sich im Laufe des Jahres 2023 geändert und dieser Beitrag zeigt auf, wie die Gruppen nun auch für OIDC/OAuth2 Tokens gefiltert werden können. Eine Alternative wäre die Gruppen der Applikation zuweisen und den Groups Claim auf Groups assigned to the application zu stellen. Damit würden nur noch die entsprechend zugewisenen Gruppen im Claim erscheinen, jedoch bedeutet dies ein händisches Verwalten der Gruppenzuweisung.

Im Portal

Zuerst muss auf der App Registration unter Token Configuration die Gruppen hinzugefügt werden. Da die Gruppen gefiltert werden sollen wird Security Groups ausgewählt.

Portal1

Nun geht es zur Enterprise Application wo das Filtering für den Gruppen Claim eingestellt wird. Dies ist zu finden unter Single sign-on und dann Attributes & Claims

Portal2

Zusätzlich muss im Manifest der Wert acceptMappedClaims auf true gesetzt werden.

Manifest

Mein Test Account ist Mitglied der Gruppen

  • Z-ServerAdmins (On-Premises Gruppe)
  • AZ-Lic-E5 (On-Premises Gruppe)
  • dyn_Synced_Users (Cloud dynamische Gruppe)

Das JWT Token sieht dann folgendermassen aus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
   aio: "redacted",
   aud: "redacted",
   exp: 1699537062,
   groups: [
      "AZ-Lic-E5"
   ],
   iat: 1699533162,
   iss: "https://login.microsoftonline.com/a5cbb983-25cb-4711-b3ef-**********/v2.0",
   nbf: 1699533162,
   nonce: "redacted",
   rh: "redacted",
   sub: "redacted",
   tid: "redacted",
   uti: "redacted",
   ver: "2.0"
}

Terraform

Meine bevorzugte Art, Konfigurationen in Microsoft Entra ID vorzunehmen, ist mittels Infrastructure as Code. Das Werkzeug meiner Wahl ist dabei Terraform mit dem entsprechenden AzureAD Provider. Die folgenden Ressourcen verwende ich für die Erstellung der App Registration und des Service Principals:

Der Code sieht folgendermassen aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
resource "azuread_application" "GroupsClaimBlogTF" {
  display_name            = "GroupsClaimBlogTF"
  prevent_duplicate_names = true
  sign_in_audience        = "AzureADMyOrg"
  group_membership_claims = ["SecurityGroup"]
  tags = [
    "WindowsAzureActiveDirectoryIntegratedApp",
  ]

  web {
    redirect_uris = [
      "https://cat.irbe.ch/oidc/callback",
    ]
    implicit_grant {
      access_token_issuance_enabled = false
      id_token_issuance_enabled     = true
    }
  }

  api {
    mapped_claims_enabled = true
  }

  optional_claims {
    access_token {
      additional_properties = ["sam_account_name"]
      essential             = false
      name                  = "groups"
    }
    id_token {
      additional_properties = ["sam_account_name"]
      essential             = false
      name                  = "groups"
    }
    saml2_token {
      additional_properties = ["sam_account_name"]
      essential             = false
      name                  = "groups"
    }
  }

  required_resource_access {
    resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
    resource_access {
      id   = "37f7f235-527c-4136-accd-4a02d197296e" # openid
      type = "Scope"
    }
  }
}

resource "azuread_service_principal" "GroupsClaimBlogTF" {
  account_enabled              = true
  application_id               = azuread_application.GroupsClaimBlogTF.application_id
  app_role_assignment_required = false
}

resource "azuread_claims_mapping_policy" "GroupsClaimBlogTF" {
  display_name = "GroupsClaimBlogTF"
  definition = [
    jsonencode(
      {
        ClaimsMappingPolicy = {
          GroupFilter = {
            MatchOn = "samaccountname"
            Type    = "prefix"
            Value   = "AZ-"
          }
          IncludeBasicClaimSet = "true"
          Version              = 1
        }
      }
    ),
  ]
}

resource "azuread_service_principal_claims_mapping_policy_assignment" "GroupsClaimBlogTF" {
  claims_mapping_policy_id = azuread_claims_mapping_policy.GroupsClaimBlogTF.id
  service_principal_id     = azuread_service_principal.GroupsClaimBlogTF.object_id
}

Die wichtigsten Zeilen sind:

  • Zeile 5: Hier wird der Groups Claim mit den Security Gruppen aktiviert
  • Zeile 20-22: Aktivieren der mapped claims (Manifest im Portal)
  • Zeile 24-40: Definition wie die Gruppen in den Claim geschrieben werden
  • Zeile 57-74: Erstellen der Claims Mapping Policy mit dem Gruppen Filter
  • Zeile 76-79: Verknüpfen der Claims Mapping Policy mit dem Service Principal