0

我看到很多关于此的主题,但似乎所有主题都使用相同的 URL 访问 KEYCLOAK。解释。我尝试建立一个由 KC 架构保护的前端+微服务。

看图:

简单的架构

如果每个人都可以使用相同的 url 看到 keycloak (kc),那么一切都会正常工作,即对于 JS:

const keycloakURL = "http://test-kc-keycloak:8080/auth";

const keycloakParams = {
  url: keycloakURL,
  realm: "Test",
  clientId: "IHM"
};
const keycloak = Keycloak(keycloakParams);
...

对于服务(project-default.yml):

thorntail:
  keycloak:
    secure-deployments:
      kc.war:
        auth-server-url: "http://test-kc-keycloak:8080/auth"
        realm: Test
        resource: service
        bearer-only: true
        ssl-required: external
  microprofile:
    jwtauth:
      realm: Test
      token:
        issuedBy: "http://test-kc-keycloak:8080/auth/realms/Test"


  logging:
    loggers:
      kc:
        level: DEBUG

https://github.com/lbroque/test-kc

但在现实世界中,前端处于网络的黑暗面,而 KC 和服务应该处于受保护的环境中。所以前端通过反向代理和 HTTPS 方案看到 KC,而服务通过 HTTP 方案看到它。

据我所知,该服务尝试使用 SSL 访问 KC:

10:37:51,102 ERROR [adapters.rotation.JWKPublicKeyLocator] (default task-1) :
>>> Error when sending request to retrieve realm keys: org.keycloak.adapters.HttpClientAdapterException: IO error
    at org.keycloak.adapters.HttpAdapterUtils.sendJsonHttpRequest(HttpAdapterUtils.java:57)
    at org.keycloak.adapters.rotation.JWKPublicKeyLocator.sendRequest(JWKPublicKeyLocator.java:99)
    at org.keycloak.adapters.rotation.JWKPublicKeyLocator.getPublicKey(JWKPublicKeyLocator.java:63)
    at org.keycloak.adapters.rotation.AdapterTokenVerifier.getPublicKey(AdapterTokenVerifier.java:121)
    at org.keycloak.adapters.rotation.AdapterTokenVerifier.createVerifier(AdapterTokenVerifier.java:111)
    at org.keycloak.adapters.rotation.AdapterTokenVerifier.verifyToken(AdapterTokenVerifier.java:47)
    at org.wildfly.swarm.keycloak.mpjwt.deployment.KeycloakJWTCallerPrincipalFactory.parse(KeycloakJWTCallerPrincipalFactory.java:26)
    at org.wildfly.swarm.microprofile.jwtauth.deployment.auth.jaas.JWTLoginModule.validate(JWTLoginModule.java:100)
    at org.wildfly.swarm.microprofile.jwtauth.deployment.auth.jaas.JWTLoginModule.login(JWTLoginModule.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
    at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
    at org.jboss.security.authentication.JBossCachedAuthenticationManager.defaultLogin(JBossCachedAuthenticationManager.java:406)
    at org.jboss.security.authentication.JBossCachedAuthenticationManager.proceedWithJaasLogin(JBossCachedAuthenticationManager.java:345)
    at org.jboss.security.authentication.JBossCachedAuthenticationManager.authenticate(JBossCachedAuthenticationManager.java:323)
    at org.jboss.security.authentication.JBossCachedAuthenticationManager.isValid(JBossCachedAuthenticationManager.java:146)
    at org.wildfly.extension.undertow.security.JAASIdentityManagerImpl.verifyCredential(JAASIdentityManagerImpl.java:123)
    at org.wildfly.extension.undertow.security.JAASIdentityManagerImpl.verify(JAASIdentityManagerImpl.java:96)
    at org.wildfly.swarm.microprofile.jwtauth.deployment.auth.JWTAuthMechanism.authenticate(JWTAuthMechanism.java:77)
    at org.wildfly.extension.undertow.security.jaspi.modules.HTTPSchemeServerAuthModule.validateRequest(HTTPSchemeServerAuthModule.java:88)
    at org.jboss.security.auth.message.config.JBossServerAuthContext.invokeModules(JBossServerAuthContext.java:157)
    at org.jboss.security.auth.message.config.JBossServerAuthContext.validateRequest(JBossServerAuthContext.java:135)
    at org.jboss.security.plugins.auth.JASPIServerAuthenticationManager.isValid(JASPIServerAuthenticationManager.java:115)
    at org.wildfly.extension.undertow.security.jaspi.JASPICAuthenticationMechanism.authenticate(JASPICAuthenticationMechanism.java:125)
    at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.transition(SecurityContextImpl.java:245)
    at io.undertow.security.impl.SecurityContextImpl$AuthAttempter.access$100(SecurityContextImpl.java:231)
    at io.undertow.security.impl.SecurityContextImpl.attemptAuthentication(SecurityContextImpl.java:125)
    at io.undertow.security.impl.SecurityContextImpl.authTransition(SecurityContextImpl.java:99)
    at io.undertow.security.impl.SecurityContextImpl.authenticate(SecurityContextImpl.java:92)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:55)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jaspi.JASPICSecureResponseHandler.handleRequest(JASPICSecureResponseHandler.java:48)
    at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
    at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:573)
    at org.keycloak.adapters.SniSSLSocketFactory.createLayeredSocket(SniSSLSocketFactory.java:114)
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:557)
    at org.keycloak.adapters.SniSSLSocketFactory.connectSocket(SniSSLSocketFactory.java:109)
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:414)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144)
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
    at org.keycloak.adapters.HttpAdapterUtils.sendJsonHttpRequest(HttpAdapterUtils.java:36)
    ... 72 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
    at sun.security.validator.Validator.validate(Validator.java:262)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
    ... 94 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
    ... 100 more

