Thursday, April 30, 2020

SharePoint Governance complicated, due deviation in permission handling within modern site templates

With the introduction of Modern Sites, Microsoft added an additional layer in the permission handling for SharePoint Online sites: via Office 365 Group (soon to be renamed/branded as 'Microsoft 365 Groups'). Below that new level, one can still authorize within the SharePoint site itself via SharePoint Permission Groups. And to make the story even more confusing: not all 'Modern' sites are equal wrt this new Permission model. In a Modern Communication Site there is no notion / connection to an Office 365 Group.
Comparision Permission Handling + Management within Modern Communication Site vs Modern Team Site
Observations:
  1. In a Modern Teams Site, site authorization is delegated done via Office 365 Group.
    1. The SharePoint Member permission Group has as single member the Office 365 Group ‘Members’
    2. The SharePoint Owners and Visitors permission Groups are both EMPTY
    3. Instead, the ‘Owners’ responsibility is assigned by having the full O365 Group Owners as SCA
  2. In a Modern Communications Site, site authorization is still on named accounts level
    1. The SharePoint Group has as members the named accounts of persons in the role
    2. And only the person that on site provision/create time was identified as ‘Site Owner’ (in SharePoint Admin portal), is assigned SCA
This deviation is intentional / by design from Microsoft, with justification: "Most often, a communication site has a small number of people with permission to author content and many people who only have permission to read content. Team sites use Office 365 Groups for permissions. Communication sites use SharePoint groups." (source: Teams Site vs. Communication Site: Which one should I choose?).
However, in concrete business usage more and more business users prefer the Communications Site for internal collaboration usage above that of Team Site. Most significant motivation being the page layout options, that make better usage of the available screen estate. And this practical usage results in a governance flaw, as the permission handling on a "team collaboration site" created via Communications Site deviates from that within a Teams site; and the typical business user has no understanding for this.
I'm not alone in my misunderstanding, a good post on this topic is How broken are Office 365 SharePoint permissions?.

Friday, April 10, 2020

Tip: How-To determine whether guest email already in-usage in your Azure AD tenant

Invitation of a new Azure AD B2B guest is blocked in case the identifying guest email is already present in the inviting Azure AD. A typical situation in which this occurs is that the intended guest is already present as regular Member account, and has to that the external email associated. To avoid the error on invoking Invite Api and instead send an informed response to the requestor, the B2B invitation automation can check first on any occurence of the external email.
The codeline for that is:
Get-AzureADUser -Filter "proxyAddresses/any(c:c eq 'smtp:external.user@externalComp.com')" | Select UserType, UserState

Needed Api Permission for Service Principal to invoke Get-AzureADUser

This week I extended our custom B2B invitation handling build as Azure Automation Runbook to check upfront whether guest account is not present yet. The way to check is by quering for potential presence of requested Guest account via the UPN:
if ($guestAccRequests.length -gt 0) {
    # Get the Service Principal connection details for the Connection name
    $servicePrincipalConnection = Get-AutomationConnection -Name $servicePrincipalConnName   

    # Logging in to Azure AD with Service Principal
    Connect-AzureAD -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint

    ...

            # 1. Check whether already present as guest account
            $guestUpn = ConvertExternalEmailToUpn -guestEmail $guestEmail
            $existingAccount =  Get-AzureADUser -Filter "userPrincipalName eq '$guestUpn'" | Select UserType, UserState
            if ($existingAccount) {
                ... 
            if ($continueToInvite) {
                try {
                    $inviteResult = New-AzureADMSInvitation -InvitedUserEmailAddress $guestEmail -InvitedUserDisplayName $guestDisplayNameWithOrg -InvitedUserMessageInfo $messageInfo -SendInvitationMessage $False -InviteRedirectUrl "http://www.wvstrien.com" -ErrorAction Stop
                    $inviteurl = $inviteResult.InviteRedeemUrl

The PowerShell coding part was quickly up-and-running. More time-consuming was identifying the proper Api Permission to grant to the Service Connection that connects into Azure AD. We already assigned the 'User.Invite.All' Api Permission from the Microsoft Graph Api, and one would expect that also permission for Get-AzureADUser is within the Graph Api permissions. However, granting the likely permissions 'User.Read.All', 'Directory.Read.All', 'Domain.Read.All'; none of these authorizes the Service Connection.
The information provided by Microsoft in identifying the needed Api Permission is not very good, or at least not easy to find. The StackOverflow post Graph API - Insufficient privileges to complete the operation put me on the right track. Turns out that for this cmdlet you still need to assign permission from the deprecated Azure Active Directory Api.