Swisscom SSO Integration

1. SAML Federation

How Does SAML Work?

SAML works by exchanging user information, such as logins, authentication state, identifiers, and other relevant attributes between the identity and service provider. As a result, it simplifies and secures the authentication process as the user only needs to log in once with a single set of authentication credentials. So, when the user tries to access a site, the identity provider passes the SAML authentication to the service provider, who then grants the user entry.

Image alt

Create the Azure Application manually
Step Description
1. Login to Azure portal: https://portal.azure.com/#home
2. Select Azure Active Directory
Image alt
3. Select Enterprise applications from the navigation menu Image alt
4. Select New application Image alt
5. Select Create your own application Image alt
6. put a name for the application, select Non-gallery radio button & create Image alt
7. Select Single sign-on from the navigation menu Image alt
8. Select SAML Image alt
9. Select Upload metadata file
The metadata file can be dowloaded here (right click, save link as…)
Image alt
10. Select Add Image alt
11. Select Save Image alt
12. Select No I’ll test later Image alt

Create the Azure Application with Powershell
  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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# Description: This script creates a service principal with SAML support for m365mySwisscomBusiness
<#
.SYNOPSIS
    This script creates a service principal with SAML support for m365mySwisscomBusiness
.DESCRIPTION
    This script creates a service principal with SAML support for m365mySwisscomBusiness
.PARAMETER spName
    none
.EXAMPLE
    none
#>

# variables
$spName = "m365mySwisscomBusiness" ### change this to your desired name
$idbrokerHost = "idbroker.swisscom.com:443"

try{
    Get-MgContext -ErrorAction Stop
}
catch{
    Connect-MgGraph -Scopes "Application.ReadWrite.All","Directory.ReadWrite.All","Policy.ReadWrite.ApplicationConfiguration","Policy.Read.All"
}
Import-Module Microsoft.Graph.Applications
Import-Module Microsoft.Graph.Identity.SignIns

# check if service principal already exists
$exists = Get-MgServicePrincipal -Filter "DisplayName eq '$spName'"
if($exists){Write-Output "The service principle already exists. Skipping creation."}
else {
	$applicationTemplateId="8adf8e6e-67b2-4cf2-a259-e3dc5476c621" #template for non-gallery apps
	Write-Host "Application Template ID for non-gallery apps: " $applicationTemplateId

	# create service principal
	$params = @{
		DisplayName = $spName
	}
	
    try{
        Invoke-MgInstantiateApplicationTemplate -ApplicationTemplateId $applicationTemplateId -BodyParameter $params -ErrorAction Stop
    }
    catch{
        Write-Host "Error creating the application and service principal object"
        exit
    }

	Write-Host "Application and Service Principal object created, Waiting for a minute before updating them "
	Start-Sleep -Seconds 60
}

# Get SPN Details
try{
    $createSPN = Get-MgServicePrincipal -Filter "DisplayName eq '$spName'" -ErrorAction Stop
    $servicePrincipalId = $createSPN.Id
}
catch{
    Write-Output "Service principal not found"
    exit
}
#Get App registration Details
try{
    $createdAppReg = Get-MgApplication -Filter "DisplayName eq '$spName'" -ErrorAction Stop
    $applicationId = $createdAppReg.Id
}
catch{
    Write-Output "Application registration not found"
    exit
}

Write-Host "Service Principal ID: $servicePrincipalId"
Write-Host "Application ID: $applicationId"

#Update Application Object first, you can choose whatever parameters you want to update
$params = @{
    Web = @{
        RedirectUris = @(
            "https://$idbrokerHost/secure/AuthConsumer/metaAlias/idbroker/sp"
        )
        logoutUrl = "https://$idbrokerHost/secure/scs/jsp/slo.jsp" #This parameter is only available in Application Object and gets updated to SP Object as Logout Url 
    }
}
try{
    Update-MgApplication -ApplicationId $applicationId -BodyParameter $params -ErrorAction Stop
}
catch{
    Write-Output "Error updating the application object"
    exit
}
# Update SamlSingleSignOnSettings such as Relay state
$params = @{
    PreferredSingleSignOnMode = "saml" #The supported values for this parameter are password, saml, notSupported, and oidc.
}
try{
    Update-MgServicePrincipal -ServicePrincipalId $servicePrincipalId -BodyParameter $params -ErrorAction Stop
}
catch{
    Write-Output "Error updating the service principal object"
    exit
}

