问题
I have a spring client with spring rest api's which are protected with keycloak. I am trying to call it using keycloakresttemplate from another client which is a pure java code with no security. I am getting the keycloak access token from java client and setting it in the header of rest url. It is not able to initialize the keycloakresttemplate.
Any view why I am facing this issue.
//Below is the code to hit the spring url using keycloakresttemplate.I have added Dependency of keycloack adapter and added the bean in my java class.
restTemplate.getForObject(<restapiURL>, class1, requestData);
//Below is the code I am using for getting the access token from keycloak
MultiValueMap<String,String> requestMap = new LinkedMultiValueMap<String,String>();
requestMap.add("client_id", "employee-service");
requestMap.add("username", "rachel");
requestMap.add("password", "rachel");
requestMap.add("grant_type", "password");
requestMap.add("client_secret", "cccebf50-3f28-4af2-8716-c4bfcfe6f5e7");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> requestData = new HttpEntity<>(requestMap, headers);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
String restApiurl = "http://localhost:8080/auth/realms/dev/protocol/openid-connect/token" ;
return restTemplate.postForObject(restApiurl, requestData, AccessTokenResponse.class);
Keycloak Setup for client: KeycloakSetup
Myworkspace structure Java Client Java Client Structure
Java Client2: REST API app structure
I have added one way ,a s per your suggestion in comment section and the other way,
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.ws.rs.InternalServerErrorException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.TrustStrategy;
import org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory;
import org.keycloak.adapters.springsecurity.client.KeycloakRestTemplate;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import com.dbaas.webagent.model.Employee;
public class KeycloakAgentClient {
@Autowired
KeycloakRestTemplate restTemplate;
//RestTemplate restTemplate;
public static final String REQUEST_URI = "http://localhost:8086/dbaasrest/addressService/getEmployees";
public static void main(String[] args) throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException {
AuthzClient authzClient = AuthzClient.create();
AuthorizationResponse response = authzClient.authorization("rachel", "rachel").authorize();
String rpt = response.getToken();
System.out.println("You got an RPT: " + rpt);
KeycloakAgentClient client = new KeycloakAgentClient();
List<Employee> list = client.getEmployeeList(rpt, new RestTemplate());
System.out.println("Employee List:***"+list);
}
private List<Employee> getEmployeeList(String accessToken, RestTemplate restTemplate) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer "+accessToken);
HttpEntity<?> requestEntity = new HttpEntity<>(headers);
//restTemplate.getInterceptors().add((ClientHttpRequestInterceptor) new BasicAuthentication("rachel","rachel"));
ResponseEntity<ArrayList> response = restTemplate.exchange(REQUEST_URI, HttpMethod.GET, requestEntity, ArrayList.class);
System.out.println("****"+response.getBody());
return response.getBody();
}
private List<Employee> callKeycloakProtectedAPI(HttpHeaders headers, RestTemplate restTemplate) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(REQUEST_URI);
String url = builder.toUriString();
//RestTemplate restTemplate = new RestTemplate();
try {
HttpEntity<Map<String,String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<ArrayList> response = restTemplate.exchange(REQUEST_URI, HttpMethod.GET, requestEntity, ArrayList.class);
if (response.getStatusCode().is2xxSuccessful()) {
return (List<Employee>) response;
}
System.out.println("Error response while getting response"+ response);
throw new InternalServerErrorException("");
} catch (Exception exp) {
System.out.println("Exception while getting response"+exp);
throw new InternalServerErrorException("");
}
}
}
回答1:
Looks the same apart from restTemplate.postForEntity(), not postForObject()
Let me share code we have, with login, logout and refresh token:
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.TrustStrategy;
import org.keycloak.RSATokenVerifier;
import org.keycloak.common.VerificationException;
import org.keycloak.exceptions.TokenNotActiveException;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.LinkedHashMap;
@Component
public class KeyCloakServiceImpl implements KeyCloakService {
private RestTemplate restTemplate;
private final KeyCloakConnectionProvider keyCloakConnectionProvider;
public KeyCloakServiceImpl(KeyCloakConnectionProvider keyCloakConnectionProvider,
RestTemplateBuilder restTemplateBuilder) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
this.keyCloakConnectionProvider = keyCloakConnectionProvider;
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
this.restTemplate = restTemplateBuilder
.requestFactory(requestFactory)
.messageConverters(new MappingJackson2HttpMessageConverter(), new FormHttpMessageConverter())
.build();
}
private AccessToken getAccessToken(String accessToken, boolean checkActive) throws VerificationException, NoSuchFieldException {
try {
PublicKey publicKey = getPublicKey();
if (publicKey != null) {
String realmUrl = keyCloakConnectionProvider.getRealmUrl();
AccessToken token =
RSATokenVerifier.verifyToken(
accessToken,
publicKey,
realmUrl,
checkActive,
true);
return token;
} else {
log.error("KeyCloakServiceImpl:verifyToken: SSO_PUBLIC_KEY is NULL.");
throw new NoSuchFieldException("KeyCloakServiceImpl:verifyToken: SSO_PUBLIC_KEY is NULL.");
}
} catch (TokenNotActiveException e) {
throw e;
} catch (VerificationException e) {
throw e;
} catch (NoSuchFieldException e) {
throw e;
} catch (Exception e) {
throw e;
}
}
@Override
public AccessToken loadAccessToken(String accessToken) throws TokenNotActiveException, VerificationException, NoSuchFieldException {
return getAccessToken(accessToken, true);
}
@Override
public AccessToken loadAccessTokenFromRefreshToken(String accessToken) throws TokenNotActiveException, VerificationException, NoSuchFieldException {
return getAccessToken(accessToken, false);
}
/**
* This method will call keycloak service to user login. after successful login it will provide
* access token.
*/
@Override
public AccessTokenResponse login(String username, String password) {
try {
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("client_id", keyCloakConnectionProvider.getResource());
requestParams.add("username", username);
requestParams.add("password", password);
requestParams.add("grant_type", "password");
requestParams.add("client_secret", keyCloakConnectionProvider.getClientSecret());
requestParams.add("scope", "openid");
AccessTokenResponse keycloakAccessToken = queryKeycloakByParams(requestParams);
return keycloakAccessToken;
} catch (Exception e) {
log.info(e.getMessage(), e);
throw e;
}
}
@Override
public AccessTokenResponse refresh(String refreshToken) {
try {
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("client_id", keyCloakConnectionProvider.getResource());
requestParams.add("grant_type", "refresh_token");
requestParams.add("client_secret", keyCloakConnectionProvider.getClientSecret());
requestParams.add("refresh_token", refreshToken);
AccessTokenResponse keycloakAccessToken = queryKeycloakByParams(requestParams);
return keycloakAccessToken;
} catch (Exception e) {
log.info(e.getMessage(), e);
throw e;
}
}
private AccessTokenResponse queryKeycloakByParams(MultiValueMap<String, String> requestParams) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
String url = keyCloakConnectionProvider.getOpenIdConnectTokenUrl();
AccessTokenResponse keycloakAccessToken = getAccessTokenResponse(request, url);
return keycloakAccessToken;
}
private AccessTokenResponse getAccessTokenResponse(HttpEntity<MultiValueMap<String, String>> request, String url) {
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (ResourceAccessException e) {
log.error("KeyCloak getAccessTokenResponse: " + e.getMessage());
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (Exception ex) {
throw ex;
}
} catch (Exception e) {
throw e;
}
}
@Override
public void logout(String refreshToken) {
try {
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("client_id", keyCloakConnectionProvider.getResource());
requestParams.add("client_secret", keyCloakConnectionProvider.getClientSecret());
requestParams.add("refresh_token", refreshToken);
logoutUserSession(requestParams);
} catch (Exception e) {
log.info(e.getMessage(), e);
throw e;
}
}
private void logoutUserSession(MultiValueMap<String, String> requestParams) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
String url = keyCloakConnectionProvider.getOpenIdConnectLogoutUrl();
restTemplate.postForEntity(url, request, Object.class);
}
private PublicKey getPublicKey() {
PublicKey publicKey = keyCloakConnectionProvider.getPublicKey();
if (publicKey == null) {
LinkedHashMap publicKeyMap = requestKeyFromKeycloak(keyCloakConnectionProvider.getOpenIdConnectCertsUrl());
publicKey = KeyCloakRsaKeyLoader.getPublicKeyFromKeyCloak(publicKeyMap);
keyCloakConnectionProvider.setPublicKey(publicKey);
}
return publicKey;
}
/**
* This method will connect to keycloak server using API call for getting public key.
*
* @param url A string value having keycloak base URL
* @return Public key JSON response string
*/
private LinkedHashMap requestKeyFromKeycloak(String url) {
try {
ResponseEntity<LinkedHashMap> response = restTemplate.getForEntity(url, LinkedHashMap.class);
LinkedHashMap body = response.getBody();
if (body != null) {
return body;
} else {
log.error("KeyCloakRsaKeyLoader:requestKeyFromKeycloak: Not able to fetch SSO public key from keycloak server");
}
} catch (Exception e) {
log.error("KeyCloakRsaKeyLoader:requestKeyFromKeycloak: Exception occurred with message = " + e.getMessage());
}
return null;
}
}
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
import org.springframework.stereotype.Component;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
@Component
@Slf4j
@AllArgsConstructor
public class KeyCloakConnectionProvider {
private static final Map<String, PublicKey> cache = new HashMap<>();
public static final String PUBLIC_KEY = "publicKey";
private KeycloakSpringBootProperties keycloakProperties;
public String getAuthServerUrl() {
return keycloakProperties.getAuthServerUrl();
}
public String getRealmUrl() {
return getAuthServerUrl()
+ "/realms/"
+ getRealm();
}
public String getOpenIdConnectUrl() {
return getRealmUrl() + "/protocol/openid-connect";
}
public String getOpenIdConnectTokenUrl() {
return getOpenIdConnectUrl() + "/token";
}
public String getOpenIdConnectLogoutUrl() {
return getOpenIdConnectUrl() + "/logout";
}
public String getOpenIdConnectCertsUrl() {
return getOpenIdConnectUrl() + "/certs";
}
public String getRealm() {
return keycloakProperties.getRealm();
}
public String getResource() {
return keycloakProperties.getResource();
}
public String getClientId() {
return getResource();
}
public String getClientSecret() {
return String.valueOf(keycloakProperties.getCredentials().get("secret"));
}
public int getConnectionPoolSize() {
return keycloakProperties.getConnectionPoolSize();
}
public PublicKey getPublicKey() {
return cache.get(PUBLIC_KEY);
}
public PublicKey setPublicKey(PublicKey publicKey) {
if (publicKey != null) {
cache.put(PUBLIC_KEY, publicKey);
}
return getPublicKey();
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.*;
import java.util.Base64.Decoder;
/**
* Class to fetch SSO public key from Keycloak server using 'certs' HTTP API call.
*/
@Slf4j
public class KeyCloakRsaKeyLoader {
private static final String MODULUS = "modulusBase64";
private static final String EXPONENT = "exponentBase64";
private static final ObjectMapper mapper = new ObjectMapper();
/**
* This method will accept keycloak base URL and realm name. Based on provided values it will
* fetch public key from keycloak.
*
* @param publicKeyMap A string value having keycloak public key as string
* @return Public key used to verify user access token.
*/
public static PublicKey getPublicKeyFromKeyCloak(LinkedHashMap publicKeyMap) {
try {
Decoder urlDecoder = Base64.getUrlDecoder();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
if (publicKeyMap != null) {
Map<String, String> valueMap = getValuesFromMap(publicKeyMap);
if (valueMap != null) {
BigInteger modulus = new BigInteger(1, urlDecoder.decode(valueMap.get(MODULUS)));
BigInteger publicExponent = new BigInteger(1, urlDecoder.decode(valueMap.get(EXPONENT)));
PublicKey publicKey = keyFactory.generatePublic(new RSAPublicKeySpec(modulus, publicExponent));
return publicKey;
}
}
} catch (Exception e) {
log.error("KeyCloakRsaKeyLoader:getPublicKeyFromKeyCloak: Exception occurred with message = " + e.getMessage());
}
return null;
}
/**
* This method will return a map containing values extracted from public key JSON string.
*
* @param publicKeyMap Public key map response
*/
private static Map<String, String> getValuesFromMap(LinkedHashMap publicKeyMap) {
try {
Map<String, String> values = new HashMap<>();
ArrayList keys = (ArrayList) publicKeyMap.get("keys");
if (keys != null && keys.size() > 0) {
LinkedHashMap value = (LinkedHashMap) keys.get(0);
values.put(MODULUS, (String) value.get("n"));
values.put(EXPONENT, (String) value.get("e"));
}
return values;
} catch (Exception e) {
log.error("KeyCloakRsaKeyLoader:getValuesFromJson: Exception occurred with message = " + e.getMessage());
}
return null;
}
}
回答2:
Regarding calling client2 from client1, take AUTHORIZATION header from client1 first request and include that in to query to client2. Like:
// Client 1
@RequestMapping(value = "/some-api", method = RequestMethod.POST) // or GET
public ResponseEntity<SomeDto> processSomething(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHeader) {
HttpHeaders headers = new HttpHeaders();
if (authHeader != null) {
headers.add(AUTHORIZATION_HEADER, authHeader);
}
SomeDto dto = someService.processSomething(headers);
return ResponseEntity.ok(dto);
}
// client1 someService
RestTemplate restTemplate = new RestTemplate();
public List<YourDto> getBla(HttpHeaders headers) {
String path = "/client2/api";
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(path);
String url = builder.toUriString();
try {
HttpEntity<?> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
return objectMapper.readValue(response.getBody(), new TypeReference<List<YourDto>>() {}).apply(response);
}
log.error("Error response while getting blabla", response);
throw new InternalServerException("");
} catch (HttpRestClientException | ResourceAccessException exp) {
log.error("Exception while getting blabla", exp);
throw new InternalServerException("");
}
}
回答3:
I am getting 401 unauthorized error now. Please check below code snippet. Client2, which is a spring rest api. RestController of spring, these api's are protected by keycloak.when I hit any of the api from browser, I get a keycloak login page and on successful authentication, it gives back response.package com.dbaas.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DBaaSRestController {
@RequestMapping(value="/",method=RequestMethod.GET)
public String getHomePage(){
return "This is the home page";
}
@RequestMapping(value="/login",method=RequestMethod.GET)
public String getMessage(){
return "admin";
}
@RequestMapping(value="/addressService/getEmployees",method=RequestMethod.GET,headers="Accept=application/json")
public List<Employee> getAllEmployees() throws IOException{
//getClientDetails();
List<Employee> employeeList = new ArrayList<Employee>();
employeeList=createEmployees();
return employeeList;
}
@RequestMapping(value = "/addressService/getEmployee/{id}", method = RequestMethod.GET,headers="Accept=application/json")
public Employee getCountryById(@PathVariable int id)
{
List<Employee> employeesList = new ArrayList();
employeesList=createEmployees();
for (Employee emp: employeesList) {
if(emp.getId()==id)
return emp;
}
return null;
}
public List<Employee> createEmployees()
{
Employee emp1=new Employee(1, "E1");
Employee emp2=new Employee(4, "E2");
Employee emp3=new Employee(3, "E3");
Employee emp4=new Employee(2, "E4");
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
employeeList.add(emp4);
return employeeList;
}
}
Now instead of accessing it directly from browser, I am trying to access it using a java client.
Client1.(Java Client)
public class KeycloakAgentClient {
RestTemplate restTemplate;
public static final String REQUEST_URI = "http://localhost:8086/dbaasrest/addressService/getEmployees";
public static void main(String[] args) throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException {
KeycloakAgentClient client = new KeycloakAgentClient();
KeyCloakServiceImpl impl = new KeyCloakServiceImpl();
AccessTokenResponse accessTokenResponse = new AccessTokenResponse();
accessTokenResponse = impl.login("rachel", "rachel");
String accessToken = accessTokenResponse.getToken();
List<Employee> list = client.getEmployeeList(accessToken);
System.out.println("Employee List:***"+list);
}
private List<Employee> getEmployeeList(String accessToken) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer "+accessToken);
List<Employee> empList= callKeycloakProtectedAPI(headers);
return empList;
}
private List<Employee> callKeycloakProtectedAPI(HttpHeaders headers) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(REQUEST_URI);
String url = builder.toUriString();
RestTemplate restTemplate = new RestTemplate();
try {
HttpEntity<Map<String,String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<ArrayList> response = restTemplate.exchange(REQUEST_URI, HttpMethod.GET, requestEntity, ArrayList.class);
if (response.getStatusCode().is2xxSuccessful()) {
return (List<Employee>) response;
}
System.out.println("Error response while getting response"+ response);
throw new InternalServerErrorException("");
} catch (Exception exp) {
System.out.println("Exception while getting response"+exp);
throw new InternalServerErrorException("");
}
}
}
KeycloakServiceImpl as per answer provided by you.
public class KeyCloakServiceImpl implements KeyCloakService{
private RestTemplate restTemplate;
//private final KeyCloakConnectionProvider keyCloakConnectionProvider;
public KeyCloakServiceImpl(/*KeyCloakConnectionProvider keyCloakConnectionProvider,*/
/*RestTemp restTemplateBuilder*/) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
//this.keyCloakConnectionProvider = keyCloakConnectionProvider;
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
this.restTemplate = new RestTemplate();/*restTemplateBuilder
.requestFactory(requestFactory)
.messageConverters(new MappingJackson2HttpMessageConverter(), new FormHttpMessageConverter())
.build();*/
}
private AccessToken getAccessToken(String accessToken, boolean checkActive) throws VerificationException, NoSuchFieldException {
/* try {
PublicKey publicKey = getPublicKey();
if (publicKey != null) {
String realmUrl = keyCloakConnectionProvider.getRealmUrl();
String realmUrl = "";
AccessToken token =
RSATokenVerifier.verifyToken(
accessToken,
publicKey,
realmUrl,
checkActive,
true);
return token;
} else {
System.out.println("KeyCloakServiceImpl:verifyToken: SSO_PUBLIC_KEY is NULL.");
throw new NoSuchFieldException("KeyCloakServiceImpl:verifyToken: SSO_PUBLIC_KEY is NULL.");
}
} catch (TokenNotActiveException e) {
throw e;
} catch (VerificationException e) {
throw e;
} catch (NoSuchFieldException e) {
throw e;
} catch (Exception e) {
throw e;
}*/
return null;
}
@Override
public AccessToken loadAccessToken(String accessToken) throws TokenNotActiveException, VerificationException, NoSuchFieldException {
return getAccessToken(accessToken, true);
}
@Override
public AccessToken loadAccessTokenFromRefreshToken(String accessToken) throws TokenNotActiveException, VerificationException, NoSuchFieldException {
return getAccessToken(accessToken, false);
}
/**
* This method will call keycloak service to user login. after successful login it will provide
* access token.
*/
@Override
public AccessTokenResponse login(String username, String password) {
try {
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
/* requestParams.add("client_id", keyCloakConnectionProvider.getResource());*/
requestParams.add("client_id", "employee-service");
requestParams.add("username", username);
requestParams.add("password", password);
requestParams.add("grant_type", "password");
requestParams.add("client_secret", "cccebf50-3f28-4af2-8716-c4bfcfe6f5e7");
requestParams.add("scope", "openid");
AccessTokenResponse keycloakAccessToken = queryKeycloakByParams(requestParams);
return keycloakAccessToken;
} catch (Exception e) {
System.out.println("login **** "+e.getMessage());
throw e;
}
}
@Override
public AccessTokenResponse refresh(String refreshToken) {
try {
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
/* requestParams.add("client_id", keyCloakConnectionProvider.getResource());*/
requestParams.add("client_id", "");
requestParams.add("grant_type", "refresh_token");
/* requestParams.add("client_secret", keyCloakConnectionProvider.getClientSecret());*/
requestParams.add("client_secret", "");
requestParams.add("refresh_token", refreshToken);
AccessTokenResponse keycloakAccessToken = queryKeycloakByParams(requestParams);
return keycloakAccessToken;
} catch (Exception e) {
/*log.info(e.getMessage(), e);*/
System.out.println("refresh**** "+e.getMessage());
throw e;
}
}
private AccessTokenResponse queryKeycloakByParams(MultiValueMap<String, String> requestParams) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
/*String url = keyCloakConnectionProvider.getOpenIdConnectTokenUrl();*/
String url = "http://localhost:8080/auth/realms/dev/protocol/openid-connect/token";
AccessTokenResponse keycloakAccessToken = getAccessTokenResponse(request, url);
return keycloakAccessToken;
}
private AccessTokenResponse getAccessTokenResponse(HttpEntity<MultiValueMap<String, String>> request, String url) {
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (ResourceAccessException e) {
/*log.error("KeyCloak getAccessTokenResponse: " + e.getMessage());*/
System.out.println("KeyCloak getAccessTokenResponse: " + e.getMessage());
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (Exception ex) {
throw ex;
}
} catch (Exception e) {
throw e;
}
}
@Override
public void logout(String refreshToken) {
try {
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
/*requestParams.add("client_id", keyCloakConnectionProvider.getResource());
requestParams.add("client_secret", keyCloakConnectionProvider.getClientSecret());*/
requestParams.add("client_id", "");
requestParams.add("client_secret", "");
requestParams.add("refresh_token", refreshToken);
logoutUserSession(requestParams);
} catch (Exception e) {
/*log.info(e.getMessage(), e);*/
System.out.println("KeyCloak logout: " + e.getMessage());
throw e;
}
}
private void logoutUserSession(MultiValueMap<String, String> requestParams) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
/* String url = keyCloakConnectionProvider.getOpenIdConnectLogoutUrl();*/
String url = "";
restTemplate.postForEntity(url, request, Object.class);
}
/*private PublicKey getPublicKey() {
PublicKey publicKey = keyCloakConnectionProvider.getPublicKey();
PublicKey publicKey = keyCloakConnectionProvider.getPublicKey();
if (publicKey == null) {
LinkedHashMap publicKeyMap = requestKeyFromKeycloak(keyCloakConnectionProvider.getOpenIdConnectCertsUrl());
LinkedHashMap publicKeyMap = requestKeyFromKeycloak("");
publicKey = KeyCloakRsaKeyLoader.getPublicKeyFromKeyCloak(publicKeyMap);
keyCloakConnectionProvider.setPublicKey(publicKey);
}
return publicKey;
}*/
/**
* This method will connect to keycloak server using API call for getting public key.
*
* @param url A string value having keycloak base URL
* @return Public key JSON response string
*/
private LinkedHashMap requestKeyFromKeycloak(String url) {
try {
ResponseEntity<LinkedHashMap> response = restTemplate.getForEntity(url, LinkedHashMap.class);
LinkedHashMap body = response.getBody();
if (body != null) {
return body;
} else {
/*log.error("KeyCloakRsaKeyLoader:requestKeyFromKeycloak: Not able to fetch SSO public key from keycloak server");*/
System.out.println("KeyCloakRsaKeyLoader:requestKeyFromKeycloak: Not able to fetch SSO public key from keycloak server");
}
} catch (Exception e) {
/* log.error("KeyCloakRsaKeyLoader:requestKeyFromKeycloak: Exception occurred with message = " + e.getMessage());*/
System.out.println("KeyCloakRsaKeyLoader:requestKeyFromKeycloak: Exception occurred with message = " + e.getMessage());
}
return null;
}
}
Now getting "Exception while getting response org.springframework.web.client.HttpClientErrorException: 401 Unauthorized" not sure, even if I am sending the access token, why it is not authorizing the user
来源:https://stackoverflow.com/questions/58837260/keycloakresttemplate-with-spring-application