SonarQube 的 IdentityProvider 账户互斥原因分析
前言
soanr 是一个代码质量管理系统,代码是开源的。在公司统一认证平台还没出来时,sonar 已接入 ldap 提供系统登录认证功能,现在使用 sonar-auth-oidc 插件以 OIDC 协议接入集中认证平台时,发现用户的账户是互斥的(如果现有用户之前采用 ldap 登录,使用 oidc 登录后会创建一个新的用户,没法关联之前的账户),即使用户的所有信息一致也是如此。本文旨在分析具体原因以及寻求一种可实施的解决方案
相关链接:
- soanrqube :https://github.com/SonarSource/sonarqube
- soanr-auth-oidc : https://github.com/vaulttec/sonar-auth-oidc
sonar 插件实现分析
以 sonar-auth-oidc 为例,实现一个 soanr 的插件,需要如下步骤:
1、实现对应的插件接口
soanr 将可以扩展的通用的功能抽象定义放到了 sonar-plugin-api 模块,实现插件首先需要依赖这个模块,然后需要实现什么功能,找到对应的接口定义,以 sonar-auth-oidc 为例,需要实现 OAuth2IdentityProvider 接口。
@ServerSide public class OidcIdentityProvider implements OAuth2IdentityProvider { private static final Logger LOGGER = Loggers.get(OidcIdentityProvider.class); public static final String KEY = "oidc"; private final OidcConfiguration config; private final OidcClient client; private final UserIdentityFactory userIdentityFactory; public OidcIdentityProvider(OidcConfiguration config, OidcClient client, UserIdentityFactory userIdentityFactory) { this.config = config; this.client = client; this.userIdentityFactory = userIdentityFactory; } //省略非关键逻辑 @Override public void init(InitContext context) { LOGGER.trace("Starting authentication workflow"); if (!isEnabled()) { throw new IllegalStateException("OpenID Connect authentication is disabled"); } String state = context.generateCsrfState(); AuthenticationRequest authenticationRequest = client.getAuthenticationRequest(context.getCallbackUrl(), state); LOGGER.trace("Redirecting to authentication endpoint"); context.redirectTo(authenticationRequest.toURI().toString()); } @Override public void callback(CallbackContext context) { LOGGER.trace("Handling authentication response"); context.verifyCsrfState(); AuthorizationCode authorizationCode = client.getAuthorizationCode(context.getRequest()); UserInfo userInfo = client.getUserInfo(authorizationCode, context.getCallbackUrl()); UserIdentity userIdentity = userIdentityFactory.create(userInfo); LOGGER.debug("Authenticating user '{}' with groups {}", userIdentity.getProviderLogin(), userIdentity.getGroups()); context.authenticate(userIdentity); LOGGER.trace("Redirecting to requested page"); context.redirectToRequestedPage(); } }
2、实现 plugin 接口,声明扩展类
public class AuthOidcPlugin implements Plugin { @Override public void define(Context context) { context.addExtensions(OidcConfiguration.class, OidcClient.class, OidcIdentityProvider.class, UserIdentityFactory.class); context.addExtensions(OidcConfiguration.definitions()); } }
3、使用插件打包工具,打包插件
<plugin> <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> <artifactId>sonar-packaging-maven-plugin</artifactId> <version>1.18.0.372</version> <extensions>true</extensions> <configuration> <pluginClass>org.vaulttec.sonarqube.auth.oidc.AuthOidcPlugin</pluginClass> </configuration> </plugin>
插件工作原理浅析
插件完成后,最终会打成 jar 包,在应用市场安装插件,相当于下载了一个 jar 放到了 soanrqube 安装目录的 ./extensions/plugins 路径下。上面的打包工具会给 jar 包清单 META-INF/MANIFEST.MF 里加上Plugin-Class: org.vaulttec.sonarqube.auth.oidc.AuthOidcPlugin 。soanrqube 启动时,插件扫描器会扫到这个 jar ,解析拿到 plugin-class 并加载插件。
sonar-auth-oidc 实现逻辑分析
从sonar 插件实现分析了解到,sonar-auth-oidc 实现 Oauth 认证的关键逻辑在 OidcIdentityProvider 类里,关键代码如下:
init 方法
集成 oidc 插件后,访问 soanr 会显示如下登录入口
该登录按钮的链接为:http://172.26.202.128:9000/sessions/init/oidc?return_to=%2F ,点击这个链接,就会触发插件里 init 方法,init 方法里拼装了 oidc 授权服务器的接口地址并重定向到这地址,等待用户授权
callback 方法
用户在授权服务器授权页面授权完成后,授权服务器会回调 soanr 服务,最终触发 callback 函数。在 callback 函数里,首先从 request 里拿到了 authorizationCode ,然后使用 code 请求 oidc 授权服务器,拿到了 UserInfo,使用 UserInfo 里的信息,组装了 soanr 内置的认证类 UserIdentity 。然后调用了 authenticate 完成认证,如果认证成功,没有异常,则重定向到了登录成功的页面。看到这里,最关键的地方是 UserIdentity ,前面一大堆逻辑,最终就为了组装出这个实体,这个类定义如下:
sonar-auth-oidc 插件里有用的信息,就这些了,关键的是 UserIdentity ,接下来需要从 sonarqube 里找到 CallBackContext 的实现类,看 authenticate() 方法里是怎么处理 UserIdentity 的。
soanrqube 的 auth 模块分析
soanr 的web 登录认证功能在 sonar-webserver-auth 模块,上文在 oidc 插件里出现的 InitContext 、 CallBackContxt 均在 OAuth2ContextFactory 类里被初始化,关键逻辑如下:
authenticate 过程
- 1、执行用户注册逻辑(内部控制了是注册还是更新)
- 2、生成登录用的 jwt 串
- 3、设置本地用户登录的 session
register 过程
1、通过 externalId 和 IdentityProvider 查询用户,如果为空,则通过 externalLogin 和 IdentityProvider 查询用户
2、如果 user 不存在或者已禁用,则创建一个新的用户,否则注册一个已存在的用户(更新用户信息)
关键点开始凸显出来了,关键逻辑在这里,通过 externalId 和 IdentityProvider、externalLogin 等条件没有查询到用户信息,所以才创建了新的用户,接下来看下数据库里 User 存储了哪些信息。
User 表数据分析
本地 sonar 尝试对接过 ldap 、gitlab 、oidc ,所以一个账户有三条用户数据,其中 ldap 账户的 identityProvider 被标记为 sonarqube 了,而使用 OIDC 登录被标记为 oidc(插件的 key),所以才导致通过 externalId 和 IdentityProvider、externalLogin 等信息都查询不到用户信息
解决方案
经过分析后,知道了 oidc 和 ldap 账户互斥的根本原因为,不同 identityProvider 的用户会被加上 provider_key 区分,导致同一个用户,即使用户信息一样,从不同的 identityProvider 认证也会生成不同的用户。所以,可以从如下两个方案出发,解决问题
方案一:重写插件,将 identityProvider 标识和 LDAP 的同步。
- 优点:兼容 LDAP 和 identityProvider 账户,可以设计下兼容所以的 identityProvider
- 缺点:实施比较困难,需要自己维护插件或者寻求官方仓库合并 pr
方案二:修改数据库中存量 LDAP 用户的 identityProvider 的标识为 oidc。
- 优点:改动较简单
- 缺点:LDAP 和 OIDC 不兼容,集成 OIDC 后,只能被动的关闭 LDAP,而原 LDAP 的输入框和本地用户密码框是一起的,没法移除,对用户使用习惯会有影响
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
推荐几款顶级好用的IDEA插件,开发效率提升几倍
前言 "工欲善其事必先利其器"在实际的开发过程中,灵活的使用好开发工具,将让我们的工作事半功倍。今天给大家推荐几款好用的IDEA插件,写代码也可以"飞起来"! 实用插件 Fast Request Fast Request是一个基于springmvc的帮助你快速生成url和参数的插件,同时也是一个http client工具,调试API的时候只需要点击生成图标,再点击发送请求按钮即可,非常实用 Easy Javadoc 快速生成javadoc文档,点击快捷键生成方法或类或属性的javadoc,同时支持各种渠道的翻译 MybatisCodeHeaderPro 最好的Mybatis代码提示,完整支持Mybatis动态sql代码提示,代码检测,写sql几乎所有地方都有代码提示,支持基于方法名动态生成sql,生成基础实体类及mapper,功能非常强大 SQL Params Setter 将mybatis sql拼接起来,此插件免费,简单实用 Translation 对于英文不好的开发者来说,这款插件就是神器,在看各种框架源码的时候十分有用; 选择右键就可以翻译,对于方法或者类上面的注释,只要按下F...
- 下一篇
同源华安加入 openEuler 社区,积极推进行业开源生态发展
近日,致力于行业市场深入服务的基础软件提供商,北京同源华安软件科技有限公司(以下简称“同源华安”)签署 CLA(Contributor License Agreement 贡献者许可协议),正式加入 openEuler 社区。 同源华安在加入社区后,将会和社区一起在虚拟化方向探索新的技术方向,目前同源华安的工程师已经加入 oVirt SIG,担任 Maintainer。 同源华安成立于 2019 年 2 月,国家高新技术企业,专注于基础软件领域的深耕发展,着力于技术精专及细分市场的行业竞争力,已拓展行业市场并培育品牌影响力。 同源华安通过构建“一体两翼“基础软件体系,提出”服务连接一切“的发展理念,提供长期跟随的技术增值服和 Linux 关键模块及研发支撑个性服务,目前已发布基于 openEuler20.03 LTS 的同源 OS 8.1 发行版、商用版全栈操作系统(TYOS)和云管平台(AmStack),支持市面上主流的 CPU(飞腾、鲲鹏、海光、兆芯、龙芯、申威、Intel、AMD、ARMv8、ARMv7)。 同源 TYOS 注重性能与场景要求,服务器 OS 面向企业级应用并提供管...
相关文章
文章评论
共有0条评论来说两句吧...