$params = @{
    IdentifierUris = @(
        "https://$idbrokerHost/secure" 
		# This parameter is is only available in Application Object and gets updated on SP object as Entity ID/Identifier.identifierUris property must use a verified domain of the organization or its subdomain.
		# It's important that no other SAML configuration exists in the tenant with the same IdentifierUri!
    )   
}

try{
    Update-MgApplication -ApplicationId $applicationId -BodyParameter $params -ErrorAction Stop
}
catch{
    Write-Output "Error updating the application object"
}
try{
	Update-MgServicePrincipal -ServicePrincipalId $servicePrincipalId -NotificationEmailAddresses 'Tenant-Swisscom.O365@swisscom.com' -ErrorAction Stop
}
catch{
	Write-Output "Error updating the service principal object"
}

Claim attributes

Claim attributes can be configured in the Azure portal or with Powershell.
If the claim attributes are configured in the azure portal, the attributes can also be edited there. Otherwise, if the claim attributes are configured with Powershell, the attributes can only be edited with Powershell.

Configure the Claim attributes manually
Step Description
1. On Attributes and claims select Edit Image alt
2. Under Required claim select Unique User identifier (Name ID) Image alt
3. Modify Name identifier format to Persistent
Modify Source attribute to user.objectid
Select Save
Image alt
4. Select Add new claim Image alt
Add following claims:
Name
Namespace
Source
Source attribute
country http://schemas.xmlsoap.org/ws/2005/05/identity/claims Attribute user.country
postalcode http://schemas.xmlsoap.org/ws/2005/05/identity/claims Attribute user.postalcode
streetaddress http://schemas.xmlsoap.org/ws/2005/05/identity/claims Attribute user.streetaddress
upn http://schemas.xmlsoap.org/ws/2005/05/identity/claims Attribute user.userprincipalname
userGUID http://schemas.xmlsoap.org/ws/2005/05/identity/claims Attribute user.objectid
mobilephone http://schemas.xmlsoap.org/ws/2005/05/identity/claims Transformation
Step
Description
Attribute Value
Transformation RegexReplace()
Parameter 1 Attribute
Attribute name user.mobilephone
Regex pattern (?'ok'.*?)(?'nok'\(0\)|\[0\]|[^+0-9]?)
Replacement pattern {ok}
Image alt

Configure the claim attributes with Powershell
 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
# Description: This script creates a new claims mapping policy and assigns it to a service principal
<#
.SYNOPSIS
    This script creates a new claims mapping policy and assigns it to a service principal
.DESCRIPTION
    This script creates a new claims mapping policy and assigns it to a service principal
.PARAMETER spName
    none
.EXAMPLE
    none
#>

# Connect to Graph
Connect-MgGraph -Scopes "Policy.ReadWrite.ApplicationConfiguration","Policy.Read.All","ServicePrincipal.ReadWrite.All"
Import-Module Microsoft.Graph.Policies

#Variables
$spName = "m365mySwisscomBusiness" ### change this to your desired/used name
# Get SPN Details
try{
    $createSPN = Get-MgServicePrincipal -Filter "DisplayName eq $spname" -ErrorAction Stop
    $servicePrincipalId = $createSPN.Id
}
catch{
    Write-Output "Service principal not found"
    exit
}

