Configuring High Trust Apps for SharePoint 2013

Home » SharePoint Development » Configuring High Trust Apps for SharePoint 2013

Configuring High Trust Apps for SharePoint 2013

Posted on

The SharePoint 2013 Application Model supports app development for both cloud and on-premise environments; however, there are distinct differences between the two implementations. In the cloud, apps rely upon an external authorization process to validate that an application hosted outside of SharePoint – in a vendor’s data center, for example – is allowed to communicate with the SharePoint site where the app has been deployed. Within the enterprise, it is unlikely that an authorization server will be present or even necessary; rather, apps developed and deployed internally are assumed to have "high trust". In order to facilitate a high trust relationship in the absence of a pre-configured authorizing entity, a specific set of configuration tasks must be performed for each app that will be deployed.

The following steps outline the process for creating a provider-hosted app (one that runs outside of SharePoint but within the same enterprise) and configuring it for high trust. ASP.NET developers should be familiar with most of the initial non-SharePoint steps; however, there are some specific requirements that can cause app deployment to fail if not performed in the right order so even basic tasks have been included. Some tasks are optional or up to the developer’s discretion, such as the publishing method used for a standard ASP.NET web site, but others, like the PowerShell configuration commands for creating a trusted token service, must be performed as indicated. The example does not include the user of JavaScript-based SharePoint chrome elements – for more information on how to add basic SharePoint 2013 look and feel to remote web applications refer to How To: Use the Client Chrome Control in Apps for SharePoint on MSDN.

Note: Before attempting to create apps for SharePoint 2013 be sure to review the MSDN guidelines on setting up an on-premise development environment.

 

1 

Create a Remote Web Project

 

The first step is to create a remote web application that users will be redirected to when they click on the app tile in a SharePoint 2013 site. In development, this site will likely be deployed as a disk-based web to the same server; however, in production, it is more likely that SharePoint and the remote web will not exist in the same farm or even in the same network.

 

In Visual Studio 2012, create a new ASP.NET Empty Web Application.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Add a default page to the project.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Modify the web.config file to support Windows authentication.

 

<configuration>

<appSettings>

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

<add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms" />

</appSettings>

<system.web>

<compilation debug="true" targetFramework="4.5" />

<httpRuntime requestValidationMode="4.5" targetFramework="4.5" encoderType="System.Web.Security.AntiXss.AntiXssEncoder, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

<pages controlRenderingCompatibilityVersion="4.5" />

<authentication mode="Windows" />

<authorization>

<allow users="*" />

</authorization>

<machineKey compatibilityMode="Framework45" />

</system.web>

</configuration>

 

2 

Publish the Remote Web Site

 

Once the project has been created there are several options for making it accessible to users. In this instance the project will be published as a disk-based web, a process familiar to most ASP.NET developers.  

Create an IIS web site (remember to set the Application Pool to use the .NET v4.0 framework instead of v2.0).

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Publish the remote web to the web site.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Create a new publishing profile.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Publish to the file system, specifying the directory and URL. Remember to create a DNS or host entry for the site URL prior to publishing in order to verify that the site is reachable after publishing is complete. Ideally, a fully qualified domain name should be used for the destination URL.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Publish the web application.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

3 

Configure Remote Web Authentication (Part 1)

 

In most cases, setting Windows authentication on the web application via web.config is sufficient; however, when creating a remote web for a provider hosted SharePoint app, there are some configuration steps which need to take place before the app can be accessed by users. In order to complete these tasks the web application must also have anonymous authentication enabled. Once configuration is complete anonymous can be disabled.  

Enable both Windows and anonymous authentication on the published web application. Depending upon your environment, it may also be necessary to promote NTLM above Negotiate as the preferred provider.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

4 

Create a Remote Web Certificate

 

SharePoint 2013 requires that all apps run over HTTPS. Apps may also run on HTTP (if, for example, they are also accessed by users outside of SharePoint) but they must have a certificate and SSL binding in order to proceed with app configuration. In development, it is acceptable to use a self-signed certificate; however, this should be replaced with a full certificate when the application is migrated to production.  

Create a self-signed certificate.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

The newly created certificate will be required in later configuration steps. Export the certificate to the remote web application and include it in the Visual Studio project. The certificate must be secured with a password.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Add certificate settings to the web.config file in the appSetttings section.

 

