/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.ranger.biz; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.security.auth.Subject; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.MediaType; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.Predicate; import org.apache.commons.collections.PredicateUtils; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.ProviderUtils; import org.apache.hadoop.security.SecureClientLogin; import org.apache.hadoop.security.authentication.util.KerberosName; import org.apache.log4j.Logger; import org.apache.ranger.common.ContextUtil; import org.apache.ranger.common.MessageEnums; import org.apache.ranger.plugin.util.PasswordUtils; import org.apache.ranger.common.PropertiesUtil; import org.apache.ranger.common.RESTErrorUtil; import org.apache.ranger.common.RangerConfigUtil; import org.apache.ranger.common.SortField; import org.apache.ranger.common.StringUtil; import org.apache.ranger.db.RangerDaoManagerBase; import org.apache.ranger.entity.XXService; import org.apache.ranger.entity.XXServiceConfigMap; import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.util.KeySearchFilter; import org.apache.ranger.view.VXKmsKey; import org.apache.ranger.view.VXKmsKeyList; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; @Component public class KmsKeyMgr { private static final Logger logger = Logger.getLogger(KmsKeyMgr.class); private static final String KMS_KEY_LIST_URI = "v1/keys/names"; //GET private static final String KMS_ADD_KEY_URI = "v1/keys"; //POST private static final String KMS_ROLL_KEY_URI = "v1/key/${alias}"; //POST private static final String KMS_DELETE_KEY_URI = "v1/key/${alias}"; //DELETE private static final String KMS_KEY_METADATA_URI = "v1/key/${alias}/_metadata"; //GET private static final String KMS_URL_CONFIG = "provider"; private static final String KMS_PASSWORD = "password"; private static final String KMS_USERNAME = "username"; private static Map<String, String> providerList = new HashMap<String, String>(); private static int nextProvider = 0; static final String NAME_RULES = "hadoop.security.auth_to_local"; static final String RANGER_AUTH_TYPE = "hadoop.security.authentication"; private static final String KERBEROS_TYPE = "kerberos"; private static final String ADMIN_USER_PRINCIPAL = "ranger.admin.kerberos.principal"; private static final String ADMIN_USER_KEYTAB = "ranger.admin.kerberos.keytab"; static final String HOST_NAME = "ranger.service.host"; @Autowired ServiceDBStore svcStore; @Autowired RESTErrorUtil restErrorUtil; @Autowired RangerConfigUtil configUtil; @Autowired RangerDaoManagerBase rangerDaoManagerBase; @SuppressWarnings("unchecked") public VXKmsKeyList searchKeys(HttpServletRequest request, String repoName) throws Exception{ String providers[] = null; try { providers = getKMSURL(repoName); } catch (Exception e) { logger.error("getKey(" + repoName + ") failed", e); } List<VXKmsKey> vXKeys = new ArrayList<VXKmsKey>(); VXKmsKeyList vxKmsKeyList = new VXKmsKeyList(); List<String> keys = null; String connProvider = null; boolean isKerberos=false; try { isKerberos = checkKerberos(); } catch (Exception e1) { logger.error("checkKerberos(" + repoName + ") failed", e1); } if(providers!=null){ for (int i = 0; i < providers.length; i++) { Client c = getClient(); String currentUserLoginId = ContextUtil.getCurrentUserLoginId(); String keyLists = KMS_KEY_LIST_URI.replaceAll( Pattern.quote("${userName}"), currentUserLoginId); connProvider = providers[i]; String uri = providers[i] + (providers[i].endsWith("/") ? keyLists : ("/" + keyLists)); if(!isKerberos){ uri = uri.concat("?user.name="+currentUserLoginId); }else{ uri = uri.concat("?doAs="+currentUserLoginId); } final WebResource r = c.resource(uri); try { String response = null; if(!isKerberos){ response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).get(String.class); }else{ Subject sub = getSubjectForKerberos(repoName); response = Subject.doAs(sub, new PrivilegedAction<String>() { @Override public String run() { return r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).get(String.class); } }); } Gson gson = new GsonBuilder().create(); logger.debug(" Search Key RESPONSE: [" + response + "]"); keys = gson.fromJson(response, List.class); Collections.sort(keys); VXKmsKeyList vxKmsKeyList2 = new VXKmsKeyList(); List<VXKmsKey> vXKeys2 = new ArrayList<VXKmsKey>(); for (String name : keys) { VXKmsKey key = new VXKmsKey(); key.setName(name); vXKeys2.add(key); } vxKmsKeyList2.setVXKeys(vXKeys2); vxKmsKeyList = getFilteredKeyList(request, vxKmsKeyList2); break; } catch (Exception e) { if (e instanceof UniformInterfaceException || i == providers.length - 1) throw e; else continue; } } } //details if (vxKmsKeyList != null && vxKmsKeyList.getVXKeys() != null && !vxKmsKeyList.getVXKeys().isEmpty()) { List<VXKmsKey> lstKMSKey = vxKmsKeyList.getVXKeys(); int startIndex=restErrorUtil.parseInt( request.getParameter("startIndex"), 0, "Invalid value for parameter startIndex", MessageEnums.INVALID_INPUT_DATA, null, "startIndex"); startIndex = startIndex < 0 ? 0 : startIndex; int pageSize=restErrorUtil.parseInt( request.getParameter("pageSize"), 0, "Invalid value for parameter pageSize", MessageEnums.INVALID_INPUT_DATA, null, "pageSize"); pageSize = pageSize < 0 ? 0 : pageSize; vxKmsKeyList.setResultSize(lstKMSKey.size()); vxKmsKeyList.setTotalCount(lstKMSKey.size()); if((startIndex+pageSize) <= lstKMSKey.size()){ lstKMSKey = lstKMSKey.subList(startIndex, (startIndex+pageSize));} else{ startIndex = startIndex >= lstKMSKey.size() ? 0 : startIndex; lstKMSKey = lstKMSKey.subList(startIndex, lstKMSKey.size()); } if(CollectionUtils.isNotEmpty(lstKMSKey)){ for (VXKmsKey kmsKey : lstKMSKey) { if(kmsKey!=null){ VXKmsKey key = getKeyFromUri(connProvider, kmsKey.getName(), isKerberos, repoName); vXKeys.add(key); } } } vxKmsKeyList.setStartIndex(startIndex); vxKmsKeyList.setPageSize(pageSize); } if(vxKmsKeyList!=null){ vxKmsKeyList.setVXKeys(vXKeys); } return vxKmsKeyList; } public VXKmsKey rolloverKey(String provider, VXKmsKey vXKey) throws Exception{ String providers[] = null; try { providers = getKMSURL(provider); } catch (Exception e) { logger.error("rolloverKey(" + provider + ", " + vXKey.getName() + ") failed", e); } VXKmsKey ret = null; boolean isKerberos=false; try { isKerberos = checkKerberos(); } catch (Exception e1) { logger.error("checkKerberos(" + provider + ") failed", e1); } if(providers!=null){ for (int i = 0; i < providers.length; i++) { Client c = getClient(); String rollRest = KMS_ROLL_KEY_URI.replaceAll(Pattern.quote("${alias}"), vXKey.getName()); String currentUserLoginId = ContextUtil.getCurrentUserLoginId(); String uri = providers[i] + (providers[i].endsWith("/") ? rollRest : ("/" + rollRest)); if(!isKerberos){ uri = uri.concat("?user.name="+currentUserLoginId); }else{ uri = uri.concat("?doAs="+currentUserLoginId); } final WebResource r = c.resource(uri); Gson gson = new GsonBuilder().create(); final String jsonString = gson.toJson(vXKey); try { String response = null; if(!isKerberos){ response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString);} else{ Subject sub = getSubjectForKerberos(provider); response = Subject.doAs(sub, new PrivilegedAction<String>() { @Override public String run() { return r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString); } }); } logger.debug("Roll RESPONSE: [" + response + "]"); ret = gson.fromJson(response, VXKmsKey.class); break; } catch (Exception e) { if (e instanceof UniformInterfaceException || i == providers.length - 1) throw e; else continue; } } } return ret; } public void deleteKey(String provider, String name) throws Exception{ String providers[] = null; try { providers = getKMSURL(provider); } catch (Exception e) { logger.error("deleteKey(" + provider + ", " + name + ") failed", e); } boolean isKerberos=false; try { isKerberos = checkKerberos(); } catch (Exception e1) { logger.error("checkKerberos(" + provider + ") failed", e1); } if(providers!=null){ for (int i = 0; i < providers.length; i++) { Client c = getClient(); String deleteRest = KMS_DELETE_KEY_URI.replaceAll(Pattern.quote("${alias}"), name); String currentUserLoginId = ContextUtil.getCurrentUserLoginId(); String uri = providers[i] + (providers[i].endsWith("/") ? deleteRest : ("/" + deleteRest)); if(!isKerberos){ uri = uri.concat("?user.name="+currentUserLoginId); }else{ uri = uri.concat("?doAs="+currentUserLoginId); } final WebResource r = c.resource(uri); try { String response = null; if(!isKerberos){ response = r.delete(String.class); }else{ Subject sub = getSubjectForKerberos(provider); response = Subject.doAs(sub, new PrivilegedAction<String>() { @Override public String run() { return r.delete(String.class); } }); } logger.debug("delete RESPONSE: [" + response + "]"); break; } catch (Exception e) { if (e instanceof UniformInterfaceException || i == providers.length - 1) throw e; else continue; } } } } public VXKmsKey createKey(String provider, VXKmsKey vXKey) throws Exception{ String providers[] = null; try { providers = getKMSURL(provider); } catch (Exception e) { logger.error("createKey(" + provider + ", " + vXKey.getName() + ") failed", e); } VXKmsKey ret = null; boolean isKerberos=false; try { isKerberos = checkKerberos(); } catch (Exception e1) { logger.error("checkKerberos(" + provider + ") failed", e1); } if(providers!=null){ for (int i = 0; i < providers.length; i++) { Client c = getClient(); String currentUserLoginId = ContextUtil.getCurrentUserLoginId(); String uri = providers[i] + (providers[i].endsWith("/") ? KMS_ADD_KEY_URI : ("/" + KMS_ADD_KEY_URI)); if(!isKerberos){ uri = uri.concat("?user.name="+currentUserLoginId); }else{ uri = uri.concat("?doAs="+currentUserLoginId); } final WebResource r = c.resource(uri); Gson gson = new GsonBuilder().create(); final String jsonString = gson.toJson(vXKey); try { String response = null; if(!isKerberos){ response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString); }else{ Subject sub = getSubjectForKerberos(provider); response = Subject.doAs(sub, new PrivilegedAction<String>() { @Override public String run() { return r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString); } }); } logger.debug("Create RESPONSE: [" + response + "]"); ret = gson.fromJson(response, VXKmsKey.class); return ret; } catch (Exception e) { if (e instanceof UniformInterfaceException || i == providers.length - 1) throw e; else continue; } } } return ret; } public VXKmsKey getKey(String provider, String name) throws Exception{ String providers[] = null; try { providers = getKMSURL(provider); } catch (Exception e) { logger.error("getKey(" + provider + ", " + name + ") failed", e); } boolean isKerberos=false; try { isKerberos = checkKerberos(); } catch (Exception e1) { logger.error("checkKerberos(" + provider + ") failed", e1); } if(providers!=null){ for (int i = 0; i < providers.length; i++) { Client c = getClient(); String keyRest = KMS_KEY_METADATA_URI.replaceAll(Pattern.quote("${alias}"), name); String currentUserLoginId = ContextUtil.getCurrentUserLoginId(); String uri = providers[i] + (providers[i].endsWith("/") ? keyRest : ("/" + keyRest)); if(!isKerberos){ uri = uri.concat("?user.name="+currentUserLoginId); }else{ uri = uri.concat("?doAs="+currentUserLoginId); } final WebResource r = c.resource(uri); try { String response = null; if(!isKerberos){ response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).get(String.class); }else{ Subject sub = getSubjectForKerberos(provider); response = Subject.doAs(sub, new PrivilegedAction<String>() { @Override public String run() { return r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).get(String.class); } }); } Gson gson = new GsonBuilder().create(); logger.debug("RESPONSE: [" + response + "]"); VXKmsKey key = gson.fromJson(response, VXKmsKey.class); return key; } catch (Exception e) { if (e instanceof UniformInterfaceException || i == providers.length - 1) throw e; else continue; } } } return null; } public VXKmsKey getKeyFromUri(String provider, String name, boolean isKerberos, String repoName) throws Exception { Client c = getClient(); String keyRest = KMS_KEY_METADATA_URI.replaceAll(Pattern.quote("${alias}"), name); String currentUserLoginId = ContextUtil.getCurrentUserLoginId(); String uri = provider + (provider.endsWith("/") ? keyRest : ("/" + keyRest)); if(!isKerberos){ uri = uri.concat("?user.name="+currentUserLoginId); }else{ uri = uri.concat("?doAs="+currentUserLoginId); } final WebResource r = c.resource(uri); String response = null; if(!isKerberos){ response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).get(String.class); }else{ Subject sub = getSubjectForKerberos(repoName); response = Subject.doAs(sub, new PrivilegedAction<String>() { @Override public String run() { return r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).get(String.class); } }); } Gson gson = new GsonBuilder().create(); logger.debug("RESPONSE: [" + response + "]"); VXKmsKey key = gson.fromJson(response, VXKmsKey.class); return key; } private String[] getKMSURL(String name) throws Exception{ String providers[] = null; RangerService rangerService = null; try { rangerService = svcStore.getServiceByName(name); if(rangerService!=null){ String kmsUrl = rangerService.getConfigs().get(KMS_URL_CONFIG); String dbKmsUrl = kmsUrl; if(providerList.containsKey(kmsUrl)){ kmsUrl = providerList.get(kmsUrl); }else{ providerList.put(kmsUrl, kmsUrl); } providers = createProvider(dbKmsUrl,kmsUrl); }else{ throw new Exception("Service " + name + " not found"); } } catch (Exception excp) { logger.error("getServiceByName(" + name + ") failed", excp); throw new Exception("getServiceByName(" + name + ") failed", excp); } if (providers == null) { throw new Exception("Providers for service " + name + " not found"); } return providers; } private String[] createProvider(String dbKmsUrl, String uri) throws IOException,URISyntaxException { URI providerUri = new URI(uri); URL origUrl = new URL(extractKMSPath(providerUri).toString()); String authority = origUrl.getAuthority(); // check for ';' which delimits the backup hosts if (Strings.isNullOrEmpty(authority)) { throw new IOException("No valid authority in kms uri [" + origUrl+ "]"); } // Check if port is present in authority // In the current scheme, all hosts have to run on the same port int port = -1; String hostsPart = authority; if (authority.contains(":")) { String[] t = authority.split(":"); try { port = Integer.parseInt(t[1]); } catch (Exception e) { throw new IOException("Could not parse port in kms uri [" + origUrl + "]"); } hostsPart = t[0]; } return createProvider(dbKmsUrl, providerUri, origUrl, port, hostsPart); } private static Path extractKMSPath(URI uri) throws MalformedURLException,IOException { return ProviderUtils.unnestUri(uri); } private String[] createProvider(String dbkmsUrl, URI providerUri, URL origUrl, int port, String hostsPart) throws IOException { String[] hosts = hostsPart.split(";"); String[] providers = new String[hosts.length]; if (hosts.length == 1) { providers[0] = origUrl.toString(); } else { String providerNext=providerUri.getScheme()+"://"+origUrl.getProtocol()+"@"; for(int i=nextProvider; i<hosts.length; i++){ providerNext = providerNext+hosts[i]; if(i!=(hosts.length-1)){ providerNext = providerNext+";"; } } for(int i=0; i<nextProvider && i<hosts.length; i++){ providerNext = providerNext+";"+hosts[i]; } if(nextProvider != hosts.length-1){ nextProvider = nextProvider+1; }else{ nextProvider = 0; } providerNext = providerNext +":"+port+origUrl.getPath(); providerList.put(dbkmsUrl, providerNext); for (int i = 0; i < hosts.length; i++) { try { String url = origUrl.getProtocol()+"://"+hosts[i]+":"+port+origUrl.getPath(); providers[i] = new URI(url).toString(); } catch (URISyntaxException e) { throw new IOException("Could not Prase KMS URL..", e); } } } return providers; } private Subject getSubjectForKerberos(String provider) throws Exception{ String userName = getKMSUserName(provider); String password = getKMSPassword(provider); String nameRules = PropertiesUtil.getProperty(NAME_RULES); if (StringUtils.isEmpty(nameRules)) { KerberosName.setRules("DEFAULT"); }else{ KerberosName.setRules(nameRules); } Subject sub = new Subject(); String rangerPrincipal = SecureClientLogin.getPrincipal(PropertiesUtil.getProperty(ADMIN_USER_PRINCIPAL), PropertiesUtil.getProperty(HOST_NAME)); if (checkKerberos()) { if(SecureClientLogin.isKerberosCredentialExists(rangerPrincipal, PropertiesUtil.getProperty(ADMIN_USER_KEYTAB))){ sub = SecureClientLogin.loginUserFromKeytab(rangerPrincipal, PropertiesUtil.getProperty(ADMIN_USER_KEYTAB), nameRules); }else{ sub = SecureClientLogin.loginUserWithPassword(userName, password); } } else { sub = SecureClientLogin.login(userName); } return sub; } private String getKMSPassword(String srvName) throws Exception { XXService rangerService = rangerDaoManagerBase.getXXService().findByName(srvName); XXServiceConfigMap xxConfigMap = rangerDaoManagerBase.getXXServiceConfigMap().findByServiceAndConfigKey(rangerService.getId(), KMS_PASSWORD); String encryptedPwd = xxConfigMap.getConfigvalue(); String pwd = PasswordUtils.decryptPassword(encryptedPwd); return pwd; } private String getKMSUserName(String srvName) throws Exception { RangerService rangerService = null; rangerService = svcStore.getServiceByName(srvName); return rangerService.getConfigs().get(KMS_USERNAME); } private boolean checkKerberos() throws Exception { if(KERBEROS_TYPE.equalsIgnoreCase(PropertiesUtil.getProperty(RANGER_AUTH_TYPE, "simple"))){ return true; }else{ return false; } } private synchronized Client getClient() { Client ret = null; ClientConfig cc = new DefaultClientConfig(); cc.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true); ret = Client.create(cc); return ret; } public VXKmsKeyList getFilteredKeyList(HttpServletRequest request, VXKmsKeyList vXKmsKeyList){ List<SortField> sortFields = new ArrayList<SortField>(); sortFields.add(new SortField(KeySearchFilter.KEY_NAME, KeySearchFilter.KEY_NAME)); KeySearchFilter filter = getKeySearchFilter(request, sortFields); Predicate pred = getPredicate(filter); if(pred != null) { CollectionUtils.filter(vXKmsKeyList.getVXKeys(), pred); } return vXKmsKeyList; } private Predicate getPredicate(KeySearchFilter filter) { if(filter == null || filter.isEmpty()) { return null; } List<Predicate> predicates = new ArrayList<Predicate>(); addPredicateForKeyName(filter.getParam(KeySearchFilter.KEY_NAME), predicates); Predicate ret = CollectionUtils.isEmpty(predicates) ? null : PredicateUtils.allPredicate(predicates); return ret; } private Predicate addPredicateForKeyName(final String name, List<Predicate> predicates) { if(StringUtils.isEmpty(name)) { return null; } Predicate ret = new Predicate() { @Override public boolean evaluate(Object object) { if(object == null) { return false; } boolean ret = false; if(object instanceof VXKmsKey) { VXKmsKey vXKmsKey = (VXKmsKey)object; if(StringUtils.isEmpty(vXKmsKey.getName())) { ret = true; }else{ ret = vXKmsKey.getName().contains(name); } } else { ret = true; } return ret; } }; if(predicates != null) { predicates.add(ret); } return ret; } private KeySearchFilter getKeySearchFilter(HttpServletRequest request, List<SortField> sortFields) { if (request == null) { return null; } KeySearchFilter ret = new KeySearchFilter(); if (MapUtils.isEmpty(request.getParameterMap())) { ret.setParams(new HashMap<String, String>()); } ret.setParam(KeySearchFilter.KEY_NAME, request.getParameter(KeySearchFilter.KEY_NAME)); extractCommonCriteriasForFilter(request, ret, sortFields); return ret; } private KeySearchFilter extractCommonCriteriasForFilter(HttpServletRequest request, KeySearchFilter ret, List<SortField> sortFields) { int startIndex = restErrorUtil.parseInt(request.getParameter(KeySearchFilter.START_INDEX), 0, "Invalid value for parameter startIndex", MessageEnums.INVALID_INPUT_DATA, null, KeySearchFilter.START_INDEX); ret.setStartIndex(startIndex); int pageSize = restErrorUtil.parseInt(request.getParameter(KeySearchFilter.PAGE_SIZE), configUtil.getDefaultMaxRows(), "Invalid value for parameter pageSize", MessageEnums.INVALID_INPUT_DATA, null, KeySearchFilter.PAGE_SIZE); ret.setMaxRows(pageSize); ret.setGetCount(restErrorUtil.parseBoolean(request.getParameter("getCount"), true)); String sortBy = restErrorUtil.validateString(request.getParameter(KeySearchFilter.SORT_BY), StringUtil.VALIDATION_ALPHA, "Invalid value for parameter sortBy", MessageEnums.INVALID_INPUT_DATA, null, KeySearchFilter.SORT_BY); boolean sortSet = false; if (!StringUtils.isEmpty(sortBy)) { for (SortField sortField : sortFields) { if (sortField.getParamName().equalsIgnoreCase(sortBy)) { ret.setSortBy(sortField.getParamName()); String sortType = restErrorUtil.validateString(request.getParameter("sortType"), StringUtil.VALIDATION_ALPHA, "Invalid value for parameter sortType", MessageEnums.INVALID_INPUT_DATA, null, "sortType"); ret.setSortType(sortType); sortSet = true; break; } } } if (!sortSet && !StringUtils.isEmpty(sortBy)) { logger.info("Invalid or unsupported sortBy field passed. sortBy=" + sortBy, new Throwable()); } if(ret.getParams() == null) { ret.setParams(new HashMap<String, String>()); } return ret; } }