Getting an Azure Access Token for a Web Application Entirely in Code

UPDATE 1/13/2016:  The Azure and/or ADAL teams have made an unannounced change to purposely break this functionality.  This is clearly a problem for those providing and provisioning SaaS offerings in a variety of scenarios, but they have chosen to make this change without input.  If you would like to provide your feedback on this you can contact the responsible Program Manager directly at vbertocci@microsoft.com.

I generally find using Azure Active Directory for securing my resources to be a joyous thing, but the simplicity of use is pretty much vastly overstated by the marketing folks at Microsoft. I’ve used it quite a bit and yet still find myself simultaneously in seemingly uncharted and undocumented waters. As is unfortunately a little too common, I found myself in a spot where I really thought I was stuck the other day trying to get an access token for a specific user to a specific resource. I don’t think the scenario is really that uncommon so thought best to share.

The gist of this scenario is, I have an application defined in Azure Active Directory. It’s configured as a web application. That means that you *must* provide the application’s client secret when you request an access token to that application. The “standard” way to do this is to request an authorization code, and then you use the authorization code to get an access token. Okay, fundamentally I can do that and it won’t kill me.   The problem however is the really bad assumption, in my opinion, that you are going to have a human at the wheel, sitting at a browser and driving this thing around. That’s exactly how the process works in this case – users gets redirected to obtain the authorization code, they sign into Azure AD, they consent to whatever permissions the application is configured to use, and then the browser is redirected back again. You end up in some server side code plucking out authorization code from the query string and then using the Active Directory Authentication Library (ADAL) you call it’s AcquireTokenByAuthorizationCode to get your access token.

Okay that will work…as long as the human is sitting there driving. So what happens when the human is absent, and you want to get an access token for that person? Well, one of the ways you can get an access token from an application that is defined as a Native Application is to stick a username and password into a UserCredential and call the AcquireToken method in ADAL. Now I’m not suggesting that everyone should be storing usernames and passwords anywhere (and in fact in most cases I specifically go out of my way to avoid it). However there are certain cases, like where you are writing code that always runs as a service account, or you’re doing some scripting of new users and adding them to applications or application features, etc. Yeah, it’s a legit scenario (otherwise ADAL wouldn’t support this to begin with).

The problem is that while you can take that approach with a Native Application, it won’t work for a Web Application. A Web Application also requires the application’s client secret as explained above. Unfortunately there isn’t an overload in ADAL that supports both the UserCredential and client secret. I thought I was in a no win situation here when I came across this, but managed to work my way out of it so I thought I would share the approach I used. I do end up with an access token when I’m done, and I get it by providing a username, and a password, AND a client secret. I just don’t have to do the whole “drive this through a browser” thing to make it work.

The solution to this problem is that you’ll end up having to go outside of ADAL to get your access token. Instead you’ll need to make a post directly to the Graph API authorization endpoint to ask for your access token. When you do that, you can include whatever form values you want when you do your post. That ends up being the way to get your access token. Here’s a little code to illustrate, and then I’ll follow with some explanation.

//create the collection of values to send to the POST

List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>();

vals.Add(new KeyValuePair<string, string>(“grant_type”, “password”));

vals.Add(new KeyValuePair<string, string>(“scope”, “openid”));

vals.Add(new KeyValuePair<string, string>(“resource”, ResourceUri));

vals.Add(new KeyValuePair<string, string>(“client_id”, ClientId));

vals.Add(new KeyValuePair<string, string>(“client_secret”, ClientSecret));

vals.Add(new KeyValuePair<string, string>(“username”, Username));

vals.Add(new KeyValuePair<string, string>(“password”, Password));

//create the post Url

//https://login.windows.net/8864cb2f-031a-5c22-fa2d-13d1cf4cb7dd/oauth2/token

