Let's start with a scenario. Bob the user has logged in to your ASP.NET Core application through Azure AD authentication. Bob then also opens their email through Office 365 in the same browser window. They decide to leave work for today, and sign out from Office 365.

Without single sign-out, Bob has to also sign out from your Core application for them to be fully signed out.

With single sign-out, Bob doesn't have to separately sign out from your application. It's already been done for them.

Defining the remote sign-out path


First you will need to define the RemoteSignoutPath in the OpenIdConnectOptions. Here is the full configuration for OpenId Connect authentication that we will use:

.AddOpenIdConnect(o =>
{
o.ClientId = Configuration["Authentication:ClientId"];
o.Authority = Configuration["Authentication:Authority"];
o.CallbackPath = "/aad-callback"; o.RemoteSignOutPath = "/aad-signout";
});

Since the URL was defined as /aad-signout and the app runs at https://mycoolapp.com, we will define the sign-out URL to Azure AD as https://mycoolapp.com/aad-signout. Here is how that looks:

Now one final thing is that due to how single sign-out works, we must remove the SameSite attribute from the authentication cookie:

.AddCookie(o =>
{
o.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
})

This security feature must currently be removed to use single sign-out. I will explain why in a bit.
And we are done. If you try a scenario like in the start, you'll notice your authentication cookie will vanish.
The complete authentication configuration just for reference:

services
.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultForbidScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(o =>
{
o.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
})
.AddOpenIdConnect(o =>
{
o.ClientId = Configuration["Authentication:ClientId"];
o.Authority = Configuration["Authentication:Authority"];
o.CallbackPath = "/aad-callback"; o.RemoteSignOutPath = "/aad-signout";
});

How it works


So, that was quite easy. The way it works is actually quite simple. Azure AD knows the user is logged in to your app, and it has a sign-out URL defined. AAD opens a hidden iframe and sets its URL to your sign-out URL.

Now this did not work for me at first due to the SameSite property that is set by default now in ASP.NET Core. The authentication cookie gets SameSite=lax by default, which means that it is passed only in GET requests that are top-level, when coming from another origin. So it will not be attached to requests from iframes or AJAX that are initiated by other sites.

Thus it must be disabled for this to work, since it works via an iframe that is hosted in another origin.

You can also use your app's normal signout URL in AAD (which you link to from a Sign Out link in your app), however it must then support GET requests. Based on my observations, it made AAD do the sign-out slightly faster as it was able to detect the iframe arriving in AAD's URL. Since the origin is the same, it is allowed access to the iframe URL and it knows the app signout is done. Otherwise it seems to wait some fixed time period.

This is known as front-channel global sign-out. There is also a back-channel global sign-out protocol specification, which AAD does not implement.

If you block framing through use of X-Frame-Options or Content-Security-Policy, it will also prevent this from working. You will have to allow https://login.microsoftonline.com to frame your app.

Front-channel sign-out

This is the method used by Azure AD. Hidden iframe that gets set to your sign-out URL. Sign-out endpoint receives the GET request and handles sign-out as it normally would.

Pros:

  • Easy to implement
  • Can use existing signout URL with no modifications to app

Cons:

  • Sort of a cross-request forgery
  • Requires turning off SameSite mode for the auth cookie (if using cookies)
  • Must allow AAD to frame your site (add login.microsoftonline.com as allowed frame-ancestor)

I would highly recommend having a CSP that blocks framing from other origins than AAD (plus others that you need to allow).

Back-channel sign-out

This is the other method for single sign-out defined in OpenId Connect specifications. It is not implemented by Azure AD. I have asked the Azure AD team about this and they did say they will look into it :)

This method works by having the identity provider send a request from its back-end to your back-end (i.e. using a back-channel). A signed token similar to an Id token is attached to the request so your back-end can know which user is signing out. It is up to your app to implement session invalidation then.

Pros:

  • More secure, can implement strict controls for cookies and framing
  • The call is authenticated, not based on a cookie, but a token signed by AAD

Cons:

  • Harder to implement
  • Even harder to implement correctly in a distributed application

You need to clear session state for the user when you get the request. Or you may need to mark the user's session as expired. And then check if the session is expired on every request.

I can definitely see the motivation for both of these flows. Front-channel is easy to implement, even existing apps can utilize it. Back-channel allows for a more secure approach for those apps willing to pay the cost of implementing it. I do wish AAD would implement the back-channel version too.

Summary


Overall, implementing OpenId Connect single sign-out has been made supremely easy in ASP.NET Core. Well, at least the front-channel version. Since Azure AD only supports front-channel single sign-out, it does require you to reduce some security controls such as removing the SameSite property from the authentication cookie. That protects from Cross-Site Request Forgery attacks, and honestly I'd like to keep that there. But since AAD needs to do an authenticated cross-site request, there is really no choice.

I think whether this feature is valuable enough to reduce the security controls in your app is a decision that the developers/architects will have to make on a case-by-case basis.

原文链接

