Skip to content

Commit

Permalink
Include a return URL in /Authenticate requests (#76)
Browse files Browse the repository at this point in the history
Some auth scenarios (WS-Fed, OIDC) were having issues with remote app auth because, as part of authentication, they redirected to an external auth provider to log the user in. When the auth provider redirected back to the app, it would re-direct back to the ASP.NET app's /systemweb-adapters/authenticate endpoint (which the ASP.NET Core app calls to in order to authenticate the user) instead of to the actual endpoint in the ASP.NET Core app that the user was originally trying to get to.

This PR fixes that by including the original request URL as a query string parameter when calling the authenticate endpoint (for example: https://localhost:4321/systemweb-adapters/authenticate?original-url=http://localhost:8765/SomeController/SomeAction (except that the original-url value is URL encoded)). Then, when the ASP.NET app handles request to /systemweb-adapters/authenticate, if no API key is provided (this is only present when called from the ASP.NET Core app), it will assume that the request may be a redirect back and if an original-url query string is present (the auth flows I tested all preserved the query string), the ASP.NET app will re-direct the request to that URL instead.

This PR also adds an OIDC sample to demonstrate this scenario working.

Fixes #72
  • Loading branch information
mjrousos authored Jul 20, 2022
1 parent 30fa213 commit 655311f
Show file tree
Hide file tree
Showing 59 changed files with 3,096 additions and 62 deletions.
14 changes: 14 additions & 0 deletions Microsoft.AspNetCore.SystemWebAdapters.sln
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FormsAuth", "samples\Remote
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FormsAuthCore", "samples\RemoteAuth\Forms\FormsAuthCore\FormsAuthCore.csproj", "{EB87A63B-D71F-43E3-B0B7-588B4BED3BE3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OIDCAuth", "samples\RemoteAuth\OIDC\OIDCAuth\OIDCAuth.csproj", "{0BA8335A-9F56-4439-9A71-4BD5B58C2273}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OIDCAuthCore", "samples\RemoteAuth\OIDC\OIDCAuthCore\OIDCAuthCore.csproj", "{32192715-5F15-4E11-B96F-971468DA33E6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SystemWebAdapters.Framework.Tests", "test\Microsoft.AspNetCore.SystemWebAdapters.Framework.Tests\Microsoft.AspNetCore.SystemWebAdapters.Framework.Tests.csproj", "{23036CE4-A4D7-4A42-868A-1FB5211A41F0}"
EndProject
Global
Expand Down Expand Up @@ -97,6 +101,14 @@ Global
{EB87A63B-D71F-43E3-B0B7-588B4BED3BE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB87A63B-D71F-43E3-B0B7-588B4BED3BE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB87A63B-D71F-43E3-B0B7-588B4BED3BE3}.Release|Any CPU.Build.0 = Release|Any CPU
{0BA8335A-9F56-4439-9A71-4BD5B58C2273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BA8335A-9F56-4439-9A71-4BD5B58C2273}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BA8335A-9F56-4439-9A71-4BD5B58C2273}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BA8335A-9F56-4439-9A71-4BD5B58C2273}.Release|Any CPU.Build.0 = Release|Any CPU
{32192715-5F15-4E11-B96F-971468DA33E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32192715-5F15-4E11-B96F-971468DA33E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32192715-5F15-4E11-B96F-971468DA33E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32192715-5F15-4E11-B96F-971468DA33E6}.Release|Any CPU.Build.0 = Release|Any CPU
{23036CE4-A4D7-4A42-868A-1FB5211A41F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23036CE4-A4D7-4A42-868A-1FB5211A41F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23036CE4-A4D7-4A42-868A-1FB5211A41F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -118,6 +130,8 @@ Global
{6ECC8509-2937-4667-AECC-C20BA62D3FC5} = {95915611-30BF-4AFF-AE41-5CDC6F57DCF7}
{87223E5F-A0B2-4827-A4A4-B4C40BEAFBE8} = {95915611-30BF-4AFF-AE41-5CDC6F57DCF7}
{EB87A63B-D71F-43E3-B0B7-588B4BED3BE3} = {95915611-30BF-4AFF-AE41-5CDC6F57DCF7}
{0BA8335A-9F56-4439-9A71-4BD5B58C2273} = {95915611-30BF-4AFF-AE41-5CDC6F57DCF7}
{32192715-5F15-4E11-B96F-971468DA33E6} = {95915611-30BF-4AFF-AE41-5CDC6F57DCF7}
{23036CE4-A4D7-4A42-868A-1FB5211A41F0} = {A1BDA50C-D70B-416C-97F1-74B0649797C5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
Expand Down
8 changes: 4 additions & 4 deletions samples/RemoteAuth/Bearer/RemoteBearer/Web.config
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
https://go.microsoft.com/fwlink/?LinkId=301879
Expand All @@ -9,9 +9,9 @@
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="ida:AadInstance" value="https://GroupManager.b2clogin.com/{0}/{1}/v2.0/.well-known/openid-configuration" />
<add key="ida:Tenant" value="GroupManager.onmicrosoft.com" />
<add key="ida:ClientId" value="aa37c024-522b-43e3-9bf3-68f310bcd010" />
<add key="ida:AadInstance" value="https://contoso.b2clogin.com/{0}/{1}/v2.0/.well-known/openid-configuration" />
<add key="ida:Tenant" value="" />
<add key="ida:ClientId" value="" />
<add key="ida:SignUpSignInPolicyId" value="B2C_1_signup-signin" />
</appSettings>
<system.web>
Expand Down
30 changes: 30 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/App_Start/BundleConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Web;
using System.Web.Optimization;

namespace OIDCAuth
{
public class BundleConfig
{
// For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.min.js"));

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*"));

// Use the development version of Modernizr to develop with and learn from. Then, when you're
// ready for production, use the build tool at https://modernizr.com to pick only the tests you need.
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*"));

bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.min.js"));

bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.min.css",
"~/Content/site.css"));
}
}
}
13 changes: 13 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/App_Start/FilterConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Web;
using System.Web.Mvc;

namespace OIDCAuth
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
}
23 changes: 23 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/App_Start/RouteConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace OIDCAuth
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
66 changes: 66 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/App_Start/Startup.Auth.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Configuration;
using System.Security.Claims;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;