$params = @{
	definition = @(
'{"ClaimsMappingPolicy":{"Version":1,"IncludeBasicClaimSet":"true","claimsSchema":[{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","source":"User","extensionID":null,"id":"givenname","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":null},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","source":"User","extensionID":null,"id":"surname","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":null},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress","source":"User","extensionID":null,"id":"mail","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":null},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name","source":"User","extensionID":null,"id":"userprincipalname","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":null},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier","samlNameIdFormat":"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent","source":"user","extensionID":null,"id":"objectid","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country","source":"user","extensionID":null,"id":"country","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode","source":"user","extensionID":null,"id":"postalcode","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress","source":"user","extensionID":null,"id":"streetaddress","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn","source":"user","extensionID":null,"id":"userprincipalname","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/userGUID","source":"user","extensionID":null,"id":"objectid","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]},{"samlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone","source":"transformation","extensionID":null,"id":"outputClaimfcee9c4e0ddd4335ab626575fbb83504-RegexReplace","value":null,"transformationId":"fcee9c4e0ddd4335ab626575fbb83504-RegexReplace","appliesToUserType":null,"memberOf":null},{"samlClaimType":null,"source":"user","extensionID":null,"id":"mobilephone","value":null,"transformationId":null,"appliesToUserType":null,"memberOf":[]}],"claimsTransformations":[{"transformationMethod":"RegexReplace","id":"fcee9c4e0ddd4335ab626575fbb83504-RegexReplace","inputParameters":[{"id":"regex","value":"(?''ok''.*?)(?''nok''\\(0\\)|\\[0\\]|[^+0-9]?)"},{"id":"replacement","value":"{ok}"}],"parameters":[{"name":"sourceClaim","required":true}],"inputClaims":[{"treatAsMultiValue":false,"claimTypeReferenceSource":"user","claimTypeReferenceId":"mobilephone","transformationClaimType":"sourceClaim","nextTransform":null}],"outputClaims":[{"claimTypeReferenceId":"outputClaimfcee9c4e0ddd4335ab626575fbb83504-RegexReplace","transformationClaimType":"outputClaim","nextTransform":null}]}]}}'
)
	displayName="m365mySwisscomBusinessClaimsPolicy"
}

try{
    $cmp = New-MgPolicyClaimMappingPolicy -BodyParameter $params -ErrorAction Stop
}
catch{
    Write-Output "Error creating the claims mapping policy"
    exit
}
# assign claims mapping policy to service principal
$cmpid = $cmp.Id
$params = @{
	"@odata.id" = "https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies/$cmpid"
}

try{
    New-MgServicePrincipalClaimMappingPolicyByRef -ServicePrincipalId $servicePrincipalId -BodyParameter $params -ErrorAction Stop
}
catch{
    Write-Output "Error assigning the claims mapping policy to the service principal"
    exit
}

# Add a token signing certifcate to the Service Principal
$ex = (get-date).AddYears(3)
$exp = get-date $ex -Format "yyyy-MM-dd"
$expi = $exp + "T00:00:00Z"
$params = @{
	displayName = "CN=$spName"
	endDateTime = [System.DateTime]::Parse($expi)
}
try{
    Add-MgServicePrincipalTokenSigningCertificate -ServicePrincipalId $servicePrincipalId -BodyParameter $params -ErrorAction Stop
}
catch{
    Write-Output "Error adding the token signing certificate to the service principal"
    exit
}

Please contact your Swisscom contact person to configure the counterpart on Swisscom side.

Certificate handling

During the configuration of SAML SSO a three years valid certificate is created. If the certificate become invalid, the certificate must be renewed. The certificate can be renewed with the following procedure

Step Description
1. In the section 3. SAML Certificate select Edit
Select new Certificate
Image alt
2. The new certificate is inactive, select and Make certificate active to activate the certificate
Certificate can only be activated if the counterpart has integrated it (see bellow)
Image alt
3. Inform Swisscom giving the App Federation Metadata Url to integrate the new certificate Image alt
4. To the Notification Email Address entered during the App creation (multiple addresses can be added) an Email is sended 60, 30 and 7 days before the certificate expires Image alt

Swisscom monitor the certificate expiration and will inform you about the integration of the new certificate.

2. SCIM Provisioning

What is SCIM Provisioning?

SCIM supports the exchange of user identity data between an enterprise identity provider (or an identity and access management system) and cloud service providers by providing an easy way to grant users access to cloud-based applications, while keeping sensitive data secure. It alleviates the burden of manual provisioning and gives employees a frictionless user experience.

Please contact your Swisscom contact person to get the Swisscom counterpart configured and receive the needed Token.
If You configure the SCIM provisioning with Powershell, you will need to add the Tenant URL and the Secret Token after the configuration.