这意味着它尝试使用 https 方案,不是吗?所以我想它使用在前端发送的 TOKEN 中找到的 URL,它使用 HTTPS 方案获得它,因为我配置了我的服务(所以它应该使用 HTTP 方案):

thorntail:
  keycloak:
    secure-deployments:
      model4xxx.war:
        auth-server-url: "http://keycloak.hnr:9090/auth"
        realm: xxx
        resource: model4xxx
        bearer-only: true
        ssl-required: external
  microprofile:
    jwtauth:
      realm: xxx
      token:
        issuedBy: "http://keycloak.hnr:9090/auth/realms/xxxx"

最后一点:KC 在 DOCKER 容器中。我尝试了几种环境变量 KEYCLOAK_FRONTEND_URL、KEYCLOAK_HOSTNAME 的组合。它似乎没有任何效果。

我想我不明白 auth-server-url 的目的。如果可以在令牌中找到信息有什么用????

我敢肯定这是我看不到或不理解的非常明显的事情……请帮忙。

4

2 回答 2

1

您不能从 HTTP 和 HTTPS(或不同的 url)为同一领域中的客户端访问 Keycloak 实例。属于令牌颁发者的auth-server-url需要相同,这是由不同的适配器检查的。

然而,这似乎直到 KEYCLOAK 版本 8

您的问题似乎反映在此JIRA 票证中,Keycloak 团队确实为此提供了解决方案,该解决方案记录在此草稿此处。可能您可以稍微调整一下您的 keycloak docker 映像并添加此配置,因此请考虑是否值得您这样做或从您的服务外部访问 Keycloak 服务器。

也可以看看:

于 2020-05-06T13:51:04.907 回答
0

香槟酒 !有了这个 conf (project-defauls.yml) :

thorntail:
  keycloak:
    secure-deployments:
      model4geo3d.war:
        auth-server-url: "http://keycloak.hnr:9090/auth"
        realm: xxxx
        resource: model4xxx
        bearer-only: true
        ssl-required: external
  microprofile:
    jwtauth:
      realm: xxx
      token:
        issuedBy: "https://keycloak.hnr/auth/realms/xxxx"

和 :

       - "KEYCLOAK_FRONTEND_URL=https://keycloak.hnr/auth/"
        - "PROXY_ADDRESS_FORWARDING=true"

在 docker-compose 的 keycloak 容器 (keycloak.environment)

keytool -import -trustcacerts -keystore /etc/ssl/certs/java/cacerts -storepass 'changeit' -file /home/core/dota/keycloak.hnr.crt -alias keycloak

在数据服务的容器中,它工作得很好。

2020-05-06 17:41:56,582 INFO  [org.keycloak.adapters.KeycloakDeployment] (default task-1) Loaded URLs from http://keycloak.hnr:9090/auth/realms/xxxx/.well-known/openid-configuration

得到了可以使用的正确配置:)

感谢 Xtreme Biker 的帮助和时间。

于 2020-05-06T15:50:11.133 回答