diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs
index 2879b4a..3cf891a 100755
--- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs
+++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs
@@ -126,14 +126,50 @@ namespace OwinOAuthProvidersDemo
// clientId: "",
// clientSecret: "");
- //in scenarios where a sandbox URL needs to be used
- //var salesforceOptions = new SalesforceAuthenticationOptions
+ // Salesforce Option 1: don't specify explicit Endpoint config and use Production endpoint defaults
+ //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 =
// new SalesforceAuthenticationOptions.SalesforceAuthenticationEndpoints
// {
- // AuthorizationEndpoint =
- // "https://ap1.salesforce.com/services/oauth2/authorize",
+ // Environment = Owin.Security.Providers.Salesforce.Constants.SandboxEnvironment
+ // },
+ // 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"
// },
// ClientId = "",
@@ -148,7 +184,7 @@ namespace OwinOAuthProvidersDemo
// }
// }
//};
- //app.UseSalesforceAuthentication(salesforceOptions);
+ //app.UseSalesforceAuthentication(salesforceOptions1);
////app.UseShopifyAuthentication("", "");
diff --git a/OwinOAuthProvidersDemo/Controllers/AccountController.cs b/OwinOAuthProvidersDemo/Controllers/AccountController.cs
index 83a640f..bc417b5 100644
--- a/OwinOAuthProvidersDemo/Controllers/AccountController.cs
+++ b/OwinOAuthProvidersDemo/Controllers/AccountController.cs
@@ -419,6 +419,13 @@ namespace OwinOAuthProvidersDemo.Controllers
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);
}
}
diff --git a/src/Owin.Security.Providers.Salesforce/Constants.cs b/src/Owin.Security.Providers.Salesforce/Constants.cs
index 80a5208..c98249b 100644
--- a/src/Owin.Security.Providers.Salesforce/Constants.cs
+++ b/src/Owin.Security.Providers.Salesforce/Constants.cs
@@ -1,7 +1,11 @@
namespace Owin.Security.Providers.Salesforce
{
- internal static class Constants
+ public static class Constants
{
public const string DefaultAuthenticationType = "Salesforce";
+
+ public const string EnvironmentAuthenticationProperty = "Environment";
+ public const string ProductionEnvironment = "Production";
+ public const string SandboxEnvironment = "Sandbox";
}
}
\ No newline at end of file
diff --git a/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationHandler.cs b/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationHandler.cs
index 27074d8..db72d5e 100644
--- a/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationHandler.cs
+++ b/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationHandler.cs
@@ -18,6 +18,12 @@ namespace Owin.Security.Providers.Salesforce
{
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 HttpClient _httpClient;
@@ -74,7 +80,7 @@ namespace Owin.Security.Providers.Salesforce
};
// 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.Content = new FormUrlEncodedContent(body);
var tokenResponse = await _httpClient.SendAsync(requestMessage);
@@ -186,8 +192,10 @@ namespace Owin.Security.Providers.Salesforce
var state = Options.StateDataFormat.Protect(properties);
- var authorizationEndpoint =
- $"{Options.Endpoints.AuthorizationEndpoint}?response_type={"code"}&client_id={Options.ClientId}&redirect_uri={HttpUtility.UrlEncode(redirectUri)}&display={"page"}&immediate={false}&state={Uri.EscapeDataString(state)}";
+ var authorizationEndpoint = ComposeAuthorizationEndpoint(properties);
+
+ 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)
{
@@ -253,5 +261,66 @@ namespace Owin.Security.Providers.Salesforce
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;
+ }
}
}
diff --git a/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationOptions.cs b/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationOptions.cs
index 4957236..97a71ce 100644
--- a/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationOptions.cs
+++ b/src/Owin.Security.Providers.Salesforce/SalesforceAuthenticationOptions.cs
@@ -19,10 +19,12 @@ namespace Owin.Security.Providers.Salesforce
/// Endpoint which is used to exchange code for access token
///
public string TokenEndpoint { get; set; }
- }
- private const string AuthorizationEndPoint = "";
- private const string TokenEndpoint = "";
+ ///
+ /// Production or Sandbox. Use Constants.ProductionEnvironment or Constants.SandboxEnvironment
+ ///
+ public string Environment { get; set; }
+ }
///
/// 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; }
///
- /// Gets the sets of OAuth endpoints used to authenticate against Salesforce. Overriding these endpoints allows you to use Salesforce Enterprise for
- /// authentication.
+ /// Gets the sets of OAuth endpoints used to authenticate against Salesforce.
+ /// Overriding these endpoints allows you to use Salesforce Enterprise for authentication.
///
public SalesforceAuthenticationEndpoints Endpoints { get; set; }
@@ -127,8 +129,8 @@ namespace Owin.Security.Providers.Salesforce
BackchannelTimeout = TimeSpan.FromSeconds(60);
Endpoints = new SalesforceAuthenticationEndpoints
{
- AuthorizationEndpoint = AuthorizationEndPoint,
- TokenEndpoint = TokenEndpoint
+ AuthorizationEndpoint = null,
+ TokenEndpoint = null
};
}
}