/// <summary> /// Gets a Salesforce token based on the refresh token and adds it to the cache. /// </summary> /// <param name="salesforceToken">The Salesforce token that contains the refresh token to use.</param> /// <returns>The asynchronous task.</returns> private static async Task AcquireAccessTokenFromRefreshTokenAsync(SalesforceToken salesforceToken) { // Remove the old token from the cache HttpContext.Current.Session[SalesforceService.TokenCacheKey] = null; try { using (AuthenticationClient authenticationClient = salesforceToken.GetAuthenticationClient()) { // Attempt to refresh the token await authenticationClient.TokenRefreshAsync( SalesforceService.GetAppSetting("Salesforce:ConsumerKey"), salesforceToken.RefreshToken, string.Empty, SalesforceService.GetAppSetting("Salesforce:Domain") + "/services/oauth2/token"); salesforceToken = new SalesforceToken(authenticationClient); // Add the new token to the cache HttpContext.Current.Session[SalesforceService.TokenCacheKey] = salesforceToken; } } catch (ForceException e) { // InvalidGrant means that the refresh token is invalid. // Just return in that case, so re-authorization can occur. if (e.Error != Error.InvalidGrant) { throw; } } }
/// <summary> /// Makes a request to the Salesforce client, wrapping the specified logic with the code necessary to handle authentication. /// </summary> /// <typeparam name="T">The type of value returned from the request.</typeparam> /// <param name="request">The request to make on the Salesforce client.</param> /// <exception cref="InvalidOperationException">The current user is not authenticated.</exception> /// <returns>The value returned by the request.</returns> public static async Task <T> MakeAuthenticatedClientRequestAsync <T>(Func <ForceClient, Task <T> > request) { bool done = false; bool refreshedToken = false; T result = default(T); do { // 1. Get the token from the cache SalesforceToken salesforceToken = HttpContext.Current.Session[SalesforceService.TokenCacheKey] as SalesforceToken; // 2. If no token is available, redirect to authorize if (salesforceToken == null) { // This exception message should be used to trigger the sign-in UI throw new InvalidOperationException("AuthorizationRequired"); } // Initialize the ForceClient ForceClient forceClient = salesforceToken.GetForceClient(); try { // 3. Invoke the request with the acquired token result = await request(forceClient); done = true; } catch (ForceException e) { // If message is "Session expired or invalid", the access token is invalid, so eat the // exception and fall through to try to update it using the refresh token. if (e.Message != "Session expired or invalid") { throw; } if (refreshedToken) { // The access token is invalid and was already refreshed once, give up and // re-throw the exception. throw; } } // 4. If the token is invalid, attempt to acquire a new access token from the refresh token if (!done) { await SalesforceService.AcquireAccessTokenFromRefreshTokenAsync(salesforceToken); refreshedToken = true; } } while (!done); return(result); }
/// <summary> /// Gets the Salesforce authorization URL. The optional target parameter allows the app to redirect to /// a specified page after authorization; if the parameter is not specified, the app redirects to the current /// request's URL. /// </summary> /// <returns>The Salesforce authorization URL.</returns> public static string GetAuthorizationUrl(string targetUri = null) { return(Common.FormatAuthUrl( SalesforceService.GetAppSetting("Salesforce:Domain") + "/services/oauth2/authorize", ResponseTypes.Code, SalesforceService.GetAppSetting("Salesforce:ConsumerKey"), HttpUtility.UrlEncode(SalesforceOAuthRedirectHandler.GetAbsoluteRedirectUri()), DisplayTypes.Page, false, HttpUtility.UrlEncode(string.IsNullOrEmpty(targetUri) ? HttpContext.Current.Request.Url.AbsoluteUri : targetUri))); }
/// <summary> /// Processes the authentication callback from Salesforce. /// </summary> /// <param name="context">The HTTP context.</param> /// <returns>The asynchronous task.</returns> public override async Task ProcessRequestAsync(HttpContext context) { await SalesforceService.AcquireTokenByAuthorizationCodeAsync( context.Request.QueryString["code"], SalesforceOAuthRedirectHandler.GetAbsoluteRedirectUri()); string state = HttpUtility.UrlDecode(context.Request.QueryString["state"]); string redirectUrl = state == null ? "~/" : state; context.Response.Redirect(redirectUrl, false); }
/// <summary> /// Gets the absolute Uri to redirect to after Salesforce has completed authenticating a user. This is the Uri /// to this handler. /// </summary> /// <returns>The absolute redirect Uri.</returns> private static string GetAbsoluteRedirectUri() { Uri redirectUri; Uri.TryCreate(SalesforceService.GetAppSetting("Salesforce:RedirectUri"), UriKind.RelativeOrAbsolute, out redirectUri); if (redirectUri.IsAbsoluteUri) { return(redirectUri.ToString()); } else { string uriAuthority = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority); return(new Uri(new Uri(uriAuthority), redirectUri).ToString()); } }
/// <summary> /// Gets a Salesforce token from an authorization code and adds it to the cache. /// </summary> /// <param name="authorizationCode">The code that was returned to the OAuth callback.</param> /// <param name="redirectUri">The redirect URI that was used to acquire the code.</param> /// <returns>The asynchronous task.</returns> public static async Task AcquireTokenByAuthorizationCodeAsync(string authorizationCode, string redirectUri) { using (AuthenticationClient authenticationClient = new AuthenticationClient()) { await authenticationClient.WebServerAsync( SalesforceService.GetAppSetting("Salesforce:ConsumerKey"), SalesforceService.GetAppSetting("Salesforce:ConsumerSecret"), redirectUri, authorizationCode, SalesforceService.GetAppSetting("Salesforce:Domain") + "/services/oauth2/token"); SalesforceToken salesforceToken = new SalesforceToken(authenticationClient); // Add the new token to the cache HttpContext.Current.Session[SalesforceService.TokenCacheKey] = salesforceToken; } }