namespace OIDCAuth
{
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string clientSecret = ConfigurationManager.AppSettings["ida:ClientSecret"];
private static string aadInstance = EnsureTrailingSlash(ConfigurationManager.AppSettings["ida:AADInstance"]);
private static string tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
private static string policyName = ConfigurationManager.AppSettings["ida:PolicyName"];
private static string scope = ConfigurationManager.AppSettings["ida:Scope"];
private static string authority = aadInstance + tenantId + "/" + policyName;

public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

app.UseCookieAuthentication(new CookieAuthenticationOptions());

app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
ClientSecret = clientSecret,
ResponseType = "id_token",
Scope = scope,
Authority = authority,
RedirectUri = redirectUri,

Notifications = new OpenIdConnectAuthenticationNotifications()
{
SecurityTokenValidated = (context) =>
{
string name = context.AuthenticationTicket.Identity.FindFirst("name").Value;
context.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Name, name, string.Empty));
return System.Threading.Tasks.Task.FromResult(0);
}
}
});

}

private static string EnsureTrailingSlash(string value)
{
if (value == null)
{
value = string.Empty;
}

if (!value.EndsWith("/", StringComparison.Ordinal))
{
return value + "/";
}

return value;
}
}
}
30 changes: 30 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/Content/Site.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
body {
padding-top: 50px;
padding-bottom: 20px;
}

/* Set padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
padding-right: 15px;
}

/* Override the default bootstrap behavior where horizontal description lists
will truncate terms that are too long to fit in the left column
*/
.dl-horizontal dt {
white-space: normal;
}

/* Set width on the form input elements since they're 100% wide by default */
input,
select,
textarea {
max-width: 280px;
}

.navbar-inverse .navbar-toggle:hover,
.navbar-inverse .navbar-toggle:focus {
background-color: #777;
border-color: #fff
}

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/Content/bootstrap.min.css

Large diffs are not rendered by default.

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.Owin.Security;

namespace OIDCAuth.Controllers
{
public class AccountController : Controller
{
public void SignIn()
{
// Send an OpenID Connect sign-in request.
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}

public void SignOut()
{
string callbackUrl = Url.Action("SignOutCallback", "Account", routeValues: null, protocol: Request.Url.Scheme);

HttpContext.GetOwinContext().Authentication.SignOut(
new AuthenticationProperties { RedirectUri = callbackUrl },
OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
}

public ActionResult SignOutCallback()
{
if (Request.IsAuthenticated)
{
// Redirect to home page if the user is authenticated.
return RedirectToAction("Index", "Home");
}

return View();
}
}
}
37 changes: 37 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace OIDCAuth.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}

public ActionResult About()
{
ViewBag.Message = "Your application description page.";

return View();
}

public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";

return View();
}


[Authorize]
public ActionResult UserInfo()
{
return View();
}
}
}
1 change: 1 addition & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/Global.asax
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%@ Application Codebehind="Global.asax.cs" Inherits="OIDCAuth.MvcApplication" Language="C#" %>
27 changes: 27 additions & 0 deletions samples/RemoteAuth/OIDC/OIDCAuth/Global.asax.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace OIDCAuth
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

SystemWebAdapterConfiguration.AddSystemWebAdapters(this)
.AddProxySupport(options => options.UseForwardedHeaders = true)
.AddRemoteApp(options => options.ApiKey = "test-key")
.AddRemoteAppAuthentication();

}
}
}
Loading

0 comments on commit 655311f

Please sign in to comment.