Salesforce provider: add Option to specify Production vs. Sandbox environment (#223)

* add Option to specify Production vs. Sandbox Environment

also fixes issue
https://github.com/TerribleDev/OwinOAuthProviders/issues/54

* ability to specify Production vs. Sandbox environment per auth session in addition to global setting

* add examples to show usage of new Production vs. Sandbox Option for Salesforce provider
This commit is contained in:
Ștefan Negrițoiu
2017-12-28 22:56:14 -08:00
committed by Tommy Parnell
parent fde4b5ebac
commit 7aeca07f08
5 changed files with 134 additions and 16 deletions

View File

@@ -126,14 +126,50 @@ namespace OwinOAuthProvidersDemo
// clientId: "", // clientId: "",
// clientSecret: ""); // clientSecret: "");
//in scenarios where a sandbox URL needs to be used // Salesforce Option 1: don't specify explicit Endpoint config and use Production endpoint defaults
//var salesforceOptions = new SalesforceAuthenticationOptions //var salesforceOptions1 = new SalesforceAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// Provider = new SalesforceAuthenticationProvider()
// {
// OnAuthenticated = async context =>
// {
// System.Diagnostics.Debug.WriteLine(context.AccessToken);
// System.Diagnostics.Debug.WriteLine(context.RefreshToken);
// System.Diagnostics.Debug.WriteLine(context.OrganizationId);
// }
// }
//};
// Salesforce Option 2: ask for Sandbox environment; no need to know what those endpoints are
//var salesforceOptions2 = new SalesforceAuthenticationOptions
//{ //{
// Endpoints = // Endpoints =
// new SalesforceAuthenticationOptions.SalesforceAuthenticationEndpoints // new SalesforceAuthenticationOptions.SalesforceAuthenticationEndpoints
// { // {
// AuthorizationEndpoint = // Environment = Owin.Security.Providers.Salesforce.Constants.SandboxEnvironment
// "https://ap1.salesforce.com/services/oauth2/authorize", // },
// ClientId = "",
// ClientSecret = "",
// Provider = new SalesforceAuthenticationProvider()
// {
// OnAuthenticated = async context =>
// {
// System.Diagnostics.Debug.WriteLine(context.AccessToken);
// System.Diagnostics.Debug.WriteLine(context.RefreshToken);
// System.Diagnostics.Debug.WriteLine(context.OrganizationId);
// }
// }
//};
// Salesforce Option 3: explicitly specify endpoints (will take precedence over Environment choice)
//var salesforceOptions3 = new SalesforceAuthenticationOptions
//{
// Endpoints =
// new SalesforceAuthenticationOptions.SalesforceAuthenticationEndpoints
// {
// AuthorizationEndpoint = "https://ap1.salesforce.com/services/oauth2/authorize",
// TokenEndpoint = "https://ap1.salesforce.com/services/oauth2/token" // TokenEndpoint = "https://ap1.salesforce.com/services/oauth2/token"
// }, // },
// ClientId = "", // ClientId = "",
@@ -148,7 +184,7 @@ namespace OwinOAuthProvidersDemo
// } // }
// } // }
//}; //};
//app.UseSalesforceAuthentication(salesforceOptions); //app.UseSalesforceAuthentication(salesforceOptions1);
////app.UseShopifyAuthentication("", ""); ////app.UseShopifyAuthentication("", "");

View File

@@ -419,6 +419,13 @@ namespace OwinOAuthProvidersDemo.Controllers
properties.Dictionary[ShopNameKey] = ShopName; properties.Dictionary[ShopNameKey] = ShopName;
} }
// if use Salesforce as OAuth provider you can ask for Sandbox auth endpoint
// for this particular request only
//properties.Dictionary.Add(
// Owin.Security.Providers.Salesforce.Constants.EnvironmentAuthenticationProperty,
// Owin.Security.Providers.Salesforce.Constants.SandboxEnvironment
// );
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
} }
} }

View File

@@ -1,7 +1,11 @@
namespace Owin.Security.Providers.Salesforce namespace Owin.Security.Providers.Salesforce
{ {
internal static class Constants public static class Constants
{ {
public const string DefaultAuthenticationType = "Salesforce"; public const string DefaultAuthenticationType = "Salesforce";
public const string EnvironmentAuthenticationProperty = "Environment";
public const string ProductionEnvironment = "Production";
public const string SandboxEnvironment = "Sandbox";
} }
} }

View File

@@ -18,6 +18,12 @@ namespace Owin.Security.Providers.Salesforce
{ {
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string ProductionHost = "https://login.salesforce.com";
private const string SandboxHost = "https://test.salesforce.com";
private const string AuthorizationEndpoint = "/services/oauth2/authorize";
private const string TokenEndpoint = "/services/oauth2/token";
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
@@ -74,7 +80,7 @@ namespace Owin.Security.Providers.Salesforce
}; };
// Request the token // Request the token
var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.Endpoints.TokenEndpoint); var requestMessage = new HttpRequestMessage(HttpMethod.Post, ComposeTokenEndpoint(properties));
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content = new FormUrlEncodedContent(body); requestMessage.Content = new FormUrlEncodedContent(body);
var tokenResponse = await _httpClient.SendAsync(requestMessage); var tokenResponse = await _httpClient.SendAsync(requestMessage);
@@ -186,8 +192,10 @@ namespace Owin.Security.Providers.Salesforce
var state = Options.StateDataFormat.Protect(properties); var state = Options.StateDataFormat.Protect(properties);
var authorizationEndpoint = var authorizationEndpoint = ComposeAuthorizationEndpoint(properties);
$"{Options.Endpoints.AuthorizationEndpoint}?response_type={"code"}&client_id={Options.ClientId}&redirect_uri={HttpUtility.UrlEncode(redirectUri)}&display={"page"}&immediate={false}&state={Uri.EscapeDataString(state)}";
authorizationEndpoint =
$"{authorizationEndpoint}?response_type={"code"}&client_id={Options.ClientId}&redirect_uri={HttpUtility.UrlEncode(redirectUri)}&display={"page"}&immediate={false}&state={Uri.EscapeDataString(state)}";
if (Options.Scope != null && Options.Scope.Count > 0) if (Options.Scope != null && Options.Scope.Count > 0)
{ {
@@ -253,5 +261,66 @@ namespace Owin.Security.Providers.Salesforce
return context.IsRequestCompleted; return context.IsRequestCompleted;
} }
private string ComposeAuthorizationEndpoint(AuthenticationProperties properties) {
string endpointPath = AuthorizationEndpoint;
string endpoint =
!String.IsNullOrEmpty(Options.Endpoints.AuthorizationEndpoint) ?
Options.Endpoints.AuthorizationEndpoint :
ComposeEndpoint(properties, endpointPath);
// if AuthenticationProperties for this session specifies an environment property
// it should take precedence over the value in AuthenticationOptions
string environmentProperty = null; ;
if (properties.Dictionary.TryGetValue(Constants.EnvironmentAuthenticationProperty, out environmentProperty)) {
endpoint =
environmentProperty == Constants.SandboxEnvironment ?
SandboxHost + endpointPath :
ProductionHost + endpointPath;
}
return endpoint;
}
private string ComposeTokenEndpoint(AuthenticationProperties properties) {
string endpointPath = TokenEndpoint;
string endpoint =
!String.IsNullOrEmpty(Options.Endpoints.TokenEndpoint) ?
Options.Endpoints.TokenEndpoint :
ComposeEndpoint(properties, endpointPath);
// if AuthenticationProperties for this session specifies an environment property
// it should take precedence over the value in AuthenticationOptions
string environmentProperty = null; ;
if (properties.Dictionary.TryGetValue(Constants.EnvironmentAuthenticationProperty, out environmentProperty)) {
endpoint =
environmentProperty == Constants.SandboxEnvironment ?
SandboxHost + endpointPath :
ProductionHost + endpointPath;
}
return endpoint;
}
private string ComposeEndpoint(AuthenticationProperties properties, string endpointPath) {
string endpoint =
!String.IsNullOrEmpty(Options.Endpoints.Environment) && Options.Endpoints.Environment == Constants.SandboxEnvironment ?
SandboxHost + endpointPath :
ProductionHost + endpointPath;
// if AuthenticationProperties for this session specifies an environment property
// it should take precedence over the value in AuthenticationOptions
string environmentProperty = null; ;
if (properties.Dictionary.TryGetValue(Constants.EnvironmentAuthenticationProperty, out environmentProperty)) {
endpoint =
environmentProperty == Constants.SandboxEnvironment ?
SandboxHost + endpointPath :
ProductionHost + endpointPath;
}
return endpoint;
}
} }
} }

View File

@@ -19,10 +19,12 @@ namespace Owin.Security.Providers.Salesforce
/// Endpoint which is used to exchange code for access token /// Endpoint which is used to exchange code for access token
/// </summary> /// </summary>
public string TokenEndpoint { get; set; } public string TokenEndpoint { get; set; }
}
private const string AuthorizationEndPoint = ""; /// <summary>
private const string TokenEndpoint = ""; /// Production or Sandbox. Use Constants.ProductionEnvironment or Constants.SandboxEnvironment
/// </summary>
public string Environment { get; set; }
}
/// <summary> /// <summary>
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used /// Gets or sets the a pinned certificate validator to use to validate the endpoints used
@@ -79,8 +81,8 @@ namespace Owin.Security.Providers.Salesforce
public string ClientSecret { get; set; } public string ClientSecret { get; set; }
/// <summary> /// <summary>
/// Gets the sets of OAuth endpoints used to authenticate against Salesforce. Overriding these endpoints allows you to use Salesforce Enterprise for /// Gets the sets of OAuth endpoints used to authenticate against Salesforce.
/// authentication. /// Overriding these endpoints allows you to use Salesforce Enterprise for authentication.
/// </summary> /// </summary>
public SalesforceAuthenticationEndpoints Endpoints { get; set; } public SalesforceAuthenticationEndpoints Endpoints { get; set; }
@@ -127,8 +129,8 @@ namespace Owin.Security.Providers.Salesforce
BackchannelTimeout = TimeSpan.FromSeconds(60); BackchannelTimeout = TimeSpan.FromSeconds(60);
Endpoints = new SalesforceAuthenticationEndpoints Endpoints = new SalesforceAuthenticationEndpoints
{ {
AuthorizationEndpoint = AuthorizationEndPoint, AuthorizationEndpoint = null,
TokenEndpoint = TokenEndpoint TokenEndpoint = null
}; };
} }
} }