Implementing Azure AD Single Sign-Out in ASP.NET Core(转载)的更多相关文章

  1. 在 Azure WebApps 中运行64位 Asp.net Core 应用

    作为微软下一代的开源的跨平台的开发框架, Asp.net core 正在吸引越来越多的开发者基于其构建现代 web 应用. 目前, Azure App Service 也实现了对 asp.net co ...

  2. Azure AD(二)调用受Microsoft 标识平台保护的 ASP.NET Core Web API 下

    一,引言 上一节讲到如何在我们的项目中集成Azure AD 保护我们的API资源,以及在项目中集成Swagger,并且如何把Swagger作为一个客户端进行认证和授权去访问我们的WebApi资源的?本 ...

  3. [Windows Azure] Adding Sign-On to Your Web Application Using Windows Azure AD

    Adding Sign-On to Your Web Application Using Windows Azure AD 14 out of 19 rated this helpful - Rate ...

  4. Azure 部署 Asp.NET Core Web App

    在云计算大行其道的时代,当你在部署一个网站时,第一选择肯定是各式各样的云端服务.那么究竟使用什么样的云端服务才能够以最快捷的方式部署一个 ASP.NET Core 的网站呢?Azure 的 Web A ...

  5. 在 Azure 上部署 Asp.NET Core Web App

    在云计算大行其道的时代,当你要部署一个网站时第一选择肯定是各式各样的云端服务.那么究竟使用什么样的云端服务才能够以最快捷的方式部署一个 ASP.NET Core的网站呢?Azure 的 Web App ...

  6. 微软Azure配置中心 App Configuration (一):轻松集成到Asp.Net Core

    写在前面 在日常开发中,我这边比较熟悉的配置中心有,携程Apollo,阿里Nacos(配置中心,服务治理一体) 之前文章: Asp.Net Core与携程阿波罗(Apollo)的第一次亲密接触 总体来 ...

  7. asp.net core 系列之Response caching 之 Distributed caching(3)

    这篇文章讲解分布式缓存,即 Distributed caching in ASP.NET Core Distributed caching in ASP.NET Core 分布式缓存是可以在多个应用服 ...

  8. 【译】ASP.NET Core updates in .NET 5 Preview 8

    .NET 5 预览版 8 现在已经可以获取了,并且已经准备好接受评估.下面列出了本次发布的新特性: 使用 Microsoft.Identity.Web 进行 Azure Active Director ...

  9. 003.ASP.NET Core tutorials--【Asp.net core 教程】

    ASP.NET Core tutorials Asp.net core 教程 2016-10-14 1 分钟阅读时长 本文内容 1.Building web applications 构建web应用 ...

随机推荐

  1. shell脚本遇到问题"$'\r': command not found"

    shell脚本写得一切正常,但是一执行就报错: line: XXX "$'\r': command not found" 问题原因:文件格式问题(虽然在window和linux上选 ...

  2. springboot中配置urlrewrite实现url伪静态强化网站seo

    关于urlrewrite urlrewrite使用强大的自定义规则来使用用户更容易记住.搜索引擎更容易找到的URL(对于seo比较重要).通过使用规则模板.重写映射,Web管理员可以轻松地设置规则,根 ...

  3. 页面预加载loading动画,再载入内容

    默认情况下如果网站请求速度慢,所以会有一段时间的空白页面等等,用户体验效果不好,见到很多的页面都有预加载的效果,加载之前先加载一个动画,后台进程继续加载页面内容,当页面内容加载完之后再退出动画显示内容 ...

  4. C#使用Xamarin开发移动应用 ---- 系列文章

    C#使用Xamarin开发移动应用 C#使用Xamarin开发可移植移动应用终章(11.获取设备信息与常用组件,开源一个可开发模版.) C#使用Xamarin开发可移植移动应用进阶篇(10.综合演练, ...

  5. Springboot JackSon

    1. SpringBoot JSON工具包默认是Jackson,只需要引入spring-boot-starter-web依赖包,自动引入相应依赖包: <dependency> <gr ...

  6. MySQL 的各种 join

    table th:first-of-type { width: 200px; } join 类型 备注 left [outer] join right [outer] join union [all ...

  7. mybatis学习3

    parameterType(输入类型) 传递简单类型::使用#{}占位符,或者${}进行sql拼接 传递pojo对象: Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为p ...

  8. TCP连接和连接释放(TCP的三次挥手和四次握手)

    TCP的运输连接管理 TCP是面向连接的协议.运输连接是用来传送TCP报文的.TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程.因此,运输连接就有三个阶段,即:连接建立.数据传送和连接 ...

  9. Python中字符串匹配函数startswith()函数

    1.函数用途含义 Python startswith() 方法用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False.如果参数 beg 和 end 指定值,则在指定范围内 ...

  10. 浅谈HTTPS传输过程

    HTTPS是什么 HTTPS不是一个新的协议,可以理解为是一个HTTP协议的加密"版本"(HTTP+SSL(TLS)).那为什么HTTP协议需要加密,不加密会出现什么问题呢?先来了 ...