string url = string.Format(“https://login.windows.net/{0}/oauth2/token “, TenantId);

//make the request

HttpClient hc = new HttpClient();

//form encode the data we’re going to POST

HttpContent content = new FormUrlEncodedContent(vals);

//plug in the post body

HttpResponseMessage hrm = hc.PostAsync(url, content).Result;

if (hrm.IsSuccessStatusCode)

{

//get the stream

Stream data = await hrm.Content.ReadAsStreamAsync();

}

So as you can see I’m creating a set of form values to send to the oauth endpoint, and I’m doing my post, and if it is successful, I’m reading the contents out into a stream in this case. The rest of the code that is less interesting is where I take that stream and serialize it into a class so I can easily refer to the access token, the refresh token, the expiration, etc. The key to making this work is to understand the various form key/value pairs. This is the “seemingly undocumented” piece I was describing above. You’ll find some documentation on MSDN about this at https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx. Since they only want to focus on the authorization code flow there there, you won’t find a complete listing of all the possible form post keys and possible values of each. Booo!!! Since I don’t have that, I’ll just document for you from my working code above, what those form values represent:

Key Value
resource The resource you are trying to obtain an access token for. If you are trying to access another Azure AD application, then you would use the APP ID URI here. If you are accessing something like Exchange Online, you would use it’s resource URI (which is https://outlook.office365.com/ for those of you following at home).
client_id This is the Client ID of the Azure application you are getting the access token for.
client_secret This is the Client Secret of the Azure application you are getting the access token for.
username This is the name of the Azure AD user for whom you are getting the access token.
password This is the password for the Azure AD user for whom you are getting the access token.
TenantId This is the ID (i.e. GUID) of the Azure Active Directory instance in which the Azure AD user is located.

Calling directly to the token endpoint in the Graph API to obtain an access token is pretty powerful really. I really don’t like resorting to that and only have this time because ADAL just didn’t cover my use case. It would be, dare I say, “idyllic” if someone would actually document all of the values you can throw up there (and/or make it easy to find, because I could not do that despite the indexing power of Bing). Meanwhile, this ends up being a nice way to get the token when you find yourself in this scenario.

Do You Need An Account In Azure Active Directory if Using ADFS?

Today’s topic is a little spin on a question that seems to be coming up more frequently, specifically when folks are using a combination of Azure Active Directory and ADFS. That question is, if I’m using ADFS do I really need to have an account in an Azure Active Directory (AAD) tenant? Well, of course, the answer is it depends.

If all you are going to use AAD for is as some kind of application registry, but all of your applications are hosted elsewhere, you really don’t need an account in AAD. You can just add your domain to the list of domains in your Azure subscription, set up the domain as a federated domain, and configure the ADFS endpoint where folks should get redirected to in order to authenticate.

Where this scenario breaks is if you are securing your applications with AAD. For example, in your AAD tenant you go to the Applications tab, you give it some configuration information, and you add one or more permissions that your application is going to need. In this case, AAD is being used to secure access to the application, and so at a minimum you have to ask for at least the right to log in and read the profile information – this is needed for AAD to be able to send your set of claims off to your application after you authenticate. In that case, there is going to be a consent process that users go through. The first time they log into the application, Azure will present a page to them that describes all of the permissions the application is asking for and the user has to consent to allow the application to have access in order to continue. This is “the consent process” (as simply explained by Steve).

In this case, if there is not a corresponding user object in AAD, the user ends up getting an error page after authenticating into AAD. The error message, which is in the fine print near the bottom of the page, will say something like hey, this external user has to be added to the directory. What this really means is hey, I need to be able to track if this user consents to letting this app get at his information, and if I can’t track his consent then we’re going to have to stop here. The way to fix this issue in this case is just to set up directory synchronization. That will populate AAD with all of the users and groups in the on premise AD, even though users will not be using AAD to authenticate. Once you do that, your error will go away and the whole end to end process will work for you.

So the net – if you are trying to use AAD to secure your application – you need users in AAD too. If not, you don’t need to populate the directory. In most cases people will end up wanting to secure apps in AAD so DirSync will be needed. If you end up going that way, the Azure AD Connect tool is used to do the synchronization for you: https://msdn.microsoft.com/en-us/library/azure/dn832695.aspx.

How to Fix the OpenId Access Denied When User Won’t Grant Rights at Login

Okay, so the title may not be the clearest thing ever here today, but it’s tough to do in just a few words, so let me explain the scenario a little more fully.  Suppose you create an ASP.NET application and you configure it to be secured by Azure Active Directory.  When you do that you have to configure your right to request Azure AD permissions to sign-on and read the user’s profile.  This is the minimum right needed to have someone use Azure AD to login to your application, so naturally everyone will agree to this, right??  🙂

Well, as you can probably guess from this post, not always.  So what happens when a user sees that consent page from Azure AD at login time and then decides no, I don’t want to let you sign me in, so they hit cancel?  Well the out of the box behavior is that you get an unhandled exception in your ASP.NET application.  This of course brings up the awesome yellow screen of indecipherable death.  If you’re running it locally you can at least see the error message, which looks something like this:

So, how to fix right?  Well try as I might, the Bing Gods were not with me this day when I decided to try and figure this out. In fact for future search engine happiness, the error is access_denied and comes from Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolException. With a little trial and error I was able to figure out the way to fix this issue so wanted to document here for those of you stuck in a similar boat.

What you need to do is go back to your Startup.Auth.cs file.  You should have something configured in there for OpenIdConnect that starts out something like this:

app.UseOpenIdConnectAuthentication(

new OpenIdConnectAuthenticationOptions

What you want to do is configure one of the NotificationOptions, which you configure inside the OpenIdConnectAuthenticationOptions like this:

Notifications = new OpenIdConnectAuthenticationNotifications()

{

To deal with the scenario of someone canceling out of granting permissions during login you need to add a handler for the AuthenticationFailed notification.  Here’s what mine looks like:

AuthenticationFailed = (context) =>

{

//this section added to handle scenario where user logs in, but cancels consenting to rights to read directory profile

string appBaseUrl = context.Request.Scheme + “://” + context.Request.Host + context.Request.PathBase;

context.ProtocolMessage.RedirectUri = appBaseUrl + “/”;

//this is where the magic happens

context.HandleResponse();

context.Response.Redirect(context.ProtocolMessage.RedirectUri);

return Task.FromResult(0);

}

Essentially what’s happening there is if someone cancels it hits this notification handler.  I just figure out what the root Url of my application is, which I’ve pushed into the context.ProtocolMessage.RedirectUri property (which I actually liberally stole from my handler for RedirectToIdentityProvider).  Then I redirect somewhere else in my site that doesn’t require authentication, which in this case is my home page.

That’s it.  I don’t really see this covered in any of the sample code locations I usually hit up for Azure AD code so thought you might find it useful.

 

Using Roles in Azure Applications

I was spending some time today (finally) looking at how to get what I really consider the baseline functionality of claims – apps, users and roles – all working together with one of my Azure AD apps.  Azure has been pushing out pieces of an RBAC-based infrastructure for a few months now, and I wanted to see about integrating my old friend Roles into my app.  Alex Simmons posted a great overview and introduction to the concept here:  http://blogs.technet.com/b/ad/archive/2014/12/18/azure-active-directory-now-with-group-claims-and-application-roles.aspx.  As I began rolling out some code and testing some different scenarios, I wanted to capture a few notes about this process for those of you heading down this path as well:

  • It’s important to distinguish and understand that you can use two different types of “roles” – the Azure AD groups you belong to, as well as custom application roles you create for your application.  Technically you can also mix and match them, by adding AD groups to an application role, but that’s a little outside the scope of where I want to take this.
  • One of the big differences in using Azure AD groups instead of an application role is that your application has to also get consent for rights to Read the Directory.
  • Dushyant Gill put together a really excellent blog post on adding application roles to your Azure AD app here:  http://www.dushyantgill.com/blog/2014/12/10/roles-based-access-control-in-cloud-applications-using-azure-ad/.  You really should take a look at that before you start building this yourself.
  • One thing that is NOT obvious at all – if you only add one role, then you won’t get a role picker when you assign users to the role in your app.  Instead when you click on the Assign User link it will just “do it” without any other dialog.  The behavior is a little odd because you’re not really sure what happened when you first do it.  If you create more than one app role then you do get the picker to select which role.
  • You can only assign a person to one role unless you have Azure AD Premium.
  • You really MUST make the change to your Startup.Auth.cs file to configure what claim type should be considered the “Role” claim type.  If you don’t do this, none of the standard role checks work because the claim value is not contained in a standard role type – the type it uses is either “groups” (if using Azure AD groups) or “roles” (if using app roles).  The exact syntax for this change is at the end of Dushyant’s blog mentioned above, in the TokenValidationParameters code snippet (specifically the RoleClaimType attribute).
  • Once you have this all integrated you can use all my favorite role checking and demand options, like:
    • [PrincipalPermission(SecurityAction.Demand, Role = “yourRoleName”)]
    • [Authorize(Roles = “yourRoleName”)]
    • if (ClaimsPrincipal.Current.IsInRole(“yourRoleName”)) { //do something }

It’s good stuff, try it out!  🙂

Configuring Forms Based Authentication in SharePoint 2010

Hopefully folks are starting to get some use out of the multitude of SharePoint 2010 postings I’ve been tossing up here.  This is a new one that I was a little hesitant to put together…given my history in SharePoint 2007 I don’t want to become typecast but…in this post I’ll give a quick walk through on creating a forms based authentication site in SharePoint 2010.

For those of you who’ve read my various blogs (http://blogs.msdn.com/sharepoint/archive/2006/08/16/702010.aspx being the most popular) and three-part series on FBA for SharePoint 2010 (part 1 starts here: http://msdn.microsoft.com/en-us/library/bb975136.aspx), most of this should look pretty familiar.  We’re going to follow a very similar process to what we did in SharePoint 2007, with a couple of twists.  At a high level, we’re going to:

1.       Create a new web application

2.       Configure support for FBA in central admin, our new web app, and a new thing in SharePoint 2010 called the STS web service

3.       Add a User Policy to our web app that will grant an FBA user rights to the site

4.       Login to the site and start using it!

For our example we’ll use the LDAP provider that ships in SharePoint 2010 for our directory.  Let’s look at each of these steps in more detail now.

Step 1 – Create a New Web Application

Start by going to the Central Administration web site.  Click on Manage Web Applications, then click on the New button in the ribbon to create a new web application.  In the new web application dialog we’re going to select the following settings:

·         Authentication:  Claims Based Authentication

·         Identity Providers

o   Check the Enable Windows Authentication box or you won’t be able to crawl the site

o   Check the Enable ASP.NET Membership and Role Provider checkbox

§  In the Membership provider name edit box, type LdapMember

§  In the Role provider name edit boxy, type LdapRole

·         I won’t cover all of the other sections in the new web app dialog because they aren’t specific to using FBA, so just fill them in with whatever values are appropriate for your implementation

When you’re all done click the OK button to create the new web application.  Now that the web app is created, I Highly Recommend That You Create A New Site Collection In It Now!  I’ll move forward assuming you have done as I’ve suggested.  Now…okay – step 1 is done, let’s keep moving.

Step 2 – Configure FBA Support

This step is where we go through that same process as 2007, where we need to add some entries to the web.config file for our web application, and we need to do it on each web front end in the farm.  The basic chunk of Xml we’re going to work with for the LDAP provider looks like this; I’ve highlighted the parts in yellow that you will want to change for your implementation:

<membership>

      <providers>

        <add name=”LdapMember”

             type=”Microsoft.Office.Server.Security.LdapMembershipProvider, Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”

             server=”stevedc.steve.local

             port=”389″

             useSSL=”false”

             userDNAttribute=”distinguishedName”

             userNameAttribute=”sAMAccountName”

             userContainer=”CN=Users,DC=steve,DC=local

             userObjectClass=”person”

             userFilter=”(ObjectClass=person)”

             scope=”Subtree”

             otherRequiredUserAttributes=”sn,givenname,cn” />

      </providers>

    </membership>

    <roleManager enabled=”true” defaultProvider=”AspNetWindowsTokenRoleProvider” >

      <providers>

        <add name=”LdapRole”   

             type=”Microsoft.Office.Server.Security.LdapRoleProvider, Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”

             server=”stevedc.steve.local

             port=”389″

             useSSL=”false”

             groupContainer=”CN=Users,DC=steve,DC=local

             groupNameAttribute=”cn”

             groupNameAlternateSearchAttribute=”samAccountName”

             groupMemberAttribute=”member”

             userNameAttribute=”sAMAccountName”

             dnAttribute=”distinguishedName”

             groupFilter=”(ObjectClass=group)”

             userFilter=”(ObjectClass=person)”

             scope=”Subtree” />

      </providers>

 </roleManager>

 

Copy this chunk of Xml into something like notepad and change the parts highlighted in yellow to values that will work in your environment.  Now you can copy from there into each of the config files we need to change.  Unfortunately we’ll need to use a slightly different version of this in each web.config file.  Let’s start with the easy one first – central admin.  Find the web.config file for central admin and open it up in your favorite editor, like notepad.  Scroll down to the <system.web> entry, and paste the entire chunk of Xml directly below it.  Save your changes and the first one’s done.

The next one we’re gonna hit is the web.config for the Security Token Service (STS) virtual directory.  Explaining what the STS does, what claims based auth is, etc. is all way beyond the scope of this posting, but we’ll get to those things in time.  For now, we need to find the directory where it’s web.config file is and the easiest way to do that is to open the IIS Manager.  Expand the plus sign next to the server name.  Expand the plus sign next to the Sites object.  Expand the plus sign next to the SharePoint Web Services virtual directory.  Beneath it, find the SecurityTokenServiceApplication virtual directory.  Click on it, then click on the Content View button in the bottom of the middle part of the screen.  That will cause the Explore link to appear in the Actions pane on the right hand side of the screen (it’s the third link down from the top).  Click the Explore link and Windows Explorer will open up and you will see the web.config file you need to work with.  Open up the web.config file in a text editor and scroll all the way down to the bottom.  Directly under the </system.net> entry, do the following:

1.       Add a <system.web> entry and press enter.

2.       Copy and paste in the chunk of Xml shown above.

3.       Add a </system.web> closing tag directly below the stuff you pasted in.

4.       Find the <roleManager> element in the chunk of Xml you pasted in, and delete the defaultProvider attribute.  That leaves your roleManager element looking like this: <roleManager enabled=”true”> 

Save your changes and the second one’s done.  Now, go find the web.config file for the new FBA web application you created and open it up in notepad.  When you configured the web application to support claims based authentication, it automatically added in some Membership and Role provider information that points to a custom set of providers SharePoint 2010 adds out of the box.  So all we need to do is to just add in our provider into the correct section in the web.config.  IMPORTANT:  For those of you who are used to doing this for SharePoint 2007, please note that the providers are in the opposite order of what you are used to seeing.  The Role provider is listed first, and the Membership provider is listed second.  Scroll down the web.config file until you find the roleManager element (it’s a ways down there).  Copy out just the role provider definition from the chunk of Xml above and paste it below the <roleManager><providers> sections.  So you will paste in just this part (with your site specific info replacing the part in yellow):

<add name=”LdapRole”   

             type=”Microsoft.Office.Server.Security.LdapRoleProvider, Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”

             server=”stevedc.steve.local

             port=”389″

             useSSL=”false”

             groupContainer=”CN=Users,DC=steve,DC=local

             groupNameAttribute=”cn”

             groupNameAlternateSearchAttribute=”samAccountName”

             groupMemberAttribute=”member”

             userNameAttribute=”sAMAccountName”

             dnAttribute=”distinguishedName”

             groupFilter=”(ObjectClass=group)”

             userFilter=”(ObjectClass=person)”

             scope=”Subtree” />

 

Now scroll down a little more and do the same thing to add in your Membership provider.  Find the <membership><providers> element and right below paste in membership provider stuff from the chunk of Xml above (with your site specific info replacing the part in yellow):

<add name=”LdapMember”

             type=”Microsoft.Office.Server.Security.LdapMembershipProvider, Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”

             server=”stevedc.steve.local

             port=”389″

             useSSL=”false”

             userDNAttribute=”distinguishedName”

             userNameAttribute=”sAMAccountName”

             userContainer=”CN=Users,DC=steve,DC=local

             userObjectClass=”person”

             userFilter=”(ObjectClass=person)”

             scope=”Subtree”

             otherRequiredUserAttributes=”sn,givenname,cn” />

 

 

Okay, good – now you’ve finished step 2.  The hardest part is done.

 

Step 3 – Add A User Policy

This part is basically exactly the same as you did in SharePoint 2007, with a couple of very minor differences.  Go to the central admin site and click on Manage web applications.  Click on your new FBA web application, then click on the User Policy button in the ribbon; this brings up the User Policy dialog.  Now do the following steps:

1.       Click on the Add Users link.

2.       In the Zones drop down, select the Default zone and click the Next button.

3.       Click the Address Book icon.  This will bring up the people picker and will let you know real quickly whether everything is configured correctly or not.  The first thing you should notice is the you see a new interface.  I think it’s going to be called the Principal Picker or some other equally nerdy name, but you get the point – it allows you to search in one dialog and show matches from all of the directories you have configured.  It’s pretty slick.  So go ahead and type in the NT login name or account name (use whatever nomenclature you prefer here) and click the search button.  If it’s working correctly you should see at least two entries for the account – one that is for the user’s Active Directory account, and one that is for that same account but which was found using the LDAP provider. 

4.       Select the account in the User section and click the Add button.

5.       Click the OK button.

6.       Check the Full Control checkbox, then click the Finish button.

That’s it – everything should be all configured now for you to log into your new FBA site.

Step 4 – Login

Go ahead now and navigate to the site in your FBA web application.  You should get an initial prompt where it asks you what kind of authentication you want to use to access the site – Windows Authentication or Forms Authentication.  Select Forms Authentication from the drop down and the page posts back with a standard forms login page.  Enter the credentials of the user to which you granted the Full Control user policy and you should log into the site.  Now you can start adding other FBA members and roles into SharePoint groups so they can access the site to.

All Done!

Well, that’s all there is too it.  If you’ve never done it before it probably seems kind of complicated, just like the first time folks did it in SharePoint 2007.  If you have set it up before in SharePoint 2007 though, the process probably seems pretty straightforward.  Hopefully this post will get everyone moving the right direction and able to start using FBA with their new SharePoint 2010 sites.  Good luck!

An Updated ClaimsTokenHelper for SharePoint 2013 High Trust Apps and SAML

When Visual Studio 2013 came out, it introduced a new class and simplified methods for obtaining a ClientContext to use with the Client Side Object Model (CSOM) to access SharePoint 2013 sites.  A new SharePointContext class was added to simplify the programming model, but internally it still called the TokenHelper class that originally shipped with Visual Studio 2012. 

Shortly after SharePoint 2013 shipped, I provided an additional class – the ClaimsTokenHelper class – to be used when your SharePoint sites are secured using SAML authentication (http://blogs.technet.com/b/speschka/archive/2013/07/23/3539509.aspx).  Neither the original TokenHelper class nor the new SharePointContext class provides a means to properly identify a SAML claims user.  I decided to take a fresh look at the ClaimsTokenHelper implementation and see if I could find a way to update things to keep it more closely aligned with the development model used in the new SharePointContext class.  What I ended up doing is creating a new SharePointContextExtensions class, and it allows you to use virtually the same exact programming model as you do now with the SharePointContext class. 

Here’s an example of the code you use to access a site title using the SharePointContext class:

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

using (var clientContext =

spContext.CreateUserClientContextForSPHost())

{

clientContext.Load(clientContext.Web, web => web.Title);

clientContext.ExecuteQuery();

Response.Write(clientContext.Web.Title);

}

 

Now, here’s an example of using the new SharePointContextExtensions class:

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

using (var clientContext =

               spContext.CreateUserClientContextForSPHost(TokenHelper.IdentityClaimType.SMTP))

{

clientContext.Load(clientContext.Web, web => web.Title);

clientContext.ExecuteQuery();

Response.Write(clientContext.Web.Title);

}

 

As you can see, literally the only difference between the two now is that you need to specify which OAuth identity attribute you want to use as the identity claim – SMTP, SIP, or UPN.  Also, there is a corresponding method for getting a ClientContext for an App Only token.  Here’s the out of the box syntax:

spContext.CreateAppOnlyClientContextForSPHost();

 

And here’s the corresponding method when using SAML:

spContext.CreateAppOnlySamlClientContextForSPHost();

 

In this case I had to actually change the method name, because it would otherwise have the same exact method name and signature as the SharePointContext class.  I’ve attached the SharePointContextExtensions and ClaimsTokenHelper classes to this posting.  Using them is pretty straightforward:

  1. Add both classes to your project
  2. Change the “namespace” declaration at the top of each class to match the namespace you are using in your project.
  3. As with the original ClaimsTokenHelper class you also need to do the following; you can find more details on both of these steps in the original blog post at http://blogs.technet.com/b/speschka/archive/2013/07/23/3539509.aspx#pi47623=1:
    1. Add the “partial” modifier to the TokenHelper.cs class that Visual Studio adds to your project, i.e. it should read public partial class TokenHelper
    2. Add the “TrustedProviderName” property to your appSettings section in web.config and put in the name of your SPTrustedIdentityTokenIssuer as the value.
    3. Start coding.

That’s it – you should be up and running in no time!

You can download the attachment here:

Developing Low Trust Provider Hosted Apps with SAML Authentication in SharePoint 2013

Low trust provider hosted apps in a SAML secured SharePoint web application is a scenario that did not work when SharePoint 2013 was released.  Things have changed fortunately, so here’s a quick run down on what you need to do in order to build these apps on premises.  The first thing you need to do is to apply the April 2014 CU or later.

Once you’ve applied that you’ll need to decide how you want to configure authentication on your provider hosted apps.  Generally you’ll find the best approach is to use a single host for your provider hosted apps, install each app into its own subdirectory, and use an authentication mechanism that is the same as you use for your SharePoint web applications.  There may be cases where you might not want to do that; for example, if your SharePoint web applications use multi-factor authentication, you may not want your users to have to enter their credentials again – twice – when they use an app that is part of a SharePoint site to which they’ve already authenticated.  As explained in the beginning, that’s okay – you can use a different authentication mechanism if needed for your low trust provider hosted app because the user identity is maintained by SharePoint even after the user authenticates to the app.

When the provider hosted environment is configured, the next thing you need to do is create a ServicePrincipal with your Office 365 tenant.  The Office 365 tenant uses a special version of Access Control Services (ACS) that is responsible for providing the tokens (context, refresh and access) that low trust SharePoint apps use to authenticate and authorize with SharePoint.  The process overall is described in greater detail in this blog post:  http://blogs.technet.com/b/speschka/archive/2013/07/29/security-in-sharepoint-apps-part-3.aspx.  More importantly, MSDN has published instructions and a script you can use to create the ServicePrincipal and configure it to allow the ServicePrincipal to issue tokens to a SharePoint web application.  You can find the MSDN article here:  http://msdn.microsoft.com/en-us/library/dn155905.aspx.  When you create your ServicePrincipal, you need to add the hostname of every SharePoint web application in which you want to use apps to a collection of SPNs on the ServicePrincipal, i.e. ServicePrincipal.ServicePrincipalNames.  In the MSDN article it includes a script at the bottom that will enumerate all of the web applications in your farm and add the hostname of each one to the ServicePrincipalNames collection.  However, if you add a new web application in the future, you also need to remember to go and add the hostname of the new web application to the ServicePrincipalNames collection.  If you don’t do that, then apps that are installed in that web application will not be able to get a valid token.

Another option that can be used so you don’t have to revisit your ServicePrincipalNames collection is to add a wildcard.  If all of your SharePoint web applications use a common domain for the host name then you can just add a wildcard for the domain.  For example, if you have two web applications – portal.contoso.com and intranet.contoso.com – then you can just add a “*.contoso.com” wildcard to the ServicePrincipalNames collection.  Here’s a PowerShell example of how to do that:

 

#you will be prompted to enter the credentials of an o365 Global Admin here

connect-msolservice

$spoid=”00000003-0000-0ff1-ce00-000000000000″

$p = Get-MsolServicePrincipal -AppPrincipalId $spoid

$spns = $p.ServicePrincipalNames

$spns.Add(“$spoid/*.contoso.com”)

Set-MsolServicePrincipal –AppPrincipalId $spoid –ServicePrincipalNames $spns

 

After you’ve completed creating and configuring the ServicePrincipal, you can begin deploying your low trust provider hosted applications on SharePoint web applications that are secured with SAML authentication.

Desktop SharePoint Apps for SAML Secured SharePoint Sites

Continuing on with the theme of SAML secured SharePoint sites and SharePoint Apps, this next posting looks at another common application model, which is using what I call a desktop app to connect to SharePoint.  By “desktop”, I mean an app that doesn’t have an HttpContext, like a console application or winforms app.  It could run on a desktop, on a server, in an Azure web job, etc. but the fundamental theme is that there is no HttpContext associated with the request and there may not be an active user context either (as is the case with a console app).

To create this solution we’re going to build upon two previous Share-n-Dipity posts:  http://blogs.technet.com/b/speschka/archive/2013/06/12/converting-a-vs-net-web-for-a-provider-hosted-sharepoint-app-to-a-full-blown-web-or-console-application.aspx and http://blogs.technet.com/b/speschka/archive/2014/09/30/an-updated-claimstokenhelper-for-sharepoint-2013-high-trust-apps-and-saml.aspx.  There are some slightly newer steps required to get your desktop application configured to be used as a SharePoint App, and then I’ve made some additions to the ClaimsTokenHelper code to facilitate this scenario.  When you’re done you’ll be able to use a desktop app for the following scenarios:

  1. High trust with an App + User context

  2. High trust with an App Only context

  3. Low trust with an App Only context

So in short we can address all of the primary app contexts except for low trust App + User; the reason we can’t do that one is that as described above, there is no HttpContext so we can’t get SharePoint to give us a low trust user context.  There’s still a lot to work with though so let’s walk through the process.

As a starting point for this scenario, I always recommend that you build out a working “standard” provider hosted SharePoint App for your scenario.  To do that, start with Visual Studio and create your application using the Visual Studio wizard.  It creates the SharePoint App as well as web application project that uses IIS Express.  From this point forward this web application project that VS.NET creates shall be referred to as the “original web app”.  Verify that everything is working correctly.

Next create the new application you are going to use – a console project or winforms project.  You now need to copy over the configuration information from the web.config file of the original web app to your application.  The difference of course is that neither a console nor winforms project has a web.config, so you will put the configuration information in the application settings.  To do so, go into the Properties of the application, click on the Settings link on the left.  If you are in a console application then you will see a link in the middle of the page that says “This project does not contain a default settings file.  Click here to create one.”; click on it to create a settings file.  A winforms project displays the settings grid by default so you can just begin creating properties.  Go ahead and create properties for each of the appSetting properties from the original web app’s web.config file – copy in both the key (as the setting Name) and value (as the setting Value).  Make sure you configure each setting an Application scope property (it is User by default).

The references required for the project should be added next.  Add the following references to your project:

  • Microsoft.IdentityModel

  • Microsoft.IdentityModel.Extensions

  • Microsoft.SharePoint.Client

  • Microsoft.SharePoint.Client.Runtime

  • System.IdentityModel

  • System.ServiceModel

  • System.Web

  • System.Web.Extensions

  • System.Configuration

Now create a new folder called “App_Code” and copy into it the TokenHelper.cs and SharePointContext.cs files from the original web project.  Also copy in the ClaimsTokenHelper.cs and SharePointContextExtensions.cs files that are included with this post.  After you’ve added the files change the namespace attribute in each class to match the namespace attribute of your project.  For example, if you create a console project called “SamlConsoleApp”, then you should change the namespace attribute in each class to be:

Namespace SamlConsoleApp

{

      //rest of your class here

}

Next you need to update the properties in TokenHelper.cs and ClaimsTokenHelper.cs that currently look to the web.config file for their values.  They should instead use the application settings, since that’s where the configuration is being stored in console and winforms apps.  In TokenHelper.cs look for the following properties:

  • ClientId

  • ClientSigningCertificatePath

  • ClientSigningCertificatePassword

  • IssuerId

  • ClientSecret

In ClaimsTokenHelper.cs find these properties:

  • TrustedProviderName

  • MembershipProviderName

 

Replace the value of each of these properties with a call to the application settings, like this:

private static readonly string TrustedProviderName = yourAppNamespace.Properties.Settings.Default.TrustedProviderName;

Where yourAppNamespace is the namespace for your console or winforms application.

NOTE:  If you did not create each of those properties in your application’s Settings file, then you will not have corresponding properties for each item listed above in TokenHelper.cs and ClaimsTokenHelper.cs.  That’s okay – just leave them as is and change the ones you DO have.

Finally, you need to change the modifier on the TokenHelper class from public to public partial.  You can do that by changing the class from “public class TokenHelper” to “public partial class TokenHelper”.  At this point all of the modifications are complete.  You should compile your code and verify that it completes without error.  If you missed any of the steps above then you will likely get compiler errors or warnings now that should direct you to the areas that need to be fixed.  Now you can finally start writing some code!

The actual code to connect to SharePoint and get a ClientContext varies depending upon the scenario you are using.  Here’s an example in a console app of all three use cases I described above:

//this is the SharePoint site we want to work

//with; you must provide this since there is no HttpContext

Uri hostWeb = new Uri(“https://samlpnp.vbtoys.com&#8221;);

 

//request using:

//1.  High Trust

//2.  App + User context

using (var userContext =

SharePointContextProvider.Current.CreateDesktopUserContext(hostWeb,

TokenHelper.IdentityClaimType.SMTP,

“sam.smith@contoso.com”))

{

     //your code here

}

 

//request using:

//1.  High Trust

//2.  App Only context

using (var highAppContext =

SharePointContextProvider.Current.

CreateDesktopHighTrustAppOnlyContext(hostWeb))

{

     //your code here

}

 

//request using:

//1.  Low Trust

//2.  App Only context

using (var lowAppContext =

SharePointContextProvider.Current.

CreateDesktopLowTrustAppOnlyContext(hostWeb))

{

     //your code here

}

Now for a couple of notes on the implementation.  I made changes to both the ClaimsTokenHelper and SharePointContextExtensions classes from my previous post on this topic.  For ClaimsTokenHelper I modified it so that you can pass it the identity claim you want to use for the user when using an App + User context.  Again, this is because there is no HttpContext so you don’t have access to things like a claims collection or an authentication process you can plug into.  You can use the current process identity, a configuration file, or even just hard code the identity you want to use into your application.  You aren’t send along credentials in this case, you’re just telling SharePoint the user context that should be used when it processes your CSOM calls.  That is exactly what high trust was designed to do.

In addition to that, I added some additional methods to the SharePointContextExtensions class.  Again, the original SharePointContextProvider class creates a SharePointContext based on an HttpContext, and then you create a ClientContext from that.  Since the HttpContext doesn’t exist, none of those methods work.  To work around that, we can bypass creating the SharePointContext and go straight to creating a ClientContext.  The extensions class was updated to add these additional methods that you see demonstrated above:  CreateDesktopUserContext, CreateDesktopHighTrustAppOnlyContext, and CreateDesktopLowTrustAppOnlyContext.  As a side note, one of the other interesting “features” of doing this in a desktop app is that you can mix both low trust and high trust calls in the same application.  Because of the way the SharePointContextProvider class that comes with Visual Studio uses session state to manage your context, this is not possible in a web application.  I don’t know if that will ever matter to anyone, but it doesn’t hurt to have another capability in the tool belt.

Here are screenshots of the code executing successfully in a console app and then in a winforms app:

 



 

That’s it for this post.  I’ve attached a zip file with the updated ClaimsTokenHelper.cs and SharePointContextExtensions.cs files, as well as two sample projects – one a console app and the other a winforms app that demonstrates using these new classes and techniques.  Good luck!

You can download the attachment here: