建立具有访问权限或ID令牌/令牌交换的SSO /设置Cookie

时间:2020-07-15 13:52:35

标签: single-sign-on keycloak token-exchange

我允许登录外部应用程序的用户通过Keycloak的身份代理和内部令牌交换外部的访问令牌跳入我们的应用程序。

现在,我想在应用程序中的嵌入式JxBrowser中建立SSO会话,类似于常规的浏览器登录流程,其中在浏览器中设置了三个Cookie:AUTH_SESSION,KEYCLOAK_SESSION_LEGACY和KEYCLOAK_IDENTITY_LEGACY。

KEYCLOAK_IDENTITY_LEGACY包含类型为Serialized-ID的令牌,看上去与ID令牌有些相似。

是否可以使用交换的(内部)访问和/或ID令牌创建KEYCLOAK_IDENTITY_LEGACY cookie,并且如果还正确创建了其他两个cookie,那么是否可以建立有效的SSO会话?

基本上我所缺少的就是如何获取或创建Serialized-ID类型的令牌。

1 个答案:

答案 0 :(得分:1)

一种实现此目的的方法:

  1. 在此example之后实施自定义终结点

请注意,该提供程序对我来说很好,而无需在standalone.xml中注册它,我只是将JAR添加到Keycloak Docker映像中。

  1. 添加一种方法,该方法可验证给定的访问令牌,查找用户,获取用户会话并在响应中设置cookie(为简洁起见,省略了大多数错误处理):

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("sso")
    public Response sso() {
        final HttpHeaders headers = keycloakSession.getContext().getRequestHeaders();
        final String authorization = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
        final String[] value = authorization.split(" ");
        final String accessToken = value[1];
        final AccessToken token = Tokens.getAccessToken(accessToken, keycloakSession);
    
        if (token == null) {
            throw new ErrorResponseException(Errors.INVALID_TOKEN, "Invalid access token", Status.UNAUTHORIZED);
        }
    
        final RealmModel realm = keycloakSession.getContext().getRealm();
        final UriInfo uriInfo = keycloakSession.getContext().getUri();
        final ClientConnection clientConnection = keycloakSession.getContext().getConnection();
    
        final UserModel user = keycloakSession.users().getUserById(token.getSubject(), realm);
    
        final UserSessionModel userSession = keycloakSession.sessions().getUserSession(realm, token.getSessionState());
    
        AuthenticationManager.createLoginCookie(keycloakSession, realm, user, userSession, uriInfo, clientConnection);
    
        return Response.noContent().build();
    }
    

免责声明:我不能完全确定此实现并不意味着任何安全问题,但是由于Tokens.getAccessToken(accessToken, keycloakSession)会完全验证访问令牌,因此只能使用有效的访问令牌来设置cookie。

对于CORS,请添加:

@OPTIONS
@Produces(MediaType.APPLICATION_JSON)
@Path("sso")
public Response preflight() {
    final HttpRequest request = Resteasy.getContextData(HttpRequest.class);
    
    return Cors.add(request, Response.ok("", MediaType.APPLICATION_JSON))
            .auth()
            .preflight()
            .allowedMethods("GET", "OPTIONS")
            .build();
}

sso()中的

    final HttpRequest request = Resteasy.getContextData(HttpRequest.class);

    return Cors.add(request, Response.ok("", MediaType.APPLICATION_JSON))
            .auth()
            .allowedMethods("GET")
            .allowedOrigins(token)
            .build();

我不确定的是Firefox为什么要对GET请求进行预检,使其有必要处理。