presto基于konx实现统一登录2

289 阅读2分钟

我们在上篇文章中介绍了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的认证逻辑和原生保持一致。