diff --git a/.editorconfig b/.editorconfig
index 7357f91a8..e1e371638 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -473,9 +473,6 @@ dotnet_diagnostic.CA1062.severity = none
# CA1303: Do not pass literals as localized parameters
dotnet_diagnostic.CA1303.severity = none
-# SA1004: Documentation lines should begin with single space
-dotnet_diagnostic.SA1004.severity = none
-
# SA1118: Parameter should not span multiple lines
dotnet_diagnostic.SA1118.severity = none
@@ -536,9 +533,6 @@ dotnet_diagnostic.SA1616.severity = none
# SA1623: Property summary documentation should match accessors
dotnet_diagnostic.SA1623.severity = none
-# SA1627: Documentation text should not be empty
-dotnet_diagnostic.SA1627.severity = none
-
# SA1642: Constructor summary documentation should begin with standard text
dotnet_diagnostic.SA1642.severity = none
diff --git a/src/Microsoft.Identity.Web/CertificateManagement/CertificateDescription.cs b/src/Microsoft.Identity.Web/CertificateManagement/CertificateDescription.cs
index eab50eb74..dcf9d2005 100644
--- a/src/Microsoft.Identity.Web/CertificateManagement/CertificateDescription.cs
+++ b/src/Microsoft.Identity.Web/CertificateManagement/CertificateDescription.cs
@@ -26,10 +26,10 @@ public static CertificateDescription FromCertificate(X509Certificate2 x509certif
}
///
- /// Creates a Certificate Description from KeyVault.
+ /// Creates a certificate description from Key Vault.
///
- ///
- ///
+ /// The Key Vault URL.
+ /// The name of the certificate in Key Vault.
/// A certificate description.
public static CertificateDescription FromKeyVault(string keyVaultUrl, string keyVaultCertificateName)
{
@@ -42,9 +42,9 @@ public static CertificateDescription FromKeyVault(string keyVaultUrl, string key
}
///
- /// Create a certificate description from a base 64 encoded value.
+ /// Create a certificate description from a Base64 encoded value.
///
- /// base 64 encoded value.
+ /// Base64 encoded certificate value.
/// A certificate description.
public static CertificateDescription FromBase64Encoded(string base64EncodedValue)
{
@@ -59,7 +59,7 @@ public static CertificateDescription FromBase64Encoded(string base64EncodedValue
/// Create a certificate description from path on disk.
///
/// Path were to find the certificate file.
- /// certificate password.
+ /// Certificate password.
/// A certificate description.
public static CertificateDescription FromPath(string path, string password = null)
{
@@ -72,7 +72,7 @@ public static CertificateDescription FromPath(string path, string password = nul
}
///
- /// Create a certificate description from a thumbprint and store location (certificate manager on Windows for instance).
+ /// Create a certificate description from a thumbprint and store location (Certificate Manager on Windows for instance).
///
/// Certificate thumbprint.
/// Store location where to find the certificate.
@@ -93,7 +93,7 @@ public static CertificateDescription FromStoreWithThumprint(
///
/// Create a certificate description from a certificate distinguished name (such as CN=name)
- /// and store location (certificate manager on Windows for instance).
+ /// and store location (Certificate Manager on Windows for instance).
///
/// Certificate distinguished named.
/// Store location where to find the certificate.
@@ -121,14 +121,14 @@ public static CertificateDescription FromStoreWithDistinguishedName(
/// Container in which to find the certificate.
///
/// - If equals , then
- /// the container is the KeyVault base URL
+ /// the container is the Key Vault base URL.
/// - If equals , then
- /// this value is not used
+ /// this value is not used.
/// - If equals , then
- /// this value is the path on disk where to find the certificate
+ /// this value is the path on disk where to find the certificate.
/// - If equals ,
/// or , then
- /// this value is the path to the certificate in the cert store, for instance CurrentUser/My
+ /// this value is the path to the certificate in the cert store, for instance CurrentUser/My.
///
///
internal string Container
@@ -177,12 +177,12 @@ internal string Container
}
///
- /// URL of the KeyVault for instance https://msidentitywebsamples.vault.azure.net.
+ /// URL of the Key Vault for instance https://msidentitywebsamples.vault.azure.net.
///
public string KeyVaultUrl { get; set; }
///
- /// Certiticate store path, for instance "CurrentUser/My".
+ /// Certificate store path, for instance "CurrentUser/My".
///
/// This property should only be used in conjunction with DistinguishName or Thumbprint.
public string CertificateStorePath { get; set; }
@@ -193,7 +193,7 @@ internal string Container
public string CertificateDistinguishedName { get; set; }
///
- /// Name of the certificate in KeyVault.
+ /// Name of the certificate in Key Vault.
///
public string KeyVaultCertificateName { get; set; }
@@ -213,7 +213,7 @@ internal string Container
public string CertificatePassword { get; set; }
///
- /// Base 64 encoded value.
+ /// Base64 encoded certificate value.
///
public string Base64EncodedValue { get; set; }
@@ -222,11 +222,11 @@ internal string Container
///
///
/// - If equals , then
- /// the reference is the name of the certificate in KeyVault (maybe the version?)
+ /// the reference is the name of the certificate in Key Vault (maybe the version?).
/// - If equals , then
- /// this value is the base 64 encoded certificate itself
+ /// this value is the base 64 encoded certificate itself.
/// - If equals , then
- /// this value is the password to access the certificate (if needed)
+ /// this value is the password to access the certificate (if needed).
/// - If equals ,
/// this value is the distinguished name.
/// - If equals ,
@@ -281,7 +281,7 @@ internal string ReferenceOrValue
}
///
- /// The certificate, either provided directly in code by the
+ /// The certificate, either provided directly in code
/// or loaded from the description.
///
public X509Certificate2 Certificate { get; internal set; }
diff --git a/src/Microsoft.Identity.Web/CertificateManagement/CertificateSource.cs b/src/Microsoft.Identity.Web/CertificateManagement/CertificateSource.cs
index 75447c23a..97827eeee 100644
--- a/src/Microsoft.Identity.Web/CertificateManagement/CertificateSource.cs
+++ b/src/Microsoft.Identity.Web/CertificateManagement/CertificateSource.cs
@@ -9,22 +9,22 @@ namespace Microsoft.Identity.Web
public enum CertificateSource
{
///
- /// Certificate itself
+ /// Certificate itself.
///
Certificate = 0,
///
- /// KeyVault
+ /// From an Azure Key Vault.
///
KeyVault = 1,
///
- /// Base 64 encoded directly in the configuration.
+ /// Base64 encoded string directly from the configuration.
///
Base64Encoded = 2,
///
- /// Local path on disk
+ /// From local path on disk.
///
Path = 3,
@@ -34,7 +34,7 @@ public enum CertificateSource
StoreWithThumbprint = 4,
///
- /// From the certificate store, described by its Distinguished name.
+ /// From the certificate store, described by its distinguished name.
///
StoreWithDistinguishedName = 5,
}
diff --git a/src/Microsoft.Identity.Web/CertificateManagement/DefaultCertificateLoader.cs b/src/Microsoft.Identity.Web/CertificateManagement/DefaultCertificateLoader.cs
index 212a32e6e..d682d36e4 100644
--- a/src/Microsoft.Identity.Web/CertificateManagement/DefaultCertificateLoader.cs
+++ b/src/Microsoft.Identity.Web/CertificateManagement/DefaultCertificateLoader.cs
@@ -54,9 +54,9 @@ private static X509Certificate2 LoadFromBase64Encoded(string certificateBase64)
}
///
- /// Load a certificate from KeyVault, including the private key.
+ /// Load a certificate from Key Vault, including the private key.
///
- /// Url of KeyVault.
+ /// URL of Key Vault.
/// Name of the certificate.
/// An certificate.
/// This code is inspired by Heath Stewart's code in:
diff --git a/src/Microsoft.Identity.Web/CertificateManagement/ICertificateLoader.cs b/src/Microsoft.Identity.Web/CertificateManagement/ICertificateLoader.cs
index 949540e09..b21efd06a 100644
--- a/src/Microsoft.Identity.Web/CertificateManagement/ICertificateLoader.cs
+++ b/src/Microsoft.Identity.Web/CertificateManagement/ICertificateLoader.cs
@@ -4,7 +4,7 @@
namespace Microsoft.Identity.Web
{
///
- /// Interface to implement load a certificate.
+ /// Interface to implement loading of a certificate.
///
internal interface ICertificateLoader
{
diff --git a/src/Microsoft.Identity.Web/ITokenAcquisitionInternal.cs b/src/Microsoft.Identity.Web/ITokenAcquisitionInternal.cs
index 7cf320790..658ea3f61 100644
--- a/src/Microsoft.Identity.Web/ITokenAcquisitionInternal.cs
+++ b/src/Microsoft.Identity.Web/ITokenAcquisitionInternal.cs
@@ -46,7 +46,7 @@ internal interface ITokenAcquisitionInternal
/// Removes the account associated with context.HttpContext.User from the MSAL.NET cache.
///
/// RedirectContext passed-in to a
- /// Openidconnect event.
+ /// OpenID Connect event.
///
Task RemoveAccountAsync(RedirectContext context);
}
diff --git a/src/Microsoft.Identity.Web/MicrosoftIdentityOptions.cs b/src/Microsoft.Identity.Web/MicrosoftIdentityOptions.cs
index f19cb89f6..30f73b8e9 100644
--- a/src/Microsoft.Identity.Web/MicrosoftIdentityOptions.cs
+++ b/src/Microsoft.Identity.Web/MicrosoftIdentityOptions.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace Microsoft.Identity.Web
{
@@ -29,28 +30,37 @@ public class MicrosoftIdentityOptions : OpenIdConnectOptions
///
/// In a web app, gets or sets the RedirectUri (URI where the token will be sent back by
- /// Azure Active Directory or Azure Active Directory B2C)
+ /// Azure Active Directory or Azure Active Directory B2C).
/// This property is exclusive with which should be used preferably if you don't want
/// to have a different deployed configuration from your developer configuration.
/// There are cases where RedirectUri is needed, for instance when you use a reverse proxy that transforms HTTPS
/// URLs (external world) to HTTP URLs (inside the protected area). This can also be useful for web apps running
- /// in containers (for the same reasons)
+ /// in containers (for the same reasons).
/// If you don't specify the redirect URI, the redirect URI will be computed from the URL on which the app is
/// deployed and the CallbackPath.
///
public string RedirectUri { get; set; }
///
- /// In a web app, gets or sets the PostLogoutRedirectUri
+ /// In a web app, gets or sets the PostLogoutRedirectUri.
/// This property is exclusive with which should be used preferably if you don't want
/// to have a different deployed configuration from your developer configuration.
/// There are cases where PostLogoutRedirectUri is needed, for instance when you use a reverse proxy that transforms HTTPS
/// URLs (external world) to HTTP URLs (inside the protected area). This can also be useful for web apps running
- /// in containers (for the same reasons)
+ /// in containers (for the same reasons).
/// If you don't specify the PostLogoutRedirectUri, it will be computed by ASP.NET Core using the SignedOutCallbackPath.
///
public string PostLogoutRedirectUri { get; set; }
+ ///
+ /// When set to true, forces the and the to use the HTTPS scheme.
+ /// This behavior can be desired, for instance, when you use a reverse proxy that transforms HTTPS
+ /// URLs (external world) to HTTP URLs (inside the protected area). This can also be useful for web apps running
+ /// in containers (for the same reasons), for example when deploying your web app to
+ /// Azure App Services in Linux containers.
+ ///
+ public bool ForceHttpsRedirectUris { get; set; }
+
///
/// Gets or sets TokenAcquisition as a Singleton. There are scenarios, like using the Graph SDK,
/// which require TokenAcquisition to be a Singleton.
diff --git a/src/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs b/src/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs
index 4e701a249..8c27cbf3c 100644
--- a/src/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs
+++ b/src/Microsoft.Identity.Web/Resource/ScopesRequiredHttpContextExtensions.cs
@@ -24,8 +24,9 @@ public static class ScopesRequiredHttpContextExtensions
///
/// HttpContext (from the controller).
/// Scopes accepted by this web API.
- /// with a set to
- ///
+ /// with a set to
+ /// .
+ ///
public static void VerifyUserHasAnyAcceptedScope(this HttpContext context, params string[] acceptedScopes)
{
if (acceptedScopes == null)
diff --git a/src/Microsoft.Identity.Web/TokenAcquisition.cs b/src/Microsoft.Identity.Web/TokenAcquisition.cs
index e3f81cf85..7385e6f05 100644
--- a/src/Microsoft.Identity.Web/TokenAcquisition.cs
+++ b/src/Microsoft.Identity.Web/TokenAcquisition.cs
@@ -284,7 +284,7 @@ public async Task GetAccessTokenForAppAsync(IEnumerable scopes)
/// Removes the account associated with context.HttpContext.User from the MSAL.NET cache.
///
/// RedirectContext passed-in to a
- /// Openidconnect event.
+ /// OpenID Connect event.
///
public async Task RemoveAccountAsync(RedirectContext context)
{
diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs
index 91822177e..06cc6aaa7 100644
--- a/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs
+++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Session/MsalSessionTokenCacheProvider.cs
@@ -10,21 +10,24 @@
namespace Microsoft.Identity.Web.TokenCacheProviders.Session
{
///
- /// An implementation of token cache for Confidential clients backed by an HTTP session.
+ /// An implementation of token cache for confidential clients backed by an HTTP session.
///
+ ///
/// For this session cache to work effectively the ASP.NET Core session has to be configured properly.
/// The latest guidance is provided at https://docs.microsoft.com/aspnet/core/fundamentals/app-state
///
- /// // In the method - public void ConfigureServices(IServiceCollection services) in startup.cs, add the following
+ /// In the method public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following:
+ ///
/// services.AddSession(option =>
/// {
/// option.Cookie.IsEssential = true;
/// });
- ///
- /// In the method - public void Configure(IApplicationBuilder app, IHostingEnvironment env) in startup.cs, add the following
- ///
+ ///
+ /// In the method public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following:
+ ///
/// app.UseSession(); // Before UseMvc()
- ///
+ ///
+ ///
/// https://aka.ms/msal-net-token-cache-serialization
public class MsalSessionTokenCacheProvider : MsalAbstractTokenCacheProvider, IMsalTokenCacheProvider
{
diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs
index 21529bf97..cb3fdd391 100644
--- a/src/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs
+++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Session/SessionTokenCacheProviderExtension.cs
@@ -12,20 +12,25 @@ namespace Microsoft.Identity.Web.TokenCacheProviders.Session
///
public static class SessionTokenCacheProviderExtension
{
- /// Adds both App and per-user session token caches.
+ ///
+ /// Adds both App and per-user session token caches.
+ ///
+ ///
/// For this session cache to work effectively the ASP.NET Core session has to be configured properly.
/// The latest guidance is provided at https://docs.microsoft.com/aspnet/core/fundamentals/app-state
///
- /// // In the method - public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following
+ /// In the method public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following:
+ ///
/// services.AddSession(option =>
/// {
/// option.Cookie.IsEssential = true;
/// });
- ///
- /// In the method - public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following
- ///
+ ///
+ /// In the method public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following:
+ ///
/// app.UseSession(); // Before UseMvc()
- ///
+ ///
+ ///
/// The services collection to add to.
/// The service collection.
public static IServiceCollection AddSessionTokenCaches(this IServiceCollection services)
@@ -56,20 +61,25 @@ public static IServiceCollection AddSessionTokenCaches(this IServiceCollection s
return services;
}
- /// Adds an HTTP session based application token cache to the service collection.
+ ///
+ /// Adds an HTTP session based application token cache to the service collection.
+ ///
+ ///
/// For this session cache to work effectively the ASP.NET Core session has to be configured properly.
/// The latest guidance is provided at https://docs.microsoft.com/aspnet/core/fundamentals/app-state
///
- /// // In the method - public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following
+ /// In the method public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following:
+ ///
/// services.AddSession(option =>
/// {
/// option.Cookie.IsEssential = true;
/// });
- ///
- /// In the method - public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following
- ///
+ ///
+ /// In the method public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following:
+ ///
/// app.UseSession(); // Before UseMvc()
- ///
+ ///
+ ///
/// The services collection to add to.
/// The service collection.
public static IServiceCollection AddSessionAppTokenCache(this IServiceCollection services)
@@ -79,20 +89,25 @@ public static IServiceCollection AddSessionAppTokenCache(this IServiceCollection
return services;
}
- /// Adds an HTTP session based per user token cache to the service collection.
+ ///
+ /// Adds an HTTP session based per user token cache to the service collection.
+ ///
+ ///
/// For this session cache to work effectively the ASP.NET Core session has to be configured properly.
/// The latest guidance is provided at https://docs.microsoft.com/aspnet/core/fundamentals/app-state
///
- /// // In the method - public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following
+ /// In the method public void ConfigureServices(IServiceCollection services) in Startup.cs, add the following:
+ ///
/// services.AddSession(option =>
/// {
/// option.Cookie.IsEssential = true;
/// });
- ///
- /// In the method - public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following
- ///
+ ///
+ /// In the method public void Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs, add the following:
+ ///
/// app.UseSession(); // Before UseMvc()
- ///
+ ///
+ ///
/// The services collection to add to.
/// The service collection.
public static IServiceCollection AddSessionPerUserTokenCache(this IServiceCollection services)
diff --git a/src/Microsoft.Identity.Web/WebAppAuthenticationBuilderExtensions.cs b/src/Microsoft.Identity.Web/WebAppAuthenticationBuilderExtensions.cs
index a1f3eb742..82134953c 100644
--- a/src/Microsoft.Identity.Web/WebAppAuthenticationBuilderExtensions.cs
+++ b/src/Microsoft.Identity.Web/WebAppAuthenticationBuilderExtensions.cs
@@ -155,6 +155,11 @@ public static AuthenticationBuilder AddSignIn(
}
}
+ if (microsoftIdentityOptions.ForceHttpsRedirectUris && (context.ProtocolMessage?.RedirectUri?.StartsWith("http://") ?? false))
+ {
+ context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http://", "https://");
+ }
+
await redirectToIdpHandler(context).ConfigureAwait(false);
};
@@ -171,6 +176,11 @@ public static AuthenticationBuilder AddSignIn(
context.ProtocolMessage.PostLogoutRedirectUri = microsoftIdentityOptions.PostLogoutRedirectUri;
}
}
+
+ if (microsoftIdentityOptions.ForceHttpsRedirectUris && (context.ProtocolMessage?.PostLogoutRedirectUri?.StartsWith("http://") ?? false))
+ {
+ context.ProtocolMessage.PostLogoutRedirectUri = context.ProtocolMessage.PostLogoutRedirectUri.Replace("http://", "https://");
+ }
};
if (microsoftIdentityOptions.IsB2C)
diff --git a/tests/Microsoft.Identity.Web.Test/WebAppExtensionsTests.cs b/tests/Microsoft.Identity.Web.Test/WebAppExtensionsTests.cs
index d2ef5b6c0..e6d7a95e7 100644
--- a/tests/Microsoft.Identity.Web.Test/WebAppExtensionsTests.cs
+++ b/tests/Microsoft.Identity.Web.Test/WebAppExtensionsTests.cs
@@ -341,6 +341,47 @@ public void AddWebAppCallsProtectedWebApi_NoScopes()
Assert.Contains(OidcConstants.ScopeProfile, oidcOptions.Scope);
}
+ [Theory]
+ [InlineData(true, "http://localhost:123", "https://localhost:123")]
+ [InlineData(true, "https://localhost:123", "https://localhost:123")]
+ [InlineData(false, "http://localhost:123", "http://localhost:123")]
+ [InlineData(false, "https://localhost:123", "https://localhost:123")]
+ public async void AddSignIn_ForceHttpsRedirectUris(bool forceHttpsRedirectUris, string actualUri, string expectedUri)
+ {
+ _configureMsOptions = (options) =>
+ {
+ options.Instance = TestConstants.AadInstance;
+ options.TenantId = TestConstants.TenantIdAsGuid;
+ options.ClientId = TestConstants.ClientId;
+ options.ForceHttpsRedirectUris = forceHttpsRedirectUris;
+ };
+
+ var services = new ServiceCollection();
+ services.AddDataProtection();
+ new AuthenticationBuilder(services)
+ .AddSignIn(_configureOidcOptions, _configureMsOptions, _oidcScheme, _cookieScheme);
+
+ var provider = services.BuildServiceProvider();
+
+ var oidcOptions = provider.GetRequiredService>().Create(_oidcScheme);
+
+ var (httpContext, authScheme, authProperties) = CreateContextParameters(provider);
+ var redirectContext = new RedirectContext(httpContext, authScheme, oidcOptions, authProperties)
+ {
+ ProtocolMessage = new OpenIdConnectMessage()
+ {
+ RedirectUri = actualUri,
+ PostLogoutRedirectUri = actualUri,
+ },
+ };
+
+ await oidcOptions.Events.RedirectToIdentityProvider(redirectContext).ConfigureAwait(false);
+ await oidcOptions.Events.RedirectToIdentityProviderForSignOut(redirectContext).ConfigureAwait(false);
+
+ Assert.Equal(expectedUri, redirectContext.ProtocolMessage.RedirectUri);
+ Assert.Equal(expectedUri, redirectContext.ProtocolMessage.PostLogoutRedirectUri);
+ }
+
private void AddSignIn_TestCommon(IServiceCollection services, ServiceProvider provider)
{
// Assert correct services added