Configure SCIM Provisioning manually
Step Description
1. On Provisioning select Get Started Image alt
2. Select Provisioning Mode: Automatic
In Tenant URL and Secret Token, enter the received Information from Swisscom
Select Test Connection if ready.
Image alt
3. In the Mapping section, set group provisioning to no Image alt

Configure the Attribute Mappings as follows:

Azure Active Directory Attribute customappsso Attribute matching precedence
objectid externalid 1
userPrincipalName userName 2
Switch([IsSoftDeleted],, “False”, “True”, “True”, “False”) active
mail emails[type eq “work”].value
givenName name.givenName
surname name,familyname
Join(" “,[givenName],[surname]) name.formatted
streetAddress addresses[type eq “work”].streetAddress
city addresses[type eq “work”].locality
postalCode addresses[type eq “work”].postalCode
Replace([country],,"^(?i)(Schweiz|Switzerland|Suisse|Svizzera)$”,,“CH”,,) addresses[type eq “work”].country
Replace([mobile],,"[()\s-]+",,"",,) phoneNumbers[type eq “mobile”].value
department urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:
departement
User urn:ietf:params:scim:schemas:swisscom:2.0.User:unifiedRoles
manager urn:ietf:params:scim:schemas:swisscom:2.0.User:managerExternalId
Step Description
4. Select Show advanced options and select Edit attribute list for customappsso Image alt
5. Make sure Multi-Value is checked for the unifiedRoles attribute Image alt

Configure SCIM provisioning with Powershell
  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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# Description: This script updates the schema of the SCIM provisioning connector for MySwisscomBusiness
# <#
# .SYNOPSIS
#     This script updates the schema of the SCIM provisioning connector for MySwisscomBusiness
# .DESCRIPTION
#     This script updates the schema of the SCIM provisioning connector for MySwisscomBusiness
# .PARAMETER spName
#     none
# .EXAMPLE
#     none
# #>

# variables
$spName = "m365mySwisscomBusiness" #set this to your ServicePrincipal name

Connect-MgGraph -Scopes "Application.ReadWrite.All","Directory.ReadWrite.All"
Import-Module Microsoft.Graph.Applications

# get the service principal id
try{
    $servicePrincipal = Get-MgServicePrincipal -Filter "DisplayName eq '$spName'"
    $spId = $servicePrincipal.Id
    Write-Output "Service Principal ID: $spId"
}
catch{
    Write-Output "Service principal not found"
    exit
}

# get the provisioning connector template
try{
    $provTemplate = Get-MgServicePrincipalSynchronizationTemplate -ServicePrincipalId $spId -Filter "Default"
    $t_id = $provTemplate.Id
    Write-Output "Provisioning template ID: $t_id"
}
catch{
    Write-Output "Provisioning template not found"
    exit
}

$syncJob = New-MgServicePrincipalSynchronizationJob -ServicePrincipalId $spId -TemplateId $t_id

# modify the schema
Write-Output "Modifying the schema"
$schema = Get-MgServicePrincipalSynchronizationJobSchema -ServicePrincipalId $spId -SynchronizationJobId $syncJob.Id
$schema_json = $schema.ToJsonString() # convert to json string (imortant because of camelCase)

$object = $schema_json | ConvertFrom-Json -Depth 99

$add1 = @'                     
{
    "anchor": false,
    "apiExpressions": [],
    "defaultValue": null,
    "metadata": [],
    "name": "urn:ietf:params:scim:schemas:swisscom:2.0:User:unifiedRoles",
    "referencedObjects": [],
    "required": false,
    "type": "String"
}
'@
$add = $add1 | ConvertFrom-Json
$object.Directories[1].Objects[1].attributes += $add

$add1 = @'
{
    "anchor": false,
    "apiExpressions": [],
    "defaultValue": null,
    "metadata": [],
    "name": "urn:ietf:params:scim:schemas:swisscom:2.0:User:managerExternalId",
    "referencedObjects": [],
    "required": false,
    "type": "String"
}
'@
$add = $add1 | ConvertFrom-Json
$object.Directories[1].Objects[1].attributes += $add

$object.directories[1].objects[1].attributes = `
    $object.directories[1].objects[1].attributes | `
    ?{$_.name -ne 'externalId'}

$add1 = @'
{
    "anchor": false,
    "caseExact": false,
    "defaultValue": null,
    "flowNullValues": false,
    "multivalued": false,
    "mutability": "ReadWrite",
    "name": "externalId",
    "required": true,
    "type": "String",
    "apiExpressions": [],
    "metadata": [],
    "referencedObjects": []
}
'@
$add = $add1 | ConvertFrom-Json
$object.directories[1].objects[1].attributes += $add

$object.directories[1].objects[1].attributes = `
    $object.directories[1].objects[1].attributes | `
    ?{$_.name -ne 'urn:ietf:params:scim:schemas:swisscom:2.0:User:unifiedRoles'}

$add1 = @'
{
    "anchor": false,
    "caseExact": false,
    "defaultValue": null,
    "flowNullValues": false,
    "multivalued": true,
    "mutability": "ReadWrite",
    "name": "urn:ietf:params:scim:schemas:swisscom:2.0:User:unifiedRoles",
    "required": false,
    "type": "String",
    "apiExpressions": [],
    "metadata": [],
    "referencedObjects": []
}
'@
$add = $add1 | ConvertFrom-Json
$object.directories[1].objects[1].attributes += $add


$object.SynchronizationRules.ObjectMappings[1].AttributeMappings = `
    $object.SynchronizationRules.ObjectMappings[1].AttributeMappings | `
    ?{$_.Source.Expression -notmatch "userPrincipalName|displayname|jobTitle|preferredLanguage|physicalDeliveryOfficeName|state|country|mobile"}

$add1 = @'
{
    "exportMissingReferences": false,
    "flowBehavior": "FlowWhenChanged",
    "flowType": "Always",
    "matchingPriority": 2,
    "targetAttributeName": "userName",
    "source": {
        "expression": "[userPrincipalName]",
        "name": "userPrincipalName",
        "parameters": [],
        "type": "Attribute"
    }
}
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add

$object.SynchronizationRules.ObjectMappings[1].AttributeMappings = `
    $object.SynchronizationRules.ObjectMappings[1].AttributeMappings | `
    ?{$_.targetAttributeName -notmatch 'addresses[type eq \"work\"].country'}

$add1 = @'
{
"defaultValue": "",
"exportMissingReferences": false,
"flowBehavior": "FlowWhenChanged",
"flowType": "Always",
"matchingPriority": 0,
"source": {
    "expression": "Replace([country], , \"^(?i)(Schweiz|Switzerland|Suisse|Svizzera)$\", , \"CH\", , )",
    "name": "Replace",
    "parameters": [
    {
        "key": "source",
        "value": {
        "expression": "[country]",
        "name": "country",
        "parameters": [],
        "type": "Attribute"
        }
    },
    {
        "key": "RegularExpression",
        "value": {
        "expression": "\"^(?i)(Schweiz|Switzerland|Suisse|Svizzera)$\"",
        "name": "^(?i)(Schweiz|Switzerland|Suisse|Svizzera)$",
        "parameters": [],
        "type": "Constant"
        }
    },
    {
        "key": "Replacement",
        "value": {
        "expression": "\"CH\"",
        "name": "CH",
        "parameters": [],
        "type": "Constant"
        }
    }
    ],
    "type": "Function"
},
"targetAttributeName": "addresses[type eq \"work\"].country"
}
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add

$object.SynchronizationRules.ObjectMappings[1].AttributeMappings = `
    $object.SynchronizationRules.ObjectMappings[1].AttributeMappings | `
    ?{$_.Source.Expression -notmatch "manager|department|employeeId|mailNickname|facsimileTelephoneNumber|telephoneNumber"}

$object.SynchronizationRules.ObjectMappings[1].AttributeMappings = `
    $object.SynchronizationRules.ObjectMappings[1].AttributeMappings | `
    ?{$_.targetAttributeName -notmatch 'phoneNumbers[type eq \"mobile\"].value'}

$add1 = @'
{
    "defaultValue": "",
    "exportMissingReferences": false,
    "flowBehavior": "FlowWhenChanged",
    "flowType": "Always",
    "matchingPriority": 0,
    "source": {
      "expression": "Replace([mobile], , \"[()\\\\s-]+\", , \"\", , )",
      "name": "Replace",
      "parameters": [
        {
          "key": "source",
          "value": {
            "expression": "[mobile]",
            "name": "mobile",
            "parameters": [],
            "type": "Attribute"
          }
        },
        {
          "key": "RegularExpression",
          "value": {
            "expression": "\"[()\\\\s-]+\"",
            "name": "[()\\s-]+",
            "parameters": [],
            "type": "Constant"
          }
        },
        {
          "key": "Replacement",
          "value": {
            "expression": "\"\"",
            "name": "",
            "parameters": [],
            "type": "Constant"
          }
        }
      ],
      "type": "Function"
    },
    "targetAttributeName": "phoneNumbers[type eq \"mobile\"].value"
  }
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add

$object.SynchronizationRules.ObjectMappings[1].AttributeMappings = `
    $object.SynchronizationRules.ObjectMappings[1].AttributeMappings | `
    ?{$_.targetAttributeName -notmatch 'externalId'}

$add1 = @'
  {
    "defaultValue": null,
    "exportMissingReferences": false,
    "flowBehavior": "FlowWhenChanged",
    "flowType": "Always",
    "matchingPriority": 1,
    "source": {
      "expression": "[objectId]",
      "name": "objectId",
      "parameters": [],
      "type": "Attribute"
    },
    "targetAttributeName": "externalId"
  }
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add

$add1 = @'
{
    "defaultValue": "",
    "exportMissingReferences": false,
    "flowBehavior": "FlowWhenChanged",
    "flowType": "Always",
    "matchingPriority": 0,
    "targetAttributeName": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department",
    "source": {
        "expression": "[department]",
        "name": "department",
        "type": "Attribute",
        "parameters": []
    }
}
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add
$add1 = @'
{
    "defaultValue": "",
    "exportMissingReferences": false,
    "flowBehavior": "FlowWhenChanged",
    "flowType": "Always",
    "matchingPriority": 0,
    "targetAttributeName": "urn:ietf:params:scim:schemas:swisscom:2.0:User:unifiedRoles",
    "source": {
        "expression": "\"User\"",
        "name": "User",
        "type": "Constant",
        "parameters": []
    }
}
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add
$add1 = @'
{
    "defaultValue": "",
    "exportMissingReferences": false,
    "flowBehavior": "FlowWhenChanged",
    "flowType": "Always",
    "matchingPriority": 0,
    "targetAttributeName": "urn:ietf:params:scim:schemas:swisscom:2.0:User:managerExternalId",
    "source": {
        "expression": "[manager]",
        "name": "manager",
        "type": "Attribute",
        "parameters": []
    }
}
'@
$add = $add1 | ConvertFrom-Json
$object.SynchronizationRules.ObjectMappings[1].AttributeMappings  += $add #>

$schema_json = $object | ConvertTo-Json -Depth 99
$uri = "https://graph.microsoft.com/beta/servicePrincipals/$spId/synchronization/jobs/$($syncJob.Id)/schema"

try{
    invoke-GraphRequest -Uri $uri -Method PUT -Body $schema_json -ContentType "application/json"
    Write-Output "Schema updated"
}
catch{
    Write-Output "Error updating schema"
    exit
}

3. Define the users and groups for the Swisscom SSO integration

Which users should be in scope

In order to manage users and their workplaces through the My Swisscom Business portal, these users need to be in the scope of the previously configured SAML Federation and SCIM Provisioning.
As part of the onboarding process, the Entra-ID groups that contain the relevant users to be added, will be defined by the customer together with the Swisscom contact person.

Configure Users & Groups

User will be handled via SAML and provisioned via SCIM only if they are added to the Enterprise Application in Azure AD.

Step Description
6. Select Users and groups from the navigation menu Image alt
7. Select None selected Image alt
8. Select the group or user you want to synchronise and select Select Image alt
9. Select Assign Image alt

In order to test the SAML configuration, sign in to the mySwisscomBusiness center with an account in the customer’s tenant.
You should be redirected to sign in with your Azure account.