• Using ADAL Access Tokens with o365 REST APIs and CSOM

    Many fine folks were generous enough to point out to me this week that you can now (actually since June’ish I’m told) use an access token you get from ADAL in conjunction with the o365 APIs to use ALSO with the SharePoint REST API as well CSOM.  Shocking!!  This may be what they call “asleep at the wheel” (or taking the red pill), but now that I’m wide awake again and aware of my surroundings it seemed like a good time to augment and update some of the content that’s out there.

    Jeremy Thake did a nice write up on this concept originally at http://www.jeremythake.com/2014/06/using-the-sharepoint-csom-and-rest-api-with-office-365-api-via-azure-ad/.  While much of it still applies, I decided to revisit it myself so a) I would appear to know what the hell I’m talking about and b) I could update the really awful goo that he was forced to use to get an access token.  So in this little sample I’m going to use a standard flow to get an access token using ADAL (Active Directory Authentication Library).  I’m also going to be a little verbose and do a few things that you can do “less manually” with some tools for Visual Studio, just to make sure you are clear on what those tools are actually doing for you (especially if you’re <gasp> not using Visual Studio).  Here we go.

    Add a New Application

    You can use the Office 365 Tools add in for Visual Studio, or just create the application yourself manually in the Azure portal.  That’s what I’m doing in this case.  I begin by opening the portal and selecting my Azure Active Directory instance that’s used with my Office 365 tenant.  Then I click on the Applications tab, and then click on the ADD button at the bottom of the page to create a new application.  Here’s how we do it:

    Click the check button and you’ve completed the first step – your application has been created.  Now go ahead and click on the Configure link so you can add the permissions you need to access your o365 content. 

    Click the Add Application button at the bottom of the page and a Permission to Other Applications dialog pops up.  Click on the Office 365 SharePoint Online application and then click on the + sign next to it.  When you’ve completed that click the check button to save your changes:

    Now you’ll have an item in the list of applications that your application wants permissions to, and you can click on the Permissions drop down for it to configure the permissions you want your application to have in the Office 365 tenant where it’s used.  Here’s what that looks like:

    After you’ve made all of these changes, click the SAVE button at the bottom of the page but DON’T close the application configuration page just yet, there’s some info we need to grab out of there for connecting to it.  Scroll up to the top of the page and copy the a) CLIENT ID and b) REDIRECT URIS values.  You are going to use this when you ask a user to consent to having your application access his or her SharePoint content:

    Okay, now we’re going to create a little winforms app that uses ADAL to get an access token, and then CSOM and REST to get data out of SharePoint.  So to begin the next step I’m going to create a new winforms application, and dive right into the code-behind in my form.  Once in there I’m going to plug in my Client ID and Redirect URI that I got from my application configuration in Azure.

    Now…if you follow my last o365 API blog post here:  http://blogs.technet.com/b/speschka/archive/2014/12/08/oauth-o365-apis-and-azure-service-management-apis-using-them-all-together.aspx, you’ll see I’m going to use nearly identical techniques that I described there to get my access token from Azure AD.  To begin with, here are the standard set of application details I’m adding to my app:

    Now I’m going to use NuGet to add in support for ADAL and o365; when I’m done it looks like this:

    I’m also going to add references to Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime so I can use CSOM from my application.  Next I’m going to add that same helper method I described in my previous blog post to get the access token, so let’s use this code here:

    private async Task<AuthenticationResult> AcquireTokenAsync(string authContextUrl,

    string resourceId)

    {

       AuthenticationResult ar = null;

     

       try

       {

           //create a new authentication context for our app

           AuthContext = new AuthenticationContext(authContextUrl);

     

           //look to see if we have an authentication context in cache already

           if (AuthContext.TokenCache.ReadItems().Count() > 0)

           {

     

              //re-bind AuthenticationContext to the authority

              //source of the cached token.

              //this is needed for the cache to work when asking

              //for a token from that authority.

              string cachedAuthority =

                 AuthContext.TokenCache.ReadItems().First().Authority;

     

              AuthContext = new AuthenticationContext(cachedAuthority);

           }

     

           //try to get the AccessToken silently using the

           //resourceId that was passed in

           //and the client ID of the application.

           ar = (await AuthContext.AcquireTokenSilentAsync(resourceId, ClientID));

       }

       catch (Exception)

       {

           //not in cache; we'll get it with the full oauth flow

       }

     

       if (ar == null)

       {

           try

           {

              ar = AuthContext.AcquireToken(resourceId, ClientID, ReturnUri);

           }

           catch (Exception acquireEx)

           {

              //utter failure here, we need let the user know we just can't do it

              MessageBox.Show("Error trying to acquire authentication result: " +

                 acquireEx.Message);

           }

       }

     

       return ar;

    }

    Okay, now we have the most important part of the guts done, let’s go back and look at the basics of what Jeremy was showing in his post:

    Retrieving Data via REST

    This one is virtually identical to Jeremy’s code, it just a) uses my updated code for obtaining an access token and b) shows how to create the Resource ID that you want to use for getting content from your SharePoint sites.  I tested this code against a couple of different o365 tenants and I can happily <small tear in eye> say that it worked in both.

    private async void RestListBtn_Click(object sender, EventArgs e)

    {

       try

       {

           AuthenticationResult ar = await AcquireTokenAsync(CommonAuthority,

              GetSharePointHost(SiteUrlTxt.Text));

     

           if (ar != null)

           {

              string requestUrl = SiteUrlTxt.Text + "/_api/Web/Lists";

     

              HttpClient hc = new HttpClient();

     

              //add the header with the access token

              hc.DefaultRequestHeaders.Authorization = new

                 System.Net.Http.Headers.AuthenticationHeaderValue(

                 "Bearer", ar.AccessToken);

     

              HttpResponseMessage hrm = await hc.GetAsync(new Uri(requestUrl));

     

              if (hrm.IsSuccessStatusCode)

                 ResultsTxt.Text = await hrm.Content.ReadAsStringAsync();

              else

                 MessageBox.Show("Unable to get subscription information.");

           }

       }

       catch (Exception ex)

       {

           MessageBox.Show("Error: " + ex.Message);

       }

    }

     

    private string GetSharePointHost(string url)

    {

       Uri theHost = new Uri(url);

       return theHost.Scheme + "://" + theHost.Host + "/";

    }

    The main thing to call out here really is the GetSharePointHost method that creates the Url that is used as the Resource ID when getting an access token.  The net of this advice is that no matter where your SharePoint site lives, you really want to use the root site as the Resource ID.  So if your o365 site is https://steve.sharepoint.com/sites/blazers, the Resource ID to get an access token should be https://steve.sharepoint.com.  Doesn’t matter where the site is in that hierarchy – from the root all the way down as far as you want to go – you want to make sure you use the root site as the Resource ID.  About a billion thanks to Dan K. for clearing that up for me; your Christmas card is in the mail!  The other thing worth noting is that you MUST include a trailing slash on the Url that you use as the Resource ID.  It cause ADAL no end of pain and suffering when you leave that out.  Both of these little gems are captured in those two lines of code above.  Yay!

    Retrieving Data via CSOM

    This one is also quite similar to Jeremy’s…again the main differences are that it uses my standard method to get the access token, and for some reason I get a somewhat different class naming structure for my WebRequestEventArgs.  Here’s the relevant code:

    private void CsomListBtn_Click(object sender, EventArgs e)

    {

       try

       {

           ClientContext ctx = new ClientContext(SiteUrlTxt.Text);

           ctx.ExecutingWebRequest += ctx_ExecutingWebRequest;

     

           ctx.Load(ctx.Web.Lists);

     

           ctx.ExecuteQuery();

     

           string theLists = string.Empty;

     

           foreach (List lst in ctx.Web.Lists)

           {

              theLists += lst.Title + Environment.NewLine;

           }

     

           ResultsTxt.Text = theLists;

       }

       catch (Exception ex)

       {

           MessageBox.Show("Error: " + ex.Message);

       }

    }

     

    async void ctx_ExecutingWebRequest(object sender, WebRequestEventArgs e)

    {

       AuthenticationResult ar = await AcquireTokenAsync(CommonAuthority,

           GetSharePointHost(SiteUrlTxt.Text));

     

       if (ar != null)

       {

           e.WebRequestExecutor.RequestHeaders["Authorization"] =

              "Bearer " + ar.AccessToken;

       }

    }

    So there you have it.  I must say, I find this ridiculously cool.  Many thanks to Jeremy for his original post and for the loads of people who basked in the glory of pointing out to me that I missed it.  :-)   Just kidding of course, I love having a legion of friends that can read on my behalf and get me pointed in the right direction as needed.  Hopefully this post will help one of you in the same way.  I’ve attached the complete source code to this post, so just change the ClientID and ReturnUri variables after you create your application and you should be good to go.  As usual, I've also included the Word document from which this sorry mess of Notepad-like content was created.

  • OAuth, o365 APIs and Azure Service Management APIs – Using Them All Together

    I’ve been spending some time lately fooling around the o365 API’s.  Frankly, it has been a hugely frustrating experience; I’ve never seen so many documentation gaps and examples and sample code that didn’t work, to flat out wouldn’t compile in a long time.  So, once I finally stumbled up on the “right” collection of code that worked to get me the all important access token for the o365 APIs I decided to take a quick detour to see if I could use the same approach to manage my Azure subscription with the Service Management APIs.  Turns out you can, and actually do so in a way that leverages both of the APIs together in kind of a weird way.  Here’s the story of how it works (with a special twist at the end, you’ll have to read all the way down to see it).

    The first step in getting any of this working is to create an application in Azure.  In that app, you can grant the rights that it is going to require – to things like Office 365 and the Azure Service APIs.  The easiest way to do this scenario is to create the application using the Microsoft Office 365 API Tools for Visual Studio, which as of this writing you can find here:  https://visualstudiogallery.msdn.microsoft.com/a15b85e6-69a7-4fdf-adda-a38066bb5155. 

    Once you have those installed, the next step is to create a new project – whatever kind of project type is appropriate for what you are trying to accomplish.  Once you’ve done that you want right-click on your project name and select “Add Connected Service”, like this:

     

     

    When you add your Connected Service the first thing you’ll do is click on the Register your app link.  It will first ask you to log in using your Azure organizational account.  This account needs to be an admin account – one that has rights to create a new application in an Azure Active Directory:

     

     

    After entering your credentials Visual Studio will take care of registering the app with Azure.  It then presents you with a list of permission scopes, and for each one you can click on the scope to select which permissions in that scope you want your app to have.  Remember that when a user installs your application it will ask if it’s okay for the app to have access to these things you’re defining in the permissions list. 

    In this case I’m just going to select the Users and Groups scope and select the permissions to Read directory data and Access your organization’s directory:

     

     

    That should be enough permissions to use the o365 Discovery Service API; I’ll explain why we want to do that in a bit.  For now just click the Apply button, then click the OK button to save your changes.  When you do that Visual Studio will begin modifying the application with the permissions you requested.  In the Output window in fact you should see it add the Discovery Service NuGet package to your project (“ServiceApi” is the name of my project in Visual Studio): 

    Adding 'Microsoft.Office365.Discovery' to ServiceApi.

    ... 

    When it’s done with that it should open up a page in the Visual Studio browser window that includes the interesting information about what you need to do next, and of course, no details on how to actually do it.  That’s why you’re reading this blog post now, right??  :-) 

    The next thing we’re going to do is to go into the Azure Management Portal and add the other rights we want for our application, which is to use the Service Management API.  So open up your browser and log into the Azure Management Portal at https://manage.windowsazure.com.  Scroll down and click on the Active Directory icon in the left navigation, then click on your Azure Active Directory domain in the right pane.  When you go into the details for your directory, click on the Applications tab, then find the application you just created.  Click on it and then click on the Configure link.   

    One of the things you’ll see at the top of the page is the CLIENT ID field.  If you look in Visual Studio at your project, you should have had something like an app.config file added to it when you set up the application (app.config is added to winforms project; the config file that is added will vary based on your project type).  Open up the app.config file and you will see an appSettings section and an entry for ida:ClientId.  The value for it should be the same as the CLIENT ID value you see for your application in the Azure portal. 

    Scroll down to the bottom of the page for the application to the “permissions to other applications” section.  You should see one entry in there already, and that’s for the permission we requested for working with the directory data.  Now click on the drop down in that section that says “Select application”, and select Windows Azure Service Management API.  On the drop down next to it that says “Delegated Permissions: 0”, click on it and check the box next to the item that says “Access Azure Service Management”. 

     

    Once you’ve done that click the SAVE button at the bottom of the page.  You’re done now with all of the configuration you need to do in Azure, so let’s shift gears back into our project. 

    The next thing we need to do is plug the application key values we need into our application.  That includes the client ID, redirect URI, the Discovery Service resource ID and the Azure Service Management resource ID.  You can get the client ID and redirect URI values from the app.config file that was added to your project.  If for some reason you can’t find it in your project, you can also find it in the Configure tab for the application in the Azure management portal.  The client ID value is in the CLIENT ID field, and the redirect URI value is in the REDIRECT URIS list.  Finally, we are also going to use what’s called the “Common Authority” for getting an authentication context – an ADAL class (Active Directory Authentication Library that is used under the covers to get an access token to the o365 and Azure resources). 

    The resource IDs are fixed – meaning they are always the same, no matter what application you are using them from.  So with that in mind, here’s what the values look like once I’ve added them to the code behind for my winforms application: 

     

    Okay, we’re getting awfully close to actually writing some code…the last thing we need to do before we start doing that though is to add the ADAL NuGet package to our application.  So in Visual Studio open up the NuGet package manager, search find and add the ADAL package and add it.  When you’re done you should see it AND the Microsoft Office 365 Discovery Library for .NET, which was added when we configured our application previously:

     

     

    Now we’ll add the last couple of helper variables we need – one which is the base Url that can be used to talk to any specific Azure tenant, and the other is a property to track our AuthenticationContext: 

    private const string BASE_TENANT_URL = https://login.windows.net/{0};

    public static AuthenticationContext AuthContext { get; set; }

     

    Okay, now let’s add the code that will get the access token for us, and then we’ll walk through it a little bit: 

    private async Task<AuthenticationResult> AcquireTokenAsync(string authContextUrl, string resourceId)

    {

       AuthenticationResult ar = null;

     

       try

       {

           //create a new authentication context for our app

           AuthContext = new AuthenticationContext(authContextUrl);

     

           //look to see if we have an authentication context in cache already

           //we would have gotten this when we authenticated previously

           if (AuthContext.TokenCache.ReadItems().Count() > 0)

           {

     

              //re-bind AuthenticationContext to the authority source of the cached token.

              //this is needed for the cache to work when asking for a

              //token from that authority.

              string cachedAuthority =

                  AuthContext.TokenCache.ReadItems().First().Authority;

     

              AuthContext = new AuthenticationContext(cachedAuthority);

           }

     

           //try to get the AccessToken silently using the resourceId that was passed in

           //and the client ID of the application.

           ar = (await AuthContext.AcquireTokenSilentAsync(resourceId, ClientID)); 

       }

       catch (Exception)

       {

           //not in cache; we'll get it with the full oauth flow

       }

     

       if (ar == null)

       {

           try

           {

              //request the token using the standard oauth flow

              ar = AuthContext.AcquireToken(resourceId, ClientID, ReturnUri);

           }

           catch (Exception acquireEx)

           {

              //let the user know we just can't do it

              MessageBox.Show("Error trying to acquire authentication result: " +

                  acquireEx.Message);

           }

       }

     

       return ar;

    The first thing we’re doing is creating a new AuthenticationContext for a particular authority.  We use an authority for working with an AuthenticationContext so that we can manage the cache of AuthenticationResults for an authority.  ADAL provides a cache out of the box, so once we get an AuthenticationResult from an AuthenticationContext, we can just pull it from that cache without having to go through the whole oAuth flow all over again.  The AuthenticationResult by the way is where we get the things we need to access a resource – an access token and a refresh token. 

    Once we’ve created our AuthenticationContext again then we can try and acquire the AuthenticationResult out of the cache, which is done with the call to AcquireTokenSilentAsync.  If there’s an AuthenticationResult in cache then it will be returned to you.  If not then it throws an exception, which we catch directly below that call. 

    Once we get through that part of the code we look to see if we were able to get an AuthenticationResult.  If not, we’ll go ahead and use the oAuth flow to obtain one.  That means a dialog will pop up and the user will have to enter their credentials and approve our application to access the content we said we needed when we configured the permissions for our application. 

    Now that we’ve got the code out of the way to get an AuthenticationResult, we can write the code to actually go work with our data.  This is where you can see this kind of interesting intersection between the o365 APIs and the Azure Service Management API that I was describing at the start of this post.  As I alluded to earlier, I really put this code together and wrote this post for two reasons:   1) there are SO MANY o365 API examples that either don’t include clear instructions on how to obtain an access token, or the code they have either does not even compile or does not work.  This is proof I guess that APIs change, right?  Now you have an example that works (at least for today). 2) the Service Management API requires the tenant ID to work with it.  Well, as it turns out, when you get your AuthenticationResult from a call to the DisoveryService through the o365 APIs, you will get the tenant ID back.  

    So you can use this pattern – call the DiscoveryService, use the CommonAuthority for the authContextUrl and authenticate, then you will have the tenant ID.  Then take the tenant ID, use the login Url for the specific tenant as the authContextUrl and get an AuthenticationResult to use with the Service Management APIs (we’ll end up getting the access token silently).  Once you have that you can take the access token from it to do whatever you’re going to do with Service Management APIs. 

    Now, let me explain one other behavior that you may not be aware of, and then explain how that impacts the code I described above.  If you read my description of the pattern above, you may notice this:  in the first call to create an AuthenticationContext I use the CommonAuthority for the authContextUrl, which is https://login.windows.net/Common.  In the next call I use an authContextUrl of https://login.windows.net/myTenantIdGuid.  So if I’m using two different Urls to create my AuthenticationContext, then how could there be something in the cache for me to use when as I say above, on the second call I’m going to get the AuthenticationResult out of the cache?  Well, it turns out that when you create the AuthenticationContext with the CommonAuthority, after the user actually authenticates ADAL changes the Authority property of the AuthenticationContext from CommonAuthority to https://login.windows.net/myTenantIdGuid.  This is actually pretty cool.  The net result of all this is – I actually don’t need to authenticate into the DiscoveryService at all to get the tenant ID for the tenant being used.  So what’s the net of everything I’ve given you so far?  Well as I explained at the beginning, you now have some nice code that actually does work with the o365 APIs.  However now that you understand how it works you can see you really don’t need to call into the DiscoveryService to get the tenant ID, so you learned a little something about how the AuthenticationContext works in the process. 

    Okay, so now that we know that, let’s take a look at the code to get our subscription data from Azure.  You’ll see that it makes just a single call to get an AuthenticationResult for working with the Service Management APIs.  Note, this code uses the new HttpClient library, which is installed as a NuGet package; here’s the package I added: 

     

    The code looks like this: 

    try

    {

       //base Url to get subscription info from

       string subscriptionUrl = "https://management.core.windows.net/subscriptions";

     

       AuthenticationResult ar =

           await AcquireTokenAsync(CommonAuthority, AzureManagementResourceId);

     

       //yeah this is me just being lazy; should really do something here

       if (ar == null)

           return;

     

       string accessToken = ar.AccessToken;

     

       if (!string.IsNullOrEmpty(accessToken))

       {

           //create an HTTP request for the subscription info

           HttpClient hc = new HttpClient();

     

           //add the header with the access token

           hc.DefaultRequestHeaders.Authorization = new

              System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);

     

           //add the header with the version (REQ'D)

           hc.DefaultRequestHeaders.Add("x-ms-version", "2014-06-01");

     

           HttpResponseMessage hrm = await hc.GetAsync(new Uri(subscriptionUrl));

     

           if (hrm.IsSuccessStatusCode)

              SubscriptionsTxt.Text = await hrm.Content.ReadAsStringAsync();

           else

              MessageBox.Show("Unable to get subscription information.");

       }

    }

    catch (Exception ex)

    {

       MessageBox.Show("Error trying to acquire access token: " + ex.Message);

    } 

    So just to recap what we’ve been talking about…the first thing I do is get an AuthenticationResult using the CommonAuthority.  If the person that signs in does not have rights to use the Service Management APIs for the tenant they sign into, then they won’t get the chance to grant the app permissions to do what it wants.  Otherwise they person will ostensibly grant rights to the app, and you’ll get your AuthenticationResult.  From that we take our access token and we add two headers to our request to the subscriptions REST endpoint:  the authorization header with our access token, and a special Microsoft version header, which is configured per the Microsoft SDK.  Then we just make our request, hopefully get some data back, and if we do we stick it in the text box in our application.  Voila – mission accomplished!  Here’s an example of the XML for a subscription (and yes, the GUIDs shown here are not the actual ones from my tenant):

     

    My biggest regret here is that even though in some ways this is “simplified”, it still takes me nine pages of a Word document to explain it.  However I do think you have some good code that you can go out and run with today to start working with both the o365 APIs as well as the Azure Service Management APIs, so I think it’s worth it.  Just bookmark this post for a rainy day, and then when you’re ready to start developing on either SDK you know where to find the info to get you started. I've also attached to this post the complete source code of the application I wrote here. You'll just need to update the client ID and return URI in order to use it. I've also included the original Word document from which this somewhat ugly post was pasted.

  • SQL Azure Connection String Settings for Visual Studio Projects Deployed to Azure Web Sites

    I recently spent HOURS looking for a silly little SQL Azure connection string in my Visual Studio project.  When I created the project I configured it to be deployed to an Azure web site and I also connected it with a SQL Azure server where I'm storing the data.  Unfortunately I had entered an old password when I created the project, and from that point every time after I deployed to Azure web sites my project bombed with malice whenever I attempted to do anything that touched the database.

    I actually tried to fix it myself in a variety of ways before stumbling across it's secret shelter.  I changed the settings in the Package/Publish SQL part of the project properties; no joy.  I tried adding the password to the project-dev.json settings file; no joy.  I added web.config transforms for both debug and release; no joy.  I even published the app to my desktop so I could make sure the web.config was getting transformed correctly.  It was, the right connection string was in there, but it was not being used.  Grr!

    Finally a particularly brilliant friend of mine, David C., pointed me in the right direction.  When you need to change that password, here's what you have to do:

    1.  Open up the Server Explorer in Visual Studio.  Expand the Azure subscription (or connect to your subscription if you haven't already), then expand the list of Azure web sites.

    2.  Right-click on the Azure web site to which you are deploying and click on the View Settings menu.

    3.  Around the middle of the page you will see a Connection Settings section.  Go in there, change your connection string value, then click the Save button at the top of the page.



    You're good to go at that point.  Just republish your application and give it a try - everything should be working at that point.  Hopefully this saves someone some time trying to find this info.

     

  • 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");

     

    //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!

  • 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.