From 470f2b7338036ba595435fbc8c8723878e438525 Mon Sep 17 00:00:00 2001 From: Tyler Palesano Date: Wed, 16 Sep 2020 14:00:09 -0500 Subject: [PATCH] Solving SameSiteMode issue that some Chrome users are seeing. --- .../Extensions/SameSiteHandlingExtensions.cs | 73 +++++++++++++++++++ .../XeroOAuth2Sample-MVC-PKCE/Startup.cs | 2 + 2 files changed, 75 insertions(+) create mode 100644 XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Extensions/SameSiteHandlingExtensions.cs diff --git a/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Extensions/SameSiteHandlingExtensions.cs b/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Extensions/SameSiteHandlingExtensions.cs new file mode 100644 index 0000000..f9d31ab --- /dev/null +++ b/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Extensions/SameSiteHandlingExtensions.cs @@ -0,0 +1,73 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; + +namespace XeroOAuth2Sample_MVC_PKCE.Extensions +{ + // Copied from https://github.com/IdentityServer/IdentityServer4/blob/main/src/IdentityServer4/host/Extensions/SameSiteHandlingExtensions.cs on https://github.com/IdentityServer/IdentityServer4/commit/e581c13c0ba0234fbc253f918f7b1d620bf35734 + // Also copied from https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/ + public static class SameSiteHandlingExtensions + { + public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services) + { + services.Configure(options => + { + options.MinimumSameSitePolicy = SameSiteMode.Unspecified; + options.OnAppendCookie = cookieContext => + CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + options.OnDeleteCookie = cookieContext => + CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + }); + + return services; + } + + private static void CheckSameSite(HttpContext httpContext, CookieOptions options) + { + if (options.SameSite == SameSiteMode.None) + { + var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); + if (!httpContext.Request.IsHttps || DisallowsSameSiteNone(userAgent)) + { + // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1) + options.SameSite = SameSiteMode.Unspecified; + } + } + } + + private static bool DisallowsSameSiteNone(string userAgent) + { + // Cover all iOS based browsers here. This includes: + // - Safari on iOS 12 for iPhone, iPod Touch, iPad + // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad + // - Chrome on iOS 12 for iPhone, iPod Touch, iPad + // All of which are broken by SameSite=None, because they use the iOS networking stack + if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12")) + { + return true; + } + + // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes: + // - Safari on Mac OS X. + // This does not include: + // - Chrome on Mac OS X + // Because they do not use the Mac OS networking stack. + if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && + userAgent.Contains("Version/") && userAgent.Contains("Safari")) + { + return true; + } + + // Cover Chrome 50-69, because some versions are broken by SameSite=None, + // and none in this range require it. + // Note: this covers some pre-Chromium Edge versions, + // but pre-Chromium Edge does not require SameSite=None. + if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6")) + { + return true; + } + + return false; + } + } +} diff --git a/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Startup.cs b/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Startup.cs index f3f7ed9..c811a7c 100644 --- a/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Startup.cs +++ b/XeroOAuth2Sample-MVC-PKCE/XeroOAuth2Sample-MVC-PKCE/Startup.cs @@ -31,6 +31,8 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + services.AddSameSiteCookiePolicy(); + services.AddHttpClient(); services.TryAddSingleton(new XeroConfiguration