我们在上篇文章中介绍了presto基于Knox实现统一登录的流程,但是有些细节没有处理好,这篇文章做个补充。presto通常有三种访问入口:ui、jdbc、cli;我们先来回顾下上篇文章。
-
ui 统一访问入口
这部分的改造思路比较简单,主要是:
-
识别登录ui,然后重定向到knox的登录入口;
这部分的改造比较简单,我们在AuthenticationFilter中isWebUi方法中做了如下改造:
-
presto原生会获取一个认证用户:
Optional<String> authenticatedUser = uiAuthenticator.getAuthenticatedUsername(request);,我们保留这个流程,如果获取不到认证用户,进入我们自己的处理流程: -
如果是登出request,清理用户cookie,并重定向到登录页面;
-
否则从request中获取jwtCookie,并解析出认证用户;
-
如果仍未获取到认证用户,则根据request获取到重定向的accessType,在重定向中做如下处理:
//筛选指定的request if (request.getMethod().equalsIgnoreCase("get") && redirectUri.getPath().equalsIgnoreCase(UiAuthenticator.LOGIN_FORM) && knoxUtils.isSecurity()) //构造统一登录url String loginUrl = knoxUtils.getLoginUrl(request); //重定向 response.sendRedirect(redirectUri.toString());
-
-
识别ui发送的其他类型的request,比如监控请求,查询请求等,对这类请求需要改造认证流程;
presto中Kerberos的认证是解析request header中的AUTHORIZATION字段,这个字段是需要浏览器支持的,目前只有火狐浏览器支持较好,但是也需要安装MIT客户端并进行复杂配置,所以这是我们需要改造的地方。改造的原则也是尽量少的修改原生代码,所以我们在原生认证失败后加了一段处理逻辑:
//原生认证失败后principal是null if (principal == null) { String prestoUser = request.getHeader(PrestoHeaders.PRESTO_USER); if (prestoUser != null) { principal = new KerberosPrincipal(prestoUser); } }我们将从request header中获取的user作为认证的依据是这样的,ui端发送的请求会将当前登录用户放入到request header中,而当前登录用户在登录的时候已经做过了认证。
这样子处理会有一个漏洞,用户可以手动在request中添加header字段混过认证,我猜presto开启Kerberos后必须使用ssl通信和这个有关。我们不想设置ssl通信,所以我们在ui的request中又加入了一个jwtCookie字段,进一步判断改请求是否合法。
-
这样子改造之后,前端ui的功能是没有问题了,但是存在这样一个问题,我们原本只想修改ui模块,但是CLI和JDBC模块的认证使用的也是这块代码,所以我们还得针对这两个模块做个小小的修改:
if ("presto-cli".equalsIgnoreCase(request.getHeader(PrestoHeaders.PRESTO_SOURCE))
|| "presto-jdbc".equalsIgnoreCase(request.getHeader(PrestoHeaders.PRESTO_SOURCE))) {
prestoUser = null;
}
加上这块代码后,cli和jdbc的认证逻辑和原生保持一致。