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