Estoy tratando de implementar la autenticación a través de mis servicios de back-end de una aplicación orientada a microService usando Keycloak primavera y de arranque con la primavera de Seguridad y JWT-tokens (portador de ajuste de sólo en Keycloak).
Tengo un servicio de back-end que requiere autenticación para acceder a los puntos finales REST. Este servicio proporciona datos para una interfaz de usuario web y también toma los datos a almacenar en la base de datos para que pueda ser procesada más tarde. Autentificación del usuario en la interfaz de usuario y la interfaz de usuario en contra de que el servicio de back-end ya tanto trabajo.
Luego, hay otro servicio de back-end que ejecuta en segundo plano, el cálculo de los valores que deben estar presentes también en el servicio de back-end mencionado en primer lugar. A medida que uno requiere autenticación, el servicio de hacer los cálculos primero hay que recuperar un token de acceso de Keycloak para la autenticación en el otro servicio de back-end para el puesto de trabajo HTTP.
Estoy tratando de hacer el cargo HTTP con el KeycloakRestTemplate, pero cuando llamo el método .postForObject, me sale una excepción:
Caused by: java.lang.IllegalStateException: Cannot set authorization header because there is no authenticated principal
at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.getKeycloakSecurityContext(KeycloakClientRequestFactory.java:70)
at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.postProcessHttpRequest(KeycloakClientRequestFactory.java:55)
at org.springframework.http.client.HttpComponentsClientHttpRequestFactory.createRequest(HttpComponentsClientHttpRequestFactory.java:160)
Parece que el servicio de cálculo no recupera el token de autenticación de forma automática antes de llamar a otro servicio REST. Hice un montón de investigación sobre Google en todas esas clases específicas Keycloak, pero no me entero de lo que tengo que hacer.
¿Puede alguien por favor, dame una pista? Asimismo, no sé qué partes de la configuración de la primavera son relevantes aquí, pero voy a proporcionarles si los necesita.
EDITAR
Mis application.properties de las miradas de servicios de cálculo como esta:
keycloak.auth-server-url=https://localhost/auth
keycloak.realm=myrealm
keycloak.bearer-only=true
keycloak.resource=backend-service2
keycloak.principal-attribute=preferred_username
keycloak.cors=true
keycloak.realm-key=<PUBKEY>
keycloak.credentials.secret=<SECRET_UUID_STYLE>
keycloak.use-resource-role-mappings=true
ACTUALIZAR
Gracias @Sai prateek y @Xtreme motorista. Esto me parece conducir a la dirección correcta.
He aplicado esta solución, pero sigo teniendo una excepción, creo que la configuración keycloak está mal. Tengo tres clientes en keycloak ahora: WebUI, backend-service1, backend-service2.
El webui se configura como: Tipo de acceso: public
El backend-service1 se configura como: Tipo de acceso: sólo portador
El backend-service2 se configura como: Tipo de acceso: sólo portador
La excepción es:
2019-02-18 11:15:32.914 DEBUG 22620 --- [ restartedMain] o.s.web.client.RestTemplate : POST request for "http://localhost:<PORT>/auth/realms/<REALM_NAME>/protocol/openid-connect/token" resulted in 400 (Bad Request); invoking error handler
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
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 org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: error="access_denied", error_description="Access token denied."
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:142)
at org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider.obtainAccessToken(ClientCredentialsAccessTokenProvider.java:44)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:148)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:121)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:683)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:644)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:399)
[STRIPPED]
... 5 more
Caused by: error="invalid_client", error_description="Bearer-only not allowed"
at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:80)
at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:33)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readInternal(AbstractJackson2HttpMessageConverter.java:217)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:198)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:237)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:730)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:688)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:654)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137)
... 18 more
También tenga en cuenta que he cambiado el keycloak.auth-server-url
que http://localhost:<PORT>/auth
(sin HTTPS) para la validación de certificados no falla debido a la auto certificado firmado en el desarrollo.
OK, encontrado la solución a mí mismo: que necesitaba para establecer el botón del interruptor "Las cuentas de servicio habilitadas" en ON en la configuración del cliente para "back-end-service2" dentro de keycloak.