KeycloakRestTemplate with spring application

☆樱花仙子☆ 提交于 2020-06-28 01:57:55

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!