Okay, I’m going to preface everything in this post by saying what I’m going to be describing is not what you would consider the most secure SharePoint web application in the world. If you are working with sensitive content then this is probably (but not absolutely) NOT the best solution for you. However, if you are totally into Yammer and the fluid collaboration that it provides, but also love the features that SharePoint brings to the table, such as document management, search, etc., then this is something worth considering. In fact I would say that yeah, I may be something of a SAML sympathizer, but this is actually pretty cool. In a nutshell, here’s what I’ve done: I’ve created a web application in SharePoint that uses Yammer “security principals” for authorization. Along the way, I’ve incorporated Azure Active Directory (AAD) and Windows Azure storage, the Yammer API, and a custom claims provider to create the solution. Let me start with a little bit of an overview.
First, let’s talk about the directory. In this scenario, I am NOT using Active Directory on premises or ADFS. This is a huge deal! Because of the capabilities in AAD and Yammer, it was not needed for this solution. Think about all of the onsite management that you no longer have to deal with, operate, patch, and maintain. I can tell you for all for all of the lab setups I use for this blog, it was pretty amazing and satisfying to not have to go through all of the typical pain I endure for something like this – creating one or more Active Directory controllers, building a new test forest, creating one or more ADFS servers, doing all the certificate setup, all the DNS setup, blah, blah, blah. Suffice to say it makes me tired. :-) This was a fantastic alternative. The solution itself looks something like this:
At a high level then it works like this: I have a Windows Azure subscription, and with that subscription is an AAD instance. In this case, my AAD instance is yammo.onmicrosoft.com. I also have an Office 365 tenant, and it also uses the “yammo” namespace, so it is at yammo.sharepoint.com and it is configured to use my yammo AAD instance. That means everything in my Office 365 tenant (if I want to use my cloud version of SharePoint) is secured with principals in my AAD yammo directory. In addition to that, I have a Yammer tenant that came with my Office 365 subscription, so my Yammer tenant also has a name of yammo.onmicrosoft.com. In this case my directories have been synced already, so they are unified. In an environment with an on premises Active Directory, I would do dirsync between it and both my AAD instance as well as Yammer to create that unified directory experience. That’s what the top three clouds in the diagram and their corresponding arrows represent.
Now, inside Yammer I have all of the users from the AAD yammo directory. In addition to that, I have Yammer groups. You can create any number of Yammer groups, and you can add whatever users you want to different Yammer groups (or they can create groups and add themselves). This model of self-deployment of groups and members is why I say that this solution is not for super sensitive content. The reason I say that is because the users and groups from Yammer become the security principals that will be used in SharePoint. There are two important pieces of code that make this happen:
I started out by creating a new Office 365 demo tenant (which includes Yammer). In this part I must admit, I cheated just a little from what you will experience if you don’t work for Microsoft. The “cheat” here is that we have a spot where we can create a demo tenant, but it also creates a number of sites, adds content (both SharePoint and Yammer groups and posts), and adds 40 or 50 demo users. If you’re doing this yourself though that’s okay – you probably just want to create something from scratch anyways so you can put in your own company’s users. Given that you’re going to want to use some Azure pieces to make all of this work by the time you’re done, the easiest thing to do to start with is just create a new Windows Azure subscription. Here’s the bad part – you will have to provide a credit card to do this. Here’s the good part – Windows Azure Active Directory is free with your subscription so it won’t be charged. In fact, now every Windows Azure subscription is associated with an auto created directory in Windows Azure Active Directory. So when you create your subscription you’ll get your AAD instance ready to go as well. Once that’s set up, you can create your trial Office 365 tenant by going here: https://portal.microsoftonline.com/Signup/MainSignUp15.aspx?OfferId=B07A1127-DE83-4a6d-9F85-2C104BDAE8B4&dl=ENTERPRISEPACK.
At this point, I have my Office 365 tenant, AAD instance, and Yammer tenant all created and working. Next, I created a storage account with the Azure subscription I have for this demo so I can store my Xml file in blob storage. Now for this, you WILL get charged. However, the rates for using blob storage (as of the time I wrote this) are $0.095 per GB for storage and $0.01 per 100,000 transactions. So in my case, roughly ten cents a month. Yeah, I can live with that.
Now to hook all the pieces up there are two things in SharePoint I need to be concerned about: authentication and authorization. For authentication, I’m going to use AAD (since that’s where all my accounts are at), and thankfully as I pointed out above, I will NOT be using ADFS and a local AD instance. As I point out in this blog posting – http://blogs.technet.com/b/speschka/archive/2013/05/10/integrating-sharepoint-2013-with-azure-active-directory-part-1-configuration.aspx – it’s not possible to connect SharePoint directly to AAD (read the post if you need the details). So instead I went through the steps described in that posting to create a new ACS namespace with my Windows Azure subscription, and then add my AAD instance as an identity provider to it. I then added my on premises SharePoint farm as a relying party, created a rule group and was pretty much good to go at that point. Again, for complete details on this process just read the blog post above, I just followed that.
Now that authentication is taken care of, I need to think about authorization. As I mentioned at the beginning of this post, I want the authorization for this SharePoint web app to be based on the model used in Yammer. To do that, I need to integrate the Yammer group concept in my authorization rules. The way I do that is with a custom claims provider. My provider is really going to do three big things:
For the claims augmentation piece, I use the same approach described here to figure out “who” the user is: http://blogs.technet.com/b/speschka/archive/2011/03/29/how-to-get-all-user-claims-at-claims-augmentation-time-in-sharepoint-2010.aspx. For my SPTrustedIdentityTokenIssuer I defined email address as the identity claim. I extract that, then do a lookup in the Xml file to get the Yammer ID for that person. Once I have that I make a REST call to Yammer to get the list of groups for the user, and then add each one to their list of role claims. The code is based on my previous post on using Yammer from a .NET client that I linked to above (http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx) and looks like this:
//look for the user
string qry = "Yammer/Entry[@email='" + upn.ToLower() + "']";
xNode = xDoc.SelectSingleNode(qry);
if (xNode != null)
//get the user ID
string ID = xNode.Attributes["id"].Value;
//query Yammer for the person
string response = MakeGetRequest(oneUserUrl.Replace("[:id]", ID), accessToken);
List<YammerGroup> userGroups =
if (userGroups != null)
//enumerate through all the groups and add them as role claims
foreach (YammerGroup yg in userGroups)
claims.Add(new SPClaim(ROLE_CLAIM, yg.Name,
A few things worth pointing out in this code:
In terms of searching data, it’s really pretty straightforward – I just have what is effectively a wildcard XPath search to look for matches, and return PickerEntity instances for each match. The key code in search looks like this:
string qry = "Yammer/Entry[@name[starts-with(.,'" + searchPattern.ToLower() +
"')] or @firstname[starts-with(.,'" + searchPattern.ToLower() +
"')] or @lastname[starts-with(.,'" + searchPattern.ToLower() + "')]]";
XmlDocument xDoc = new XmlDocument();
nl = xDoc.SelectNodes(qry);
So nothing earth-shattering there, just figuring out the XPath took a bit of time but once you have it down it all “just works” pretty well.
Finally resolving names is pretty similar to search, as you would expect. The only real difference is in the version of FillResolve that includes a claim, I know whether I’m looking for a user or group so I end up modifying my XPath slightly; the simplified version of it looks like this:
if (resolveInput.ClaimType == USER_CLAIM)
string qry = "Yammer/Entry[@email='" + resolveInput.Value.ToLower() + "']"; ;
//do stuff with the query here
//look for the group
string qry = "Yammer/Entry[@name='" + resolveInput.Value.ToLower() + "'
After that, as I alluded to above, I simply make my custom claims provider the default provider and I’m good to go. Here’s a screenshot of my claim set, which includes my Yammer groups:
Here’s a couple of screenshots where I’ve added a Yammer group to a SharePoint group to authorize it to the site:
Finally, here’s an example of a user that’s logged in just by virtue of her membership in the Yammer “Operations” group:
That pretty much wraps this up. I’ve included the source code to the custom claims provider I used. You will of course have to modify the account settings to get it to work in your environment. If you’re full on social then sharing this can be an interesting option for integrating SharePoint with your Yammer content.
Hi Steve,Awesome post man, this is really informative in terms of the problem I'm trying to solve. One question though - would it be possible to run some variation of this solution completely in Office 365 - i.e. something that allows an O365 equivalent to a Custom Claims Provider to provide custom authorisation claims to SharePoint 2013 Online?Thanks for the blog, keep the posts coming!
thanks for sharing.