SSL 代理后面的 OWIN WS-Federation 重定向
OWIN WS-Federation Redirect behind SSL Proxy
我正在尝试编写我的第一个支持 ADFS 的 ASP.Net 网络应用程序。该应用程序在我的本地计算机上运行时运行良好,但是当我将它发布到 SSL 代理后面的 IIS 时,我的应用程序最终将经过身份验证的用户重定向到应用程序的 http 地址,而不是 https 地址。我该如何解决这个问题?
为了阐明进程在哪里中断,这里是正在发生的事情:
- 未经身份验证的用户浏览到应用程序的主页并被重定向到 Idp [好]
- 用户在 Idp 进行身份验证,令牌通过 https POST 发送回我的应用程序 [good]
- 我的应用分配了一个 cookie,并将用户重定向到 http 主页[坏]
在我的 Startup.Auth.cs 中,我只是使用样板代码:
public partial class Startup
{
private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = adfsMetadata
});
}
}
我读过几篇关于 identity/auth 在 ssl 代理背后的类似问题的帖子, 的建议对我没有影响。我猜是因为重定向是由 ws-fed 中间件而不是 cookie 提供程序执行的。
知道了!
通读 OWIN/Katana 源代码后,我在 ws-fed 代码中找到了允许您操作 URL 的挂钩。就我而言,如果我检测到 SSL 代理的存在(通过检查请求 headers),我将重写 URL 以实现 https 而不是 http。
public partial class Startup
{
private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = adfsMetadata,
Notifications = new WsFederationAuthenticationNotifications
{
SecurityTokenValidated = (notification) =>
{
notification.AuthenticationTicket.Properties.RedirectUri = ApplySchemeFromSSLProxy(notification.Request, notification.AuthenticationTicket.Properties.RedirectUri);
return Task.FromResult(0);
},
RedirectToIdentityProvider = (notification) =>
{
if (notification.ProtocolMessage.IsSignOutMessage)
{
notification.ProtocolMessage.Wreply = ApplySchemeFromSSLProxy(notification.Request, notification.ProtocolMessage.Wreply);
}
return Task.FromResult(0);
}
}
});
}
/// <summary>
/// If there is evidence of an SSL proxy in use, convert the uri to https.
/// </summary>
/// <param name="request"></param>
/// <param name="uri"></param>
/// <returns>Converted URI</returns>
private string ApplySchemeFromSSLProxy(IOwinRequest request, string uri)
{
if (
Uri.IsWellFormedUriString(uri, UriKind.Absolute) &&
request.Headers.Any(h =>
h.Key.ToLower().StartsWith("x-forwarded-proto") &&
h.Value.Contains(Uri.UriSchemeHttps)
)
)
{
var uriBuilder = new UriBuilder(uri)
{
Scheme = Uri.UriSchemeHttps,
Port = -1 // default port for scheme
};
return uriBuilder.ToString();
}
else
{
return uri;
}
}
}
我正在尝试编写我的第一个支持 ADFS 的 ASP.Net 网络应用程序。该应用程序在我的本地计算机上运行时运行良好,但是当我将它发布到 SSL 代理后面的 IIS 时,我的应用程序最终将经过身份验证的用户重定向到应用程序的 http 地址,而不是 https 地址。我该如何解决这个问题?
为了阐明进程在哪里中断,这里是正在发生的事情:
- 未经身份验证的用户浏览到应用程序的主页并被重定向到 Idp [好]
- 用户在 Idp 进行身份验证,令牌通过 https POST 发送回我的应用程序 [good]
- 我的应用分配了一个 cookie,并将用户重定向到 http 主页[坏]
在我的 Startup.Auth.cs 中,我只是使用样板代码:
public partial class Startup
{
private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = adfsMetadata
});
}
}
我读过几篇关于 identity/auth 在 ssl 代理背后的类似问题的帖子,
知道了!
通读 OWIN/Katana 源代码后,我在 ws-fed 代码中找到了允许您操作 URL 的挂钩。就我而言,如果我检测到 SSL 代理的存在(通过检查请求 headers),我将重写 URL 以实现 https 而不是 http。
public partial class Startup
{
private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = adfsMetadata,
Notifications = new WsFederationAuthenticationNotifications
{
SecurityTokenValidated = (notification) =>
{
notification.AuthenticationTicket.Properties.RedirectUri = ApplySchemeFromSSLProxy(notification.Request, notification.AuthenticationTicket.Properties.RedirectUri);
return Task.FromResult(0);
},
RedirectToIdentityProvider = (notification) =>
{
if (notification.ProtocolMessage.IsSignOutMessage)
{
notification.ProtocolMessage.Wreply = ApplySchemeFromSSLProxy(notification.Request, notification.ProtocolMessage.Wreply);
}
return Task.FromResult(0);
}
}
});
}
/// <summary>
/// If there is evidence of an SSL proxy in use, convert the uri to https.
/// </summary>
/// <param name="request"></param>
/// <param name="uri"></param>
/// <returns>Converted URI</returns>
private string ApplySchemeFromSSLProxy(IOwinRequest request, string uri)
{
if (
Uri.IsWellFormedUriString(uri, UriKind.Absolute) &&
request.Headers.Any(h =>
h.Key.ToLower().StartsWith("x-forwarded-proto") &&
h.Value.Contains(Uri.UriSchemeHttps)
)
)
{
var uriBuilder = new UriBuilder(uri)
{
Scheme = Uri.UriSchemeHttps,
Port = -1 // default port for scheme
};
return uriBuilder.ToString();
}
else
{
return uri;
}
}
}