<appSettings>

<add key="ClientSigningCertificatePath" value="c:\inetpub\wwwroot\ContosTestWeb\ContosoTestCertificate.pfx" />

<add key="ClientSigningCertificatePassword" value="password" />

</appSettings>

 

Edit the bindings of the web site and apply the certificate. Assuming that other web sites are running on the same machine, it will probably be necessary to create a secondary IP address and assign ports 80 and 443 to that address. In addition, the site should use a fully-qualified domain name, such as "contosotestweb.contoso.com" instead of just "contosotestweb" (remember to add a host entry on the machine for the FQDN).

 

5 

Create a Remote Web Metadata Document

 

Configuring a remote web for SharePoint trust involves the execution of PowerShell commands to create a new SPTrustedSecurityTokenService (as detailed in Step 12). In order for these commands to succeed, an HTTP Handler class must exist in the remote web. This class relies upon the certificate and web.config settings from Step 4.  

Add a Generic Handler to the remote web project.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Add the following reference to the remote web project:

 

System.Runtime.Serialization

 

Replace the contents of the MetadataDocument.ashx.cs file with the following code (substitute the correct namespace):

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Runtime.Serialization.Json;

using System.IO;

using System.Text;

using System.Security.Cryptography.X509Certificates;

using System.Web.Configuration;

using System.Runtime.Serialization;

 

namespace Contoso.TestWeb

{

public class MetadataDocument : IHttpHandler

{

#region IHttpHandler Members

 

public bool IsReusable

{

get { return true; }

}

 

public void ProcessRequest(HttpContext context)

{

if (null == context ||

null == context.Request ||

null == context.Request.QueryString ||

null == context.Response)

{

throw new ArgumentNullException("context");

}

 

string realm = context.Request.QueryString["realm"];  

JsonMetadataDocument document = GenerateMetadataDocument(realm);  

string responseText = Serialize(document);  

HttpResponse response = context.Response;

response.ContentType = "application/json";

response.Write(responseText);

response.Flush();

}

 

#endregion

 

private static string Serialize(JsonMetadataDocument metadataDocument)

{

if (null == metadataDocument)

{

throw new ArgumentNullException("metadataDocument");

}

 

string serializedDocument = null;

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(metadataDocument.GetType());

 

using (MemoryStream stream = new MemoryStream())

{

jsonSerializer.WriteObject(stream, metadataDocument);

serializedDocument = Encoding.UTF8.GetString(stream.ToArray());

}

 

return serializedDocument;

}

 

private static void AddCertificiateToMetadata(

JsonMetadataDocument metadataDocument,

X509Certificate2 certificate)

{

if (null == metadataDocument)

{

throw new ArgumentNullException("metadataDocument");

}

 

if (null == certificate)

{

throw new ArgumentNullException("certificate");

}

 

metadataDocument.Keys.Add(CreateKeyMetadata(certificate, SPSecurityTokenServiceJsonMetadataKeyUsage.Signing));

}

 

private static JsonMetadataKey CreateKeyMetadata(X509Certificate2 certificate, SPSecurityTokenServiceJsonMetadataKeyUsage usage)

{

if (null == certificate)

{

throw new ArgumentNullException("certificate");

}

 

JsonMetadataKey keyMetadata = new JsonMetadataKey

{

Usage = usage.ToString(),

KeyValue = new JsonMetadataKeyValue

{

Type = "x509certificate",

Value = Convert.ToBase64String(certificate.Export(X509ContentType.Cert))

}

};

 

return keyMetadata;

}

 

private static JsonMetadataDocument GenerateMetadataDocument(string realm)

{

JsonMetadataDocument metadataDocument = new JsonMetadataDocument();  

metadataDocument.ServiceName = metadataDocument.Name = HostedAppName;  

metadataDocument.Realm = realm;  

metadataDocument.Keys = new List<JsonMetadataKey>();

X509Certificate2 clientCertificate = new X509Certificate2(ClientSigningCertificatePath, ClientSigningCertificatePassword);

AddCertificiateToMetadata(metadataDocument, clientCertificate);  

return metadataDocument;

}

 

private static readonly string HostedAppName = WebConfigurationManager.AppSettings.Get("ClientId");

private static readonly string ClientSigningCertificatePath = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePath");

private static readonly string ClientSigningCertificatePassword = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePassword");

 

[DataContract]

private class JsonMetadataDocument

{

[DataMember(Name = "serviceName", EmitDefaultValue = false)]

public string ServiceName { get; set; }

 

[DataMember(Name = "name", EmitDefaultValue = false)]

public string Name { get; set; }

 

[DataMember(Name = "realm", EmitDefaultValue = false)]

public string Realm { get; set; }

 

[DataMember(Name = "issuer", EmitDefaultValue = false)]

public string Issuer { get; set; }

 

[DataMember(Name = "keys", EmitDefaultValue = false)]

public List<JsonMetadataKey> Keys { get; set; }

}

 

[DataContract]

private sealed class JsonMetadataKey

{

[DataMember(Name = "usage", EmitDefaultValue = false)]

public string Usage { get; set; }

 

[DataMember(Name = "keyValue", EmitDefaultValue = false)]

public JsonMetadataKeyValue KeyValue { get; set; }

}

 

[DataContract]

private sealed class JsonMetadataKeyValue

{

[DataMember(Name = "type", EmitDefaultValue = false)]

public string Type { get; set; }

 

[DataMember(Name = "value", EmitDefaultValue = false)]

public string Value { get; set; }

}

 

private enum SPSecurityTokenServiceJsonMetadataKeyUsage

{

Signing,

RootSigningCertificate,

}

}

}

