Contents tagged with Apps

  • JavaScript multi-line string hack - a nifty JavaScript and CSS trick

    Tags: JavaScript, Apps, Add-Ins

    JavaScript is the new black and each and everyone has re-discovered JavaScript and it's inevitable not to have JavaScript as one of your tools. Especially if you're working with SharePoint, Office or Office 365 Apps or Add-Ins.

    In this short post I'm just documenting and sharing a small and nifty JavaScript hack that is very handy when you're doing for instance JavaScript injection, one of the most popular customization patterns for Office 365 and SharePoint Online at the moment. I often find myself in the situation that I need to deploy and inject a JavaScript file and an accompanying CSS file. More than often both the JS file and the CSS file is very small and I've found it very handy to combine the JS and CSS file into one JS file.

    Keep calm...Unfortunately the multi-line string features in JavaScript sucks, at best, unless you know this little trick. For instance you need to end each line with a backslash (\) and if you need line breaks you need to insert backslash + n (\n). If you're working with a CSS tool or like to write your CSS then it's annoying to add all that extra fluff when copying and pasting the CSS.

    So instead I've been using a technique that involves creating a small function like this:

    Wictor.MultiString = function (f) {
        return f.toString().split('\n').slice(1, -1).join('\n');
    }

    Using this function (and hack) I can now write multi-line strings as follows, and that allows me to copy-paste CSS from any tool without redecorating it in JavaScript.

    Wictor.CSS = Wictor.MultiString(function(){/**
     body {
         font-family: Consolas !Important;
     }
     **/});

    I can then use this method like this, in for instance SharePoint Online, to inject some CSS without deploying a CSS file:

    var Wictor = Wictor || {}
    
    Wictor.MultiString = function (f) {
        return f.toString().split('\n').slice(1, -1).join('\n');
    }
    
    Wictor.CSS = Wictor.MultiString(function(){/**
     body {
        font-family: Consolas !Important;
     }
     **/});
     
     (function () {
        ExecuteOrDelayUntilScriptLoaded(function() {
            var css = document.createElement("style");
            css.type = "text/css";
            css.innerHTML = Wictor.CSS;
            document.body.appendChild(css);
            alert('You\'re injected')
        }, 'sp.js');
     })();
    

     

    Happy JavaScripting….

  • SharePoint Online: App Only policy PowerShell tasks with ACS

    Tags: SharePoint, Office 365, PowerShell, Apps

    Here’s a little nugget that I’ve planned to blog about for some time, that I needed today for a small task. I needed to do a background job to SharePoint Online that at a scheduled interval downloads list data, process them and optionally updates some data in my site. This can of course be done by creating an executable storing username and password combos, and with the help of the TokenHelper.cs class from the App for SharePoint Web Toolkit NuGet package and some stored username and password combos we can make the Auth pieces quite easy. I don’t like that approach. There’s two big drawbacks with that approach. The first one is storing the username and password – we can solve that with an AppOnly policy, which I blogged about in the SharePoint 2013: Using the App Only policy and App Principals instead of username and password combos post. The second issue is that I very much prefer to script these kind of tasks, it makes it more flexible. Problem with that approach is that we need to manually do the Auth pieces. But from now on you just copy and paste from this post.

    Creating the App Principal

    In order to create our PowerShell script we need to create an App for it. This step is exactly the same as we did in the blog post mentioned above. But let’s repeat it. Note! I do use the traditional way of registering apps in this scenario using ACS – I do not use an Azure AD app. The reason for this is I want every Site Collection admin to be able to script like this. Azure AD apps requires way to much permissions for the normal user.

    imageIn your site collection, navigate to /_layouts/15/appregnew.aspx. Click on both Generate buttons, so that you get one Client Id and one Client Secret. Next enter a Title, an App Domain and the Redirect URI. The App Domain and Redirect URI can be basically anything in this scenario. Then click Create to create the App Principal. On the next screen you will get all the details of your App. Copy and paste that data so you don’t loose it.

    Next head on over to /_layouts/15/appinv.aspx. Paste your Client Id in the App Id (Microsoft has never been good in naming conventions) text box and click Lookup. This will retrieve the rest of the app details. Since we will not have any UI or install any App we need to manually ask for permissions and then grant the permissions. What we do is that we create a permission request XML. Depending on your requirements your XML may be different from the one below. The following permission request XML asks for Full Read permissions on the whole web.

    <AppPermissionRequests AllowAppOnlyPolicy="true">
      <AppPermissionRequest
        Scope="http://sharepoint/content/sitecollection/web"
        Right="Read"/>
    </AppPermissionRequests>

    Note the AllowAppOnlyPolicy=”true” attribute – that one is the key to allowing the App to run without username and password. Once you paste the XML into the permission request XML textbox and then click on Create. You will see the Trust screen for your app. Make sure the permission request is what you expect and if so, click on Trust it!.

    Auth in PowerShell

    Now, let’s get to the core of this post and let’s create a PowerShell script that uses this app to read items from a list. I split it up in a few different parts to make it easier to follow. In the end of the post you will get a link to the full code sample.

    Defining some constants

    Let’s start by defining some constants:

    $clientId = "16119847-8ac7-4a3a-a2e5-18debd9fc9d2"
    $secret = "KuZj5UD22oy2.....=";
    $redirecturi = "https://localhost"
    
    $url = "https://tenant.sharepoint.com/sites/thesite/"
    $domain = "tenant.sharepoint.com"
    $identifier = "00000003-0000-0ff1-ce00-000000000000"
    
    

    The $clientId, $secret and $redirecturi are copied directly from the results of my app registration. The $url parameter is the URL of the site where I registered the app, and $domain is just the server part of that URL. Finally the $identifier is a static Guid value, which represents SharePoint (Exchange, Lync, Workflow etc has their own Id’s).

    Retrieving the Realm

    The next step is to retrieve the Realm or Tenant Id. You might already know this or you might just run these commands once and store it as a static variable.

    $realm = ""
    $headers = @{Authorization = "Bearer "} 
    try { 
        $x = Invoke-WebRequest -Uri "$($url)_vti_bin/client.svc" -Headers $headers -Method POST -UseBasicParsing
    } catch {
        #We will get a 401 here
          $realm = $_.Exception.Response.Headers["WWW-Authenticate"].Substring(7).Split(",")[0].Split("=")[1].Trim("`"")
    }
    

    What we do here is to send a request to the client.svc endpoint and actually expect to get thrown a 401 back. When we get the 401 we’ll locate the WWW-Authenticate headers and retrieve the Realm property. Yea, that PoSh line could be a bit more prettier and failsafe, but it works on my machine.

    Retrieving the access token

    When we have the realm we can create the authorization code. This is how we combine all our variables into an authorization code:

    [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
    $body = "grant_type=client_credentials"
    $body += "&client_id=" +[System.Web.HttpUtility]::UrlEncode( $clientId + "@" + $realm)
    $body += "&client_secret=" +[System.Web.HttpUtility]::UrlEncode( $secret)
    $body += "&redirect_uri=" +[System.Web.HttpUtility]::UrlEncode( $redirecturi)
    $body += "&resource=" +[System.Web.HttpUtility]::UrlEncode($identifier + "/" + $domain + "@" + $realm)
    

    Let’s walk this through. First of all I load the System.Web assembly, if you run this as a scheduled task this assembly is not loaded in your app domain, compared to when running it in PowerShell ISE for instance, and we need that assembly for some encoding.

    The actual authorization code starts with a grant_type which we set to the static variable of client_credentials, which means that we do not pass any user credentials or refresh tokens. Client_Id is not exactly the same Client Id as above, here we need to append “@” and the realm to scope the request to our tenant. The Client secret and redirect Uri is the same as when creating the app. Finally we have the resource token which is a combination of the SharePoint identifier, the domain and the realm. Note that if you’re targeting the anything in a Personal Site, you not only have to update the $url variable but also the $domain variable.

    We send all this data to the Azure Access Control Services (ACS), remember we did not use Azure AD, endpoint like this:

    $or = Invoke-WebRequest -Uri "https://accounts.accesscontrol.windows.net/$realm/tokens/OAuth/2" `
        -Method Post -Body $body `
        -ContentType "application/x-www-form-urlencoded"
    $json = $or.Content | ConvertFrom-Json
    
    When invoking the endpoint, using our authorization code above, we will get a JSON formatted string back. We convert this string into an object using ConvertFrom-Json.

    Use the access token

    Finally we can use the result from the ACS endpoint and get our access token which we’ll pass into the REST end point (as an Authorization Bearer token) of the site where we want to do operations.

    $headers = @{
        Authorization = "Bearer " + $json.access_token;
        Accept ="application/json"
    } 
    
    Invoke-RestMethod -Uri "$($url)_api/lists/GetByTitle('Documents')/Items" -Method Get -Headers $headers
    

    Summary

    That wasn’t to hard right? All we needed to know was the basic process of OAuth 2.0 and know how to create and pars the requests and responses. The full code sample can be found here: https://gist.github.com/wictorwilen/db67725a66a3e40789e3

  • SharePoint 2013: Using the App Only policy and App Principals instead of username and password combos

    Tags: SharePoint 2013, Apps

    Introduction

    One of the blog post I receive the most e-mails about is the How to do active authentication to Office 365 and SharePoint Online. Some of the feedback I get is “thank you” etc. and some of them are people that are modifying it for all kind of things, especially when trying to do “background jobs” or integrations using user credentials. And this is what this post is all about. My standard answer to that question is that you do not want to use the methods in that post for those scenarios, nowadays, since you can actually build an App for that. And even better you can build an App with a so called App Only policy – which means that we do not need to have any user credentials or anything like that. So in order to save me some time in replying that and then another reply on the “how do I do that?” question I can from now on only link to this post :-)

    Scenario

    Before we dig down to the actual nuts and bolts, let’s have a scenario in front of us. Assume we have a SharePoint site containing a product list (or similar). We would like an application/app/service/background job (you name it) to read and potentially write to this list. This is a very common scenario and traditionally this was built as timer jobs in SharePoint, or scheduled tasks running as specific users or even with hardcoded username and passwords (yikes!). In this sample we will instead use an App Principal, this is very much like a user principal which you can give permissions to in SharePoint.

    In this simple example I will use a site containing a list of products (two columns; Title and Price) and then an ASP.NET MVC web site that will show that list of products. An no, I will not build a SharePoint App, but instead show how you can take advantage of App Principals to get the products from SharePoint without using any user credentials whatsoever.

    Create the App Principal

    Register an App The first thing we would like to do once we have created our site and the list of products is to generate an App Principal with access to read from this list of products. This is done by navigating to your site and then appending /_layouts/15/AppRegNew.aspx to the URL so that you end up on the “Register an App” page. On that page click on the two Generate buttons to generate an App Id and an App Secret, then provide a Title for your App and the domain (localhost in this demo) for your app.

    Once that is done you will get a confirmation and a summary of the app identifier created. Screenshot this and/or copy and paste it so that you have the details, you will need them later.

    Give the app some permissonsNext we need to grant permissions to this app. This is done by navigating to /_layouts/15/AppInv.aspx. On that page paste your App Id (generated previously) into the App Id text box and click on the Lookup button, this will retrieve the details of the app and give us the opportunity to give the app some permissions.

    Giving the app permissions is not for the faint hearted and the UI is horrible (just like basically any admin UI in SharePoint). You need to write a valid app permission request XML. In this case I only want read rights to a specific list, nothing more, and I also want the app to be able to retrieve this data without any user credentials (App Only). The resulting XML looks like below, and the key thing is the AllowAppOnlyPolicy attribute:

    <AppPermissionRequests AllowAppOnlyPolicy="true">
      <AppPermissionRequest
        Scope="http://sharepoint/content/sitecollection/web/list"
        Right="Read"/>
    </AppPermissionRequests>

    When you click the Create button you will be taken to the “Do you trust” page, where you should trust your app. Since we requested to be able read from a list, we must also choose which list that we should read from. Once we’ve done that we click “Trust it”. One crappy thing is that if you would like to modify the permissions later, you need to re-write the XML completely since the UI does not retrieve the current requested permissions, so you need to document and save your XML.

    Trust the app!

    If you don’t want to study the app permission request schema I recommend you to look at this MSDN page which will give you some more insights.

    (Optional) High-trust apps for on-premises usage

    If you’re now doing this for on-premises deployments and do not have configured your farm for low-trust apps (integration with ACS), then you also need to register a high-trust app. To not repeat myself, you can use the same set of PowerShell that I used in the SharePoint 2013 with SAML Claims and Provider Hosted Apps blog post. Just make sure that you generate a new Issuer Id (which is not the same as the Client Id you got above when registering the app.

    Building the ASP.NET MVC site

    Now it is time to start building the consumer of this products list, in this case an ASP.NET MVC site (but it could be basically anything). Fire up Visual Studio 2013, create a new ASP.NET Web Application, then choose MVC and configure it as you like.

    App for SharePoint Web Toolkit NuGet packageThe first thing we need to do is to download a very sweet NuGet package. It is called “App for SharePoint Web Toolkit”. This “little” package will install the SharePoint 2013 client assemblies and also add the TokenHelper.cs and SharePointContext.cs files that you should be familiar with from a normal Provider Hosted SharePoint App.

    Update the web.config

    Before we start writing the code to retrieve the products from the SharePoint list we need to add some plumbing into the web.config. Depending on if you’re using ACS or using the High-Trust approach you need to add different configuration. For a low-trust approach you only need the first two lines (ClientId and ClientSecret that you got from AppRegNew.aspx) and for the high-trust approach you need all settings below, except the ClientSecret, and you also need to have the pfx file of the certificate used for the high-trust configuration.

    <add key="ClientId" value="d0ee6f6d-1c39-44b2-a284-f3143e820ec2"/>
    <add key="ClientSecret" value="11Flt0LME9mnToNhRN5nmgeynAXW3nMBvJBrIBGlT/o="/>
    
    <add key="ClientSigningCertificatePath" value="C:\temp\AppOnlySite.pfx" />
    <add key="ClientSigningCertificatePassword" value="Pass@word1" />
    <add key="IssuerId" value="93d08816-eb35-4ed9-be90-ea352cc81130" />
    

    Modifying the Home Controller

    To read the stuff from our SharePoint list I modify the Index action of the Home Controller so that it looks like this:

    public async Task<ActionResult> Index()
    {            
        Uri site = new Uri("https://intranet.sp01.contoso.com/sites/productlist");
        string realm = TokenHelper.GetRealmFromTargetUrl(site);
    
        // For use with ACS/SPO
        //var tokenResponse = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, site.Authority, realm);
        //var accessToken = tokenResponse.AccessToken;
                
        // High Trust
        var accessToken = TokenHelper.GetS2SAccessTokenWithWindowsIdentity(site, null);
                
        UriBuilder builder = new UriBuilder(site);
        builder.Path += "/_api/lists/GetByTitle('Products')/Items";
        builder.Query = "$select=Title,Price";
    
        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
    
        var response = await client.GetAsync(builder.Uri);
    
        var result = JsonConvert.DeserializeObject<ProductResponse>(await response.Content.ReadAsStringAsync());
    
        return View(result.Data.Results);
    }

    The first thing I do is to modify the method signature (#1) and declare it with the async keyword, so that I later can use the await keyword for the asynchronous operations. Then I use the TokenHelper class to retrieve the realm (#4)and the access token (#8 || #11). As you can see there are two different ways to retrieve the access token for an App Only principal, one when using ACS and one when using the High-Trust approach.

    Once I have the access token I build the REST URL (#13-15) and then create the HttpClient that I will use to invoke the REST end-point. On line #18 I specify that I want the data back in JSON format and on line #19 I pass the access token for authorization.

    Once that is all done we only need to invoke our HTTP client and retrieve the result. Once we have the result I use the JsonConverter to deserialize the data into a nice object structure (ProductResponse). In order to more easily work with the data returned I created these POCOs:

    public class ProductResponse
    {
        [JsonProperty("d")]
        public ProductResult Data { get; set; }
    }
    public class ProductResult
    {
        [JsonProperty("results")]
        public IEnumerable<Product> Results { get; set; }
    }
    public class Product
    {
        [JsonProperty("Title")]
        public string Title { get; set; }
        [JsonProperty("Price")]
        public float Price { get; set; }
    }

    The JsonConverter converts my JSON data into this object structure and I can easily then retrieve the actual Product results and return it my View.

    Modifying the View

    To display the set of products I use the built-in WebGrid in my Index View:

    <div class="row">
        <div class="col-md-4">
        @{
            WebGrid grid = new WebGrid(this.Model);
            @grid.GetHtml();
        }  
        </div>    
    </div>

    This will result in a grid view of my SharePoint products list like this:

    Wow, this dude has some serious UI skillz

    There you have it! This example can easily be extended with write operations or other stuff you would like to do, as long as you can express the requested permissions using the permission request XML.

    Summary

    In this post you have seen how we can leverage SharePoint data in other applications without using any user credentials and/or saved passwords. It requires minimal effort, especially when you’re using SharePoint Online (or ACS on-premises) since you only require Site Collection permissions to create the App Principal. All this thanks to the App Only policy.

  • SharePoint 2013 with SAML Claims and Provider Hosted Apps

    Tags: SharePoint 2013, AD FS, Claims, Windows Server 2012 R2, Apps

    Introduction

    The other week I posted an article about how to use SharePoint Hosted Apps when using SAML Claims, I did not expect that amount of feedback I had on that blog post, in e-mail, comments, tweets etc. Some of that feedback was how do you do it with Provider Hosted apps. Well you’re about to find out. It took me a while to get it properly done and there are some things that you should be aware of. In this post I will walk you through the simplest scenario and you will notice that there are a couple of moving parts. But, since I am such an influencer I thought I should make it easier for you. I will show you how to do this without the minimal changes to your current provider hosted apps – you only have to add an extension file to your solution, make a small modification to the helper files that Visual Studio gives you and a couple of web.config modifications! All the code you need will be published in a Github repository (https://github.com/wictorwilen/SharePointContextSaml) for you to consume and do all the fancy gitty stuff that you code dweebs out there like.

    Let’s get started, bare with me this is a long post and for some of you the first parts might be just a repeat of what you’ve seen/done previously…

    Creating a Provider Hosted High Trust App

    The first thing we need is to create us a High Trust Provider Hosted App. That is an app that does not run in SharePoint and is using the Server to Server (S2S) protocol for authorization. In my case (and it should be yours as well if you want to use my helper code) is to use Visual Studio 2013 and create a SharePoint App, choose a provider hosted app using the ASP.NET MVC template. To create a High Trust App we then need to specify a certificate for the S2S trust. This is how you can create a cert using makecert.exe and some PowerShell. In the script below all you need to do is modify the four properties; domain, name and password of cert and the location where we will store the certificate files:

    #ALIASES
    set-alias makecert "C:\Program Files\Microsoft Office Servers\15.0\Tools\makecert.exe"
    
    # CREATE SELF SIGNED DEV CERTS
    $domain = "localhost"
    $certName = "HightTrustSAMLDemo" 
    $password = "Pass@word1"
    $dir = "c:\HighTrustCerts\"
    
    New-Item $dir -ItemType Directory -Force -Confirm:$false | Out-Null
    
    $publicPath = $dir + $certName + ".cer"
    $privatePath = $dir + $certName + ".pfx"
    
    makecert -r -pe -n "CN=$domain" -b 01/01/2012 -e 01/01/2022 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sy 12 -sp "Microsoft RSA SChannel Cryptographic Provider" $publicPath 
    
    $publicCert = Get-PfxCertificate -FilePath $publicPath
    $publicThumbprint = $publicCert.Thumbprint
    
    Get-ChildItem Cert:\LocalMachine\My | 
        Where-Object {$_.Thumbprint -eq $publicThumbprint} | 
        ForEach-Object {
            $_.Export("PFX",$password) |Set-Content $privatePath -Encoding Byte        
        }

    Once we have the certificate we need to install the certificate in the SharePoint certificate store as well as register a Trusted Security Token Issuer. And to do this we need a Guid! You can use any preferred tool to generate your Guid or generate and register your very own unique Guid at www.vanityguid.com. Here’s a script the does the trick; give it your very own unique Guid/Issuer Id and a unique display name:

    $issuerId = '17721805-67c2-46ba-92d1-fd1fdf91bb01' # MUST BE UNIQUE
    $displayName = "High Trust SAML Demo" # MUST BE UNIQUE
    
    Add-PSSnapin Microsoft.SharePoint.PowerShell -EA 0
    $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($publicCert)
    
    New-SPTrustedRootAuthority -Name $certName -Certificate $certificate
    $realm = Get-SPAuthenticationRealm
    $fullIssuerId = $issuerId + "@" + $realm
    
    New-SPTrustedSecurityTokenIssuer -Name $displayName -Certificate $certificate -RegisteredIssuerName $fullIssuerId –IsTrustBroker
    iisreset 

    Yes I trust Wictor!Ok, this was standard High Trust App procedure. Copy and paste the issuer Id into the Visual Studio wizard and enter the certificate details to complete the app creation. What you have right now is a standard High Trust app ready to work with Windows (claims) users. Before you start hacking in some code into this app – just make sure that it properly deploys and executes (ie press F5), so that you haven’t messed up any Guids or anything else. This app should now run using IISExpress and it uses Windows Authentication (remove http(s)://localhost from Local Intranet sites in Internet Explorer if you want to test different users).

    What about them SAML users?

    So let’s see what happens if we log into our SharePoint Developer site, where we deployed our High Trust app, as a SAML user (using for instance AD FS 3.0). Of course you need to setup a trusted identity token issuer before doing that, how that’s done is out of scope of this post. When logged in as a SAML user and I click on the High Trust App I either get logged into the app as the currently logged on Windows user or I get the Windows login dialog (if http(s)://localhost was removed from Local Intranet sites). So, it doesn’t really work! We don’t even get the chance of authentication with our AD FS (or similar federation service).

    Configuring the app for federated Authentication

    ASP.NET devs get all the new shiny stuffWhat we need to do is modify our web application (the provider hosted web) to use federated authentication. Unfortunately we are SharePoint developers, and are not given all the love that ordinary ASP.NET developers are from the Visual Studio team. When creating a standard ASP.NET project we get the really awesome option of specifying which authentication method we would like to use and we can point out our federation service and Visual Studio fixes everything for us.

    We can do this in two different ways. Either we add a new ASP.NET MVC project and remove the default web project and convert that ASP.NET MVC project into a SharePoint app project (which is the easiest way) or we start fiddling with web.config and configure it ourselves – which is exactly what we’re going to do here!

    The first thing we need to do is to use NuGet and add the Microsoft ASP.NET Identity Core package and the Microsoft Token Validation Extension for .NET 4.5. These package will give us all the assemblies and references we need to run the app.

    NuGet FTW!

    In your web application project open up web.config, now we’re going to do some copy-paste work! First of all we need to add a configSections element for the System.IdentityModel. Insert the snippet below directly after the configuration element:

    <configSections>
      <section name="system.identityModel" 
        type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
      <section name="system.identityModel.services" 
        type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    </configSections>

    Then head on over to the system.web element and below the authorization element add the following.

    <authentication mode="None" />  

    This means that we’re not letting ASP.NET do the Authentication, but instead handling it over to a new module which we’re going to add. Directly after the system.web element copy and paste the following, which will add two new modules to the ASP.NET pipeline:

    <system.webServer>
      <modules>
        <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
        <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      </modules>
    </system.webServer>
    These two modules are called WSFAM and SAM (two more acronyms for you JB). WSFAM is responsible for the login/logout process and SAM takes care of session management by using cookies.

    Then we need to add the configuration for our Relying Party. This is done by adding the system.identityModel element after the system.serviceModel element. It’s a handful of configuration and we need to modify it in a few places to match our app and our federation service.

    <system.identityModel>
      <identityConfiguration>
        <audienceUris>
          <add value="uri:SharePoint:App:SAML" />
        </audienceUris>
        <securityTokenHandlers>
          <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
        </securityTokenHandlers>
        <certificateValidation certificateValidationMode="None" />
        <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
          <authority name="fs.contoso.com">
            <keys>
              <add thumbprint="EF66CEF27067637D296C403691DBBE2A8B5C7BAA" />
            </keys>
            <validIssuers>
              <add name="http://fs.contoso.com/adfs/services/trust" />
            </validIssuers>
          </authority>
        </issuerNameRegistry>
      </identityConfiguration>
    </system.identityModel>

    First of all on line #4 – that row must contain the relying party identifier for our app registered in AD FS. I prefer using a URI, since that makes it easier when I need to deploy this into production, but you could use the URL of your web application (https://localhost:44305/ for instance). I’ll show you in just a minute how to configure this in AD FS. Line 12 should contain the name of our authority and line 17 must have the Federation Service Identifier of AD FS (found under Federation Service Properties in the AD FS Console). On line 14 we need to specify the thumbprint of the AD FS Token-signing certificate (you’ll find that easy in the AD FS Console under Service/Certificates).

    Ok, only one more thing to fiddle with in the web.config.

    <system.identityModel.services>
      <federationConfiguration>
        <cookieHandler requireSsl="true" />
        <wsFederation passiveRedirectEnabled="true"
          issuer="https://fs.contoso.com/adfs/ls/"  
          realm="uri:SharePoint:App:SAML" 
          requireHttps="true" />
      </federationConfiguration>
    </system.identityModel.services>

    Here there are two things we need to modify. First of all we need to point to the SAM/WS-Federation endpoint of AD FS, the login page, that Url is set in the issuer property of the wsFederation element. Secondly we must add the realm of our app – which should be the same as the audienceUri specified above. As I said earlier, I use a URI instead of the web application Url.

    A quick note here as well, notice that I use HTTPS and SSL all the way. For my SharePoint web application and for my app web application. If you prefer to be sloppy you can still use HTTP but that requires some extra work in SharePoint and the app web application config.

    Let’s take our High Trust App for a ride! Press F5 to get the app up and running. Doesn’t work…well some of it do. You should now be taken to the AD FS login page, but that one will just tell you an error occurred and the details doesn’t give much of a hint. You have to take a look in the AD FS server and the event log for AD FS. The error message is pretty clear on what we haven’t done yet:

    MSIS7007: The requested relying party trust 'uri:SharePoint:App:SAML' is unspecified or unsupported. 
    If a relying party trust was specified, it is possible that you do not have permission to 
    access the trust relying party. 
    Contact your administrator for details.
    

    Yes, we haven’t created our Relying Party Trust yet.

    Creating the Relying Party Trust in AD FS

    Claims rulesNow we need to create our Relying Part Trust in AD FS, it’s pretty straightforward, but comes with a couple of caveats. Add a new Relying Party Trust and choose to enter data manually, then give the trust a display name (I prefer to use the realm here). Continue by choosing to use the AD FS Profile, skip the certificate page in the wizard, and then select to enable support for the WS-Federation Passive protocol and enter the URL of your App. On the next page add a new identifier and now use the realm of your app, then just keep on clicking Next until you’re done. Once you’re done with creating the Relying Party Trust a new dialog will open up in AD FS in which you need to create Claims Rules for this new trust. This is a very important step, you need to get the rules correct and include the correct claims. In this case I will add two claims. One which augments the E-Mail claim from Active Directory (LDAP) for my Active Directory users and one which will just pass through the E-Mail claim from my third party Identity Provider (Thinktecture Identity Server). You have to pass either E-Mail, SIP address or UPN to get this to work. SharePoint needs at least one of those claims to be able to rehydrate the user from the User Profile Service Application.

    Once that is done, go back to your App and start it again using F5. Now logon using one of the Active Directory, use some other account than the one you are currently logged on to your machine as (otherwise you’ll think you are home safe already). You should see the default ASP.NET MVC SharePoint App page which says “Welcome Someone”, where Someone is the name of the logged in user. But what! That’s not the name of the account you logged in using? You can easy check that you are actually properly logged in using AD FS by setting a break point in the HomeController.cs in the Index action and take a look at some watches. You can clearly see that we are authenticated through federation and you’ll see the e-mail claim for that user who authenticated through AD FS, but the identity shown is the wrong one!

    Visual Studio Baby!

    Well, it turns out that the SharePointContext.cs and TokenHelper.cs classes that the Visual Studio and Office Dev team so kindly wrote for us only works with Windows Claims for High Trust apps. Bummer!

    Steve Peschka to the rescue!

    I barely gave up when I hit this, but my Bing-fu found a single blog post by Steve Peschka (who knew!) called “Using SharePoint Apps with SAML and FBA Sites in SharePoint 2013” who solved my problems, almost. This post of Steve was written some time ago when the TokenHelper.cs class looked very different and it forced you to make modifications to your app to support federated users. So I took his example code and modified it to fit the new helper classes provided by Visual Studio 2013 and made them in such way that you do not have to re-write your apps and packaged it into a single .cs file; SharePointContextSaml.cs. I will NOT post the entire thing here, since it is a lot of code. But if you’re like me you should read through it, it gives you tons of knowledge on how the app authorization actually works beneath the hood.

    So you just download the .cs extension file and add to your app web application project and then you have to do a couple of tweaks to your app configuration and to the default TokenHelper.cs and SharePointContext.cs files. This is how you do it.

    1) After you copied the SharePointContextSaml.cs file into your project, modify the namespace of that file to match the namespace of your project.

    2) Modify the default TokenHelper.cs class declaration so that the TokenHelper class is a partial class declaration, we need this to be able to extend the TokenHelper class. (This declaration should have been there by default imho!)

    public static partial class TokenHelper {...}

    3) In the SharePointContext.cs file locate the static constructor for the SharePointContextProvider class and modify it so it looks like below. This is needed so that we can use our custom context provider if the user is authenticated through federation.

    static SharePointContextProvider()
    {
        if (!TokenHelper.IsHighTrustApp())
        {
            SharePointContextProvider.current = new SharePointAcsContextProvider();
        }
        else
        {
            if(HttpContext.Current.User.Identity.AuthenticationType == "Federation") {
                SharePointContextProvider.current = new SharePointHighTrustSamlContextProvider();
            } else {
                SharePointContextProvider.current = new SharePointHighTrustContextProvider();
            }
        }
    }

    4) Finally we need to add three entries to the appSettings in web.config:

    <add key="spsaml:ClaimProviderType" value="SAML"/>
    <add key="spsaml:TrustedProviderName" value="High Trust SAML Demo"/>
    <add key="spsaml:IdentityClaimType" value="SMTP"/>

    The first entry is used to tell our custom context provider that we use SAML claims (there is support for Forms based authentication, value = FBA, in the extensions that Steve originally wrote but I have not yet tested it at all in my edition, and personally I prefer using something like IdentityServer instead of FBA). The second entry must be the name of the Trusted Security Token Issuer that you created using PowerShell for your app. And finally we need to specify what claim we will extract and use as identity claim; possible values are SMTP (e-mail), SIP or UPN.

    Yet another hobbit e-mailLet’s try to run the app once again. Most likely you will be able to logon but then you get an exception in the HomeController, an access denied. Then you need to check two things. First make sure that the user that you’re logging in with have permissions on your site. Since we’re talking about SAML claims here the people picker behaves a bit differently, enter the e-mail address of the user and make sure to choose the e-mail claim name (hover the mouse over the suggested options to see the claim type). Secondly you must make sure that the user has the WorkEmail attribute in the user profile store populated. This can be done either by using the User Profile Synchronization, if you’re authenticating with an Active Directory or LDAP source. But if you’re using some other IdP, for instance IdentityServer that I use here, you must add the WorkEmail manually through PowerShell or some other method. Once that is done you should see a nice and warm welcome to your SAML claims user!

    That’s it! All you need to do to enable SAML Claims user for your SharePoint 2013 High Trust App.

    Show me the codez!

    I’ve created a Github repository to host the SharePointContextSaml.cs file, you can find it here: https://github.com/wictorwilen/SharePointContextSaml

    I’d really like to get feedback in form of features, bugs, fixes etc. Please use the issue feature on Github, instead of e-mailing me…

    Currently it is not documented at all, there are some comments; a mix of mine and Steves original ones.

    I’d like to maintain it as long as possible, but my hope is that the Office Dev Team picks this up and do some proper testing and then merges this with the default Visual Studio helper files. Well, one can at least wish!

    Summary

    Yet another long blog post. I really hope I didn’t miss anything, there’s quite a few step once you do this the first time. I’ve shown you the complete example here; how to create and register a high trust SharePoint 2013 app, how to convert the default MVC project to a Claims based web application, registering a Trusted Relying Party in AD FS and then finally adding the new SharePointContextSaml.cs file and enabling you to use federated users in your Provider hosted app. Good luck to you all and thanks Steve for doing all the hard work!

  • SharePoint 2013 with SAML Claims and SharePoint Hosted Apps

    Tags: SharePoint 2013, AD FS, Claims, Windows Server 2012 R2, Apps

    Introduction

    By now each and every SharePoint developer out there should spend their time building SharePoint Apps instead of the old trusted friend of ours; Full Trust Code. Ok, Apps doesn’t solve the equivalent of world hunger in SharePoint at the moment, but that’s a discussion for another time. I assume you get my point. We have two types of apps (we used to have three little monkeys jumping in the bed, but one just bumped his head); Provider hosted apps and SharePoint hosted apps. Without going into details, Provider hosted apps are the apps that are hosted outside of SharePoint on a specific location (URL) and SharePoint hosted apps are running on top of SharePoint (using JavaScript) on a “random” location. This location is called the App Web and is a SharePoint SPWeb with a specific randomly generated URL. That URL could look something like this:

    https://app-2d4f884a19b8e8.apps.sp03-apps.com/sites/dev/SharePointApp1

    In that URL the first part is something that is randomly generated for each and every instance and deployment of that App. That is why we are required to use a Web Application listening on all incoming host headers, SAN wildcard certificates and users are also required to log in if we’re using Windows Authentication and the base App URL isn’t in the Local Intranet Zone.

    There is also another interesting issue specifically when we are using SAML Claims Authentication. Originally this did not work at all with SharePoint and specifically not with AD FS 2.0. One of the requirements of running SharePoint hosted apps with SAML claims is that the identity provider, IdP. (AD FS for instance) supports a wildcard return URL and that it uses the wreply parameter [Source]. Whenever you are trying to authenticate with the app you have to visit the IdP to get your claims and then be redirected back to the app, which is on a “random” URL. Using AD FS 2.0 you have to add a relying party trust for each and every app instance (something your IT people really enjoy doing).

    Fortunately all this is resolved in AD FS 3.0 that is shipped with Windows Server 2012 R2! Let’s take a look on how to set it up!

    Configure AD FS 3.0

    The first thing we need to do is to configure our AD FS 3.0 service. I assume you already have set up and installed AD FS 3.0 on a Windows Server 2012 R2 and that you have Claims authentication working for normal SharePoint sites. If you haven’t come this far yet please take a look at Steve Peschkas end-to-end guide for this, its for SharePoint 2010 and AD FS 2.0 but everything is almost the same.

    Here’s our scenario: We’re having one Web Application hosting both the Intranet (intranet.sp03.contoso.com) and the My Site host (mysite.sp03.contoso.com). We would like users with Windows Claims and SAML Claims with users from Active Directory and a third party to be able to use SharePoint Hosted Apps.

    The traditional way of setting it up in AD FS is to create two Relying Party Trusts; one for the Intranet and one for the My Site, like this:

    AD FS Relying Party Trusts

    Each Relying Party Trust has its unique realm. In this case urn:sharepoint:contoso:sp03:intranet and urn:sharepoint:contoso:sp03:mysite. And on our Trusted Identity Token Issuer in SharePoint we specify an additional Realm for the My Site, which could look similar to below:

    $tit = Get-SPTrustedIdentityTokenIssuer fs.contoso.com
    $tit.ProviderRealms.Add( (New-Object System.Uri("https://mysite.sp03.contoso.com")), 
      "urn:sharepoint:contoso:sp03:mysite")
    $tit.Update()

    It’s a pretty straightforward approach and works fine.

    But there is a much better way. Let’s get rid of this additional Relying Party Trust in AD FS and remove the additional Realm on the Trusted Identity Token Issuer. Well that doesn’t work! Now we get “An error has occurred” when trying to log in to the My Site. Fortunately it is very easy to fix.

    First head on over to AD FS and your (now single) Relying Party Trust and choose to edit its Properties. In the properties dialog choose the Endpoints tab and then choose to add a new endpoint by clicking on “Add WS-Federation”. As the Trusted URL type in your My Site host URL and add /_trust/ at the end. Once you click OK it should look something similar to this.

    Relying Party Trust Properties

    Finish it all by clicking OK. If you now try to log you will still see the same error, and if you take a look at the URL you’re being redirected back to you will see that you are redirected to the Intranet URL, which is the Default endpoint for the Relying Party Trust. So we have to do one more thing to get it to work, and this time on the SharePoint side. We need to tell SharePoint to use the WS-Fed wreply parameter.

    From the WS-Fed specification: wreply: This optional parameter is the URL to which responses are directed. Note that this serves roughly the same purpose as the WS-Addressing <wsa:ReplyTo> header for the WS-Trust SOAP RST messages

    Use the following PowerShell script to modify the Trusted Identity Token Issuer to use the wreply parameter:

    $tit = Get-SPTrustedIdentityTokenIssuer fs.contoso.com
    $tit.UseWReplyParameter = $true
    $tit.Update()

    Now! Let’s try to log in to the My Site once again using one of the providers we have configured in AD FS. If you have given the correct permissions to the user on the My Site host you will actually see it load and you’re golden.

    What about them Apps?

    Ok, I know I told you that this post was about getting SharePoint hosted apps to work with SAML Claims and I’ve only shown you how to log on to the My Site. Well, you see if you get this to work there is very little extra you have to do to get the SharePoint Hosted Apps to work. If I now was logged in as a SAML Claims user on the My Site and decided to install an app onto My Site (or any site for that matter), once I try to open the app I will get “An error has occurred on the server” and I will be redirected to the Intranet site.

    Just as we did get redirected to the Intranet site when not having the additional Endpoint on the Relying Party trust the same will happen with SharePoint Hosted Apps. The SharePoint Hosted Apps lives in these “random” App URLs and AD FS has no idea on how to and where to redirect the user after trying to authenticate on one of those. Now we have two options; add an endpoint for each and every single instance of our SharePoint Hosted Apps or…in AD FS 3.0 use a wildcard endpoint! Let’s try that!

    Just as we added the My Site endpoint to the Relying Party Trust let’s add our App Domain as en endpoint. The URL we need to add as a passive endpoint is formatted like this (of course you should use the app domain that you have configured in your SharePoint environment):
    https://*.apps.sp03-apps.com/_trust

    Notice that I use a * (star) as the wildcard character at the position where the randomly generated app id is used. It is required that you already have configured the Trusted Identity Token Issuer to use the wreply parameter like we did above, without that you will still get redirected to the default endpoint.

    Once done your Relying Party Trust should look like this:

    The App wildcard Endpoint

    If you now install and/or browse to a SharePoint Hosted App within your environment you will get prompted to authenticate and once that is done you should see your app. The picture below shows a user, stored in a third party IdP federated with AD FS, that has installed the default Visual Studio demo SharePoint Hosted App onto his My Site.

    Just another crappy app

    Note: Not a single iisreset was required to set this up! That doesn’t happen often!

    Summary

    In this post I have shown you how to configure AD FS 3.0 in Windows Server 2012 R2 to use a wildcard redirection endpoint to support Claims users to use SharePoint Hosted Apps in SharePoint 2013. A combination of new features in AD FS 3.0 and correct configuration in SharePoint 2013 was all that was needed.

About Wictor...

Wictor Wilén is the Nordic Digital Workplace Lead working at Avanade. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for seven consecutive years.

And a word from our sponsors...