Wednesday, March 13, 2019

Get login name of special group “Everyone except external users” programmatically in Sharepoint

In Sharepoint Online you may assign permissions to all employees of your organization using special group “Everyone except external users”. In order to add permissions to this group programmatically we need to know login name of the appropriate object in Sharepoint object model. In this article I will show how to get login name of this special group programmatically.

The main difficulty is that login name of “Everyone except external users” group is different per tenant. But the good thing is that it is built using known rule:

c:0-.f|rolemanager|spo-grid-all-users/{realm}

where instead of {realm} placeholder you need to use realm for your tenant. We can get realm using TokenHelper.GetRealmFromTargetUrl() method. So code will look like this:

protected virtual string GetEveryoneExceptExternalsLoginName(string siteUrl)
{
 var realm = TokenHelper.GetRealmFromTargetUrl(new Uri(siteUrl));
 return string.Format("c:0-.f|rolemanager|spo-grid-all-users/{0}", realm);
}

public static string GetRealmFromTargetUrl(Uri targetApplicationUri)
{
 #if ONPREMISES
 if (targetApplicationUri.Scheme.ToLower() == "https")
  ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
 #endif

 WebRequest request = WebRequest.Create(targetApplicationUri + "/_vti_bin/client.svc");
 request.Headers.Add("Authorization: Bearer ");

 try
 {
  using (request.GetResponse())
  {
  }
 }
 catch (WebException e)
 {
  if (e.Response == null)
  {
   return null;
  }

  string bearerResponseHeader = e.Response.Headers["WWW-Authenticate"];
  if (string.IsNullOrEmpty(bearerResponseHeader))
  {
   return null;
  }

  const string bearer = "Bearer realm=\"";
  int bearerIndex = bearerResponseHeader.IndexOf(bearer, StringComparison.Ordinal);
  if (bearerIndex < 0)
  {
   return null;
  }

  int realmIndex = bearerIndex + bearer.Length;

  if (bearerResponseHeader.Length >= realmIndex + 36)
  {
   string targetRealm = bearerResponseHeader.Substring(realmIndex, 36);

   Guid realmGuid;

   if (Guid.TryParse(targetRealm, out realmGuid))
   {
    return targetRealm;
   }
  }
 }
 return null;
}

After that you will be able to grant permissions to “Everyone except external users” programmatically.

Update 2020-02-10: method described here may not work for old tenants. See this article for workaround for old tenants: Resolve “Everyone except external users” group on old tenants

Wednesday, March 6, 2019

Strange behavior of Sharepoint Online when specify different users as primary site collection administrator

When you create new site collection (doesn’t matter modern or classic) using Tenant.CreateSite() method you need to specify primary site collection administrator in SiteCreationProperties.Owner property. So if you would check site collection administrators of the newly created site you would expect to see specified user there. However it is not always the case. Sometimes Sharepoint really shows specified user there:

But sometimes instead of actual user account there will be Company Administrator – special user which covers all users in the directory with Global Administrator rights (see e.g. Special SharePoint Groups):

It happens regardless of specified user directory role: it may have Global Administrator role and may not have it:

And even more – if user have more directory roles there may be both Company Administrator and Sharepoint Service Administrator:

I.e. looks like Sharepoint get’s user’s roles and assigns permissions to these roles instead of actual user account. But again – for some user accounts it just adds actual user account to Site collection administrators. Logic behind this behavior is not yet clear so if you have any thoughts on that please share it in comments.