Monday, February 12, 2018

PowerShell to assess the external access authorization per site

As clarified in previous post, Azure AD Access Reviews capability although promising qua concept, is in it's current implementation yet unfit to assess the external access per site. But luckily we have PowerShell, which enables us per site, determine the collection of guest authorizations and ask site owner to review + re-confirm the authorizations. Crucial is to provide insight and awareness; who all has access authorization to my business site, and as site / business owner I still are ok with each indivdual guest authorization? For those not / no longer; explicit revoke, for good secure housekeeping in your external shared site.
PowerShell script to assess the external authorization per site in the tenant:

Access Review of guest users into the SharePoint tenant

#Connection to SharePoint Online
try {
    Connect-SPOService -Url $SPOAdminSiteUrl -ErrorAction Stop
} catch {

$externalUsersInfoDictionary= @{}

$externalSharedSites = Get-SPOSite | Where-Object {$_.SharingCapability -eq "ExistingExternalUserSharingOnly"}
foreach ($site in $externalSharedSites)
    $externalUsersInfoCollection= @()

    $position = 0
    $page = 0
    $pageSize = 50
    while ($position -eq $page * $pageSize) {
        foreach ($externalUser in Get-SPOExternalUser -Position ($page * $pageSize) -PageSize $pageSize -SiteUrl $site.Url | Select DisplayName,Email,WhenCreated) {
            if (!$externalUsersInfoDictionary.ContainsKey($externalUser.Email)) {
                $externalUsersInfoDictionary[$externalUser.Email] = @()
            $externalUsersInfo = new-object psobject 
            $externalUsersInfo | add-member noteproperty -name "Site Url" -value $site.Url
            $externalUsersInfo | add-member noteproperty -name "Email" -value $externalUser.Email
            $externalUsersInfo | add-member noteproperty -name "DisplayName" -value $externalUser.DisplayName
            $externalUsersInfo | add-member noteproperty -name "WhenCreated" -value $externalUser.WhenCreated
            $externalUsersInfo | add-member noteproperty -name "Preserve Access?" -value "Yes"


    if ($externalUsersInfoCollection.Count -ne 0) {
        $exportFile = "External Access Review (" + $site.Url.SubString($site.Url.LastIndexOf("/")+ 1) + ")- " +  $(get-date -f yyyy-MM-dd) + ".csv"
        $externalUsersInfoCollection |  Export-Csv $exportFile -NoTypeInformation

# Export matrix overview: per user, in which of the external sites granted access
$externalUsersInfoCollection= @()

$externalUsersInfoDictionary.Keys | ForEach-Object {
    $externalUsersInfo = new-object psobject
    $externalUsersInfo | add-member noteproperty -name "User Email" -value $_

    foreach ($site in $externalSharedSites) {
        if ($externalUsersInfoDictionary[$_].Contains($site.Url)) {
            $externalUsersInfo | add-member noteproperty -name $site.Url -value "X"           
        } else {
            $externalUsersInfo | add-member noteproperty -name $site.Url -value ""             


$exportFile = "External Access Review user X site - " +  $(get-date -f yyyy-MM-dd) + ".csv"
$externalUsersInfoCollection |  Export-Csv $exportFile -NoTypeInformation


Friday, February 9, 2018

Azure AD Access Review yet useless for SharePoint External Sharing

In order to remain compliant with company-internal information security policies, it is essential to regular assess the authorizations of external guests to the external shared SharePoint Online Sites. At Ignite 2017 Microsoft announced the Azure AD capability Access Reviews. Initial I was rather enthusiastic about the concept of 'Manage guest access with Azure AD access reviews', but after some evaluation I make the personal conclusion that in the current implementation stage it is pretty useless to assess SharePoint external access.
In the current setup you can select between 2 modes to assess:
  1. Assess on Azure AD Group Membership
  2. Assess on access to an Office 365 application
However, both are useless for assessing the access to one or more specific SharePoint Online sites. In Azure AD B2B based external sharing, externals are invited to a SharePoint site via their Azure AD guest account. In this model, the guests access is neither via a specific Azure AD Group, nor are they on Azure AD level specific authorization to SharePoint Online as application. Their authorization to SharePoint as application is implicit, resulting from their invitation to one or more specific sites.
I played a bit with the 'access review' (note: the documentation on it is very scarce, and incomplete):
  • In the review mode on 'O365 SharePoint Online as application'; I get no results at all.

  • In the review mode on 'Group Membership' I selected the dynamic group that includes all guest accounts. With this review mode I do get results to review their access. But the value is limited to gain insight on last logon per guest account. You can then as reviewer make a decision to Approve or Deny the continued group membership. But in reality this review decision cannot be effectuated: the group membership is dynamic, based on condition; not on concrete addition to the group.

    Access Review on (dynamic) Azure AD Group membership Applied Access Review decision on (dynamic) Azure AD Group membership

My thoughts shared with product team + community

I reported my 'negative' evaluation as feedback to a contact in the Azure AD productgroup: "I question how it would be applied: removing the 'refused' accounts from the Dynamic Group does not make sense; they should be blocked or removed from Azure AD to block access. Also, as a site owner only wants to take responsibility for access to his/her site, the access decision application should be applied there. Not on tenant level."

His response: "I think you have some interesting use cases. As the product is still in preview, documentation is limited. I will discuss your use cases with my colleagues in Redmond responsible for Access Reviews."

In addition, I also submitted a SharePoint uservoice idea: Azure AD access review on level of single (shared) site collection

Nice post on the topic, including 'manual': Checking Office 365 Group Membership with Azure AD Access Reviews

Saturday, February 3, 2018

(Risky) Approach to invoke SharePoint Online API on whatever site from external automation client

For an external automation client to access SharePoint Online via the API, same holds as for you as human visitor: it first needs to authenticate itself against the accessed SharePoint Online tenant, and next it must have the needed authorization in the specific accessed SharePoint content entity (site collection, site or list). This can be achieved by registrating an Add-In, and assign it the needed permissions. Then that Add-In can be used as authentication + authorization endpoint for the external client. Post Access SharePoint Online using Postman includes a good reference of the steps that you should automate in the external client. Drawback of the described approach is that it is on scope of individual site collection or even site. The Add-In registration is not utilizable as generic gateway to all sites in the SharePoint Online tenat.
To extend the scope to full tenant, the Add-In Only permissions must be requested on the 'tenant' level'. This can only be done by a tenant administrator; and must be done via the tenant-admin site (How to provide add-in app only tenant administrative permissions in SharePoint Online). But be very careful and considerated before going this approach: the implication is that whoever knows the client id and secret of the registrated Add-In, is now enabled to access via an external client data from whatever site in your tenant. Making site-specific permission management pretty useless / even a laughter. But your information security will certainly not consider it a good + acceptable joke...
With Add-In Only permission on 'tenant' level; external client that knows the Add-In's client id + secret can request an accesstoken; and then use that same single token to access whatever site in the SharePoint tenant:

Friday, January 26, 2018

AADConnect can block Azure AD B2B invitation

One of the approaches to work with externals of a business partner organization is to administrate full accounts for them in your on-prem Active Directory. With the arrival of Azure AD B2B capability, it is no longer required to have full accounts including password management for the externals; they can now be invited as 'guest' via the concept of "bring your own identity". However, for organizations that have a legacy of earlier external collaboration approach (note: does not necessarily have to be SharePoint based; it can also be for instance via SAP Portal, on-premisse webapplications, ....), an account provisioning conflict may arise.
Situation sketch:
  • Externals of business partner are added as full accounts to your on-prem Active Directory
  • Administrate in AD their own external company email as primary email address; as that is the mailbox they will typically use and monitor
  • Utilize AADConnect to sync on-prem AD accounts to Office 365 / Azure AD
  • Invite externals of same business partner as guest for Azure AD B2B; with their own external company email as identifier...
The result of this situation is error: BadRequest; The object is either sourced from an on prem directory or is undergoing migration
In general, Microsoft states that "duplicate identifying attributes are not allowed in a tenant with AAD Connect" (see Troubleshooting Errors during synchronization). The primary email-address is one of these: "For the proxyAddresses attribute only the value with SMTP:, that is the primary email address, is used for the evaluation". (source)

Saturday, January 13, 2018

Approach to a more trusted Azure AD B2B invite handling

Simple approach to invite guest users is via the Azure AD admin portal. Disadvantage is that you have no control at all over the invite email that is being sent:
  • It comes from the mail origin instead of the inviting company
  • It is sent on behalf of the account of Azure AD Admin (or other admin account that possesses the 'Guest inviter role'), iso an account of the actual business user at the inviting company
  • The mail is in a standard format, without branded to the inviting company
  • The mail includes a suspicious looking "Get Started" button
  • The mail includes a "Click here to unsubscribe" link, which again looks suspicious as the receiver never subscribed to invites from
This results that - and in my opinion, in current days very understandable and justified - invited persons may not trust the invite email, suspect it is a phishing mail.
My first approach to improve on this is to invite the guest users via 'New-AzureADMSInvitation' PowerShell cmdlet, and make up the email text itself. However, you still have very little control over the mail setup: the only thing you can do it to specify the invite message. And this is limited to plain text, you cannot make a rich format including company logo. All of the above drawbacks still hold.
On questioning to Microsoft, their advice for now is to use the Azure AD B2B Invite API to make a company-customized invite experience. But this requires an Azure App to be designed, developed + deployed. Although sure would be fun to do, current I lack the time for that.
Therefore I decide for an approach in the middle. Still use the PowerShell cmdlet to create the guest accounts. But instead of direct sending the invite email, I let the PowerShell script make up a 'mailto:' specification that includes the guest user redeem-url. These specifications are exported per invited user via a .csv file. Next the Azure AD admin sends the .csv file to the responsible business user of the inviting company. And he or she can then direct from the received .csv file with the 'mailto:'specifications make up an invite mail in their own email outbox, make some final changes and additions (e.g. add personal mail signature; including items like company logo, contact details of the business user, ...); and next send out the mail. The invited guest then receives the mail from the mail domain of the inviting company, and of a person (s)he likely already is in contact with. As extra bonus I apply Office 365 email encryption, to give the invited user the trust that only he or she is able to read the invite mail.

Friday, December 29, 2017

How-To: enable Azure Active Directory for Powershell on Windows 7 system

The AzureAD PowerShell module contains multiple convenient cmdlet's to manage an Azure AD tenant, a.o. to invite external accounts (e.g.: Automatically Provision Azure AD B2B Guest Accounts). When you try to use the AzureAD PowerShell module on a Windows 7 system, you may run into issue: The specified module 'AzureAD' was not loaded because no valid module file was found in any module directory
If so, the solution is import the module file via it's exacte filepath (inspiration for this: Azure RM PowerShell Module / Other Installation methods)
And the AzureAD cmdlets can be succesful utilized:

SharePoint Online External Sharing: blacklisting overrules whitelisting

Via the configuration capabilities of Office 365 SharePoint Online External Sharing, the SharePoint administrator has full control to both allow and disallow specific organizations by domain. Be aware that the 'disallow' configuration has higher prevalence then the 'allow': if you run into a situation that you cannot invite a guest account of whitelisted domain, then check your blacklisting (on tenant plus site collection level) whether the organization domain is also listed there.
Result: blacklisting overrules the whitelisting allowance