Share-n-dipity

SharePoint serendipity is the effect by which one accidentally discovers something fortunate, especially while looking for something else entirely. In this case, it is the occassional musings, observations, and Ouija board readings about the phabulously

Security in SharePoint Apps - Part 4

Security in SharePoint Apps - Part 4

  • Comments 5
  • Likes

PREVIOUS:  Security in SharePoint Apps – Part 3

In Part 3 I talked about how SharePoint sends over a context token with the request for an App when using low trust (this does NOT come over to a high trust app).  It’s worth looking at what a context token is, and how we compare that to a special class called SharePointTokenHelper that’s in TokenHelper.cs (the class that’s automatically added to your Visual Studio project when you create a new SharePoint App).

The context token that comes from SharePoint can be extracted out of the request using TokenHelper’s GetContextTokenFromRequest method.  When a request is made for a low trust App in SharePoint, SharePoint will initially go out to ACS and get this token, and it will contain information about the user making the request and the application being requested.  ACS sends a token back to SharePoint that is signed with the client secret for the application, so if you don’t have that, you can’t unwrap it.  SharePoint then sends that along with the request to the application.  Once the App has it, it uses the ReadAndValidateContextToken method in TokenHelper to extract it out into a SharePointContextToken class; that’s where the client secret is used. 

The data itself is really just a JWT token (pronounced “JWOT” – more information can be found here:  http://openid.net/specs/draft-jones-json-web-token-07.html), which contains some claims information in a JSON format.  ReadAndValidateContextToken just serializes that into the SharePointContextToken class.  There are some very important things that you can do with the SharePointContextToken class:

  • Get a refresh token – your refresh token is good for six months. 
  • Get an access token – use the refresh token to get your access token; the access token is what you need to present to SharePoint to access data.  Access tokens are good for 12 hours.  An access token can be cached and used on subsequent requests, which saves you the performance hit of having to go out and using the refresh token to get a new access token.
  • Get a cache key – as mentioned above, an access token can be cached.  Keeping track of all the different users, apps, sites and potentially tenants can be quite a challenge.  Fortunately the SharePointContextToken includes a cache key just for this purpose.  It does all the work of creating a separate cache key for each combination of user, app, site and tenant.  That allows you to just grab it and use it when caching an access token.

 Here’s an example of what the SharePointContextToken and its constituent properties looks like:

 

 

So having all this information in hand, this is what the typical use case might look like:

  • User clicks on link in SharePoint site that launches an App
  • App extracts SharePointContextToken and uses cache key to determine if it has an access token
    • If it does, it checks to see if the access token is still valid.  If so, it can use that access token; if not then it needs to follow the steps below to get a new one.
    • If it does not, it uses the refresh token to get a new access token and then it saves the access token in cache.

Here’s some code that demonstrates this process:

 

private class AccessTokenInfo

{

public string AccessToken { get; set; }

public DateTime Expires { get; set; }

 

public AccessTokenInfo() { }

 

public AccessTokenInfo(string accessToken, DateTime expires)

{

this.AccessToken = accessToken;

this.Expires = expires;

}

}

 

That class is used in the Page_Load event:

 

//get the context token first; it includes the cache key and refresh token

var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);

var hostWeb = Page.Request["SPHostUrl"];

 

//get the context token details

SharePointContextToken tokenContent = TokenHelper.ReadAndValidateContextToken(contextToken, Request.Url.Authority);

 

string accessToken = string.Empty;

 

//now look to see if we have cached an access token for this yet

if (Session[tokenContent.CacheKey] != null)

{

//we do, so extract out the info so we can see

//if the access token is expired yet

AccessTokenInfo ati = (AccessTokenInfo)Session[tokenContent.CacheKey];

 

//check the expiration

if (DateTime.Now < ati.Expires)

accessToken = ati.AccessToken;

}

           

//if we didn't have a valid access token, then get one here

if (string.IsNullOrEmpty(accessToken))

{

//get an access token from the refresh token

accessToken = TokenHelper.GetAccessToken(

tokenContent.RefreshToken, TokenHelper.SharePointPrincipal,

new Uri(hostWeb).Authority, TokenHelper.GetRealmFromTargetUrl(

new Uri(hostWeb))).AccessToken;

 

//create a new AccessTokenInformation item and set the

//expiration of the access token to 11 hours and 50 minutes

//and put it in session state for next time

Session.Add(tokenContent.CacheKey,

new AccessTokenInfo(accessToken, DateTime.Now.AddMinutes(710)));

}

Hopefully the explanation and code demonstrates what the cache key is and how it can be used within your applications.  I’ve also attached the sample project that contains this code along with this posting so you can play with it yourself.  Just remember that you will need to configure the provider hosted app to work on your development system with your application values in the web.config file.

In the next part in this series we’ll take a look at an interesting application option that doesn’t even require you to install the App in the site collection!  It’s different from your ordinary App, and we’ll discuss that next.

NEXT:  Security in SharePoint Apps - Part 5

Attachment: LowBlow.zip
Comments
  • The example context token must have been taken from a pre-release version of SharePoint 2013. Context tokens in the RTM version have a somewhat different set of claims and are structured somewhat differently.

  • Mmm, no, this is from an RTM (possibly plus March PU, can't recall) capture that I did specifically for and at the time I wrote this posting.

  • Hi Steve - does this approach work for an auto-hosted app on the SharePoint Online Public Website? My problem is as soon as we make the website "online", the context token string is null. We have set it to be an app-only policy as the user is anonymous, and I use the following line of code to retrieve the context token string: var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);

    Any ideas?

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment