/// <summary> /// Uses the information regarding the requesting app to obtain an access token and caches that using the cachekey. /// This method is called from the Register WebAPI service api. /// </summary> /// <param name="sharePointServiceContext">Object holding information about the requesting SharePoint app</param> public static void AddToCache(WebAPIContext sharePointServiceContext) { if (sharePointServiceContext == null) { throw new ArgumentNullException("sharePointServiceContext"); } TokenHelper.ClientId = sharePointServiceContext.ClientId; TokenHelper.ClientSecret = sharePointServiceContext.ClientSecret; TokenHelper.HostedAppHostName = sharePointServiceContext.HostedAppHostName; SharePointContextToken sharePointContextToken = TokenHelper.ReadAndValidateContextToken(sharePointServiceContext.Token); OAuth2AccessTokenResponse accessToken = TokenHelper.GetAccessToken(sharePointContextToken, new Uri(sharePointServiceContext.HostWebUrl).Authority); WebAPIContexCacheItem cacheItem = new WebAPIContexCacheItem() { RefreshToken = sharePointContextToken.RefreshToken, AccessToken = accessToken, SharePointServiceContext = sharePointServiceContext }; WebAPIContextCache.Instance.Put(sharePointServiceContext.CacheKey, cacheItem); }
/// <summary> /// This method needs to be called from a code behind of the SharePoint app startup page (default.aspx). It registers the calling /// SharePoint app by calling a specific "Register" api in your WebAPI service. /// /// Note: /// Given that method is async you'll need to add the Async="true" page directive to the page that uses this method. /// </summary> /// <param name="page">The page object, needed to insert the services token cookie and read the querystring</param> /// <param name="apiRequest">Route to the "Register" API</param> /// <param name="serviceEndPoint">Optional Uri to the WebAPI service endpoint. If null then the assumption is taken that the WebAPI is hosted together with the page making this call</param> public static async void RegisterWebAPIService(this Page page, string apiRequest, Uri serviceEndPoint = null) { if (page == null) throw new ArgumentNullException("page"); if (string.IsNullOrEmpty(apiRequest)) throw new ArgumentNullException("apiRequest"); if (!page.IsPostBack) { if (page.Request.QueryString.AsString(SERVICES_TOKEN, string.Empty).Equals(string.Empty)) { // Construct a JsonWebSecurityToken so we can fetch the cachekey...implementation is copied from tokenhelper approach string cacheKey = string.Empty; string contextToken = TokenHelper.GetContextTokenFromRequest(page.Request); JsonWebSecurityTokenHandler tokenHandler = TokenHelper.CreateJsonWebSecurityTokenHandler(); SecurityToken securityToken = tokenHandler.ReadToken(contextToken); JsonWebSecurityToken jsonToken = securityToken as JsonWebSecurityToken; string appctx = GetClaimValue(jsonToken, "appctx"); if (appctx != null) { ClientContext ctx = new ClientContext("http://tempuri.org"); Dictionary<string, object> dict = (Dictionary<string, object>)ctx.ParseObjectFromJsonString(appctx); cacheKey = (string)dict["CacheKey"]; } // Remove special chars (=, +, /, {}) from cachekey as there's a flaw in CookieHeaderValue when the // cookie is read. This flaw replaces special chars with a space. cacheKey = RemoveSpecialCharacters(cacheKey); bool httpOnly = true; if (serviceEndPoint != null) { if (!serviceEndPoint.Host.Equals(page.Request.Url.Host, StringComparison.InvariantCultureIgnoreCase)) { httpOnly = false; } } else { serviceEndPoint = new Uri(String.Format("{0}://{1}:{2}", page.Request.Url.Scheme, page.Request.Url.Host, page.Request.Url.Port)); } // Write the cachekey in a cookie HttpCookie cookie = new HttpCookie(SERVICES_TOKEN) { Value = cacheKey, Secure = true, HttpOnly = httpOnly, }; page.Response.AppendCookie(cookie); //Register the ClientContext WebAPIContext sharePointServiceContext = new WebAPIContext() { CacheKey = cacheKey, ClientId = TokenHelper.ClientId, ClientSecret = TokenHelper.ClientSecret, Token = contextToken, HostWebUrl = page.Request.QueryString.AsString("SPHostUrl", null), AppWebUrl = page.Request.QueryString.AsString("SPAppWebUrl", null), HostedAppHostName = String.Format("{0}:{1}", page.Request.Url.Host, page.Request.Url.Port), }; using (var client = new HttpClient()) { client.BaseAddress = serviceEndPoint; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.PutAsJsonAsync(apiRequest, sharePointServiceContext); if (!response.IsSuccessStatusCode) { LoggingUtility.Internal.TraceError((int)EventId.ServicesRegistrationFailed, CoreResources.Service_RegistrationFailed, apiRequest, serviceEndPoint.ToString(), cacheKey); throw new Exception(String.Format("Service registration failed: {0}", response.StatusCode)); } LoggingUtility.Internal.TraceInformation((int)EventId.ServicesRegistered, CoreResources.Services_Registered, apiRequest, serviceEndPoint.ToString(), cacheKey); } } } }
/// <summary> /// Uses the information regarding the requesting app to obtain an access token and caches that using the cachekey. /// This method is called from the Register WebAPI service api. /// </summary> /// <param name="sharePointServiceContext">Object holding information about the requesting SharePoint app</param> public static void AddToCache(WebAPIContext sharePointServiceContext) { if (sharePointServiceContext == null) throw new ArgumentNullException("sharePointServiceContext"); TokenHelper.ClientId = sharePointServiceContext.ClientId; TokenHelper.ClientSecret = sharePointServiceContext.ClientSecret; TokenHelper.HostedAppHostName = sharePointServiceContext.HostedAppHostName; SharePointContextToken sharePointContextToken = TokenHelper.ReadAndValidateContextToken(sharePointServiceContext.Token); OAuth2AccessTokenResponse accessToken = TokenHelper.GetAccessToken(sharePointContextToken, new Uri(sharePointServiceContext.HostWebUrl).Authority); WebAPIContexCacheItem cacheItem = new WebAPIContexCacheItem() { RefreshToken = sharePointContextToken.RefreshToken, AccessToken = accessToken, SharePointServiceContext = sharePointServiceContext }; WebAPIContextCache.Instance.Put(sharePointServiceContext.CacheKey, cacheItem); }
public void Register(WebAPIContext sharePointServiceContext) { WebAPIHelper.AddToCache(sharePointServiceContext); }
/// <summary> /// This method needs to be called from a code behind of the SharePoint app startup page (default.aspx). It registers the calling /// SharePoint app by calling a specific "Register" api in your WebAPI service. /// /// Note: /// Given that method is async you'll need to add the Async="true" page directive to the page that uses this method. /// </summary> /// <param name="page">The page object, needed to insert the services token cookie and read the querystring</param> /// <param name="apiRequest">Route to the "Register" API</param> /// <param name="serviceEndPoint">Optional Uri to the WebAPI service endpoint. If null then the assumption is taken that the WebAPI is hosted together with the page making this call</param> public static async void RegisterWebAPIService(this Page page, string apiRequest, Uri serviceEndPoint = null) { if (page == null) { throw new ArgumentNullException("page"); } if (string.IsNullOrEmpty(apiRequest)) { throw new ArgumentNullException("apiRequest"); } if (!page.IsPostBack) { if (page.Request.QueryString.AsString(SERVICES_TOKEN, string.Empty).Equals(string.Empty)) { // Construct a JsonWebSecurityToken so we can fetch the cachekey...implementation is copied from tokenhelper approach string cacheKey = string.Empty; string contextToken = TokenHelper.GetContextTokenFromRequest(page.Request); JsonWebSecurityTokenHandler tokenHandler = TokenHelper.CreateJsonWebSecurityTokenHandler(); SecurityToken securityToken = tokenHandler.ReadToken(contextToken); JsonWebSecurityToken jsonToken = securityToken as JsonWebSecurityToken; string appctx = GetClaimValue(jsonToken, "appctx"); if (appctx != null) { ClientContext ctx = new ClientContext("http://tempuri.org"); Dictionary <string, object> dict = (Dictionary <string, object>)ctx.ParseObjectFromJsonString(appctx); cacheKey = (string)dict["CacheKey"]; } // Remove special chars (=, +, /, {}) from cachekey as there's a flaw in CookieHeaderValue when the // cookie is read. This flaw replaces special chars with a space. cacheKey = RemoveSpecialCharacters(cacheKey); bool httpOnly = true; if (serviceEndPoint != null) { if (!serviceEndPoint.Host.Equals(page.Request.Url.Host, StringComparison.InvariantCultureIgnoreCase)) { httpOnly = false; } } else { serviceEndPoint = new Uri(String.Format("{0}://{1}:{2}", page.Request.Url.Scheme, page.Request.Url.Host, page.Request.Url.Port)); } // Write the cachekey in a cookie HttpCookie cookie = new HttpCookie(SERVICES_TOKEN) { Value = cacheKey, Secure = true, HttpOnly = httpOnly, }; page.Response.AppendCookie(cookie); //Register the ClientContext WebAPIContext sharePointServiceContext = new WebAPIContext() { CacheKey = cacheKey, ClientId = TokenHelper.ClientId, ClientSecret = TokenHelper.ClientSecret, Token = contextToken, HostWebUrl = page.Request.QueryString.AsString("SPHostUrl", null), AppWebUrl = page.Request.QueryString.AsString("SPAppWebUrl", null), HostedAppHostName = String.Format("{0}:{1}", page.Request.Url.Host, page.Request.Url.Port), }; using (var client = new HttpClient()) { client.BaseAddress = serviceEndPoint; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.PutAsJsonAsync(apiRequest, sharePointServiceContext); if (!response.IsSuccessStatusCode) { Log.Error(CoreResources.Service_RegistrationFailed, apiRequest, serviceEndPoint.ToString(), cacheKey); throw new Exception(String.Format("Service registration failed: {0}", response.StatusCode)); } Log.Info(CoreResources.Services_Registered, apiRequest, serviceEndPoint.ToString(), cacheKey); } } } }
/// <summary> /// This method needs to be called from a code behind of the SharePoint app startup page (default.aspx). It registers the calling /// SharePoint app by calling a specific "Register" api in your WebAPI service. /// /// Note: /// Given that method is async you'll need to add the Async="true" page directive to the page that uses this method. /// </summary> /// <param name="context">The HttpContextBase object, needed to insert the services token cookie and read the querystring</param> /// <param name="apiRequest">Route to the "Register" API</param> /// <param name="serviceEndPoint">Optional Uri to the WebAPI service endpoint. If null then the assumption is taken that the WebAPI is hosted together with the page making this call</param> public static void RegisterWebAPIService(HttpContextBase context, string apiRequest, Uri serviceEndPoint = null) { if (context == null) { throw new ArgumentNullException("context"); } if (string.IsNullOrEmpty(apiRequest)) { throw new ArgumentNullException("apiRequest"); } HttpRequestBase request = context.Request; try { if (request.QueryString.AsString(SERVICES_TOKEN, string.Empty).Equals(string.Empty)) { // Construct a JsonWebSecurityToken so we can fetch the cachekey...implementation is copied from tokenhelper approach string cacheKey = string.Empty; string contextToken = TokenHelper.GetContextTokenFromRequest(request); JsonWebSecurityTokenHandler tokenHandler = TokenHelper.CreateJsonWebSecurityTokenHandler(); SecurityToken securityToken = tokenHandler.ReadToken(contextToken); JsonWebSecurityToken jsonToken = securityToken as JsonWebSecurityToken; string appctx = GetClaimValue(jsonToken, "appctx"); if (appctx != null) { ClientContext ctx = new ClientContext("http://tempuri.org"); Dictionary <string, object> dict = (Dictionary <string, object>)ctx.ParseObjectFromJsonString(appctx); cacheKey = (string)dict["CacheKey"]; } // Remove special chars (=, +, /, {}) from cachekey as there's a flaw in CookieHeaderValue when the // cookie is read. This flaw replaces special chars with a space. cacheKey = RemoveSpecialCharacters(cacheKey); bool httpOnly = true; if (serviceEndPoint != null) { if (!serviceEndPoint.Host.Equals(context.Request.Url.Host, StringComparison.InvariantCultureIgnoreCase)) { httpOnly = false; } } else { serviceEndPoint = new Uri(String.Format("{0}://{1}:{2}", context.Request.Url.Scheme, context.Request.Url.Host, context.Request.Url.Port)); } // Write the cachekey in a cookie HttpCookie cookie = new HttpCookie(SERVICES_TOKEN) { Value = cacheKey, Secure = true, HttpOnly = httpOnly, }; context.Response.AppendCookie(cookie); //Register the ClientContext WebAPIContext sharePointServiceContext = new WebAPIContext() { CacheKey = cacheKey, ClientId = TokenHelper.ClientId, ClientSecret = TokenHelper.ClientSecret, Token = contextToken, HostWebUrl = context.Request.QueryString.AsString("SPHostUrl", null), AppWebUrl = context.Request.QueryString.AsString("SPAppWebUrl", null), HostedAppHostName = String.Format("{0}:{1}", context.Request.Url.Host, context.Request.Url.Port), }; WebAPIHelper.AddToCache(sharePointServiceContext); } } catch (Exception ex) { throw new UnauthorizedAccessException("The context token cannot be validated.", ex); } }