6 

Configure Remote Web for OAuth/S2S

 

The SharePoint 2013 app model relies upon the OAuth protocol for authorization. OAuth integration for SharePoint and Office apps is made possible via the Azure Connect Service. Although it is certainly possible for an on-premise environment to make use of ACS it is unlikely that an organization will have this in place or will be implementing it in the near future. This is one distinct advantage of deploying remote apps to Office365 – OAuth and ACS are already configured and available to developers without any additional effort or investment. In order to facilitate on-premised deployments without ACS, Microsoft makes a fallback configuration available known as "Server to Server". This allows specific entities, such as web applications, to be explicitly trusted for authorization and is the crux of the entire High Trust Configuration method described in this guide.  

For those who are interested in learning the details of how the OAuth authorization process functions with SharePoint 2013 apps, the following graphic provides a high-level summary:

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

More information is available at: http://msdn.microsoft.com/en-us/library/fp142382(v=office.15).aspx  

The code to handle S2S authorization and client context initialization is somewhat complex; fortunately, Microsoft has provided sample code in the form of a C# class which abstracts the underlying methods and leaves developers free to concentrate on implementation of the process. To enable the remote web to handle S2S authorization, begin by adding the following references to the project:

 

System.IdentityModel

System.IdentityModel.Selectors

Microsoft.IdentityModel

Microsoft.IdentityModel.Extensions

Microsoft.SharePoint.Client

Microsoft.SharePoint.Client.Runtime

 

The SharePoint client DLL’s can be found in the following directory:

 

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI

 

The Microsoft.IdentityModel DLL’s can be found in the following directories:

 

C:\Windows\assembly\GAC_MSIL\Microsoft.IdentityModel\3.5.0.0__31bf3856ad364e35

C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.IdentityModel.Extensions\

v4.0_2.0.0.0__69c3241e6f0468ca

 

Copy the TokenHelper.cs file from the SharePoint 2013 samples on MSDN (http://code.msdn.microsoft.com/sharepoint/) into the remote web project (substitute the correct namespace). It will then be necessary to edit the default.aspx.cs file to handle incoming traffic from SharePoint, calling out to the TokenHelper methods to handle authorization and establish context.  

When a user clicks on an app tile in SharePoint, the ensuing request takes the form of either a POST (in Office365 with full OAuth present) or a GET with a specific set of parameters. These parameters, specified in the app manifest file (Step 10), provide the remote web with the host and appweb URL’s in SharePoint. If the operation is a POST the parameters will also include the token provided by ACS. In an on-premise implementation, there is no token so the process falls back to using the windows identity of the requestor to establish context (via the GetS2SClientContextWithWindowsIdentity method in TokenHelper.cs).  

As the remote web runs on an accessible port reachable from outside SharePoint, pages in the app should handle establishment of context for each user and catch those instances where a user is not authorized to access resources in SharePoint. As a simple example, the following code, when added to the Page_Load event of default.aspx.cs, will attempt to establish context, displaying an error message if the user is not authorized (the attempt to establish context fails):

 

try

{

string hostTitle = string.Empty;

Uri spUrl = null;

 

foreach (string key in Request.QueryString.Keys)

{

if (key == "HostUrl" || key == "SPHostUrl")

{

spUrl = new Uri(Request.QueryString[key]);

break;

}

}

 

ClientContext clientContext = null;

clientContext = TokenHelper.GetS2SClientContextWithWindowsIdentity(spUrl, Request.LogonUserIdentity);

clientContext.Load(clientContext.Web);

clientContext.Load(clientContext.Web.CurrentUser);

clientContext.ExecuteQuery();

hostTitle = clientContext.Web.Title;

Response.Write("Successfully authorized for: " + hostTitle);

}

catch (System.Exception ex)

{

Response.Write(ex.Message);

}

 

*Note: Be sure to include a using statement for Microsoft.SharePoint.Client

 

At this stage, the application should return an "Object reference not set to an instance of an object" error as the SPHostUrl parameter is null. Proper context will be established once the app is accessed from SharePoint; however, it is important to point out that this process may have a detrimental impact to applications which are being ported to the app model but still need to be accessed outside of SharePoint. It is also worth noting that the above sample is very simple – developers will want to account for various scenarios in production code, such as persisting tokens and/or context so as not to make repeated calls back to SharePoint, porting to Office365 and processing of actual token values, etc.

 

7 

Create a Developer Site

 

SharePoint 2013 contains several new site templates, one of which is "Developer Site". This template includes several artifacts that enable one-click deployment of apps from Visual Studio without the need for publication to a corporate catalog. In addition, this site template is roughly equivalent to the Developer Site in Office365, resulting in a more cohesive experience when creating apps that may be published both on-prem and to the cloud.  

Create a new site collection and choose "Developer Site" from the list of available templates.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

8 

Create a New App Registration

 

In Office365, app providers are assigned unique GUID’s and key values for applications that will be sold in the marketplace. This helps Microsoft track individual apps and provides a level of verification that the app is genuine. For on-premise deployments, there is no marketplace; instead, SharePoint 2013 introduces the concept of the Corporate Catalog. This is a repository of trusted apps which administrators have made available for installation throughout the enterprise. The catalog is an effective mechanism for final publication but doesn’t suit iterative development processes very well.  

In order to facilitate the traditional Build -> Deploy -> Test -> Refactor development cycle, SharePoint 2013 allows individual apps to be registered on a specific site. A GUID and secret value are assigned and those values are used in both the app manifest and the remote web. When development is complete and the app is ready for publication, these values will be replaced by global identifiers.  

Browse to the App Registration URL in the Developer Site.  

http://<SiteCollectionRoot>/_layouts/15/appregnew.aspx  

Generate a new App Id and App Secret using the buttons provided on the form. Enter the title of the app and the FQDN of the remote web without the protocol prefix (i.e. "contosotestweb.contoso.com" instead of "http://contosottestweb.contoso.com"). Finally, enter the full path to the default page of the remote web ("redirect" is a bit of a misnomer – it’s actually the landing page that the user will be sent to when the app tile is clicked; however, this can be overridden in the app manifest). The Redirect URI must use https – http is not permitted.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Copy these values to a text file or other temporary location as they will be needed in the following step.

 

9 

Create and Configure a Provider Hosted App

 

An "app" in and of itself is nothing more than a manifest file and related artifacts (if any), much like a Feature. There are several different hosting models for SharePoint apps (see Introducing the SharePoint 2013 Application Model), some of which can include actual SharePoint elements such as pages, lists and libraries. For a remote web app, there are no SharePoint components – all that is required is an app manifest file that contains configuration parameters and displays a link to the remote web within a SharePoint site.  

Create a new App for SharePoint 2013.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Provide a name for the app (which should be the same as the name from the app registration but it is not required that they match), select a target URL (for F5 deployment) and pick a hosting model – in this case "Self-hosted".

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

The Visual Studio tools assume that you want to create a new web application and app at the same time and that they should both be in the same solution. Although this is perfectly feasible, it does not really fit a distribution model for marketplace/catalog apps nor does it apply to existing apps being ported to SharePoint 2013. One advantage that it does provide is that the TokenHelper.cs file is automatically included (this is also available in most of the samples on MSDN). For purposes of keeping the SharePoint and non-SharePoint solutions separate, the web application Visual Studio creates will be removed from these examples but that is neither a recommendation nor a best practice; it is merely individual preference.  

The app project is very simple – just an image file and the app manifest XML.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

The app manifest file, much like Feature and Solution manifests, sets all the configuration options for the app. A visual designer is available to simplify the process of applying settings:

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Unfortunately, the configuration page assumes that the app uses the included web application created by Visual Studio and that the Redirect URI from the app registration will function as the remote web URL. It also fails to provide any facility for setting the app Client ID, which is an absolute necessity for provider-hosted apps. Instead of using the design surface, right-click on the AppManifest.xml file and choose "View Code". This will open the file in the Visual Studio text editor.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Note the <StartPage> node and the {StandardTokens} query string parameter. This parameter insures that the values needed for the remote web to call back into SharePoint are included in the request (such as the "SPHostUrl" value required by TokenHelper). The Redirect URI from the app registration can be overridden in this node by replacing the ~remoteAppUrl token with a full url:

 

<Properties>

<Title>Contoso Test App</Title>

<StartPage>https://contosotestweb.contoso.com/Default.aspx?{StandardTokens}</StartPage>

</Properties>

 

Enter the App Id from the app registration step as the ClientId value.

 

<AppPrincipal>

<RemoteWebApplication ClientId="922e5692-8369-4ee1-b121-e95310c8e6ac" />

</AppPrincipal>

 

In addition to establishing context for client object model commands in the code-behind of the Default.aspx, an app must also be granted an explicit permission set which specifies what type of resources the app can access and at what level. For lists, libraries, and other common resources, the permission scope is "http://sharepoint/content", followed by the level in the hierarchy where access is permitted, such as "sitecollection", "web" or "list" (i.e. "http://sharepoint/content/sitecollection" or "http://sharepoint/content/sitecollection/web/list"). Scopes are cumulative, such that a permission value of "sitecollection" also grants permission for "web" and "list"; however, if the lowest permission level is specified explicitly, such as "http://sharepoint/content/sitecollection/web/list", then no higher-level permissions are available unless specifically allowed by additional AppPermissionRequest entries. Furthermore, the type of access must be specified. This is done via the "Right" attribute, which allows four permission types – "Read", "Write", "Manage" and "FullControl". Other scopes have different syntax and rights – see App Permissions in SharePoint 2013 on MSDN for more information on app permissions.  

Add an AppPermissionRequest entry for Read permissions at the Site Collection level.  

<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="Read" />  

The final app manifest file should resemble the following:  

<?xml version="1.0" encoding="utf-8" ?>

<App xmlns="http://schemas.microsoft.com/sharepoint/2012/app/manifest"

Name="ContosoTestApp"

ProductID="{5c965d63-0919-45a5-b57c-84c2ec168551}"

Version="1.0.0.0"

SharePointMinVersion="15.0.0.0" >

<Properties>

<Title>Contoso Test App</Title>

<StartPage>https://contosotestweb.contoso.com/Default.aspx?{StandardTokens}</StartPage>

</Properties>

<AppPrincipal>

<RemoteWebApplication ClientId="922e5692-8369-4ee1-b121-e95310c8e6ac" />

</AppPrincipal>

<AppPermissionRequests>

<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="Read" />

</AppPermissionRequests>

</App>

 

10

Modify Remote Web Configuration

 

Before the app can be deployed, the remote web must be configured with the App Id and App Secret values from the app registration. Edit the web.config file in the remote web project and add the following entries to the <appSettings> node, where ClientId and ClientSecret equal the App Id and App Secret values copied from the app registration:  

<add key="ClientId" value="922e5692-8369-4ee1-b121-e95310c8e6ac" />

<add key="ClientSecret" value="2RM054YeWEKvjqJFxSFeD64TU6M8IAm9txdxacL7RKc=" />

 

11

Configure Remote Web Trust

 

With all the prerequisites in place, the environment can now be configured for the server to server trust relationship between the remote web and SharePoint. This configuration is done via PowerShell. Begin by establishing a variable for the Developer Site web object (where the app registration was performed):

 

$web = Get-SPWeb http://dev.contoso.com

 

Create a variable for the metadata document URL.

 

$metadataDocumentUrl = "http://contosotestweb.contoso.com/MetadataDocument.ashx"

 

Get the authentication realm and store it in another variable.

 

$realm = Get-SPAuthenticationRealm -ServiceContext $web.Site

 

Create a new Trusted Security Token Service instance using the specified metadata document.

 

$trustedTokenService = New-SPTrustedServiceTokenIssuer -Name "Contoso Test App Token Service" -MetadataEndPoint $metadataDocumentUrl –confirm:$false

 

Register the app principal with the new token service.

 

$appPrincipal = Register-SPAppPrincipal -NameIdentifier $trustedTokenService.RegisteredIssuerName.Replace(‘*’,$realm) -Site $web -DisplayName "Contoso Test App Principal"

 

Set the app principal permission.

 

Set-SPAppPrincipalPermission -Site $web -AppPrincipal $appPrincipal -Scope Site -Right FullControl

 

Note that the scope value in PowerShell does not use a URI syntax; instead, the allowable values are either "Site", "Web" or "List". Once complete, the remote web will be permitted to access SharePoint via the trust specified in the token service. It is important to note that each app must have a unique certificate AND a unique SPTrustedSecurityTokenService instance. At present these cannot be shared between apps.  

When the configuration commands are complete execute an IISRESET operation.

 


NOTE: The above procedure was applicable only to the SharePoint 2013 Beta releases.  For RTM and later, and in combination with subsequent releases of the developer tools, the procedure has changed.  See Kirk Evan’s blog post and this MSDN article for further background and the new PowerShell commands for RTM.

 

12

Configure Remote Web Authentication (Part 2)

 

Once the trust relationship has been successfully established, anonymous authentication can be removed from the remote web.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

13

Deploy Provider Hosted App

 

The app is now ready for deployment to the developer site. From the ContosoTestApp project, press F5. A prompt will be displayed asking for confirmation of the permission request being made by the app:

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

Clicking "Trust It" will add the app to the site contents.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

Clicking on the app tile will load the default page of the remote web. The code in the default.aspx page will parse out the SPHostUrl query string parameter, passing it, along with the windows identify of the user, to the token helper method to establish context with the SharePoint site. The Client Side Object Model query will then be executed and, when the site title is successfully retrieved, the authorization message will be displayed.

 

Eric Shupps Eric Alan Shupps eshupps @eshupps SharePoint Cowboy BinaryWave SmartTrack

 

The process is now complete. Follow the same steps for adding new apps to the developer site. Changes to the existing app will not require any further trust configuration modifications unless the URL, certificate, or AppPrincipal changes.

 

Troubleshooting

The most common error encountered in configuring high trust apps is a "401 – Unauthorized" exception after clicking on the app tile and being redirected to the remote web. This is most likely due to a bad setting or configuration parameter in the PowerShell commands. Check the following to resolve this issue:

  1. Ensure that the path and password are correct for the certificate in the web.config file and that it has been applied successfully to the SSL binding for the site in IIS.
  2. Leave anonymous authentication enabled on the remote web until after the PowerShell commands have been run. Then it must be removed in order for a valid windows identity to be established.
  3. The SPTrustedSecurityTokenService "Name" and SPAppPrincipal "DisplayName" values must be unique. If a mistake is made during configuration, re-run the commands using new values for each of these entities.

Additional troubleshooting steps:

  1. Be certain to set the Redirect URI value in the app registration to an HTTPS address – HTTP will not work. The same applies to substituting a full URL for the ~remoteAppUrl in the appmanifest.xml file.
  2. If the JavaScript OM is being utilized (such as invoking the SharePoint chrome via SP.UI.Controls.js) client context must first be established via the TokenHelper methods; otherwise, calls to retrieve the chrome controls will fail.
  3. Pay careful attention to the AppPermissionRequest scope value being used. If a granular scope is selected, such as "http://sharepoint/contents/sitecollection/web/lists", then access to data from parent web and site objects will be blocked.