org.slf4j
slf4j-api
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/client/AbstractRangerAuditMetricRESTClient.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/AbstractRangerAuditMetricRESTClient.java
new file mode 100644
index 0000000000..084f4fe074
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/AbstractRangerAuditMetricRESTClient.java
@@ -0,0 +1,48 @@
+/*
+ * 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.audit.client;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.ranger.audit.model.RangerAuditMetrics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractRangerAuditMetricRESTClient {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractRangerAuditMetricRESTClient.class);
+ public Gson gson;
+
+ public void init(String url, String sslConfigFileName, Configuration config) {
+ Gson gson = null;
+
+ try {
+ gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
+ } catch (Throwable excp) {
+ LOG.error("AbstractRangerAdminClient: failed to create GsonBuilder object", excp);
+ }
+
+ this.gson = gson;
+ }
+
+ public RangerAuditMetrics createAuditMetrics(RangerAuditMetrics request) throws Exception {
+ return null;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RESTResponse.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RESTResponse.java
new file mode 100644
index 0000000000..73254bee02
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RESTResponse.java
@@ -0,0 +1,208 @@
+/**
+ * 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.audit.client;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.ranger.audit.utils.JsonUtils;
+import org.apache.ranger.audit.utils.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.Response;
+
+import java.util.List;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RESTResponse implements java.io.Serializable {
+ /**
+ * values for statusCode
+ */
+ public static final int STATUS_SUCCESS = 0;
+ public static final int STATUS_ERROR = 1;
+ public static final int STATUS_VALIDATION = 2;
+ public static final int STATUS_WARN = 3;
+ public static final int STATUS_INFO = 4;
+ public static final int STATUS_PARTIAL_SUCCESS = 5;
+ public static final int ResponseStatus_MAX = 5;
+ private static final Logger LOG = LoggerFactory.getLogger(RESTResponse.class);
+ private int httpStatusCode;
+ private int statusCode;
+ private String msgDesc;
+ private List messageList;
+
+ public static RESTResponse fromClientResponse(Response response) {
+ RESTResponse ret = null;
+
+ String jsonString = response == null ? null : response.readEntity(String.class);
+ int httpStatus = response == null ? 0 : response.getStatus();
+
+ if (!StringUtil.isEmpty(jsonString)) {
+ ret = RESTResponse.fromJson(jsonString);
+ }
+
+ if (ret == null) {
+ ret = new RESTResponse();
+ }
+
+ ret.setHttpStatusCode(httpStatus);
+
+ return ret;
+ }
+
+ public static RESTResponse fromJson(String jsonString) {
+ try {
+ return JsonUtils.jsonToObj(jsonString, RESTResponse.class);
+ } catch (Exception e) {
+ LOG.debug("fromJson({}) failed", jsonString, e);
+ }
+
+ return null;
+ }
+
+ public int getHttpStatusCode() {
+ return httpStatusCode;
+ }
+
+ public void setHttpStatusCode(int httpStatusCode) {
+ this.httpStatusCode = httpStatusCode;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public String getMsgDesc() {
+ return msgDesc;
+ }
+
+ public void setMsgDesc(String msgDesc) {
+ this.msgDesc = msgDesc;
+ }
+
+ public List getMessageList() {
+ return messageList;
+ }
+
+ public void setMessageList(List messageList) {
+ this.messageList = messageList;
+ }
+
+ public String getMessage() {
+ return StringUtil.isEmpty(msgDesc) ? ("HTTP " + httpStatusCode) : msgDesc;
+ }
+
+ public String toJson() {
+ try {
+ return JsonUtils.objToJson(this);
+ } catch (Exception e) {
+ LOG.debug("toJson() failed", e);
+ }
+
+ return "";
+ }
+
+ @Override
+ public String toString() {
+ return toJson();
+ }
+
+ @JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class Message implements java.io.Serializable {
+ private String name;
+ private String rbKey;
+ private String message;
+ private Long objectId;
+ private String fieldName;
+
+ public static RESTResponse fromJson(String jsonString) {
+ try {
+ return JsonUtils.jsonToObj(jsonString, RESTResponse.class);
+ } catch (Exception e) {
+ LOG.debug("fromJson('{}') failed", jsonString, e);
+ }
+
+ return null;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getRbKey() {
+ return rbKey;
+ }
+
+ public void setRbKey(String rbKey) {
+ this.rbKey = rbKey;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Long getObjectId() {
+ return objectId;
+ }
+
+ public void setObjectId(Long objectId) {
+ this.objectId = objectId;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ public String toJson() {
+ try {
+ return JsonUtils.objToJson(this);
+ } catch (Exception e) {
+ LOG.debug("toJson() failed", e);
+ }
+
+ return "";
+ }
+
+ @Override
+ public String toString() {
+ return toJson();
+ }
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RangerAuditMetricRESTClient.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RangerAuditMetricRESTClient.java
new file mode 100644
index 0000000000..3d5719a3dd
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RangerAuditMetricRESTClient.java
@@ -0,0 +1,736 @@
+/*
+ * 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.audit.client;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.AccessControlException;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ranger.audit.model.RangerAuditMetrics;
+import org.apache.ranger.audit.provider.MiscUtil;
+import org.apache.ranger.audit.token.TokenRetriever;
+import org.apache.ranger.audit.utils.StringUtil;
+import org.apache.ranger.authorization.hadoop.utils.RangerCredentialProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class RangerAuditMetricRESTClient extends AbstractRangerAuditMetricRESTClient {
+ public static final String RANGER_PROP_JWT_TOKEN_RETRIEVER_CLASS = "ranger.audit.auth.jwt.retriever.class";
+ public static final String RANGER_PROP_JWT_TOKEN_RETRIEVER_CLASS_DEFAULT = "org.apache.ranger.audit.token.JwTokenRetrieverEnv";
+ public static final String RANGER_PROP_JWT_SERVER_COOKIE_NAME = "ranger.audit.auth.jwt.server.cookie.name";
+ public static final String RANGER_PROP_JWT_IGNOREIF_OTHER_AUTH_EXISTS = "ranger.audit.auth.jwt.ignoreif.other.auth.exists";
+ public static final String RANGER_PROP_JWT_ENABLED = "ranger.audit.auth.jwt.enabled";
+ public static final String RANGER_PROP_AUTH_TYPE = "AUTH_TYPE";
+ public static final String RANGER_AUTH_TYPE_KERBEROS = "KERBEROS";
+ public static final String RANGER_AUTH_TYPE_RAZ_DT = "RAZ-DT";
+ public static final String RANGER_PROP_DT_OPERATION_TYPE = "DT_OPERATION_TYPE";
+ public static final String RANGER_DT_OPERATION_TYPE_GET = "GETDELEGATIONTOKEN";
+ public static final String RANGER_DT_OPERATION_TYPE_RENEW = "RENEWDELEGATIONTOKEN";
+ public static final String RANGER_DT_OPERATION_TYPE_CANCEL = "CANCELDELEGATIONTOKEN";
+ public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE = "xasecure.policymgr.clientssl.keystore";
+ public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE = "xasecure.policymgr.clientssl.keystore.type";
+ public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL = "xasecure.policymgr.clientssl.keystore.credential.file";
+ public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL_ALIAS = "sslKeyStore";
+ public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE_DEFAULT = "jks";
+ public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE = "xasecure.policymgr.clientssl.truststore";
+ public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE = "xasecure.policymgr.clientssl.truststore.type";
+ public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL = "xasecure.policymgr.clientssl.truststore.credential.file";
+ public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL_ALIAS = "sslTrustStore";
+ public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT = "jks";
+ public static final String JWT_COOKIE_NAME_DEFAULT = "hadoop-jwt";
+ public static final String REST_URL_CREATE_AUDIT_METRICS = "/service/audit/metrics";
+ public static final String RANGER_PROP_SERVICE_TYPE = "ranger.plugin.serviceType";
+ public static final String RANGER_PROP_CLIENT_CONNECTION_TIMEOUT_MS = "ranger.plugin.%s.policy.rest.client.connection.timeoutMs";
+ public static final String RANGER_PROP_CLIENT_READ_TIMEOUT_MS = "ranger.plugin.%s.policy.rest.client.read.timeoutMs";
+ public static final String RANGER_PROP_CLIENT_MAX_RETRY_ATTEMPTS = "ranger.plugin.%s.policy.rest.client.max.retry.attempts";
+ public static final String RANGER_PROP_CLIENT_RETRY_INTERVAL_MS = "ranger.plugin.%s.policy.rest.client.retry.interval.ms";
+ public static final String RANGER_SSL_KEYMANAGER_ALGO_TYPE = KeyManagerFactory.getDefaultAlgorithm();
+ public static final String RANGER_SSL_TRUSTMANAGER_ALGO_TYPE = TrustManagerFactory.getDefaultAlgorithm();
+ public static final String RANGER_SSL_CONTEXT_ALGO_TYPE = "TLS";
+ public static final String REST_EXPECTED_MIME_TYPE = "application/json";
+ public static final String REST_MIME_TYPE_JSON = "application/json";
+ private static final Logger LOG = LoggerFactory.getLogger(RangerAuditMetricRESTClient.class);
+ private String mUrl;
+ private String mSslConfigFileName;
+ private String mUsername;
+ private String mPassword;
+ private boolean mIsSSL;
+
+ private String mKeyStoreURL;
+ private String mKeyStoreAlias;
+ private String mKeyStoreFile;
+ private String mKeyStoreType;
+ private String mTrustStoreURL;
+ private String mTrustStoreAlias;
+ private String mTrustStoreFile;
+ private String mTrustStoreType;
+ private String serviceType;
+
+ private Gson gsonBuilder;
+ private int mRestClientConnTimeOutMs;
+ private int mRestClientReadTimeOutMs;
+ private int maxRetryAttempts;
+ private int retryIntervalMs;
+ private int lastKnownActiveUrlIndex;
+
+ private List configuredURLs;
+ private volatile Client client;
+ private TokenRetriever tokenRetriever;
+ private String jwtServerCookieName;
+ private boolean ignoreJwtIfAuthExists;
+
+ protected WebTarget setQueryParams(WebTarget webTarget, Map params) {
+ WebTarget ret = webTarget;
+
+ if (webTarget != null && params != null) {
+ Set> entrySet = params.entrySet();
+ for (Map.Entry entry : entrySet) {
+ ret = ret.queryParam(entry.getKey(), entry.getValue());
+ }
+ }
+
+ return ret;
+ }
+
+ @Override
+ public void init(String url, String sslConfigFileName, Configuration config) {
+ mUrl = url;
+ mSslConfigFileName = sslConfigFileName;
+ configuredURLs = StringUtil.getURLs(mUrl);
+ setLastKnownActiveUrlIndex((new Random()).nextInt(getConfiguredURLs().size()));
+
+ serviceType = config.get(RANGER_PROP_SERVICE_TYPE);
+ mRestClientConnTimeOutMs = config.getInt(String.format(RANGER_PROP_CLIENT_CONNECTION_TIMEOUT_MS, serviceType), 120 * 1000);
+ mRestClientReadTimeOutMs = config.getInt(String.format(RANGER_PROP_CLIENT_READ_TIMEOUT_MS, serviceType), 30 * 1000);
+ maxRetryAttempts = config.getInt(String.format(RANGER_PROP_CLIENT_MAX_RETRY_ATTEMPTS, serviceType), 3);
+ retryIntervalMs = config.getInt(String.format(RANGER_PROP_CLIENT_RETRY_INTERVAL_MS, serviceType), 1000);
+
+ init(config);
+ }
+
+ @Override
+ public RangerAuditMetrics createAuditMetrics(RangerAuditMetrics request) throws Exception {
+ LOG.debug("==> RangerAdminRESTClient.createAuditMetrics({})", request);
+
+ RangerAuditMetrics ret = null;
+
+ Response response = null;
+ UserGroupInformation user = MiscUtil.getUGILoginUser();
+ boolean isSecureMode = user != null && UserGroupInformation.isSecurityEnabled();
+ String relativeURL = REST_URL_CREATE_AUDIT_METRICS;
+ Map queryParams = new HashMap<>();
+
+ if (isSecureMode) {
+ PrivilegedAction action = new PrivilegedAction() {
+ public Response run() {
+ Response clientResp = null;
+ try {
+ clientResp = post(relativeURL, queryParams, request);
+ } catch (Exception e) {
+ LOG.error("Failed to get response, Error is : {}", e.getMessage());
+ }
+ return clientResp;
+ }
+ };
+
+ LOG.debug("create createAuditMetrics as user {}", user);
+ response = user.doAs(action);
+ } else {
+ response = post(relativeURL, queryParams, request);
+ }
+
+ if (response != null) {
+ if (response.getStatus() != Response.Status.OK.getStatusCode()) {
+ RESTResponse resp = RESTResponse.fromClientResponse(response);
+ LOG.error("createAuditMetrics() failed: HTTP status={}, message={}, isSecure={}", response.getStatus(), resp.getMessage(), isSecureMode + (isSecureMode ? (", user=" + user) : ""));
+
+ if (response.getStatus() == Response.Status.UNAUTHORIZED.getStatusCode()) {
+ throw new AccessControlException("Unauthorized access.");
+ }
+
+ throw new Exception("HTTP " + response.getStatus() + " Error: " + resp.getMessage());
+ } else {
+ ret = response.readEntity(RangerAuditMetrics.class);
+ }
+ } else {
+ throw new Exception("unknown error during createAuditMetrics. AuditMetrics = " + request);
+ }
+
+ LOG.debug("<== RangerAdminRESTClient.createAuditMetrics({})", request);
+
+ return ret;
+ }
+
+ public String getUrl() {
+ return mUrl;
+ }
+
+ public void setUrl(String url) {
+ this.mUrl = url;
+ }
+
+ public String getUsername() {
+ return mUsername;
+ }
+
+ public String getPassword() {
+ return mPassword;
+ }
+
+ public int getRestClientConnTimeOutMs() {
+ return mRestClientConnTimeOutMs;
+ }
+
+ public void setRestClientConnTimeOutMs(int mRestClientConnTimeOutMs) {
+ this.mRestClientConnTimeOutMs = mRestClientConnTimeOutMs;
+ }
+
+ public int getRestClientReadTimeOutMs() {
+ return mRestClientReadTimeOutMs;
+ }
+
+ public void setRestClientReadTimeOutMs(int mRestClientReadTimeOutMs) {
+ this.mRestClientReadTimeOutMs = mRestClientReadTimeOutMs;
+ }
+
+ public int getMaxRetryAttempts() {
+ return maxRetryAttempts;
+ }
+
+ public void setMaxRetryAttempts(int maxRetryAttempts) {
+ this.maxRetryAttempts = maxRetryAttempts;
+ }
+
+ public int getRetryIntervalMs() {
+ return retryIntervalMs;
+ }
+
+ public void setRetryIntervalMs(int retryIntervalMs) {
+ this.retryIntervalMs = retryIntervalMs;
+ }
+
+ public void setBasicAuthInfo(String username, String password) {
+ mUsername = username;
+ mPassword = password;
+ }
+
+ public String toJson(Object obj) {
+ return gsonBuilder.toJson(obj);
+ }
+
+ public T fromJson(String json, Class cls) {
+ return gsonBuilder.fromJson(json, cls);
+ }
+
+ public Client getClient() {
+ // result saves on access time when client is built at the time of the call
+ Client result = client;
+ if (result == null) {
+ synchronized (this) {
+ result = client;
+ if (result == null) {
+ client = buildClient();
+ result = client;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ protected void setClient(Client client) {
+ this.client = client;
+ }
+
+ public void resetClient() {
+ client = null;
+ }
+
+ public KeyManager[] getKeyManagers(String keyStoreFile, String keyStoreFilePwd) {
+ KeyManager[] kmList = null;
+
+ if (StringUtils.isNotEmpty(keyStoreFile) && StringUtils.isNotEmpty(keyStoreFilePwd)) {
+ InputStream in = null;
+
+ try {
+ in = getFileInputStream(keyStoreFile);
+
+ if (in != null) {
+ KeyStore keyStore = KeyStore.getInstance(mKeyStoreType);
+
+ keyStore.load(in, keyStoreFilePwd.toCharArray());
+
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(RANGER_SSL_KEYMANAGER_ALGO_TYPE);
+
+ keyManagerFactory.init(keyStore, keyStoreFilePwd.toCharArray());
+
+ kmList = keyManagerFactory.getKeyManagers();
+ } else {
+ LOG.error("Unable to obtain keystore from file [{}]", keyStoreFile);
+ throw new IllegalStateException("Unable to find keystore file :" + keyStoreFile);
+ }
+ } catch (KeyStoreException e) {
+ LOG.error("Unable to obtain from KeyStore :{}", e.getMessage(), e);
+ throw new IllegalStateException("Unable to init keystore:" + e.getMessage(), e);
+ } catch (NoSuchAlgorithmException e) {
+ LOG.error("SSL algorithm is NOT available in the environment", e);
+ throw new IllegalStateException("SSL algorithm is NOT available in the environment :" + e.getMessage(), e);
+ } catch (CertificateException e) {
+ LOG.error("Unable to obtain the requested certification ", e);
+ throw new IllegalStateException("Unable to obtain the requested certification :" + e.getMessage(), e);
+ } catch (FileNotFoundException e) {
+ LOG.error("Unable to find the necessary SSL Keystore Files", e);
+ throw new IllegalStateException("Unable to find keystore file :" + keyStoreFile + ", error :" + e.getMessage(), e);
+ } catch (IOException e) {
+ LOG.error("Unable to read the necessary SSL Keystore Files", e);
+ throw new IllegalStateException("Unable to read keystore file :" + keyStoreFile + ", error :" + e.getMessage(), e);
+ } catch (UnrecoverableKeyException e) {
+ LOG.error("Unable to recover the key from keystore", e);
+ throw new IllegalStateException("Unable to recover the key from keystore :" + keyStoreFile + ", error :" + e.getMessage(), e);
+ } finally {
+ close(in, keyStoreFile);
+ }
+ }
+
+ return kmList;
+ }
+
+ public TrustManager[] getTrustManagers(String trustStoreFile, String trustStoreFilepwd) {
+ TrustManager[] tmList = null;
+
+ if (StringUtils.isNotEmpty(trustStoreFile) && StringUtils.isNotEmpty(trustStoreFilepwd)) {
+ InputStream in = null;
+
+ try {
+ in = getFileInputStream(trustStoreFile);
+
+ if (in != null) {
+ KeyStore trustStore = KeyStore.getInstance(mTrustStoreType);
+
+ trustStore.load(in, trustStoreFilepwd.toCharArray());
+
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(RANGER_SSL_TRUSTMANAGER_ALGO_TYPE);
+
+ trustManagerFactory.init(trustStore);
+
+ tmList = trustManagerFactory.getTrustManagers();
+ } else {
+ LOG.error("Unable to obtain truststore from file [{}]", trustStoreFile);
+ throw new IllegalStateException("Unable to find truststore file :" + trustStoreFile);
+ }
+ } catch (KeyStoreException e) {
+ LOG.error("Unable to obtain from KeyStore", e);
+ throw new IllegalStateException("Unable to init keystore:" + e.getMessage(), e);
+ } catch (NoSuchAlgorithmException e) {
+ LOG.error("SSL algorithm is NOT available in the environment :{}", e.getMessage(), e);
+ throw new IllegalStateException("SSL algorithm is NOT available in the environment :" + e.getMessage(), e);
+ } catch (CertificateException e) {
+ LOG.error("Unable to obtain the requested certification :{}", e.getMessage(), e);
+ throw new IllegalStateException("Unable to obtain the requested certification :" + e.getMessage(), e);
+ } catch (FileNotFoundException e) {
+ LOG.error("Unable to find the necessary SSL TrustStore File:{}", trustStoreFile, e);
+ throw new IllegalStateException("Unable to find trust store file :" + trustStoreFile + ", error :" + e.getMessage(), e);
+ } catch (IOException e) {
+ LOG.error("Unable to read the necessary SSL TrustStore Files :{}", trustStoreFile, e);
+ throw new IllegalStateException("Unable to read the trust store file :" + trustStoreFile + ", error :" + e.getMessage(), e);
+ } finally {
+ close(in, trustStoreFile);
+ }
+ }
+
+ return tmList;
+ }
+
+ public Response get(String relativeUrl, Map params) throws Exception {
+ return performRequest("GET", relativeUrl, params, null);
+ }
+
+ public Response get(String relativeUrl, Map params, Cookie sessionId) throws Exception {
+ return performRequest("GET", relativeUrl, params, sessionId);
+ }
+
+ public Response post(String relativeUrl, Map params, Object obj) throws Exception {
+ return performRequest("POST", relativeUrl, params, obj);
+ }
+
+ private Response performRequest(String method, String relativeUrl, Map params, Object requestBody) throws Exception {
+ Response finalResponse = null;
+ int startIndex = this.lastKnownActiveUrlIndex;
+ int retryAttempt = 0;
+
+ for (int index = 0; index < configuredURLs.size(); index++) {
+ int currentIndex = (startIndex + index) % configuredURLs.size();
+ try {
+ Client clientToUse = getClient();
+
+ WebTarget webTarget = clientToUse.target(configuredURLs.get(currentIndex) + relativeUrl);
+ webTarget = setQueryParams(webTarget, params);
+
+ Invocation.Builder builder = webTarget.request(MediaType.APPLICATION_JSON);
+
+ Invocation.Builder finalBuilder = handleJwt(builder, params);
+
+ if ("POST".equalsIgnoreCase(method)) {
+ finalResponse = finalBuilder.post(Entity.entity(requestBody, MediaType.APPLICATION_JSON));
+ } else {
+ finalResponse = finalBuilder.get();
+ }
+
+ if (finalResponse != null) {
+ setLastKnownActiveUrlIndex(currentIndex);
+ break;
+ }
+ } catch (ProcessingException | WebApplicationException ex) {
+ if (shouldRetry(configuredURLs.get(currentIndex), index, retryAttempt, ex)) {
+ retryAttempt++;
+
+ index = -1; // start from first url
+ }
+ }
+ }
+ return finalResponse;
+ }
+
+ public int getLastKnownActiveUrlIndex() {
+ return lastKnownActiveUrlIndex;
+ }
+
+ protected void setLastKnownActiveUrlIndex(int lastKnownActiveUrlIndex) {
+ this.lastKnownActiveUrlIndex = lastKnownActiveUrlIndex;
+ }
+
+ public List getConfiguredURLs() {
+ return configuredURLs;
+ }
+
+ public boolean isSSL() {
+ return mIsSSL;
+ }
+
+ public void setSSL(boolean mIsSSL) {
+ this.mIsSSL = mIsSSL;
+ }
+
+ protected SSLContext getSSLContext(KeyManager[] kmList, TrustManager[] tmList) {
+ if (tmList == null) {
+ try {
+ String algo = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(algo);
+ tmf.init((KeyStore) null);
+ tmList = tmf.getTrustManagers();
+ } catch (NoSuchAlgorithmException | KeyStoreException | IllegalStateException e) {
+ LOG.error("Unable to get the default SSL TrustStore for the JVM", e);
+ tmList = null;
+ }
+ }
+ Validate.notNull(tmList, "TrustManager is not specified");
+ try {
+ SSLContext sslContext = SSLContext.getInstance(RANGER_SSL_CONTEXT_ALGO_TYPE);
+
+ sslContext.init(kmList, tmList, new SecureRandom());
+
+ return sslContext;
+ } catch (NoSuchAlgorithmException e) {
+ LOG.error("SSL algorithm is not available in the environment", e);
+ throw new IllegalStateException("SSL algorithm is not available in the environment: " + e.getMessage(), e);
+ } catch (KeyManagementException e) {
+ LOG.error("Unable to initials the SSLContext", e);
+ throw new IllegalStateException("Unable to initials the SSLContex: " + e.getMessage(), e);
+ }
+ }
+
+ protected boolean shouldRetry(String currentUrl, int index, int retryAttemptCount, Exception ex) throws Exception {
+ LOG.warn("Failed to communicate with Ranger Admin URL: {} Error: {}", currentUrl, ex.getMessage());
+
+ boolean isLastUrl = index == (configuredURLs.size() - 1);
+
+ // attempt retry after failure on the last url
+ boolean ret = isLastUrl && (retryAttemptCount < maxRetryAttempts);
+
+ if (ret) {
+ LOG.warn("Waiting for {} ms before retry attempt #{}", retryIntervalMs, (retryAttemptCount + 1));
+
+ try {
+ TimeUnit.MILLISECONDS.sleep(retryIntervalMs);
+ } catch (InterruptedException excp) {
+ LOG.error("Failed while waiting to retry", excp);
+ Thread.currentThread().interrupt();
+ }
+ } else if (isLastUrl) {
+ LOG.error("Failed to communicate with all Ranger Admin's URL's : [ {} ]", configuredURLs);
+
+ throw ex;
+ }
+
+ return ret;
+ }
+
+ protected void setKeyStoreType(String mKeyStoreType) {
+ this.mKeyStoreType = mKeyStoreType;
+ }
+
+ protected void setTrustStoreType(String mTrustStoreType) {
+ this.mTrustStoreType = mTrustStoreType;
+ }
+
+ private Client buildClient() {
+ Client client;
+
+ // Use RangerJersey2ClientBuilder to create clients with MOXy prevention
+ if (mIsSSL) {
+ try {
+ KeyManager[] kmList = getKeyManagers();
+ TrustManager[] tmList = getTrustManagers();
+ SSLContext sslContext = getSSLContext(kmList, tmList);
+
+ HostnameVerifier hv = new HostnameVerifier() {
+ public boolean verify(String urlHostName, SSLSession session) {
+ return session.getPeerHost().equals(urlHostName);
+ }
+ };
+
+ // Use RangerJersey2ClientBuilder to create secure client with MOXy prevention
+ client = RangerJersey2ClientBuilder.createSecureClient(sslContext, hv, mRestClientConnTimeOutMs, mRestClientReadTimeOutMs);
+ } catch (Exception e) {
+ LOG.error("Failed to build SSL client. Falling back to HTTP.");
+ throw new IllegalStateException("Failed to build SSL client.", e);
+ }
+ } else {
+ // Use RangerJersey2ClientBuilder to create standard client with MOXy prevention
+ client = RangerJersey2ClientBuilder.createClient(mRestClientConnTimeOutMs, mRestClientReadTimeOutMs);
+ }
+
+ // Register basic authentication filter if credentials are provided
+ if (StringUtils.isNotEmpty(mUsername) && StringUtils.isNotEmpty(mPassword)) {
+ client.register(new javax.ws.rs.client.ClientRequestFilter() {
+ @Override
+ public void filter(javax.ws.rs.client.ClientRequestContext requestContext) {
+ String authHeader = "Basic " + java.util.Base64.getEncoder().encodeToString((mUsername + ":" + mPassword).getBytes());
+ requestContext.getHeaders().add("Authorization", authHeader);
+ }
+ });
+ }
+
+ return client;
+ }
+
+ private void init(Configuration config) {
+ try {
+ gsonBuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
+ } catch (Throwable excp) {
+ LOG.error("RangerRESTClient.init(): failed to create GsonBuilder object", excp);
+ }
+
+ mIsSSL = isSsl(mUrl);
+
+ if (mIsSSL) {
+ InputStream in = null;
+
+ try {
+ in = getFileInputStream(mSslConfigFileName);
+
+ if (in != null) {
+ config.addResource(in);
+ }
+
+ mKeyStoreURL = config.get(RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL);
+ mKeyStoreAlias = RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL_ALIAS;
+ mKeyStoreType = config.get(RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE, RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE_DEFAULT);
+ mKeyStoreFile = config.get(RANGER_POLICYMGR_CLIENT_KEY_FILE);
+
+ mTrustStoreURL = config.get(RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL);
+ mTrustStoreAlias = RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL_ALIAS;
+ mTrustStoreType = config.get(RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE, RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT);
+ mTrustStoreFile = config.get(RANGER_POLICYMGR_TRUSTSTORE_FILE);
+ } catch (IOException ioe) {
+ LOG.error("Unable to load SSL Config FileName: [{}]", mSslConfigFileName, ioe);
+ } finally {
+ close(in, mSslConfigFileName);
+ }
+ }
+
+ boolean isJwtFetcherEnabled = config.getBoolean(RANGER_PROP_JWT_ENABLED, true);
+ if (isJwtFetcherEnabled) {
+ tokenRetriever = getJwtTokenRetriever(config);
+ jwtServerCookieName = config.get(RANGER_PROP_JWT_SERVER_COOKIE_NAME, JWT_COOKIE_NAME_DEFAULT);
+ } else {
+ LOG.warn("RangerAdminJersey2RESTClient.init(): Skipping JWT fetcher, use property {} to enable.", RANGER_PROP_JWT_ENABLED);
+ }
+
+ ignoreJwtIfAuthExists = config.getBoolean(RANGER_PROP_JWT_IGNOREIF_OTHER_AUTH_EXISTS, ignoreJwtIfAuthExists);
+ }
+
+ @SuppressWarnings("unchecked")
+ private TokenRetriever getJwtTokenRetriever(Configuration config) {
+ String clsName = config.get(RANGER_PROP_JWT_TOKEN_RETRIEVER_CLASS, RANGER_PROP_JWT_TOKEN_RETRIEVER_CLASS_DEFAULT);
+ ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
+ TokenRetriever ret = null;
+ Class> cls;
+
+ try {
+ cls = (Class>) clsLoader.loadClass(clsName.trim());
+ ret = cls.getConstructor(Configuration.class).newInstance(config);
+ } catch (Exception e) {
+ LOG.error("RangerAdminJersey2RESTClient.getJwtTokenRetriever(): Failed to initialize JWT token retriever.", e);
+ }
+
+ return ret;
+ }
+
+ private boolean isSsl(String url) {
+ return !StringUtils.isEmpty(url) && url.toLowerCase().startsWith("https");
+ }
+
+ private KeyManager[] getKeyManagers() {
+ KeyManager[] kmList = null;
+
+ String keyStoreFilepwd = getCredential(mKeyStoreURL, mKeyStoreAlias);
+
+ kmList = getKeyManagers(mKeyStoreFile, keyStoreFilepwd);
+ return kmList;
+ }
+
+ private TrustManager[] getTrustManagers() {
+ TrustManager[] tmList = null;
+ if (StringUtils.isNotEmpty(mTrustStoreURL) && StringUtils.isNotEmpty(mTrustStoreAlias)) {
+ String trustStoreFilepwd = getCredential(mTrustStoreURL, mTrustStoreAlias);
+ if (StringUtils.isNotEmpty(trustStoreFilepwd)) {
+ tmList = getTrustManagers(mTrustStoreFile, trustStoreFilepwd);
+ }
+ }
+ return tmList;
+ }
+
+ private String getCredential(String url, String alias) {
+ return RangerCredentialProvider.getInstance().getCredentialString(url, alias);
+ }
+
+ private InputStream getFileInputStream(String fileName) throws IOException {
+ InputStream in = null;
+
+ if (StringUtils.isNotEmpty(fileName)) {
+ File f = new File(fileName);
+
+ if (f.exists()) {
+ in = new FileInputStream(f);
+ } else {
+ in = ClassLoader.getSystemResourceAsStream(fileName);
+ }
+ }
+
+ return in;
+ }
+
+ private void close(InputStream str, String filename) {
+ if (str != null) {
+ try {
+ str.close();
+ } catch (IOException excp) {
+ LOG.error("Error while closing file: [{}]", filename, excp);
+ }
+ }
+ }
+
+ private Invocation.Builder handleJwt(Invocation.Builder builder, Map queryParams) {
+ if (!isDtOperation(queryParams) && !(ignoreJwtIfAuthExists && otherAuthCredExists(queryParams))) {
+ if (tokenRetriever != null) {
+ Optional jwtOptional = tokenRetriever.retrieve();
+
+ if (jwtOptional.isPresent()) {
+ builder.cookie(new Cookie(jwtServerCookieName, jwtOptional.get()));
+ }
+ } else {
+ LOG.warn("RangerAdminRESTClient.handleJwt(): Since JWTokenRetriever init failed, skipping JWT auth.");
+ }
+ } else {
+ LOG.debug("RangerAdminRESTClient.handleJwt(): Skipping JWT as required condition does not meet.");
+ LOG.debug("RangerAdminRESTClient.handleJwt(): [isDtOperation(queryParams)={}], [ignoreJwtIfAuthExists={}], [otherAuthCredExists(queryParams)={}]", isDtOperation(queryParams), ignoreJwtIfAuthExists, otherAuthCredExists(queryParams));
+ }
+
+ return builder;
+ }
+
+ private boolean otherAuthCredExists(Map queryParams) {
+ boolean ret = false;
+
+ if (queryParams != null && (!queryParams.isEmpty())) {
+ String authType = queryParams.get(RANGER_PROP_AUTH_TYPE);
+ if (StringUtils.isNotBlank(authType)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+
+ private boolean isDtOperation(Map queryParams) {
+ boolean ret = false;
+
+ if (queryParams != null && (!queryParams.isEmpty())) {
+ String authType = queryParams.get(RANGER_PROP_DT_OPERATION_TYPE);
+ if (StringUtils.isNotBlank(authType)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RangerJersey2ClientBuilder.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RangerJersey2ClientBuilder.java
new file mode 100644
index 0000000000..bdc4267e41
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/client/RangerJersey2ClientBuilder.java
@@ -0,0 +1,370 @@
+/*
+ * 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.audit.client;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+
+/**
+ * Comprehensive Jersey client utility for Ranger components.
+ *
+ * This utility provides MOXy-safe Jersey client creation with the following guarantees:
+ *
+ * Jackson JSON provider is explicitly registered with high priority
+ * Jersey auto-discovery is disabled to prevent MOXy interference
+ * SSL/TLS configuration support for secure communications
+ * Configurable connection and read timeouts
+ * Comprehensive logging and validation
+ *
+ *
+ * Usage Patterns:
+ *
+ * // Basic client
+ * Client client = RangerJersey2ClientBuilder.createStandardClient();
+ *
+ * // Client with timeouts
+ * Client client = RangerJersey2ClientBuilder.createClient(5000, 30000);
+ *
+ * // Secure client with SSL
+ * Client client = RangerJersey2ClientBuilder.createSecureClient(sslContext, hostnameVerifier, 5000, 30000);
+ *
+ * // Drop-in replacements for unsafe patterns
+ * Client client = RangerJersey2ClientBuilder.newClient(); // Instead of ClientBuilder.newClient()
+ * Client client = RangerJersey2ClientBuilder.newBuilder().build(); // Instead of ClientBuilder.newBuilder().build()
+ *
+ *
+ * @author Apache Ranger Team
+ * @since Ranger 2.6.0
+ */
+public class RangerJersey2ClientBuilder {
+ private static final Logger LOG = LoggerFactory.getLogger(RangerJersey2ClientBuilder.class);
+
+ // Configuration constants
+ private static final String DISABLE_AUTO_DISCOVERY_PROPERTY = "jersey.config.disableAutoDiscovery";
+ private static final String PROVIDER_SCANNING_RECURSIVE_PROPERTY = "jersey.config.server.provider.scanning.recursive";
+ private static final int DEFAULT_CONNECT_TIMEOUT_MS = 5000;
+ private static final int DEFAULT_READ_TIMEOUT_MS = 30000;
+
+ // Private constructor to prevent instantiation
+ private RangerJersey2ClientBuilder() {
+ // Utility class - no instances
+ }
+
+ /**
+ * Creates a standard Jersey client with MOXy prevention and default timeouts.
+ *
+ * @return A configured Jersey client safe from MOXy interference
+ */
+ public static Client createStandardClient() {
+ return createClient(DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
+ }
+
+ /**
+ * Creates a Jersey client with MOXy prevention and custom timeouts.
+ *
+ * @param connectTimeoutMs Connection timeout in milliseconds
+ * @param readTimeoutMs Read timeout in milliseconds
+ * @return A configured Jersey client safe from MOXy interference
+ */
+ public static Client createClient(int connectTimeoutMs, int readTimeoutMs) {
+ LOG.debug("Creating standard Jersey client with timeouts: connect={}ms, read={}ms", connectTimeoutMs, readTimeoutMs);
+
+ ClientConfig config = new ClientConfig();
+ applyAntiMoxyConfiguration(config);
+
+ // Set timeouts
+ config.property(ClientProperties.CONNECT_TIMEOUT, connectTimeoutMs);
+ config.property(ClientProperties.READ_TIMEOUT, readTimeoutMs);
+
+ // Create client with configuration
+ Client client = ClientBuilder.newClient(config);
+
+ // Validate configuration
+ validateAntiMoxyConfiguration(config);
+
+ LOG.debug("Successfully created standard Jersey client");
+ return client;
+ }
+
+ /**
+ * Creates a secure Jersey client with SSL/TLS support and MOXy prevention.
+ *
+ * @param sslContext SSL context for secure connections (can be null for default)
+ * @param hostnameVerifier Hostname verifier for SSL validation (can be null for default)
+ * @param connectTimeoutMs Connection timeout in milliseconds
+ * @param readTimeoutMs Read timeout in milliseconds
+ * @return A configured secure Jersey client safe from MOXy interference
+ */
+ public static Client createSecureClient(SSLContext sslContext, HostnameVerifier hostnameVerifier, int connectTimeoutMs, int readTimeoutMs) {
+ LOG.debug("Creating secure Jersey client with SSL - connect={}ms, read={}ms", connectTimeoutMs, readTimeoutMs);
+
+ ClientConfig config = new ClientConfig();
+ applyAntiMoxyConfiguration(config);
+
+ // Set timeouts
+ config.property(ClientProperties.CONNECT_TIMEOUT, connectTimeoutMs);
+ config.property(ClientProperties.READ_TIMEOUT, readTimeoutMs);
+
+ // Create builder with configuration
+ ClientBuilder builder = ClientBuilder.newBuilder().withConfig(config);
+
+ // Configure SSL if provided
+ if (sslContext != null) {
+ builder.sslContext(sslContext);
+ LOG.debug("Applied custom SSL context");
+ }
+
+ if (hostnameVerifier != null) {
+ builder.hostnameVerifier(hostnameVerifier);
+ LOG.debug("Applied custom hostname verifier");
+ }
+
+ // Build client
+ Client client = builder.build();
+
+ // Validate configuration
+ validateAntiMoxyConfiguration(config);
+
+ LOG.debug("Successfully created secure Jersey client");
+ return client;
+ }
+
+ // ========== DROP-IN REPLACEMENTS for unsafe ClientBuilder patterns ==========
+
+ /**
+ * Drop-in replacement for {@code ClientBuilder.newClient()}.
+ * Creates a MOXy-safe client with default configuration.
+ *
+ * @return A configured Jersey client safe from MOXy interference
+ */
+ public static Client newClient() {
+ LOG.debug("Creating MOXy-safe client as drop-in replacement for ClientBuilder.newClient()");
+ validateSafeUsage("newClient()");
+ return createStandardClient();
+ }
+
+ /**
+ * Drop-in replacement for {@code ClientBuilder.newBuilder()}.
+ * Returns a builder that creates MOXy-safe clients.
+ *
+ * @return A safe client builder
+ */
+ public static SafeClientBuilder newBuilder() {
+ LOG.debug("Creating MOXy-safe builder as drop-in replacement for ClientBuilder.newBuilder()");
+ validateSafeUsage("newBuilder()");
+ return new SafeClientBuilder();
+ }
+
+ /**
+ * Safe client builder that ensures MOXy prevention in all created clients.
+ * This class provides a familiar builder pattern while ensuring security.
+ */
+ public static class SafeClientBuilder {
+ private SSLContext sslContext;
+ private HostnameVerifier hostnameVerifier;
+ private int connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS;
+ private int readTimeoutMs = DEFAULT_READ_TIMEOUT_MS;
+ private ClientConfig clientConfig;
+
+ // Package-private constructor
+ SafeClientBuilder() {
+ // Only accessible through RangerJersey2ClientBuilder.newBuilder()
+ }
+
+ /**
+ * Configures SSL context for the client.
+ *
+ * @param sslContext SSL context to use
+ * @return This builder for method chaining
+ */
+ public SafeClientBuilder sslContext(SSLContext sslContext) {
+ this.sslContext = sslContext;
+ return this;
+ }
+
+ /**
+ * Configures hostname verifier for the client.
+ *
+ * @param hostnameVerifier Hostname verifier to use
+ * @return This builder for method chaining
+ */
+ public SafeClientBuilder hostnameVerifier(HostnameVerifier hostnameVerifier) {
+ this.hostnameVerifier = hostnameVerifier;
+ return this;
+ }
+
+ /**
+ * Configures connection timeout.
+ *
+ * @param timeoutMs Connection timeout in milliseconds
+ * @return This builder for method chaining
+ */
+ public SafeClientBuilder connectTimeout(int timeoutMs) {
+ this.connectTimeoutMs = timeoutMs;
+ return this;
+ }
+
+ /**
+ * Configures read timeout.
+ *
+ * @param timeoutMs Read timeout in milliseconds
+ * @return This builder for method chaining
+ */
+ public SafeClientBuilder readTimeout(int timeoutMs) {
+ this.readTimeoutMs = timeoutMs;
+ return this;
+ }
+
+ /**
+ * Applies an existing ClientConfig, ensuring it gets MOXy-safe configuration.
+ *
+ * @param config Existing ClientConfig to enhance
+ * @return This builder for method chaining
+ */
+ public SafeClientBuilder withConfig(ClientConfig config) {
+ this.clientConfig = config;
+ return this;
+ }
+
+ /**
+ * Builds the configured Jersey client with MOXy prevention.
+ *
+ * @return A configured Jersey client safe from MOXy interference
+ */
+ public Client build() {
+ if (clientConfig != null) {
+ // Apply anti-MOXy configuration to the provided config
+ applyAntiMoxyConfiguration(clientConfig);
+
+ // Set timeouts if not already configured
+ if (!clientConfig.getProperties().containsKey(ClientProperties.CONNECT_TIMEOUT)) {
+ clientConfig.property(ClientProperties.CONNECT_TIMEOUT, connectTimeoutMs);
+ }
+ if (!clientConfig.getProperties().containsKey(ClientProperties.READ_TIMEOUT)) {
+ clientConfig.property(ClientProperties.READ_TIMEOUT, readTimeoutMs);
+ }
+
+ // Create ClientBuilder with MOXy-safe configuration
+ ClientBuilder builder = ClientBuilder.newBuilder().withConfig(clientConfig);
+
+ if (sslContext != null) {
+ builder.sslContext(sslContext);
+ }
+ if (hostnameVerifier != null) {
+ builder.hostnameVerifier(hostnameVerifier);
+ }
+
+ // Validate configuration before building
+ validateAntiMoxyConfiguration(clientConfig);
+
+ return builder.build();
+ } else {
+ // Use the standard secure client creation method
+ return createSecureClient(sslContext, hostnameVerifier, connectTimeoutMs, readTimeoutMs);
+ }
+ }
+ }
+
+ // ========== VALIDATION AND CONFIGURATION METHODS ==========
+
+ /**
+ * Validates that the calling code is using safe patterns.
+ * Logs warnings for potentially unsafe usage.
+ *
+ * @param methodName Name of the method being called for logging
+ */
+ public static void validateSafeUsage(String className) {
+ // This method can be extended to perform runtime validation
+ // of calling patterns and log warnings for potentially unsafe usage
+ LOG.debug("Safe Jersey client usage validated for: {}", className);
+ }
+
+ /**
+ * Applies comprehensive anti-MOXy configuration to a ClientConfig.
+ *
+ * @param config ClientConfig to configure
+ * @return The same ClientConfig for method chaining
+ */
+ public static ClientConfig applyAntiMoxyConfiguration(ClientConfig config) {
+ if (config == null) {
+ throw new IllegalArgumentException("ClientConfig cannot be null");
+ }
+
+ LOG.debug("Applying anti-MOXy configuration to ClientConfig");
+
+ // 1. Explicitly register Jackson JSON provider with high priority
+ // Note: JacksonJaxbJsonProvider should be registered with @Priority(1) annotation
+ config.register(JacksonJaxbJsonProvider.class);
+
+ // 2. Disable Jersey's auto-discovery to prevent MOXy from being found and registered
+ config.property(DISABLE_AUTO_DISCOVERY_PROPERTY, true);
+ config.property(PROVIDER_SCANNING_RECURSIVE_PROPERTY, false);
+
+ LOG.debug("Anti-MOXy configuration applied: Jackson registered, auto-discovery disabled");
+ return config;
+ }
+
+ /**
+ * Validates that anti-MOXy configuration is properly applied.
+ *
+ * @param config ClientConfig to validate
+ * @return true if configuration is valid, false otherwise
+ * @throws IllegalStateException if critical MOXy prevention measures are missing
+ */
+ public static boolean validateAntiMoxyConfiguration(ClientConfig config) {
+ if (config == null) {
+ LOG.warn("Cannot validate null ClientConfig");
+ return false;
+ }
+
+ boolean isValid = true;
+
+ // Check if auto-discovery is disabled
+ Object autoDiscoveryValue = config.getProperty(DISABLE_AUTO_DISCOVERY_PROPERTY);
+ if (autoDiscoveryValue == null || !Boolean.TRUE.equals(autoDiscoveryValue)) {
+ LOG.error("CRITICAL: Jersey auto-discovery is not disabled! MOXy may be loaded.");
+ isValid = false;
+ }
+
+ // Check if Jackson is registered
+ boolean jacksonRegistered = config.getClasses().contains(JacksonJaxbJsonProvider.class) || config.getInstances().stream().anyMatch(instance -> instance instanceof JacksonJaxbJsonProvider);
+
+ if (!jacksonRegistered) {
+ LOG.error("CRITICAL: Jackson JSON provider is not registered! Default JSON processing may fail.");
+ isValid = false;
+ }
+
+ if (isValid) {
+ LOG.debug("Anti-MOXy configuration validation passed");
+ } else {
+ throw new IllegalStateException("Critical MOXy prevention configuration is missing or invalid");
+ }
+
+ return isValid;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/destination/MetricsAuditDestination.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/destination/MetricsAuditDestination.java
new file mode 100644
index 0000000000..3fcea0a673
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/destination/MetricsAuditDestination.java
@@ -0,0 +1,289 @@
+/*
+ * 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.audit.destination;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ranger.audit.model.AuditEventBase;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
+import org.apache.ranger.audit.model.RangerAuditMetrics;
+import org.apache.ranger.audit.model.RangerAuditMetricsText;
+import org.apache.ranger.audit.provider.MiscUtil;
+import org.apache.ranger.audit.utils.JsonUtils;
+import org.apache.ranger.audit.utils.RangerAuditMetricsUtil;
+import org.apache.ranger.audit.utils.RollingTimeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.Properties;
+
+public class MetricsAuditDestination extends AuditDestination {
+ private static final Logger logger = LoggerFactory.getLogger(MetricsAuditDestination.class);
+ private static final String PROP_SERVICE_TYPE = "ranger.plugin.serviceType";
+ private static final String PROP_RAZ_SERVICE_TYPE = "ranger.plugin.raz.serviceType";
+ private static final String PROP_APP_ID = "ranger.plugin.appId";
+ private static final String PROP_SERVICE_NAME = "ranger.plugin.%s.service.name";
+ private static final String PROP_AUDIT_METRICS_LOGGING_PERIOD = "metrics.logging.period";
+ private static final String AUDIT_METRICS_LOGGING_PERIOD_DEFAULT = "1m";
+ private static final String AUDIT_METRICS_LOGGING_PERIOD_DEFAULT_STR = "PER MINUTE";
+ private static final String PROP_RAZ_SERVICE_TYPE_ID = "raz";
+
+ private RollingTimeUtil rollingTimeUtil;
+ private RangerAuditMetricsUtil rangerAuditMetricsUtil;
+ private String serviceName;
+ private String serviceType;
+ private String razServiceType;
+ private String appId;
+ private String metricLoggingPeriod;
+ private String metricLoggingPeriodInStr;
+ private Instant startTime;
+ private long metricLoggingPeriodinMs;
+ private int auditCount;
+
+ public MetricsAuditDestination() {
+ startTime = Instant.now();
+ logger.info("MetricsAuditDestination() called..");
+ }
+
+ @Override
+ public void init(Properties props, String propPrefix) {
+ super.init(props, propPrefix);
+ rollingTimeUtil = RollingTimeUtil.getInstance();
+ metricLoggingPeriod = MiscUtil.getStringProperty(props, propPrefix + "." + PROP_AUDIT_METRICS_LOGGING_PERIOD);
+ if (StringUtils.isBlank(metricLoggingPeriod)) {
+ metricLoggingPeriod = AUDIT_METRICS_LOGGING_PERIOD_DEFAULT;
+ }
+ try {
+ String computePeriod = rollingTimeUtil.getTimeLiteral(metricLoggingPeriod);
+ int timeNumeral = rollingTimeUtil.getTimeNumeral(metricLoggingPeriod, computePeriod);
+ metricLoggingPeriodinMs = rollingTimeUtil.getTimeInMilliSeconds(timeNumeral, computePeriod);
+ metricLoggingPeriodInStr = rollingTimeUtil.getTimeString(timeNumeral, computePeriod);
+ } catch (Exception e) {
+ logger.error("Invalid logging period in Audit metrics...Using default period of 1 minute...");
+ metricLoggingPeriodinMs = RollingTimeUtil.MILLISECOND_CONVERSION_FACTOR;
+ metricLoggingPeriodInStr = AUDIT_METRICS_LOGGING_PERIOD_DEFAULT_STR;
+ }
+
+ rangerAuditMetricsUtil = new RangerAuditMetricsUtil(props);
+ this.serviceType = props.getProperty(PROP_SERVICE_TYPE);
+ this.serviceName = props.getProperty(String.format(PROP_SERVICE_NAME, serviceType));
+ this.appId = props.getProperty(PROP_APP_ID);
+ this.razServiceType = props.getProperty(PROP_RAZ_SERVICE_TYPE);
+ }
+
+ public void setRollingTimeUtil(RollingTimeUtil rollingTimeUtil) {
+ this.rollingTimeUtil = rollingTimeUtil;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getRazServiceType() {
+ return razServiceType;
+ }
+
+ public void setRazServiceType(String razServiceType) {
+ this.razServiceType = razServiceType;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public int getAuditCount() {
+ return auditCount;
+ }
+
+ public void setAuditCount(int auditCount) {
+ this.auditCount = auditCount;
+ }
+
+ @Override
+ public boolean log(AuditEventBase event) {
+ try {
+ if (event != null) {
+ addAuditCount(1);
+ if (checkIfThreshHoldReached()) {
+ //Call Ranger API to send metrics
+ logger.debug("Total number of Audits : {}, {}", auditCount, metricLoggingPeriodInStr);
+ persistAuditMetrics(metricLoggingPeriodInStr, auditCount, event);
+ resetAuditMetricsCount();
+ }
+ }
+ } catch (Exception e) {
+ resetAuditMetricsCount();
+ logger.error("Failed to log audit metrics....", e);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean logJSON(String event) {
+ try {
+ if (event != null) {
+ addAuditCount(1);
+ if (checkIfThreshHoldReached()) {
+ //Call Ranger API to send metrics
+ logger.debug("Total number of Audits : {}, {}", auditCount, metricLoggingPeriodInStr);
+ persistAuditMetrics(metricLoggingPeriodInStr, auditCount, getSingleEvent(event));
+ resetAuditMetricsCount();
+ }
+ }
+ } catch (Exception e) {
+ resetAuditMetricsCount();
+ logger.error("Failed to log audit metrics....", e);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean logJSON(Collection events) {
+ try {
+ if (CollectionUtils.isNotEmpty(events)) {
+ addAuditCount(events.size());
+ if (checkIfThreshHoldReached()) {
+ //Call Ranger API to send metrics
+ logger.debug("Total number of Audits : {}, {}", auditCount, metricLoggingPeriodInStr);
+ persistAuditMetrics(metricLoggingPeriodInStr, auditCount, getSingleEventFromEvents(events));
+ resetAuditMetricsCount();
+ }
+ }
+ } catch (Exception e) {
+ resetAuditMetricsCount();
+ logger.error("Failed to log audit metrics....", e);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean log(Collection events) {
+ try {
+ if (CollectionUtils.isNotEmpty(events)) {
+ addAuditCount(events.size());
+ if (checkIfThreshHoldReached()) {
+ //Call Ranger API to send metrics
+ logger.debug("Total number of Audits :{}, {}", auditCount, metricLoggingPeriodInStr);
+ persistAuditMetrics(metricLoggingPeriodInStr, auditCount, getSingleEvent(events));
+ resetAuditMetricsCount();
+ }
+ }
+ } catch (Exception e) {
+ resetAuditMetricsCount();
+ logger.error("Failed to log audit metrics....", e);
+ }
+ return true;
+ }
+
+ private boolean checkIfThreshHoldReached() {
+ boolean ret = false;
+ Duration timeElapsed = Duration.between(startTime, Instant.now());
+ logger.debug("TimeElapsed in MilliSec: {}", timeElapsed.toMillis());
+ if (timeElapsed.toMillis() >= metricLoggingPeriodinMs) {
+ ret = true;
+ }
+ return ret;
+ }
+
+ private void addAuditCount(int count) {
+ auditCount = auditCount + count;
+ }
+
+ private void persistAuditMetrics(String metricLogginPeriod, int auditCount, AuditEventBase event) throws Exception {
+ RangerAuditMetrics rangerAuditMetrics = buildRangerAuditMetrics(metricLogginPeriod, auditCount, event);
+ rangerAuditMetricsUtil.createAuditMetrics(rangerAuditMetrics);
+ }
+
+ private RangerAuditMetrics buildRangerAuditMetrics(String interval, int auditCount, AuditEventBase event) {
+ RangerAuditMetrics ret = new RangerAuditMetrics();
+ AuthzAuditEvent authzAuditEvent = (AuthzAuditEvent) event;
+
+ ret.setServiceName(getServiceName());
+ String serviceType = getServiceType();
+ if (PROP_RAZ_SERVICE_TYPE_ID.equals(serviceType)) {
+ serviceType = getRazServiceType();
+ }
+ ret.setServiceType(serviceType);
+ ret.setAppId(getAppId());
+ ret.setClusterName(authzAuditEvent.getClusterName());
+ ret.setclientIP(getIPAddress(authzAuditEvent));
+ ret.setThroughPutUnit(interval);
+ ret.setNumberOfAudits(auditCount);
+ RangerAuditMetricsText metricText = new RangerAuditMetricsText();
+ HashMap metricsData = new HashMap<>();
+ metricsData.put(interval, Integer.toString(auditCount));
+ metricText.setMetrics(metricsData);
+ ret.setMetricsText(metricText);
+
+ return ret;
+ }
+
+ private AuditEventBase getSingleEvent(Collection events) {
+ Optional auditEventBase = events.stream().findFirst();
+ return auditEventBase.get();
+ }
+
+ private AuditEventBase getSingleEvent(String event) {
+ return JsonUtils.jsonToObject(event, AuthzAuditEvent.class);
+ }
+
+ private AuditEventBase getSingleEventFromEvents(Collection events) {
+ Optional auditEventBase = events.stream().findFirst();
+ return JsonUtils.jsonToObject(auditEventBase.get(), AuthzAuditEvent.class);
+ }
+
+ private String getIPAddress(AuthzAuditEvent event) {
+ String ret = event.getClientIP();
+ if (StringUtils.isBlank(ret)) {
+ try {
+ InetAddress ip = InetAddress.getLocalHost();
+ if (ip != null) {
+ ret = ip.getHostAddress();
+ }
+ } catch (Exception e) {
+ ret = StringUtils.EMPTY;
+ }
+ }
+ return ret;
+ }
+
+ private void resetAuditMetricsCount() {
+ startTime = Instant.now();
+ auditCount = 0;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerAuditMetrics.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerAuditMetrics.java
new file mode 100644
index 0000000000..becf3698cd
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerAuditMetrics.java
@@ -0,0 +1,186 @@
+/*
+ * 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.audit.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+@JsonAutoDetect(fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerAuditMetrics extends RangerBaseModelObject implements java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String serviceType;
+ private String serviceName;
+ private String appId;
+ private String clusterName;
+ private String clientIP;
+ private String throughPutUnit;
+ private int numberOfAudits;
+ private RangerAuditMetricsText metricsText;
+
+ /**
+ * @param
+ */
+ public RangerAuditMetrics() {
+ }
+
+ /**
+ * @param serviceType
+ * @param serviceName
+ * @param metricsText
+ */
+ public RangerAuditMetrics(String serviceType, String serviceName, String appId, String clusterName, String clientIP, String throughPutUnit, int numberOfAudits, RangerAuditMetricsText metricsText) {
+ super();
+ setServiceType(serviceType);
+ setServiceName(serviceName);
+ setAppId(appId);
+ setClusterName(clusterName);
+ setclientIP(clientIP);
+ setMetricsText(metricsText);
+ setThroughPutUnit(throughPutUnit);
+ setNumberOfAudits(numberOfAudits);
+ }
+
+ /**
+ * @param other
+ */
+ public void updateFrom(RangerAuditMetrics other) {
+ super.updateFrom(other);
+ setServiceType(other.getServiceType());
+ setServiceName(other.getServiceName());
+ setAppId(other.getAppId());
+ setClusterName(other.getClusterName());
+ setclientIP(other.getclientIP());
+ setMetricsText(other.getMetricsText());
+ setThroughPutUnit(other.getThroughPutUnit());
+ setNumberOfAudits(other.getNumberOfAudits());
+ }
+
+ /**
+ * @return the serviceType
+ */
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ /**
+ * @param serviceType to set
+ */
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ /**
+ * @return the serviceName
+ */
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ /**
+ * @param serviceName to set
+ */
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getclientIP() {
+ return clientIP;
+ }
+
+ public void setclientIP(String clientIP) {
+ this.clientIP = clientIP;
+ }
+
+ public String getThroughPutUnit() {
+ return throughPutUnit;
+ }
+
+ public void setThroughPutUnit(String throughPutUnit) {
+ this.throughPutUnit = throughPutUnit;
+ }
+
+ public int getNumberOfAudits() {
+ return numberOfAudits;
+ }
+
+ public void setNumberOfAudits(int numberOfAudits) {
+ this.numberOfAudits = numberOfAudits;
+ }
+
+ /**
+ * @return the metricsText
+ */
+
+ public RangerAuditMetricsText getMetricsText() {
+ return metricsText;
+ }
+
+ /**
+ * @param metricsText to set
+ */
+ public void setMetricsText(RangerAuditMetricsText metricsText) {
+ this.metricsText = metricsText;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb);
+ return sb.toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("RangerAuditMetrics={ ");
+ super.toString(sb);
+ sb.append("serviceType={").append(serviceType).append("} ");
+ sb.append("serviceName={").append(serviceName).append("} ");
+ sb.append("appId={").append(appId).append("} ");
+ sb.append("clusterName={").append(clusterName).append("} ");
+ sb.append("clientIP={").append(clientIP).append("} ");
+ sb.append("throughPutUnit={").append(throughPutUnit).append("} ");
+ sb.append("numberOfAudits={").append(numberOfAudits).append("} ");
+ sb.append("metricsText={").append(metricsText).append("} ");
+ sb.append("numberOfAudits={").append(numberOfAudits).append("} ");
+ sb.append("metricsText={").append(metricsText).append("} ");
+ sb.append("}");
+ return sb;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerAuditMetricsText.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerAuditMetricsText.java
new file mode 100644
index 0000000000..9eab8e5d46
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerAuditMetricsText.java
@@ -0,0 +1,47 @@
+/*
+ * 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.audit.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerAuditMetricsText {
+ Map metrics = new HashMap<>();
+
+ public Map getMetrics() {
+ return metrics;
+ }
+
+ public void setMetrics(Map metrics) {
+ this.metrics = metrics;
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("metrics={").append(metrics).append("} ");
+ return sb;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerBaseModelObject.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerBaseModelObject.java
new file mode 100644
index 0000000000..f0de76bca2
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/model/RangerBaseModelObject.java
@@ -0,0 +1,185 @@
+/*
+ * 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.audit.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.util.Date;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerBaseModelObject implements java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private Long id;
+ private String guid;
+ private Boolean isEnabled;
+ private String createdBy;
+ private String updatedBy;
+ private Date createTime;
+ private Date updateTime;
+ private Long version;
+
+ public RangerBaseModelObject() {
+ setIsEnabled(null);
+ }
+
+ public void updateFrom(RangerBaseModelObject other) {
+ setIsEnabled(other.getIsEnabled());
+ }
+
+ /**
+ * @return the id
+ */
+ public Long getId() {
+ return id;
+ }
+
+ /**
+ * @param id the id to set
+ */
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ /**
+ * @return the guid
+ */
+ public String getGuid() {
+ return guid;
+ }
+
+ /**
+ * @param guid the guid to set
+ */
+ public void setGuid(String guid) {
+ this.guid = guid;
+ }
+
+ /**
+ * @return the isEnabled
+ */
+ public Boolean getIsEnabled() {
+ return isEnabled;
+ }
+
+ /**
+ * @param isEnabled the isEnabled to set
+ */
+ public void setIsEnabled(Boolean isEnabled) {
+ this.isEnabled = isEnabled == null ? Boolean.TRUE : isEnabled;
+ }
+
+ /**
+ * @return the createdBy
+ */
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ /**
+ * @param createdBy the createdBy to set
+ */
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ /**
+ * @return the updatedBy
+ */
+ public String getUpdatedBy() {
+ return updatedBy;
+ }
+
+ /**
+ * @param updatedBy the updatedBy to set
+ */
+ public void setUpdatedBy(String updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ /**
+ * @return the createTime
+ */
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * @param createTime the createTime to set
+ */
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * @return the updateTime
+ */
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ /**
+ * @param updateTime the updateTime to set
+ */
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ /**
+ * @return the version
+ */
+ public Long getVersion() {
+ return version;
+ }
+
+ /**
+ * @param version the version to set
+ */
+ public void setVersion(Long version) {
+ this.version = version;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ toString(sb);
+
+ return sb.toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("id={").append(id).append("} ");
+ sb.append("guid={").append(guid).append("} ");
+ sb.append("isEnabled={").append(isEnabled).append("} ");
+ sb.append("createdBy={").append(createdBy).append("} ");
+ sb.append("updatedBy={").append(updatedBy).append("} ");
+ sb.append("createTime={").append(createTime).append("} ");
+ sb.append("updateTime={").append(updateTime).append("} ");
+ sb.append("version={").append(version).append("} ");
+
+ return sb;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/provider/AuditProviderFactory.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/provider/AuditProviderFactory.java
index 2fca686273..1004af598e 100644
--- a/agents-audit/core/src/main/java/org/apache/ranger/audit/provider/AuditProviderFactory.java
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/provider/AuditProviderFactory.java
@@ -20,6 +20,7 @@
import org.apache.hadoop.util.ShutdownHookManager;
import org.apache.ranger.audit.destination.AuditDestination;
+import org.apache.ranger.audit.destination.MetricsAuditDestination;
import org.apache.ranger.audit.queue.AuditAsyncQueue;
import org.apache.ranger.audit.queue.AuditBatchQueue;
import org.apache.ranger.audit.queue.AuditFileQueue;
@@ -445,6 +446,8 @@ private AuditHandler getProviderFromConfig(Properties props, String propPrefix,
provider = getAuditProvider(props, propPrefix, consumer);
} else if (providerName.equalsIgnoreCase("async")) {
provider = new AuditAsyncQueue(consumer);
+ } else if (providerName.equalsIgnoreCase("metrics")) {
+ provider = new MetricsAuditDestination();
} else {
LOG.error("Provider name doesn't have any class associated with it. providerName={}, propertyPrefix={}", providerName, propPrefix);
}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/token/JwTokenRetrieverEnv.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/token/JwTokenRetrieverEnv.java
new file mode 100644
index 0000000000..ba36a87707
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/token/JwTokenRetrieverEnv.java
@@ -0,0 +1,66 @@
+/*
+ * 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.audit.token;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+public class JwTokenRetrieverEnv implements TokenRetriever {
+ private static final Logger LOG = LoggerFactory.getLogger(JwTokenRetrieverEnv.class);
+ private static final String DEFAULT_JWT_ENV_VAR_NAME = "RANGER_AUTH_JWT";
+ private static final String RANGER_PROP_JWT_ENV_VAR_NAME = "ranger.auth.jwt.env.var.name";
+
+ private String jwtEnvVarName = DEFAULT_JWT_ENV_VAR_NAME;
+
+ public JwTokenRetrieverEnv(Configuration config) {
+ init(config);
+ }
+
+ @Override
+ public Optional retrieve() {
+ LOG.debug("==> JwTokenRetrieverEnv.retrieve()");
+
+ Optional ret = Optional.empty();
+
+ try {
+ String jwt = System.getenv(jwtEnvVarName);
+ if (StringUtils.isNotBlank(jwt)) {
+ ret = Optional.of(jwt);
+ }
+ } catch (Exception e) {
+ LOG.error("JwTokenRetrieverEnv.retrieve(): Failed to get JWT token.", e);
+ }
+
+ LOG.debug("<== JwTokenRetrieverEnv.retrieve(): isJwTokenPresent={}", ret.isPresent());
+ return ret;
+ }
+
+ private void init(Configuration config) {
+ LOG.debug("==> JwTokenRetrieverEnv.init()");
+
+ this.jwtEnvVarName = config.get(RANGER_PROP_JWT_ENV_VAR_NAME, DEFAULT_JWT_ENV_VAR_NAME);
+
+ LOG.debug("<== JwTokenRetrieverEnv.init(): jwtEnvVarName={}", jwtEnvVarName);
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/token/JwTokenRetrieverFile.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/token/JwTokenRetrieverFile.java
new file mode 100644
index 0000000000..840b80ae2e
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/token/JwTokenRetrieverFile.java
@@ -0,0 +1,80 @@
+/*
+ * 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.audit.token;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Optional;
+
+public class JwTokenRetrieverFile implements TokenRetriever {
+ private static final Logger LOG = LoggerFactory.getLogger(JwTokenRetrieverFile.class);
+ private static final String RANGER_PROP_JWT_FILENAME = "ranger.auth.jwt.file.name";
+ private final Optional cachedJWT = Optional.empty();
+ private File jwtFile;
+ private Long lastModified = -1L;
+
+ public JwTokenRetrieverFile(Configuration config) {
+ init(config);
+ }
+
+ @Override
+ public Optional retrieve() {
+ LOG.debug("==> JwTokenRetrieverFile.retrieve()");
+
+ Optional ret = cachedJWT;
+
+ if (jwtFile != null && jwtFile.lastModified() > this.lastModified) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(jwtFile))) {
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ if (StringUtils.isNotBlank(line) && !line.startsWith("#")) {
+ ret = Optional.of(line);
+ this.lastModified = jwtFile.lastModified();
+ break;
+ }
+ }
+ } catch (IOException e) {
+ LOG.error("JwTokenRetrieverFile.retrieve(): Failed to get JWT token.", e);
+ }
+ }
+
+ LOG.debug("<== JwTokenRetrieverFile.retrieve(): isJwTokenPresent={}", ret.isPresent());
+
+ return ret;
+ }
+
+ private void init(Configuration config) {
+ LOG.debug("==> JwTokenRetrieverFile.init()");
+
+ String fileName = config.get(RANGER_PROP_JWT_FILENAME, "");
+ if (StringUtils.isNotBlank(fileName)) {
+ jwtFile = new File(fileName);
+ }
+
+ LOG.debug("<== JwTokenRetrieverFile.init(): fileName={}", fileName);
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/token/TokenRetriever.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/token/TokenRetriever.java
new file mode 100644
index 0000000000..733e45d39c
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/token/TokenRetriever.java
@@ -0,0 +1,26 @@
+/*
+ * 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.audit.token;
+
+import java.util.Optional;
+
+public interface TokenRetriever {
+ Optional retrieve();
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/JsonUtils.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/JsonUtils.java
new file mode 100644
index 0000000000..0f829551fa
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/JsonUtils.java
@@ -0,0 +1,130 @@
+/*
+ * 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.audit.utils;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class JsonUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(JsonUtils.class);
+ private static final ThreadLocal mapper = new ThreadLocal() {
+ @Override
+ protected ObjectMapper initialValue() {
+ return new ObjectMapper();
+ }
+ };
+ private static final ThreadLocal gson = new ThreadLocal() {
+ @Override
+ protected Gson initialValue() {
+ return new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
+ }
+ };
+
+ private JsonUtils() {
+ //Block Instantiation
+ }
+
+ public static ObjectMapper getMapper() {
+ return mapper.get();
+ }
+
+ public static Map jsonToMap(String jsonStr) throws Exception {
+ final Map ret;
+
+ if (jsonStr == null || jsonStr.isEmpty()) {
+ ret = new HashMap<>();
+ } else {
+ ret = getMapper().readValue(jsonStr, new TypeReference>() {});
+ }
+
+ return ret;
+ }
+
+ public static String mapToJson(Map, ?> map) throws Exception {
+ return getMapper().writeValueAsString(map);
+ }
+
+ public static String listToJson(List> list) throws Exception {
+ return getMapper().writeValueAsString(list);
+ }
+
+ public static String objToJson(Serializable obj) throws Exception {
+ return getMapper().writeValueAsString(obj);
+ }
+
+ public static T jsonToObj(String json, Class tClass) throws Exception {
+ return getMapper().readValue(json, tClass);
+ }
+
+ public static String objectToJson(Object object) {
+ String ret = null;
+
+ if (object != null) {
+ try {
+ ret = gson.get().toJson(object);
+ } catch (Exception excp) {
+ LOG.warn("objectToJson() failed to convert object to Json", excp);
+ }
+ }
+
+ return ret;
+ }
+
+ public static T jsonToObject(String jsonStr, Class clz) {
+ T ret = null;
+
+ if (StringUtils.isNotEmpty(jsonStr)) {
+ try {
+ ret = gson.get().fromJson(jsonStr, clz);
+ } catch (Exception excp) {
+ LOG.warn("jsonToObject() failed to convert json to object: {}", jsonStr, excp);
+ }
+ }
+
+ return ret;
+ }
+
+ public static Map jsonToMapStringString(String jsonStr) {
+ Map ret = null;
+
+ if (StringUtils.isNotEmpty(jsonStr)) {
+ try {
+ Type mapType = new TypeToken>() {}.getType();
+ ret = gson.get().fromJson(jsonStr, mapType);
+ } catch (Exception excp) {
+ LOG.warn("jsonToObject() failed to convert json to object: {}", jsonStr, excp);
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RangerAuditConfig.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RangerAuditConfig.java
new file mode 100644
index 0000000000..c4719111c8
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RangerAuditConfig.java
@@ -0,0 +1,51 @@
+/**
+ * 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.audit.utils;
+
+import org.apache.hadoop.conf.Configuration;
+
+import java.util.Properties;
+
+public class RangerAuditConfig {
+ private static final String CORE_SITE_CONFIG_FILE = "core-site.xml";
+ private static volatile RangerAuditConfig me;
+
+ public static RangerAuditConfig getInstance() {
+ RangerAuditConfig result = me;
+ if (result == null) {
+ synchronized (RangerAuditConfig.class) {
+ result = me;
+ if (result == null) {
+ result = new RangerAuditConfig();
+ me = result;
+ }
+ }
+ }
+ return result;
+ }
+
+ public Configuration getConfig(Properties props) {
+ XMLUtils.loadConfig(CORE_SITE_CONFIG_FILE, props);
+ Configuration ret = new Configuration();
+ for (String propName : props.stringPropertyNames()) {
+ ret.set(propName, props.getProperty(propName));
+ }
+ return ret;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RangerAuditMetricsUtil.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RangerAuditMetricsUtil.java
new file mode 100644
index 0000000000..5957a8a03c
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RangerAuditMetricsUtil.java
@@ -0,0 +1,97 @@
+/**
+ * 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.audit.utils;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.ranger.audit.client.AbstractRangerAuditMetricRESTClient;
+import org.apache.ranger.audit.client.RangerAuditMetricRESTClient;
+import org.apache.ranger.audit.model.RangerAuditMetrics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+public class RangerAuditMetricsUtil {
+ public static final String RANGER_ADMIN_URL = "ranger.plugin.%s.policy.rest.url";
+ public static final String RANGER_ADMIN_SSL_CONFIG_FILENAME = "ranger.plugin.%s.policy.rest.ssl.config.file";
+ public static final String RANGER_ADMIN_IMPL_CLASS_CONF = "ranger.plugin.%s.policy.source.impl";
+ public static final String RANGER_SERVICE_TYPE_CONFIG = "ranger.plugin.serviceType";
+ public static final String RANGER_ADMIM_IMPL_CLASS = "org.apache.ranger.admin.client.RangerAdminRESTClient";
+ public static final String RANGER_ADMIM_IMPL_JERSEY2_CLASS = "org.apache.ranger.admin.client.RangerAdminJersey2RESTClient";
+ public static final String RANGER_ADMIN_AUDIT_METRICS_JERSEY2_CLASS = "org.apache.ranger.admin.client.RangerAuditMetricsJersey2RESTClient";
+ private static final Logger LOG = LoggerFactory.getLogger(RangerAuditMetricsUtil.class);
+ private final Properties props;
+ private Configuration auditConfig;
+ private AbstractRangerAuditMetricRESTClient auditMetricRESTClient;
+
+ public RangerAuditMetricsUtil(Properties props) {
+ this.props = props;
+ init(this.props);
+ }
+
+ public RangerAuditMetrics createAuditMetrics(RangerAuditMetrics request) throws Exception {
+ LOG.debug("==> RangerAuditMetricsUtil.createAuditMetrics({})", request);
+
+ if (auditMetricRESTClient == null) {
+ throw new Exception("RangerAuditMetricRESTClient is null...Audit Metrics cannot be logged..");
+ }
+
+ RangerAuditMetrics ret = null;
+
+ try {
+ auditMetricRESTClient.createAuditMetrics(request);
+ } catch (Exception e) {
+ LOG.error("Error creating auditMetric: {}", request, e);
+ }
+ return ret;
+ }
+
+ private void init(Properties props) {
+ auditConfig = RangerAuditConfig.getInstance().getConfig(props);
+ auditMetricRESTClient = getRangerClient();
+ if (auditMetricRESTClient == null) {
+ LOG.error("Error create RangerAuditMetricRESTClient...Audit Metrics collection won't happen");
+ }
+ }
+
+ private AbstractRangerAuditMetricRESTClient getRangerClient() {
+ AbstractRangerAuditMetricRESTClient ret = null;
+ String serviceType = auditConfig.get(RANGER_SERVICE_TYPE_CONFIG);
+ String url = auditConfig.get(String.format(RANGER_ADMIN_URL, serviceType));
+ String sslConfigFileName = auditConfig.get(String.format(RANGER_ADMIN_SSL_CONFIG_FILENAME, serviceType));
+ String adminCls = auditConfig.get(String.format(RANGER_ADMIN_IMPL_CLASS_CONF, serviceType));
+
+ if (adminCls.equals(RANGER_ADMIM_IMPL_CLASS)) {
+ ret = new RangerAuditMetricRESTClient();
+ } else if (adminCls.equals(RANGER_ADMIM_IMPL_JERSEY2_CLASS)) {
+ try {
+ @SuppressWarnings("unchecked")
+ Class auditMetricRESTClientClass = (Class) Class.forName(RANGER_ADMIN_AUDIT_METRICS_JERSEY2_CLASS);
+ ret = auditMetricRESTClientClass.newInstance();
+ } catch (Exception excp) {
+ LOG.error("failed to instantiate policy source of type {}", RANGER_ADMIN_AUDIT_METRICS_JERSEY2_CLASS, excp);
+ }
+ }
+
+ if (ret != null) {
+ ret.init(url, sslConfigFileName, auditConfig);
+ }
+ return ret;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RollingTimeUtil.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RollingTimeUtil.java
index 9064a1da08..f8872eaac7 100644
--- a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RollingTimeUtil.java
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/RollingTimeUtil.java
@@ -31,10 +31,15 @@ public class RollingTimeUtil {
public static final String MONTHS = "M"; //months
public static final String YEARS = "y"; //years
+ public static final String MINUTE_STR = "MINUTE";
+ public static final String HOUR_STR = "HOUR";
+ public static final String DAY_STR = "WEEK";
private static final int SECONDS_IN_MINUTE = 60;
private static final int SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE;
private static final int SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR;
+ public static final long MILLISECOND_CONVERSION_FACTOR = 60000L; // 1 min = 60000 milli second.
+
private static volatile RollingTimeUtil me;
public RollingTimeUtil() {
@@ -61,9 +66,9 @@ public static void main(String[] args) {
// Test Method for RolloverTime calculation
// Set rollOverPeriod 10m,30m..,1h,2h,..1d,2d..,1w,2w..,1M,2M..1y..2y
// If nothing is set for rollOverPeriod or Duration default rollOverPeriod is 1 day
- String rollOverPeriod = "";
- RollingTimeUtil rollingTimeUtil = new RollingTimeUtil();
- int duration = 86400;
+ String rollOverPeriod = "";
+ RollingTimeUtil rollingTimeUtil = new RollingTimeUtil();
+ int duration = 86400;
Date nextRollOvertime;
try {
@@ -166,6 +171,66 @@ public long computeNextRollingTime(long durationSeconds, Date previousRolloverTi
return nextRolloverTime;
}
+ public int getTimeNumeral(String rollOverPeriod, String timeLiteral) throws Exception {
+ int ret = Integer.valueOf(rollOverPeriod.substring(0, rollOverPeriod.length() - (rollOverPeriod.length() - rollOverPeriod.indexOf(timeLiteral))));
+
+ return ret;
+ }
+
+ public String getTimeLiteral(String rollOverPeriod) throws Exception {
+ String ret = null;
+ if (StringUtils.isEmpty(rollOverPeriod)) {
+ throw new Exception("empty rollover period");
+ } else if (rollOverPeriod.endsWith(MINUTES)) {
+ ret = MINUTES;
+ } else if (rollOverPeriod.endsWith(HOURS)) {
+ ret = HOURS;
+ } else if (rollOverPeriod.endsWith(DAYS)) {
+ ret = DAYS;
+ } else if (rollOverPeriod.endsWith(WEEKS)) {
+ ret = WEEKS;
+ } else if (rollOverPeriod.endsWith(MONTHS)) {
+ ret = MONTHS;
+ } else if (rollOverPeriod.endsWith(YEARS)) {
+ ret = YEARS;
+ } else {
+ throw new Exception(rollOverPeriod + ": invalid rollover period");
+ }
+ return ret;
+ }
+
+ public long getTimeInMilliSeconds(int timeNumeral, String computePeriod) throws Exception {
+ long ret;
+
+ if (computePeriod.equals(MINUTES)) {
+ ret = Integer.toUnsignedLong(timeNumeral) * MILLISECOND_CONVERSION_FACTOR;
+ } else if (computePeriod.equals(HOURS)) {
+ ret = (timeNumeral * 60L) * MILLISECOND_CONVERSION_FACTOR;
+ } else if (computePeriod.equals(DAYS)) {
+ ret = ((long) timeNumeral * 24 * 60) * MILLISECOND_CONVERSION_FACTOR;
+ } else {
+ throw new Exception("Unsupported time interval = " + timeNumeral + computePeriod);
+ }
+
+ return ret;
+ }
+
+ public String getTimeString(int timeNumeral, String computePeriod) throws Exception {
+ String ret;
+
+ if (computePeriod.equals(MINUTES)) {
+ ret = "PER" + " " + ((timeNumeral == 1) ? "" : timeNumeral) + " " + ((timeNumeral > 1) ? MINUTE_STR + "S" : MINUTE_STR);
+ } else if (computePeriod.equals(HOURS)) {
+ ret = "PER" + " " + ((timeNumeral == 1) ? "" : timeNumeral) + " " + ((timeNumeral > 1) ? HOUR_STR + "S" : HOUR_STR);
+ } else if (computePeriod.equals(DAYS)) {
+ ret = "PER" + " " + ((timeNumeral == 1) ? "" : timeNumeral) + " " + ((timeNumeral > 1) ? DAY_STR + "S" : DAY_STR);
+ } else {
+ throw new Exception("Unsupported time interval = " + timeNumeral + computePeriod);
+ }
+
+ return ret;
+ }
+
private Date computeTopOfYearDate(int years) {
Calendar calendarStart = Calendar.getInstance();
@@ -238,32 +303,4 @@ private Date computeTopOfMinuteDate(int mins) {
return calendarMin.getTime();
}
-
- private int getTimeNumeral(String rollOverPeriod, String timeLiteral) {
- return Integer.parseInt(rollOverPeriod.substring(0, rollOverPeriod.length() - (rollOverPeriod.length() - rollOverPeriod.indexOf(timeLiteral))));
- }
-
- private String getTimeLiteral(String rollOverPeriod) throws Exception {
- final String ret;
-
- if (StringUtils.isEmpty(rollOverPeriod)) {
- throw new Exception("empty rollover period");
- } else if (rollOverPeriod.endsWith(MINUTES)) {
- ret = MINUTES;
- } else if (rollOverPeriod.endsWith(HOURS)) {
- ret = HOURS;
- } else if (rollOverPeriod.endsWith(DAYS)) {
- ret = DAYS;
- } else if (rollOverPeriod.endsWith(WEEKS)) {
- ret = WEEKS;
- } else if (rollOverPeriod.endsWith(MONTHS)) {
- ret = MONTHS;
- } else if (rollOverPeriod.endsWith(YEARS)) {
- ret = YEARS;
- } else {
- throw new Exception(rollOverPeriod + ": invalid rollover period");
- }
-
- return ret;
- }
}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/StringUtil.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/StringUtil.java
new file mode 100644
index 0000000000..9273b580c4
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/StringUtil.java
@@ -0,0 +1,312 @@
+/*
+ * 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.audit.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+public class StringUtil {
+ private static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT+0");
+
+ private StringUtil() {
+ // to block instantiation
+ }
+
+ public static boolean equals(String str1, String str2) {
+ boolean ret = false;
+
+ if (str1 == null) {
+ ret = str2 == null;
+ } else if (str2 == null) {
+ ret = false;
+ } else {
+ ret = str1.equals(str2);
+ }
+
+ return ret;
+ }
+
+ public static boolean equalsIgnoreCase(String str1, String str2) {
+ boolean ret = false;
+
+ if (str1 == null) {
+ ret = str2 == null;
+ } else if (str2 == null) {
+ ret = false;
+ } else {
+ ret = str1.equalsIgnoreCase(str2);
+ }
+
+ return ret;
+ }
+
+ public static boolean equals(Collection set1, Collection set2) {
+ boolean ret = false;
+
+ if (set1 == null) {
+ ret = set2 == null;
+ } else if (set2 == null) {
+ ret = false;
+ } else if (set1.size() == set2.size()) {
+ ret = set1.containsAll(set2);
+ }
+
+ return ret;
+ }
+
+ public static boolean equalsIgnoreCase(Collection set1, Collection set2) {
+ boolean ret = false;
+
+ if (set1 == null) {
+ ret = set2 == null;
+ } else if (set2 == null) {
+ ret = false;
+ } else if (set1.size() == set2.size()) {
+ int numFound = 0;
+
+ for (String str1 : set1) {
+ boolean str1Found = false;
+
+ for (String str2 : set2) {
+ if (equalsIgnoreCase(str1, str2)) {
+ str1Found = true;
+
+ break;
+ }
+ }
+
+ if (str1Found) {
+ numFound++;
+ } else {
+ break;
+ }
+ }
+
+ ret = numFound == set1.size();
+ }
+
+ return ret;
+ }
+
+ public static boolean matches(String pattern, String str) {
+ boolean ret = false;
+
+ if (pattern == null || str == null || pattern.isEmpty() || str.isEmpty()) {
+ ret = true;
+ } else {
+ ret = str.matches(pattern);
+ }
+
+ return ret;
+ }
+
+ public static boolean contains(String str, String strToFind) {
+ return str != null && strToFind != null && str.contains(strToFind);
+ }
+
+ public static boolean containsIgnoreCase(String str, String strToFind) {
+ return str != null && strToFind != null && str.toLowerCase().contains(strToFind.toLowerCase());
+ }
+
+ public static boolean contains(String[] strArr, String str) {
+ boolean ret = false;
+
+ if (strArr != null && strArr.length > 0 && str != null) {
+ for (String s : strArr) {
+ ret = equals(s, str);
+
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean containsIgnoreCase(String[] strArr, String str) {
+ boolean ret = false;
+
+ if (strArr != null && strArr.length > 0 && str != null) {
+ for (String s : strArr) {
+ ret = equalsIgnoreCase(s, str);
+
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public static String toString(Iterable iterable) {
+ String ret = "";
+
+ if (iterable != null) {
+ int count = 0;
+ for (String str : iterable) {
+ if (count == 0) {
+ ret = str;
+ } else {
+ ret += (", " + str);
+ }
+ count++;
+ }
+ }
+
+ return ret;
+ }
+
+ public static String toString(String[] arr) {
+ String ret = "";
+
+ if (arr != null && arr.length > 0) {
+ ret = arr[0];
+ for (int i = 1; i < arr.length; i++) {
+ ret += (", " + arr[i]);
+ }
+ }
+
+ return ret;
+ }
+
+ public static String toString(List arr) {
+ String ret = "";
+
+ if (arr != null && !arr.isEmpty()) {
+ ret = arr.get(0);
+ for (int i = 1; i < arr.size(); i++) {
+ ret += (", " + arr.get(i));
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean isEmpty(String str) {
+ return str == null || str.trim().isEmpty();
+ }
+
+ public static boolean isEmpty(Collection set) {
+ return set == null || set.isEmpty();
+ }
+
+ public static String toLower(String str) {
+ return str == null ? null : str.toLowerCase();
+ }
+
+ public static byte[] getBytes(String str) {
+ return str == null ? null : str.getBytes();
+ }
+
+ public static Date getUTCDate() {
+ Calendar local = Calendar.getInstance();
+ int offset = local.getTimeZone().getOffset(local.getTimeInMillis());
+
+ GregorianCalendar utc = new GregorianCalendar(gmtTimeZone);
+
+ utc.setTimeInMillis(local.getTimeInMillis());
+ utc.add(Calendar.MILLISECOND, -offset);
+
+ return utc.getTime();
+ }
+
+ public static Date getUTCDateForLocalDate(Date date) {
+ Calendar local = Calendar.getInstance();
+ int offset = local.getTimeZone().getOffset(local.getTimeInMillis());
+
+ GregorianCalendar utc = new GregorianCalendar(gmtTimeZone);
+
+ utc.setTimeInMillis(date.getTime());
+ utc.add(Calendar.MILLISECOND, -offset);
+
+ return utc.getTime();
+ }
+
+ public static Map toStringObjectMap(Map map) {
+ Map ret = null;
+
+ if (map != null) {
+ ret = new HashMap<>(map.size());
+
+ for (Map.Entry e : map.entrySet()) {
+ ret.put(e.getKey(), e.getValue());
+ }
+ }
+
+ return ret;
+ }
+
+ public static Set toSet(String str) {
+ Set values = new HashSet();
+ if (StringUtils.isNotBlank(str)) {
+ for (String item : str.split(",")) {
+ if (StringUtils.isNotBlank(item)) {
+ values.add(StringUtils.trim(item));
+ }
+ }
+ }
+ return values;
+ }
+
+ public static List toList(String str) {
+ List values;
+ if (StringUtils.isNotBlank(str)) {
+ values = new ArrayList<>();
+ for (String item : str.split(",")) {
+ if (StringUtils.isNotBlank(item)) {
+ values.add(StringUtils.trim(item));
+ }
+ }
+ } else {
+ values = Collections.emptyList();
+ }
+ return values;
+ }
+
+ public static List getURLs(String configURLs) {
+ List configuredURLs = new ArrayList<>();
+ if (configURLs != null) {
+ String[] urls = configURLs.split(",");
+ for (String strUrl : urls) {
+ if (!StringUtils.isEmpty(StringUtils.trimToEmpty(strUrl))) {
+ if (strUrl.endsWith("/")) {
+ strUrl = strUrl.substring(0, strUrl.length() - 1);
+ }
+ configuredURLs.add(strUrl);
+ }
+ }
+ }
+ return configuredURLs;
+ }
+}
diff --git a/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/XMLUtils.java b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/XMLUtils.java
new file mode 100644
index 0000000000..e048bdd420
--- /dev/null
+++ b/agents-audit/core/src/main/java/org/apache/ranger/audit/utils/XMLUtils.java
@@ -0,0 +1,133 @@
+/*
+ * 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.audit.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Map;
+
+public class XMLUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(XMLUtils.class);
+
+ private static final String XMLCONFIG_PROPERTY_TAGNAME = "property";
+ private static final String XMLCONFIG_NAME_TAGNAME = "name";
+ private static final String XMLCONFIG_VALUE_TAGNAME = "value";
+
+ private XMLUtils() {
+ //block instantiation
+ }
+
+ public static void loadConfig(String configFileName, Map properties) {
+ try (InputStream input = getFileInputStream(configFileName)) {
+ loadConfig(input, properties);
+ } catch (Exception e) {
+ LOG.error("Error loading : ", e);
+ }
+ }
+
+ public static void loadConfig(InputStream input, Map properties) {
+ try {
+ DocumentBuilderFactory xmlDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
+ xmlDocumentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ xmlDocumentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ xmlDocumentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ xmlDocumentBuilderFactory.setIgnoringComments(true);
+ xmlDocumentBuilderFactory.setNamespaceAware(true);
+
+ DocumentBuilder xmlDocumentBuilder = xmlDocumentBuilderFactory.newDocumentBuilder();
+ Document xmlDocument = xmlDocumentBuilder.parse(input);
+ xmlDocument.getDocumentElement().normalize();
+
+ NodeList nList = xmlDocument.getElementsByTagName(XMLCONFIG_PROPERTY_TAGNAME);
+
+ for (int temp = 0; temp < nList.getLength(); temp++) {
+ Node nNode = nList.item(temp);
+
+ if (nNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element eElement = (Element) nNode;
+
+ String propertyName = "";
+ String propertyValue = "";
+ if (eElement.getElementsByTagName(XMLCONFIG_NAME_TAGNAME).item(0) != null) {
+ propertyName = eElement.getElementsByTagName(XMLCONFIG_NAME_TAGNAME).item(0).getTextContent().trim();
+ }
+ if (eElement.getElementsByTagName(XMLCONFIG_VALUE_TAGNAME).item(0) != null) {
+ propertyValue = eElement.getElementsByTagName(XMLCONFIG_VALUE_TAGNAME).item(0).getTextContent().trim();
+ }
+
+ if (properties.get(propertyName) != null) {
+ properties.remove(propertyName);
+ }
+
+ properties.put(propertyName, propertyValue);
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Error loading : ", e);
+ }
+ }
+
+ private static InputStream getFileInputStream(String path) throws FileNotFoundException {
+ InputStream ret = null;
+
+ // Guard against path traversal attacks
+ String sanitizedPath = new File(path).getName();
+ if ("".equals(sanitizedPath)) {
+ return null;
+ }
+ File f = new File(sanitizedPath);
+
+ if (f.exists()) {
+ ret = new FileInputStream(f);
+ } else {
+ ret = XMLUtils.class.getResourceAsStream(path);
+
+ if (ret == null) {
+ if (!path.startsWith("/")) {
+ ret = XMLUtils.class.getResourceAsStream("/" + path);
+ }
+ }
+
+ if (ret == null) {
+ ret = ClassLoader.getSystemClassLoader().getResourceAsStream(path);
+ if (ret == null) {
+ if (!path.startsWith("/")) {
+ ret = ClassLoader.getSystemResourceAsStream("/" + path);
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
index 83cae22d89..2f4a246c57 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
@@ -137,6 +137,14 @@ public enum ValidationErrorCode {
ROLE_VALIDATION_ERR_INVALID_ROLE_NAME(4007, "No RangerRole found for name[{0}]"),
ROLE_VALIDATION_ERR_UNSUPPORTED_ACTION(4008, "Internal error: method signature isValid(Long) is only supported for DELETE"),
+ //RANGER ROLE Validations
+ AUDIT_METRICS_VALIDATION_ERR_NULL_AUDIT_METRICS__OBJECT(5001, "Internal error: RangerRole object passed in was null"),
+ AUDIT_METRICS_VALIDATION_ERR_MISSING_FIELD(5002, "Internal error: missing field[{0}]"),
+ AUDIT_METRICS_VALIDATION_ERR_NULL_RANGER_ROLE_NAME(5003, "Internal error: RangerRole name passed in was null/empty"),
+ AUDIT_METRICS_VALIDATION_ERR_INVALID_ROLE_ID(5006, "No RangerRole found for id[{0}]"),
+ AUDIT_METRICS_VALIDATION_ERR_INVALID_ROLE_NAME(5007, "No RangerRole found for name[{0}]"),
+ AUDIT_METRICS_VALIDATION_ERR_UNSUPPORTED_ACTION(5008, "Internal error: method signature isValid(Long) is only supported for DELETE"),
+
GDS_VALIDATION_ERR_NON_EXISTING_USER(4101, "User [{0}] does not exist"),
GDS_VALIDATION_ERR_NON_EXISTING_GROUP(4102, "Group [{0}] does not exist"),
GDS_VALIDATION_ERR_NON_EXISTING_ROLE(4103, "Role [{0}] does not exist"),
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetrics.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetrics.java
new file mode 100644
index 0000000000..d35ee4e11d
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetrics.java
@@ -0,0 +1,184 @@
+/*
+ * 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.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonAutoDetect(fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerAuditMetrics extends RangerBaseModelObject implements java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String serviceType;
+ private String serviceName;
+ private String appId;
+ private String clusterName;
+ private String clientIP;
+ private String throughPutUnit;
+ private int numberOfAudits;
+ private RangerAuditMetricsText metricsText;
+
+ /**
+ * @param
+ */
+ public RangerAuditMetrics() {
+ }
+
+ /**
+ * @param serviceType
+ * @param serviceName
+ * @param metricsText
+ */
+ public RangerAuditMetrics(String serviceType, String serviceName, String appId, String clusterName, String clientIP, String throughPutUnit, int numberOfAudits, RangerAuditMetricsText metricsText) {
+ super();
+ setServiceType(serviceType);
+ setServiceName(serviceName);
+ setAppId(appId);
+ setClusterName(clusterName);
+ setclientIP(clientIP);
+ setMetricsText(metricsText);
+ setThroughPutUnit(throughPutUnit);
+ setNumberOfAudits(numberOfAudits);
+ }
+
+ /**
+ * @param other
+ */
+ public void updateFrom(RangerAuditMetrics other) {
+ super.updateFrom(other);
+ setServiceType(other.getServiceType());
+ setServiceName(other.getServiceName());
+ setAppId(other.getAppId());
+ setClusterName(other.getClusterName());
+ setclientIP(other.getclientIP());
+ setMetricsText(other.getMetricsText());
+ setThroughPutUnit(other.getThroughPutUnit());
+ setNumberOfAudits(other.getNumberOfAudits());
+ }
+
+ /**
+ * @return the serviceType
+ */
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ /**
+ * @param serviceType to set
+ */
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ /**
+ * @return the serviceName
+ */
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ /**
+ * @param serviceName to set
+ */
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getclientIP() {
+ return clientIP;
+ }
+
+ public void setclientIP(String clientIP) {
+ this.clientIP = clientIP;
+ }
+
+ public String getThroughPutUnit() {
+ return throughPutUnit;
+ }
+
+ public void setThroughPutUnit(String throughPutUnit) {
+ this.throughPutUnit = throughPutUnit;
+ }
+
+ public int getNumberOfAudits() {
+ return numberOfAudits;
+ }
+
+ public void setNumberOfAudits(int numberOfAudits) {
+ this.numberOfAudits = numberOfAudits;
+ }
+
+ /**
+ * @return the metricsText
+ */
+
+ public RangerAuditMetricsText getMetricsText() {
+ return metricsText;
+ }
+
+ /**
+ * @param metricsText to set
+ */
+ public void setMetricsText(RangerAuditMetricsText metricsText) {
+ this.metricsText = metricsText;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb);
+ return sb.toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("RangerAuditMetrics={ ");
+ super.toString(sb);
+ sb.append("serviceType={").append(serviceType).append("} ");
+ sb.append("serviceName={").append(serviceName).append("} ");
+ sb.append("appId={").append(appId).append("} ");
+ sb.append("clusterName={").append(clusterName).append("} ");
+ sb.append("clientIP={").append(clientIP).append("} ");
+ sb.append("metricsText={").append(metricsText).append("} ");
+ sb.append("numberOfAudits={").append(numberOfAudits).append("} ");
+ sb.append("metricsText={").append(metricsText).append("} ");
+ sb.append("}");
+ return sb;
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByDays.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByDays.java
new file mode 100644
index 0000000000..961b8e8913
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByDays.java
@@ -0,0 +1,174 @@
+/*
+ * 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.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerAuditMetricsByDays extends RangerBaseModelObject implements java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String serviceType;
+ private String serviceName;
+ private String appId;
+ private String clusterName;
+ private String clientIP;
+ private Integer days;
+ private Long auditDate;
+ private Long numberOfAudits;
+
+ /**
+ * @param
+ */
+ public RangerAuditMetricsByDays() {
+ this(null, null, null, null, null, null, null, null);
+ }
+
+ /**
+ * @param serviceType
+ * @param serviceName
+ * @param appId
+ * @param clusterName
+ * @param clientIP
+ * @param days
+ * @param auditDate
+ * @param numberOfAudits
+ */
+ public RangerAuditMetricsByDays(String serviceType, String serviceName, String appId, String clusterName, String clientIP, Integer days, Long auditDate, Long numberOfAudits) {
+ super();
+ setServiceType(serviceType);
+ setServiceName(serviceName);
+ setAppId(appId);
+ setClusterName(clusterName);
+ setClientIP(clientIP);
+ setDays(days);
+ setAuditDate(auditDate);
+ setNumberOfAudits(numberOfAudits);
+ }
+
+ /**
+ * @param other
+ */
+ public void updateFrom(RangerAuditMetricsByDays other) {
+ super.updateFrom(other);
+ setServiceType(other.getServiceType());
+ setServiceName(other.getServiceName());
+ setAppId(other.getAppId());
+ setClusterName(other.getClusterName());
+ setClientIP(other.getClientIP());
+ setAuditDate(other.getAuditDate());
+ setNumberOfAudits(other.getNumberOfAudits());
+ }
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getClientIP() {
+ return clientIP;
+ }
+
+ public void setClientIP(String clientIP) {
+ if (clientIP == null) {
+ this.clientIP = "";
+ } else {
+ this.clientIP = clientIP;
+ }
+ }
+
+ public Integer getDays() {
+ return days;
+ }
+
+ public void setDays(Integer days) {
+ this.days = days;
+ }
+
+ public Long getNumberOfAudits() {
+ return numberOfAudits;
+ }
+
+ public void setNumberOfAudits(Long numberOfAudits) {
+ this.numberOfAudits = numberOfAudits;
+ }
+
+ public Long getAuditDate() {
+ return auditDate;
+ }
+
+ public void setAuditDate(Long auditDate) {
+ this.auditDate = auditDate;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb);
+ return sb.toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("RangerAuditMetricsByDays={ ");
+ super.toString(sb);
+ sb.append("serviceType={").append(serviceType).append("} ");
+ sb.append("serviceName={").append(serviceName).append("} ");
+ sb.append("appId={").append(appId).append("} ");
+ sb.append("clusterName={").append(clusterName).append("} ");
+ sb.append("clientIP={").append(clientIP).append("} ");
+ sb.append("days={").append(days).append("} ");
+ sb.append("auditDate={").append(auditDate).append("} ");
+ sb.append("numberOfAudits={").append(numberOfAudits).append("} ");
+ sb.append("}");
+ return sb;
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByHours.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByHours.java
new file mode 100644
index 0000000000..4702d38896
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByHours.java
@@ -0,0 +1,159 @@
+/*
+ * 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.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonAutoDetect(fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerAuditMetricsByHours extends RangerBaseModelObject implements java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String serviceType;
+ private String serviceName;
+ private String appId;
+ private String clusterName;
+ private String clientIP;
+ private Integer hours;
+ private Long numberOfAudits;
+
+ /**
+ * @param
+ */
+ public RangerAuditMetricsByHours() {
+ this(null, null, null, null, null, null, null);
+ }
+
+ /**
+ * @param serviceType
+ * @param serviceName
+ * @param hours
+ * @param numberOfAudits
+ */
+ public RangerAuditMetricsByHours(String serviceType, String serviceName, String appId, String clusterName, String clientIP, Integer hours, Long numberOfAudits) {
+ super();
+ setServiceType(serviceType);
+ setServiceName(serviceName);
+ setAppId(appId);
+ setClusterName(clusterName);
+ setClientIP(clientIP);
+ setHours(hours);
+ setNumberOfAudits(numberOfAudits);
+ }
+
+ /**
+ * @param other
+ */
+ public void updateFrom(RangerAuditMetricsByHours other) {
+ super.updateFrom(other);
+ setServiceType(other.getServiceType());
+ setServiceName(other.getServiceName());
+ setAppId(other.getAppId());
+ setClusterName(other.getClusterName());
+ setClientIP(other.getClientIP());
+ setHours(other.getHours());
+ setNumberOfAudits(other.getNumberOfAudits());
+ }
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public Integer getHours() {
+ return hours;
+ }
+
+ public void setHours(Integer hours) {
+ this.hours = hours;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getClientIP() {
+ return clientIP;
+ }
+
+ public void setClientIP(String clientIP) {
+ if (clientIP == null) {
+ this.clientIP = "";
+ } else {
+ this.clientIP = clientIP;
+ }
+ }
+
+ public Long getNumberOfAudits() {
+ return numberOfAudits;
+ }
+
+ public void setNumberOfAudits(Long numberOfAudits) {
+ this.numberOfAudits = numberOfAudits;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb);
+ return sb.toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("RangerAuditMetricsByHours={ ");
+ super.toString(sb);
+ sb.append("serviceType={").append(serviceType).append("} ");
+ sb.append("serviceName={").append(serviceName).append("} ");
+ sb.append("appId={").append(appId).append("} ");
+ sb.append("clusterName={").append(clusterName).append("} ");
+ sb.append("clientIP={").append(clientIP).append("} ");
+ sb.append("Hours={").append(hours).append("} ");
+ sb.append("numberOfAudits={").append(numberOfAudits).append("} ");
+ sb.append("}");
+ return sb;
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsText.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsText.java
new file mode 100644
index 0000000000..983c8b917a
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsText.java
@@ -0,0 +1,47 @@
+/*
+ * 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.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RangerAuditMetricsText {
+ Map metrics = new HashMap<>();
+
+ public Map getMetrics() {
+ return metrics;
+ }
+
+ public void setMetrics(Map metrics) {
+ this.metrics = metrics;
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ sb.append("metrics={").append(metrics).append("} ");
+ return sb;
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
index 3a3411d30d..feec4d6f26 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
@@ -404,6 +404,9 @@ public void init() {
AuditProviderFactory providerFactory = AuditProviderFactory.getInstance();
if (!providerFactory.isInitDone()) {
+ pluginConfig.set("ranger.plugin.serviceName", getServiceName());
+ pluginConfig.set("ranger.plugin.serviceType", getServiceType());
+ pluginConfig.set("ranger.plugin.appId", getAppId());
providerFactory.init(pluginConfig.getProperties(), getAppId());
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/AuditMetricsPredicateUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/AuditMetricsPredicateUtil.java
new file mode 100644
index 0000000000..8049ce36fd
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/AuditMetricsPredicateUtil.java
@@ -0,0 +1,219 @@
+/*
+ * 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.plugin.store;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByDays;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByHours;
+import org.apache.ranger.plugin.util.SearchFilter;
+
+import java.util.List;
+
+public class AuditMetricsPredicateUtil extends AbstractPredicateUtil {
+ public AuditMetricsPredicateUtil() {
+ super();
+ }
+
+ @Override
+ public void addPredicates(SearchFilter filter, List predicates) {
+ addPredicateForServiceType(filter.getParam(SearchFilter.SERVICE_TYPE), predicates);
+ addPredicateForServiceName(filter.getParam(SearchFilter.SERVICE_NAME), predicates);
+ addPredicateForAppId(filter.getParam(SearchFilter.APP_ID), predicates);
+ addPredicateForClusterName(filter.getParam(SearchFilter.CLUSTER_NAME), predicates);
+ addPredicateForClientIP(filter.getParam(SearchFilter.CLIENT_IP), predicates);
+ }
+
+ private Predicate addPredicateForServiceType(final String serviceType, List predicates) {
+ if (StringUtils.isEmpty(serviceType)) {
+ return null;
+ }
+
+ Predicate ret = new Predicate() {
+ @Override
+ public boolean evaluate(Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ boolean ret = false;
+
+ if (object instanceof RangerAuditMetrics) {
+ RangerAuditMetrics rangerAuditMetrics = (RangerAuditMetrics) object;
+ ret = StringUtils.equals(rangerAuditMetrics.getServiceType().toString(), serviceType);
+ } else if (object instanceof RangerAuditMetricsByHours) {
+ RangerAuditMetricsByHours rangerAuditMetricsByHours = (RangerAuditMetricsByHours) object;
+ ret = StringUtils.equals(rangerAuditMetricsByHours.getServiceType().toString(), serviceType);
+ } else if (object instanceof RangerAuditMetricsByDays) {
+ RangerAuditMetricsByDays rangerAuditMetricsByDays = (RangerAuditMetricsByDays) object;
+ ret = StringUtils.equals(rangerAuditMetricsByDays.getServiceType().toString(), serviceType);
+ }
+ return ret;
+ }
+ };
+
+ if (predicates != null) {
+ predicates.add(ret);
+ }
+
+ return ret;
+ }
+
+ private Predicate addPredicateForServiceName(final String serviceName, List predicates) {
+ if (StringUtils.isEmpty(serviceName)) {
+ return null;
+ }
+
+ Predicate ret = new Predicate() {
+ @Override
+ public boolean evaluate(Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ boolean ret = false;
+
+ if (object instanceof RangerAuditMetrics) {
+ RangerAuditMetrics rangerAuditMetrics = (RangerAuditMetrics) object;
+ ret = StringUtils.equals(rangerAuditMetrics.getServiceName(), serviceName);
+ } else if (object instanceof RangerAuditMetricsByHours) {
+ RangerAuditMetricsByHours rangerAuditMetricsByHours = (RangerAuditMetricsByHours) object;
+ ret = StringUtils.equals(rangerAuditMetricsByHours.getServiceName(), serviceName);
+ } else if (object instanceof RangerAuditMetricsByDays) {
+ RangerAuditMetricsByDays rangerAuditMetricsByDays = (RangerAuditMetricsByDays) object;
+ ret = StringUtils.equals(rangerAuditMetricsByDays.getServiceName(), serviceName);
+ }
+ return ret;
+ }
+ };
+
+ if (predicates != null) {
+ predicates.add(ret);
+ }
+
+ return ret;
+ }
+
+ private Predicate addPredicateForAppId(final String appId, List predicates) {
+ if (StringUtils.isEmpty(appId)) {
+ return null;
+ }
+
+ Predicate ret = new Predicate() {
+ @Override
+ public boolean evaluate(Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ boolean ret = false;
+
+ if (object instanceof RangerAuditMetrics) {
+ RangerAuditMetrics rangerAuditMetrics = (RangerAuditMetrics) object;
+ ret = StringUtils.equals(rangerAuditMetrics.getAppId(), appId);
+ } else if (object instanceof RangerAuditMetricsByHours) {
+ RangerAuditMetricsByHours rangerAuditMetricsByHours = (RangerAuditMetricsByHours) object;
+ ret = StringUtils.equals(rangerAuditMetricsByHours.getAppId(), appId);
+ } else if (object instanceof RangerAuditMetricsByDays) {
+ RangerAuditMetricsByDays rangerAuditMetricsByDays = (RangerAuditMetricsByDays) object;
+ ret = StringUtils.equals(rangerAuditMetricsByDays.getAppId(), appId);
+ }
+ return ret;
+ }
+ };
+
+ if (predicates != null) {
+ predicates.add(ret);
+ }
+
+ return ret;
+ }
+
+ private Predicate addPredicateForClusterName(final String clusterName, List predicates) {
+ if (StringUtils.isEmpty(clusterName)) {
+ return null;
+ }
+
+ Predicate ret = new Predicate() {
+ @Override
+ public boolean evaluate(Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ boolean ret = false;
+
+ if (object instanceof RangerAuditMetrics) {
+ RangerAuditMetrics rangerAuditMetrics = (RangerAuditMetrics) object;
+ ret = StringUtils.equals(rangerAuditMetrics.getClusterName(), clusterName);
+ } else if (object instanceof RangerAuditMetricsByHours) {
+ RangerAuditMetricsByHours rangerAuditMetricsByHours = (RangerAuditMetricsByHours) object;
+ ret = StringUtils.equals(rangerAuditMetricsByHours.getClusterName(), clusterName);
+ } else if (object instanceof RangerAuditMetricsByDays) {
+ RangerAuditMetricsByDays rangerAuditMetricsByDays = (RangerAuditMetricsByDays) object;
+ ret = StringUtils.equals(rangerAuditMetricsByDays.getClusterName(), clusterName);
+ }
+ return ret;
+ }
+ };
+
+ if (predicates != null) {
+ predicates.add(ret);
+ }
+
+ return ret;
+ }
+
+ private Predicate addPredicateForClientIP(final String clientIP, List predicates) {
+ if (StringUtils.isEmpty(clientIP)) {
+ return null;
+ }
+
+ Predicate ret = new Predicate() {
+ @Override
+ public boolean evaluate(Object object) {
+ if (object == null) {
+ return false;
+ }
+
+ boolean ret = false;
+
+ if (object instanceof RangerAuditMetrics) {
+ RangerAuditMetrics rangerAuditMetrics = (RangerAuditMetrics) object;
+ ret = StringUtils.equals(rangerAuditMetrics.getclientIP(), clientIP);
+ } else if (object instanceof RangerAuditMetricsByHours) {
+ RangerAuditMetricsByHours rangerAuditMetricsByHours = (RangerAuditMetricsByHours) object;
+ ret = StringUtils.equals(rangerAuditMetricsByHours.getClientIP(), clientIP);
+ } else if (object instanceof RangerAuditMetricsByDays) {
+ RangerAuditMetricsByDays rangerAuditMetricsByDays = (RangerAuditMetricsByDays) object;
+ ret = StringUtils.equals(rangerAuditMetricsByDays.getClientIP(), clientIP);
+ }
+ return ret;
+ }
+ };
+
+ if (predicates != null) {
+ predicates.add(ret);
+ }
+
+ return ret;
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/AuditMetricsStore.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/AuditMetricsStore.java
new file mode 100644
index 0000000000..1ea3a7c22c
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/AuditMetricsStore.java
@@ -0,0 +1,45 @@
+/*
+ * 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.plugin.store;
+
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByDays;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByHours;
+import org.apache.ranger.plugin.util.SearchFilter;
+
+import java.util.List;
+
+public interface AuditMetricsStore {
+ void init() throws Exception;
+
+ RangerAuditMetrics createRangerAuditMetrics(RangerAuditMetrics rangerAuditMetrics) throws RuntimeException;
+
+ RangerAuditMetrics getRangerAuditMetrics(Long id) throws RuntimeException;
+
+ RangerAuditMetrics getLatestRangerAuditMetrics(String serviceType, String serviceName) throws RuntimeException;
+
+ List getAllLatestRangerAuditMetrics(SearchFilter searchFilter) throws RuntimeException;
+
+ List getRangerAuditMetricsByHours(SearchFilter searchFilter) throws RuntimeException;
+
+ List getRangerAuditMetricsByDays(Integer olderThanInDays, SearchFilter searchFilter) throws RuntimeException;
+
+ void deleteRangerAuditMetrics(Integer olderThanInDays, String serviceName, String serviceType) throws RuntimeException;
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
index 9db01a3f59..472d1bbe48 100755
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
@@ -95,6 +95,10 @@ public class SearchFilter {
public static final String SERVICE_NAME_PARTIAL = "serviceNamePartial";
+ public static final String AUDIT_METRICS_ID = "auditMerticsId";
+ public static final String CLIENT_IP = "clientIP";
+ public static final String APP_ID = "appId";
+
public static final String PLUGIN_HOST_NAME = "pluginHostName";
public static final String PLUGIN_APP_TYPE = "pluginAppType";
public static final String PLUGIN_ENTITY_TYPE = "pluginEntityType";
diff --git a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
index 46f53a73b0..69cd169068 100644
--- a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
+++ b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
@@ -14,6 +14,9 @@
-- limitations under the License.
DROP VIEW IF EXISTS `vx_principal`;
+DROP VIEW IF EXISTS `vx_audit_metrics_by_hours`;
+DROP VIEW IF EXISTS `vx_audit_metrics_by_days`;
+DROP TABLE IF EXISTS `x_audit_metrics`;
DROP TABLE IF EXISTS `x_rms_mapping_provider`;
DROP TABLE IF EXISTS `x_rms_resource_mapping`;
DROP TABLE IF EXISTS `x_rms_notification`;
@@ -1516,6 +1519,32 @@ CREATE INDEX x_policy_label_label_id ON x_policy_label(id);
CREATE INDEX x_policy_label_label_name ON x_policy_label(label_name);
CREATE INDEX x_policy_label_label_map_id ON x_policy_label_map(id);
+CREATE TABLE IF NOT EXISTS `x_audit_metrics` (
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`service_type` bigint(20) NULL DEFAULT NULL,
+`service_name` varchar(255) NULL DEFAULT NULL,
+`app_id` varchar(255) NULL DEFAULT NULL,
+`cluster_name` varchar(255) NULL DEFAULT NULL,
+`client_ip` varchar(255) NULL DEFAULT NULL,
+`metrics_text` varchar(4000) NULL DEFAULT NULL,
+`throughput_unit` varchar(255) NULL DEFAULT NULL,
+`number_of_audits` bigint(20) NULL DEFAULT NULL,
+`version` bigint(20) NULL DEFAULT NULL,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_audit_metrics_FK_service_type` FOREIGN KEY (`service_type`) REFERENCES `x_service_def` (`id`),
+ CONSTRAINT `x_audit_metrics_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_audit_metrics_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`)
+) ROW_FORMAT=DYNAMIC;
+
+
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(HOUR from create_time) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where (cast(CREATE_TIME as date) = CURRENT_DATE) group by service_type, service_name, app_id, cluster_name, client_ip, hours ORDER BY hours;
+
+CREATE OR REPLACE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(DAY from create_time) as days, sum(number_of_audits) as numberOfAudits, cast(create_time as date) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, days, auditDate ORDER BY auditDate, days;
+
CREATE VIEW vx_principal as (SELECT u.user_name AS principal_name, 0 AS principal_type, u.status status, u.is_visible is_visible, u.other_attributes other_attributes, u.create_time create_time, u.update_time update_time, u.added_by_id added_by_id, u.upd_by_id upd_by_id FROM x_user u) UNION (SELECT g.group_name principal_name, 1 AS principal_type, g.status status, g.is_visible is_visible, g.other_attributes other_attributes, g.create_time create_time, g.update_time update_time, g.added_by_id added_by_id, g.upd_by_id upd_by_id FROM x_group g) UNION (SELECT r.name principal_name, 2 AS principal_name, 1 status, 1 is_visible, null other_attributes, r.create_time create_time, r.update_time update_time, r.added_by_id added_by_id, r.upd_by_id upd_by_id FROM x_role r);
DELIMITER $$
@@ -1940,6 +1969,8 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('058',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('059',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('060',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('063',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('064',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('065',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('066',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('067',UTC_TIMESTAMP(),'Ranger 3.0.0',UTC_TIMESTAMP(),'localhost','Y');
diff --git a/security-admin/db/mysql/patches/063-create-audit-metrics-schema.sql b/security-admin/db/mysql/patches/063-create-audit-metrics-schema.sql
new file mode 100644
index 0000000000..b8e9538394
--- /dev/null
+++ b/security-admin/db/mysql/patches/063-create-audit-metrics-schema.sql
@@ -0,0 +1,37 @@
+-- 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.
+
+DROP TABLE IF EXISTS `x_audit_metrics`;
+
+CREATE TABLE IF NOT EXISTS `x_audit_metrics` (
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`service_type` bigint(20) NULL DEFAULT NULL,
+`service_name` varchar(255) NULL DEFAULT NULL,
+`app_id` varchar(255) NULL DEFAULT NULL,
+`cluster_name` varchar(255) NULL DEFAULT NULL,
+`client_ip` varchar(255) NULL DEFAULT NULL,
+`metrics_text` varchar(4000) NULL DEFAULT NULL,
+`throughput_unit` varchar(255) NULL DEFAULT NULL,
+`number_of_audits` bigint(20) NULL DEFAULT NULL,
+`version` bigint(20) NULL DEFAULT NULL,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_audit_metrics_FK_service_type` FOREIGN KEY (`service_type`) REFERENCES `x_service_def` (`id`),
+ CONSTRAINT `x_audit_metrics_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_audit_metrics_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`)
+) ROW_FORMAT=DYNAMIC;
diff --git a/security-admin/db/mysql/patches/064-create-view-for-audit-metrics-graph.sql b/security-admin/db/mysql/patches/064-create-view-for-audit-metrics-graph.sql
new file mode 100644
index 0000000000..ac07486c82
--- /dev/null
+++ b/security-admin/db/mysql/patches/064-create-view-for-audit-metrics-graph.sql
@@ -0,0 +1,45 @@
+-- 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.
+
+
+DROP VIEW IF EXISTS vx_audit_metrics_by_hours;
+DROP VIEW IF EXISTS vx_audit_metrics_by_days;
+
+CREATE VIEW vx_audit_metrics_by_hours AS select
+ service_type,
+ service_name,
+ app_id,
+ cluster_name,
+ client_ip,
+ EXTRACT(HOUR from create_time) as hours,
+ sum(number_of_audits) as numberOfAudits
+ from x_audit_metrics
+ where (cast(CREATE_TIME as date) = CURRENT_DATE)
+ group by service_type, service_name, app_id, cluster_name, client_ip, hours
+ ORDER BY hours;
+
+CREATE OR REPLACE VIEW vx_audit_metrics_by_days AS
+ select
+ service_type,
+ service_name,
+ app_id,
+ cluster_name,
+ client_ip,
+ EXTRACT(DAY from create_time) as days,
+ sum(number_of_audits) as numberOfAudits,
+ cast(create_time as date) as auditDate
+ from x_audit_metrics
+ group by service_type, service_name, app_id, cluster_name, client_ip, days, auditDate
+ ORDER BY auditDate, days;
diff --git a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
index 006c047881..cee33caf0c 100644
--- a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
+++ b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
@@ -112,6 +112,7 @@ call spdropsequence('X_GDS_DATASET_POLICY_MAP_SEQ');
call spdropsequence('X_GDS_PROJECT_POLICY_MAP_SEQ');
CREATE SEQUENCE SEQ_GEN_IDENTITY START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_AUDIT_METRICS_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
CREATE SEQUENCE X_ACCESS_AUDIT_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
CREATE SEQUENCE X_ASSET_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
CREATE SEQUENCE X_AUDIT_MAP_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
@@ -223,6 +224,9 @@ BEGIN
END;/
/
+call spdropview('vx_audit_metrics_by_hours');
+call spdropview('vx_audit_metrics_by_days');
+call spdroptable('x_audit_metrics');
call spdroptable('X_RMS_MAPPING_PROVIDER');
call spdroptable('X_RMS_RESOURCE_MAPPING');
call spdroptable('X_RMS_NOTIFICATION');
@@ -2044,6 +2048,34 @@ CREATE TABLE x_gds_project_policy_map (
CREATE INDEX x_gds_ppm_project_id ON x_gds_project_policy_map(project_id);
CREATE INDEX x_gds_ppm_policy_id ON x_gds_project_policy_map(policy_id);
+CREATE TABLE x_audit_metrics(
+id NUMBER(20) NOT NULL,
+service_type NUMBER(20) DEFAULT NULL NULL,
+service_name varchar(255) DEFAULT NULL NULL,
+app_id varchar(255) DEFAULT NULL NULL,
+cluster_name varchar(255) DEFAULT NULL NULL,
+client_ip varchar(255) DEFAULT NULL NULL,
+metrics_text varchar(4000) DEFAULT NULL NULL,
+throughput_unit varchar(255) DEFAULT NULL NULL,
+number_of_audits NUMBER(20) DEFAULT NULL NULL,
+version NUMBER(20) DEFAULT NULL NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+PRIMARY KEY (id),
+CONSTRAINT x_audit_metrics_FK_service_type FOREIGN KEY (service_type) REFERENCES x_service_def (id),
+CONSTRAINT x_audit_metrics_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+CONSTRAINT x_audit_metrics_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
+
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(HOUR from CAST(create_time AS TIMESTAMP)) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where CREATE_TIME >= TRUNC(CURRENT_DATE) group by service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(HOUR from CAST(create_time AS TIMESTAMP)) ORDER BY hours;
+commit;
+
+CREATE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(DAY from CAST(create_time AS TIMESTAMP)) AS days, sum(number_of_audits) as numberOfAudits, trunc(create_time) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(DAY from CAST(create_time AS TIMESTAMP)), trunc(create_time) ORDER BY auditDate, days;
+commit;
+
CREATE VIEW vx_principal as
(SELECT u.user_name AS principal_name, 0 AS principal_type, u.status AS status, u.is_visible AS is_visible, u.other_attributes AS other_attributes, u.create_time AS create_time, u.update_time AS update_time, u.added_by_id AS added_by_id, u.upd_by_id AS upd_by_id FROM x_user u) UNION ALL
(SELECT g.group_name AS principal_name, 1 AS principal_type, g.status AS status, g.is_visible AS is_visible, g.other_attributes AS other_attributes, g.create_time AS create_time, g.update_time AS update_time, g.added_by_id AS added_by_id, g.upd_by_id AS upd_by_id FROM x_group g) UNION ALL
@@ -2132,6 +2164,8 @@ INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,act
INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '058',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '059',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '060',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
+INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '063',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
+INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '064',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '065',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '066',sys_extract_utc(systimestamp),'Ranger 3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '067',sys_extract_utc(systimestamp),'Ranger 3.0.0',sys_extract_utc(systimestamp),'localhost','Y');
diff --git a/security-admin/db/oracle/patches/063-create-audit-metrics-schema.sql b/security-admin/db/oracle/patches/063-create-audit-metrics-schema.sql
new file mode 100644
index 0000000000..8a20285355
--- /dev/null
+++ b/security-admin/db/oracle/patches/063-create-audit-metrics-schema.sql
@@ -0,0 +1,67 @@
+-- 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.
+
+
+CREATE OR REPLACE PROCEDURE spdropsequence(ObjName IN varchar2)
+IS
+v_counter integer;
+BEGIN
+ select count(*) into v_counter from user_sequences where sequence_name = upper(ObjName);
+ if (v_counter > 0) then
+ execute immediate 'DROP SEQUENCE ' || ObjName;
+ end if;
+END;/
+/
+
+CREATE OR REPLACE PROCEDURE spdroptable(ObjName IN varchar2)
+IS
+v_counter integer;
+BEGIN
+ select count(*) into v_counter from user_tables where table_name = upper(ObjName);
+ if (v_counter > 0) then
+ execute immediate 'drop table ' || ObjName || ' cascade constraints';
+ end if;
+END;/
+/
+
+
+call spdropsequence('X_AUDIT_METRICS_SEQ');
+
+CREATE SEQUENCE X_AUDIT_METRICS_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+
+call spdroptable('x_audit_metrics');
+commit;
+
+CREATE TABLE x_audit_metrics(
+id NUMBER(20) NOT NULL,
+service_type NUMBER(20) DEFAULT NULL NULL,
+service_name varchar(255) DEFAULT NULL NULL,
+app_id varchar(255) DEFAULT NULL NULL,
+cluster_name varchar(255) DEFAULT NULL NULL,
+client_ip varchar(255) DEFAULT NULL NULL,
+metrics_text varchar(4000) DEFAULT NULL NULL,
+throughput_unit varchar(255) DEFAULT NULL NULL,
+number_of_audits NUMBER(20) DEFAULT NULL NULL,
+version NUMBER(20) DEFAULT NULL NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+PRIMARY KEY (id),
+CONSTRAINT x_audit_metrics_FK_service_type FOREIGN KEY (service_type) REFERENCES x_service_def (id),
+CONSTRAINT x_audit_metrics_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+CONSTRAINT x_audit_metrics_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
diff --git a/security-admin/db/oracle/patches/064-create-view-for-audit-metrics-graph.sql b/security-admin/db/oracle/patches/064-create-view-for-audit-metrics-graph.sql
new file mode 100644
index 0000000000..78236c4530
--- /dev/null
+++ b/security-admin/db/oracle/patches/064-create-view-for-audit-metrics-graph.sql
@@ -0,0 +1,59 @@
+-- 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.
+
+
+CREATE OR REPLACE PROCEDURE spdropview(ObjName IN varchar2)
+IS
+v_counter integer;
+BEGIN
+ select count(*) into v_counter from User_Views where VIEW_NAME = upper(ObjName);
+ if (v_counter > 0) then
+ execute immediate 'DROP VIEW ' || ObjName;
+ end if;
+END;/
+/
+
+call spdropview('vx_audit_metrics_by_hours');
+call spdropview('vx_audit_metrics_by_days');
+commit;
+
+CREATE VIEW vx_audit_metrics_by_hours AS
+ select
+ service_type,
+ service_name,
+ app_id,
+ cluster_name,
+ client_ip,
+ EXTRACT(HOUR from CAST(create_time AS TIMESTAMP)) as hours,
+ sum(number_of_audits) as numberOfAudits
+ from x_audit_metrics
+ where CREATE_TIME >= TRUNC(CURRENT_DATE)
+ group by service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(HOUR from CAST(create_time AS TIMESTAMP))
+ ORDER BY hours;
+
+CREATE VIEW vx_audit_metrics_by_days AS
+ select
+ service_type,
+ service_name,
+ app_id,
+ cluster_name,
+ client_ip,
+ EXTRACT(DAY from CAST(create_time AS TIMESTAMP)) AS days,
+ sum(number_of_audits) as numberOfAudits,
+ trunc(create_time) as auditDate
+ from x_audit_metrics
+ group by service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(DAY from CAST(create_time AS TIMESTAMP)), trunc(create_time)
+ ORDER BY auditDate, days;
+commit;
diff --git a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
index 8aa20a8dde..0dafd49bb6 100644
--- a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
+++ b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
@@ -98,6 +98,7 @@ DROP TABLE IF EXISTS x_gds_data_share CASCADE;
DROP TABLE IF EXISTS x_gds_shared_resource CASCADE;
DROP TABLE IF EXISTS x_gds_data_share_in_dataset CASCADE;
DROP TABLE IF EXISTS x_gds_dataset_in_project CASCADE;
+DROP TABLE IF EXISTS x_audit_metrics CASCADE;
DROP SEQUENCE IF EXISTS x_sec_zone_ref_group_seq;
DROP SEQUENCE IF EXISTS x_sec_zone_ref_user_seq;
@@ -180,6 +181,7 @@ DROP SEQUENCE IF EXISTS X_GDS_DATA_SHARE_SEQ;
DROP SEQUENCE IF EXISTS X_GDS_SHARED_RESOURCE_SEQ;
DROP SEQUENCE IF EXISTS X_GDS_DATA_SHARE_IN_DATASET_SEQ;
DROP SEQUENCE IF EXISTS X_GDS_DATASET_IN_PROJECT_SEQ;
+DROP SEQUENCE IF EXISTS x_audit_metrics_seq;
create table x_db_version_h(
id SERIAL primary key,
@@ -1801,6 +1803,28 @@ CREATE INDEX x_gds_ppm_project_id ON x_gds_project_policy_map(project_id);
CREATE INDEX x_gds_ppm_policy_id ON x_gds_project_policy_map(policy_id);
commit;
+CREATE SEQUENCE x_audit_metrics_seq;
+CREATE TABLE x_audit_metrics(
+id BIGINT DEFAULT nextval('x_audit_metrics_seq'::regclass),
+service_type BIGINT DEFAULT NULL NULL,
+service_name varchar(255) DEFAULT NULL NULL,
+app_id varchar(255) DEFAULT NULL NULL,
+cluster_name varchar(255) DEFAULT NULL NULL,
+client_ip varchar(255) DEFAULT NULL NULL,
+metrics_text varchar(4000) DEFAULT NULL NULL,
+throughput_unit varchar(255) DEFAULT NULL NULL,
+number_of_audits BIGINT DEFAULT '0' NULL,
+version BIGINT DEFAULT '0' NOT NULL,
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_audit_metrics_FK_service_type FOREIGN KEY (service_type) REFERENCES x_service_def (id),
+ CONSTRAINT x_audit_metrics_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_audit_metrics_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
CREATE INDEX x_tag_change_log_IDX_service_id ON x_tag_change_log(service_id);
CREATE INDEX x_tag_change_log_IDX_tag_version ON x_tag_change_log(service_tags_version);
@@ -2046,6 +2070,8 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('058',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('059',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('060',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('063',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('064',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('065',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('066',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('067',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
@@ -2163,5 +2189,13 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('J10064',current_timestamp,'Ranger 3.0.0',current_timestamp,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('JAVA_PATCHES',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
+DROP VIEW IF EXISTS vx_audit_metrics_by_hours;
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(HOUR from create_time) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where (cast(CREATE_TIME as date) = CURRENT_DATE) group by service_type, service_name, app_id, cluster_name, client_ip, hours ORDER BY hours;
+commit;
+
+DROP VIEW IF EXISTS vx_audit_metrics_by_days;
+CREATE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, EXTRACT(DAY from create_time) as days, sum(number_of_audits) as numberOfAudits, cast(create_time as date) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, days, auditDate ORDER BY auditDate, days;
+commit;
+
DROP VIEW IF EXISTS vx_principal;
CREATE VIEW vx_principal as (SELECT u.user_name AS principal_name, 0 AS principal_type, u.status status, u.is_visible is_visible, u.other_attributes other_attributes, u.create_time create_time, u.update_time update_time, u.added_by_id added_by_id, u.upd_by_id upd_by_id FROM x_user u) UNION (SELECT g.group_name principal_name, 1 AS principal_type, g.status status, g.is_visible is_visible, g.other_attributes other_attributes, g.create_time create_time, g.update_time update_time, g.added_by_id added_by_id, g.upd_by_id upd_by_id FROM x_group g) UNION (SELECT r.name principal_name, 2 AS principal_name, 1 status, 1 is_visible, null other_attributes, r.create_time create_time, r.update_time update_time, r.added_by_id added_by_id, r.upd_by_id upd_by_id FROM x_role r);
diff --git a/security-admin/db/postgres/patches/063-create-audit-metrics-schema.sql b/security-admin/db/postgres/patches/063-create-audit-metrics-schema.sql
new file mode 100644
index 0000000000..3c7e764000
--- /dev/null
+++ b/security-admin/db/postgres/patches/063-create-audit-metrics-schema.sql
@@ -0,0 +1,41 @@
+-- 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.
+
+
+DROP TABLE IF EXISTS x_audit_metrics CASCADE;
+DROP SEQUENCE IF EXISTS x_audit_metrics_seq;
+
+CREATE SEQUENCE x_audit_metrics_seq;
+CREATE TABLE x_audit_metrics(
+id BIGINT DEFAULT nextval('x_audit_metrics_seq'::regclass),
+service_type BIGINT DEFAULT NULL NULL,
+service_name varchar(255) DEFAULT NULL NULL,
+app_id varchar(255) DEFAULT NULL NULL,
+cluster_name varchar(255) DEFAULT NULL NULL,
+client_ip varchar(255) DEFAULT NULL NULL,
+metrics_text varchar(4000) DEFAULT NULL NULL,
+throughput_unit varchar(255) DEFAULT NULL NULL,
+number_of_audits BIGINT DEFAULT '0' NULL,
+version BIGINT DEFAULT '0' NOT NULL,
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_audit_metrics_FK_service_type FOREIGN KEY (service_type) REFERENCES x_service_def (id),
+ CONSTRAINT x_audit_metrics_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_audit_metrics_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
\ No newline at end of file
diff --git a/security-admin/db/postgres/patches/064-create-view-for-audit-metrics-graph.sql b/security-admin/db/postgres/patches/064-create-view-for-audit-metrics-graph.sql
new file mode 100644
index 0000000000..c704f55094
--- /dev/null
+++ b/security-admin/db/postgres/patches/064-create-view-for-audit-metrics-graph.sql
@@ -0,0 +1,48 @@
+-- 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.
+
+
+DROP VIEW IF EXISTS vx_audit_metrics_by_hours;
+CREATE VIEW vx_audit_metrics_by_hours AS select
+ service_type,
+ service_name,
+ app_id,
+ cluster_name,
+ client_ip,
+ EXTRACT(HOUR from create_time) as hours,
+ sum(number_of_audits) as numberOfAudits
+ from x_audit_metrics
+ where
+ (cast(CREATE_TIME as date) = CURRENT_DATE)
+ group by service_type, service_name, app_id, cluster_name, client_ip, hours
+ ORDER BY hours
+;
+commit;
+
+DROP VIEW IF EXISTS vx_audit_metrics_by_days;
+CREATE OR REPLACE VIEW vx_audit_metrics_by_days AS
+ select
+ service_type,
+ service_name,
+ app_id,
+ cluster_name,
+ client_ip,
+ EXTRACT(DAY from create_time) as days,
+ sum(number_of_audits) as numberOfAudits,
+ cast(create_time as date) as auditDate
+ from x_audit_metrics
+ group by service_type, service_name, app_id, cluster_name, client_ip, days, auditDate
+ ORDER BY auditDate, days;
+commit;
\ No newline at end of file
diff --git a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
index df950c85ce..c26a7d289f 100644
--- a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
+++ b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
@@ -35,6 +35,12 @@ BEGIN
execute(@drpstmt)
END
+GO
+DROP VIEW IF EXISTS dbo.vx_audit_metrics_by_hours
+GO
+DROP VIEW IF EXISTS dbo.vx_audit_metrics_by_days
+GO
+call dbo.removeForeignKeysAndTable('x_audit_metrics')
GO
call dbo.removeForeignKeysAndTable('x_rms_mapping_provider')
GO
@@ -2092,6 +2098,35 @@ CONSTRAINT x_rms_mapping_provider_UK_name UNIQUE(name)
);
GO
+CREATE TABLE dbo.x_audit_metrics(
+id bigint IDENTITY NOT NULL,
+service_type bigint DEFAULT NULL NULL,
+service_name varchar(255) DEFAULT NULL NULL,
+app_id varchar(255) DEFAULT NULL NULL,
+cluster_name varchar(255) DEFAULT NULL NULL,
+client_ip varchar(255) DEFAULT NULL NULL,
+metrics_text varchar(4000) DEFAULT NULL NULL,
+throughput_unit varchar(255) DEFAULT NULL NULL,
+number_of_audits bigint DEFAULT 0 NOT NULL,
+version bigint DEFAULT 0 NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+CONSTRAINT x_x_audit_metrics_PK_id PRIMARY KEY CLUSTERED(id),
+)
+GO
+ALTER TABLE dbo.x_audit_metrics ADD CONSTRAINT x_audit_metrics_FK_service_type FOREIGN KEY(service_type) REFERENCES dbo.x_service_def (id)
+GO
+ALTER TABLE dbo.x_audit_metrics ADD CONSTRAINT x_audit_metrics_FK_added_by_id FOREIGN KEY(added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_audit_metrics ADD CONSTRAINT x_audit_metrics_FK_upd_by_id FOREIGN KEY(upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, HOUR(create_time) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where (cast(CREATE_TIME as date) = CURRENT_DATE) group by service_type, service_name, app_id, cluster_name, client_ip, hours ORDER BY hours;
+GO
+CREATE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, DAY(create_time) as days, sum(number_of_audits) as numberOfAudits, cast(create_time as date) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, days, auditDate ORDER BY auditDate, days;
+GO
+
insert into x_portal_user (create_time,update_time,first_name,last_name,pub_scr_name,login_id,password,email,status) values (GETDATE(),GETDATE(),'Admin','','Admin','admin','ceb4f32325eda6142bd65215f4c0f371','',1)
GO
insert into x_portal_user_role (create_time,update_time,user_id,user_role,status) values (GETDATE(),GETDATE(),dbo.getXportalUIdByLoginId('admin'),'ROLE_SYS_ADMIN',1)
@@ -2222,6 +2257,10 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
GO
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('060',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('063',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+GO
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('064',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+GO
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('065',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('066',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
diff --git a/security-admin/db/sqlanywhere/patches/063-create-x-audit-metrics-schema.sql b/security-admin/db/sqlanywhere/patches/063-create-x-audit-metrics-schema.sql
new file mode 100644
index 0000000000..23714b3a65
--- /dev/null
+++ b/security-admin/db/sqlanywhere/patches/063-create-x-audit-metrics-schema.sql
@@ -0,0 +1,66 @@
+-- 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.
+
+
+CREATE OR REPLACE PROCEDURE dbo.removeForeignKeysAndTable (IN table_name varchar(100))
+AS
+BEGIN
+ DECLARE @stmt VARCHAR(300)
+ DECLARE @tblname VARCHAR(300)
+ DECLARE @drpstmt VARCHAR(1000)
+ DECLARE cur CURSOR FOR select 'alter table dbo.' + table_name + ' drop constraint ' + role from SYS.SYSFOREIGNKEYS where foreign_creator ='dbo' and foreign_tname = table_name
+ OPEN cur WITH HOLD
+ fetch cur into @stmt
+ WHILE (@@sqlstatus = 0)
+ BEGIN
+ execute(@stmt)
+ fetch cur into @stmt
+ END
+ close cur
+ DEALLOCATE CURSOR cur
+ SET @tblname ='dbo.' + table_name;
+ SET @drpstmt = 'DROP TABLE IF EXISTS ' + @tblname;
+ execute(@drpstmt)
+END
+GO
+
+call dbo.removeForeignKeysAndTable('x_audit_metrics')
+GO
+
+CREATE TABLE dbo.x_audit_metrics(
+id bigint IDENTITY NOT NULL,
+service_type bigint DEFAULT NULL NULL,
+service_name varchar(255) DEFAULT NULL NULL,
+app_id varchar(255) DEFAULT NULL NULL,
+cluster_name varchar(255) DEFAULT NULL NULL,
+client_ip varchar(255) DEFAULT NULL NULL,
+metrics_text varchar(4000) DEFAULT NULL NULL,
+throughput_unit varchar(255) DEFAULT NULL NULL,
+number_of_audits bigint DEFAULT 0 NOT NULL,
+version bigint DEFAULT 0 NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+CONSTRAINT x_x_audit_metrics_PK_id PRIMARY KEY CLUSTERED(id),
+)
+GO
+ALTER TABLE dbo.x_audit_metrics ADD CONSTRAINT x_audit_metrics_FK_service_type FOREIGN KEY(service_type) REFERENCES dbo.x_service_def (id)
+GO
+ALTER TABLE dbo.x_audit_metrics ADD CONSTRAINT x_audit_metrics_FK_added_by_id FOREIGN KEY(added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_audit_metrics ADD CONSTRAINT x_audit_metrics_FK_upd_by_id FOREIGN KEY(upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+exit
\ No newline at end of file
diff --git a/security-admin/db/sqlanywhere/patches/064-create-view-for-audit-metrics-graph.sql b/security-admin/db/sqlanywhere/patches/064-create-view-for-audit-metrics-graph.sql
new file mode 100644
index 0000000000..dfe7c022fb
--- /dev/null
+++ b/security-admin/db/sqlanywhere/patches/064-create-view-for-audit-metrics-graph.sql
@@ -0,0 +1,24 @@
+-- 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.
+
+DROP VIEW IF EXISTS dbo.vx_audit_metrics_by_hours
+GO
+DROP VIEW IF EXISTS dbo.vx_audit_metrics_by_days
+GO
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, HOUR(create_time) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where (cast(CREATE_TIME as date) = CURRENT_DATE) group by service_type, service_name, app_id, cluster_name, client_ip, hours ORDER BY hours;
+GO
+CREATE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, DAY(create_time) as days, sum(number_of_audits) as numberOfAudits, cast(create_time as date) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, days, auditDate ORDER BY auditDate, days;
+GO
+exit
\ No newline at end of file
diff --git a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
index 315a3bc50a..488ee7d249 100644
--- a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
+++ b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
@@ -726,6 +726,31 @@ IF (OBJECT_ID('x_gds_ppm_FK_policy_id') IS NOT NULL)
BEGIN
ALTER TABLE [dbo].[x_gds_project_policy_map] DROP CONSTRAINT x_gds_ppm_FK_policy_id
END
+IF (OBJECT_ID('x_audit_metrics_FK_service_type') IS NOT NULL)
+BEGIN
+ ALTER TABLE [dbo].[x_audit_metrics] DROP CONSTRAINT x_audit_metrics_FK_service_type
+END
+IF (OBJECT_ID('x_audit_metrics_FK_added_by_id') IS NOT NULL)
+BEGIN
+ ALTER TABLE [dbo].[x_audit_metrics] DROP CONSTRAINT x_audit_metrics_FK_added_by_id
+END
+IF (OBJECT_ID('x_audit_metrics_FK_upd_by_id') IS NOT NULL)
+BEGIN
+ ALTER TABLE [dbo].[x_audit_metrics] DROP CONSTRAINT x_audit_metrics_FK_upd_by_id
+END
+IF (OBJECT_ID('vx_audit_metrics_by_hours') IS NOT NULL)
+BEGIN
+ DROP VIEW [dbo].[vx_audit_metrics_by_hours]
+END
+IF (OBJECT_ID('vx_audit_metrics_by_days') IS NOT NULL)
+BEGIN
+ DROP VIEW [dbo].[vx_audit_metrics_by_days]
+END
+
+IF (OBJECT_ID('x_audit_metrics') IS NOT NULL)
+BEGIN
+ DROP TABLE [dbo].[x_audit_metrics]
+END
IF (OBJECT_ID('x_rms_mapping_provider') IS NOT NULL)
BEGIN
DROP TABLE [dbo].[x_rms_mapping_provider]
@@ -4435,6 +4460,36 @@ CREATE NONCLUSTERED INDEX [x_gds_ppm_policy_id] ON [x_gds_project_policy_map]
WITH (SORT_IN_TEMPDB = OFF,DROP_EXISTING = OFF,IGNORE_DUP_KEY = OFF,ONLINE = OFF) ON [PRIMARY]
GO
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_audit_metrics](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[service_type] [bigint] DEFAULT NULL NULL,
+[service_name] [nvarchar](255) DEFAULT NULL NULL,
+[app_id] [nvarchar](255) DEFAULT NULL NULL,
+[cluster_name] [nvarchar](255) DEFAULT NULL NULL,
+[client_ip] [nvarchar](255) DEFAULT NULL NULL,
+[metrics_text] [nvarchar](4000) DEFAULT NULL NULL,
+[throughput_unit] [nvarchar](255) DEFAULT NULL NULL,
+[number_of_audits] bigint DEFAULT NULL NULL,
+[version] [bigint] DEFAULT NULL NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+ PRIMARY KEY CLUSTERED
+(
+ [id] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY])
+GO
+ALTER TABLE [dbo].[x_audit_metrics] WITH CHECK ADD CONSTRAINT [x_audit_metrics_FK_service_type] FOREIGN KEY([service_type]) REFERENCES [dbo].[x_service_def] ([id])
+GO
+ALTER TABLE [dbo].[x_audit_metrics] WITH CHECK ADD CONSTRAINT [x_audit_metrics_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_audit_metrics] WITH CHECK ADD CONSTRAINT [x_audit_metrics_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+
insert into x_portal_user (CREATE_TIME,UPDATE_TIME,FIRST_NAME,LAST_NAME,PUB_SCR_NAME,LOGIN_ID,PASSWORD,EMAIL,STATUS) values (CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'Admin','','Admin','admin','ceb4f32325eda6142bd65215f4c0f371','',1);
insert into x_portal_user_role (CREATE_TIME,UPDATE_TIME,USER_ID,USER_ROLE,STATUS) values (CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,dbo.getXportalUIdByLoginId('admin'),'ROLE_SYS_ADMIN',1);
insert into x_user (CREATE_TIME,UPDATE_TIME,user_name,status,descr) values (CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'admin',0,'Administrator');
@@ -4502,6 +4557,8 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('058',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('059',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('060',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('063',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('064',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('065',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('066',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('067',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
@@ -4596,3 +4653,7 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('J10064',CURRENT_TIMESTAMP,'Ranger 3.0.0',CURRENT_TIMESTAMP,'localhost','Y');
INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('JAVA_PATCHES',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
GO
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, DATEPART(HOUR,create_time) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where (cast(CREATE_TIME as date) = CAST( GETDATE() AS Date )) group by service_type, service_name, app_id, cluster_name, client_ip, DATEPART(HOUR,create_time) ;
+GO
+CREATE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, DAY(create_time) as days, sum(number_of_audits) as numberOfAudits, cast(create_time as date) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, DAY(create_time), cast(create_time as date) ;
+GO
diff --git a/security-admin/db/sqlserver/patches/063-create-x-audit-metrics-schema.sql b/security-admin/db/sqlserver/patches/063-create-x-audit-metrics-schema.sql
new file mode 100644
index 0000000000..596686951e
--- /dev/null
+++ b/security-admin/db/sqlserver/patches/063-create-x-audit-metrics-schema.sql
@@ -0,0 +1,52 @@
+-- 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.
+
+GO
+IF (OBJECT_ID('x_audit_metrics') IS NOT NULL)
+BEGIN
+ DROP TABLE [dbo].[x_audit_metrics]
+END
+
+GO
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_audit_metrics](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[service_type] [bigint] DEFAULT NULL NULL,
+[service_name] [nvarchar](255) DEFAULT NULL NULL,
+[app_id] [nvarchar](255) DEFAULT NULL NULL,
+[cluster_name] [nvarchar](255) DEFAULT NULL NULL,
+[client_ip] [nvarchar](255) DEFAULT NULL NULL,
+[metrics_text] [nvarchar](4000) DEFAULT NULL NULL,
+[throughput_unit] [nvarchar](255) DEFAULT NULL NULL,
+[number_of_audits] bigint DEFAULT NULL NULL,
+[version] [bigint] DEFAULT NULL NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+ PRIMARY KEY CLUSTERED
+(
+ [id] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY])
+GO
+ALTER TABLE [dbo].[x_audit_metrics] WITH CHECK ADD CONSTRAINT [x_audit_metrics_FK_service_type] FOREIGN KEY([service_type]) REFERENCES [dbo].[x_service_def] ([id])
+GO
+ALTER TABLE [dbo].[x_audit_metrics] WITH CHECK ADD CONSTRAINT [x_audit_metrics_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_audit_metrics] WITH CHECK ADD CONSTRAINT [x_audit_metrics_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+exit
\ No newline at end of file
diff --git a/security-admin/db/sqlserver/patches/064-create-view-for-audit-metrics-graph.sql b/security-admin/db/sqlserver/patches/064-create-view-for-audit-metrics-graph.sql
new file mode 100644
index 0000000000..1ee9ee0f22
--- /dev/null
+++ b/security-admin/db/sqlserver/patches/064-create-view-for-audit-metrics-graph.sql
@@ -0,0 +1,30 @@
+-- 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.
+
+GO
+IF (OBJECT_ID('vx_audit_metrics_by_hours') IS NOT NULL)
+BEGIN
+ DROP VIEW [dbo].[vx_audit_metrics_by_hours]
+END
+IF (OBJECT_ID('vx_audit_metrics_by_days') IS NOT NULL)
+BEGIN
+ DROP VIEW [dbo].[vx_audit_metrics_by_days]
+END
+
+GO
+CREATE VIEW vx_audit_metrics_by_hours AS select service_type, service_name, app_id, cluster_name, client_ip, DATEPART(HOUR,create_time) as hours, sum(number_of_audits) as numberOfAudits from x_audit_metrics where (cast(CREATE_TIME as date) = CAST( GETDATE() AS Date )) group by service_type, service_name, app_id, cluster_name, client_ip, DATEPART(HOUR,create_time) ;
+GO
+CREATE VIEW vx_audit_metrics_by_days AS select service_type, service_name, app_id, cluster_name, client_ip, DAY(create_time) as days, sum(number_of_audits) as numberOfAudits, cast(create_time as date) as auditDate from x_audit_metrics group by service_type, service_name, app_id, cluster_name, client_ip, DAY(create_time), cast(create_time as date) ;
+GO
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/AuditMetricsDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/AuditMetricsDBStore.java
new file mode 100644
index 0000000000..e61bb7f141
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/biz/AuditMetricsDBStore.java
@@ -0,0 +1,283 @@
+/*
+ * 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 org.apache.commons.collections.CollectionUtils;
+import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig;
+import org.apache.ranger.common.MessageEnums;
+import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXAuditMetrics;
+import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByDays;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByHours;
+import org.apache.ranger.plugin.store.AbstractPredicateUtil;
+import org.apache.ranger.plugin.store.AuditMetricsPredicateUtil;
+import org.apache.ranger.plugin.store.AuditMetricsStore;
+import org.apache.ranger.plugin.util.SearchFilter;
+import org.apache.ranger.service.RangerAuditMetricsService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Component
+public class AuditMetricsDBStore implements AuditMetricsStore {
+ private static final Logger LOG = LoggerFactory.getLogger(AuditMetricsDBStore.class);
+
+ private static final String PROP_AUDIT_METRICS_RETENTION_PERIOD_IN_DAYS = "ranger.audit.metrics.retention.period";
+ private static final Integer PROP_AUDIT_METRICS_RETENTION_PERIOD_IN_DAYS_DEFAULT = 7;
+ private static final String PROP_AUDIT_METRICS_MAX_SUPPORTED_DAYS = "ranger.audit.metrics.max.supported.days";
+ private static final Integer PROP_AUDIT_METRICS_MAX_SUPPORTED_DAYS_DEFAULT = 90;
+
+ @Autowired
+ RangerAuditMetricsService rangerAuditMetricsService;
+
+ @Autowired
+ RangerDaoManager daoMgr;
+
+ @Autowired
+ RESTErrorUtil restErrorUtil;
+
+ RangerAdminConfig config;
+ AbstractPredicateUtil predicateUtil;
+ private final Boolean populateExistingBaseFields = true;
+
+ public void init() throws Exception {}
+
+ @Override
+ public RangerAuditMetrics createRangerAuditMetrics(RangerAuditMetrics rangerAuditMetrics) throws RuntimeException {
+ LOG.debug("==> AuditMetricsDBStore.createRangerAuditMetrics()");
+ //Delete older Ranger Audit metrics if any present.
+ String serviceName = rangerAuditMetrics.getServiceName();
+ String serviceType = rangerAuditMetrics.getServiceType();
+
+ Integer retentionPeriod = config.getInt(PROP_AUDIT_METRICS_RETENTION_PERIOD_IN_DAYS, PROP_AUDIT_METRICS_RETENTION_PERIOD_IN_DAYS_DEFAULT);
+ if (auditMetricsExistsForDeletion(retentionPeriod, serviceName, serviceType)) {
+ deleteRangerAuditMetrics(retentionPeriod, serviceName, serviceType);
+ }
+
+ //Create new audit metrics
+ RangerAuditMetrics ret = rangerAuditMetricsService.create(rangerAuditMetrics);
+
+ LOG.debug("<== AuditMetricsDBStore.createRangerAuditMetrics() {}", ret);
+
+ return ret;
+ }
+
+ @Override
+ public RangerAuditMetrics getRangerAuditMetrics(Long id) throws RuntimeException {
+ XXAuditMetrics xxAuditMetrics = daoMgr.getXXAuditMetricsDao().findById(id);
+ if (xxAuditMetrics == null) {
+ throw restErrorUtil.createRESTException("AuditMetrics with Id: " + id + " does not exist");
+ }
+ return rangerAuditMetricsService.read(xxAuditMetrics.getId());
+ }
+
+ @Override
+ public RangerAuditMetrics getLatestRangerAuditMetrics(String serviceType, String serviceName) throws RuntimeException {
+ XXServiceDef xxServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
+ if (xxServiceDef == null) {
+ throw restErrorUtil.createRESTException("No ServiceDefinition found with Service Type :" + serviceType, MessageEnums.INVALID_INPUT_DATA);
+ }
+ Long svcType = xxServiceDef.getId();
+ XXAuditMetrics xxAuditMetrics = daoMgr.getXXAuditMetricsDao().findLatestAuditMetricsByServiceTypeAndName(svcType, serviceName);
+ if (xxAuditMetrics == null) {
+ throw restErrorUtil.createRESTException("Error fetching audit metrics for given service type: " + serviceType + " service name: " + serviceName);
+ }
+ return rangerAuditMetricsService.read(xxAuditMetrics.getId());
+ }
+
+ @Override
+ public List getAllLatestRangerAuditMetrics(SearchFilter filter) throws RuntimeException {
+ List ret = new ArrayList<>();
+
+ List xxAuditMetricsList = daoMgr.getXXAuditMetricsDao().findAllLatestAuditMetrics();
+ if (xxAuditMetricsList == null) {
+ throw restErrorUtil.createRESTException("Error fetching audit metrics....");
+ }
+
+ if (CollectionUtils.isNotEmpty(xxAuditMetricsList)) {
+ for (XXAuditMetrics xxAuditMetric : xxAuditMetricsList) {
+ ret.add(rangerAuditMetricsService.read(xxAuditMetric.getId()));
+ }
+ if (predicateUtil != null && filter != null && !filter.isEmpty()) {
+ List copy = new ArrayList<>(ret);
+ predicateUtil.applyFilter(copy, filter);
+ ret = copy;
+ }
+ }
+
+ return ret;
+ }
+
+ @Override
+ public List getRangerAuditMetricsByHours(SearchFilter filter) throws RuntimeException {
+ List ret = new ArrayList<>();
+ String xxSvcTypeName = null;
+ List objList = daoMgr.getXXAuditMetricsDao().getRangerAuditMetricsByHours();
+ if (objList == null) {
+ throw restErrorUtil.createRESTException("Error fetching audit metrics by hours...");
+ }
+
+ if (CollectionUtils.isNotEmpty(objList)) {
+ for (Object[] obj : objList) {
+ Long svcType = getLongValueFromObj(obj[0]);
+ String svcName = (String) obj[1];
+ String appId = (String) obj[2];
+ String clientName = (String) obj[3];
+ String clientIP = (String) obj[4];
+ Integer hours = getIntegerValueFromObj(obj[5]);
+ Long nOfA = getLongValueFromObj(obj[6]);
+
+ if (svcType != null) {
+ XXServiceDef xxServiceDef = daoMgr.getXXServiceDef().getById(svcType);
+ if (xxServiceDef == null) {
+ LOG.error("No Service Definition for serviceType: {}, Skipping the service from metrics", svcType);
+ } else {
+ xxSvcTypeName = xxServiceDef.getName();
+ }
+ }
+ RangerAuditMetricsByHours rangerAuditMetricsByHours = new RangerAuditMetricsByHours(xxSvcTypeName, svcName, appId, clientName, clientIP, hours, nOfA);
+ ret.add(rangerAuditMetricsByHours);
+ }
+ if (predicateUtil != null && filter != null && !filter.isEmpty()) {
+ List copy = new ArrayList<>(ret);
+ predicateUtil.applyFilter(copy, filter);
+ ret = copy;
+ }
+ }
+ LOG.debug("<== AuditMetricsDBStore.getRangerAuditMetricsByHours() ret:{}", ret);
+ return ret;
+ }
+
+ @Override
+ public List getRangerAuditMetricsByDays(Integer olderThanInDays, SearchFilter filter) throws RuntimeException {
+ List ret = new ArrayList<>();
+ String xxSvcTypeName = null;
+ List objList = daoMgr.getXXAuditMetricsDao().getRangerAuditMetricsByDays(olderThanInDays);
+ if (objList == null) {
+ throw restErrorUtil.createRESTException("Error fetching audit metrics by days....");
+ }
+
+ if (CollectionUtils.isNotEmpty(objList)) {
+ for (Object[] obj : objList) {
+ Long svcType = getLongValueFromObj(obj[0]);
+ String svcName = (String) obj[1];
+ String appId = (String) obj[2];
+ String clientName = (String) obj[3];
+ String clientIP = (String) obj[4];
+ Integer days = getIntegerValueFromObj(obj[5]);
+ Long nOfA = getLongValueFromObj(obj[6]);
+ Date auditDate = (Date) obj[7];
+
+ if (svcType != null) {
+ XXServiceDef xxServiceDef = daoMgr.getXXServiceDef().getById(svcType);
+ if (xxServiceDef == null) {
+ LOG.error("No Service Definition for service: {}, Skipping the service from metrics", svcType);
+ } else {
+ xxSvcTypeName = xxServiceDef.getName();
+ }
+ }
+ RangerAuditMetricsByDays rangerAuditMetricsByDays = new RangerAuditMetricsByDays(xxSvcTypeName, svcName, appId, clientName, clientIP, days, auditDate.getTime(), nOfA);
+ ret.add(rangerAuditMetricsByDays);
+ }
+ if (predicateUtil != null && filter != null && !filter.isEmpty()) {
+ List copy = new ArrayList<>(ret);
+ predicateUtil.applyFilter(copy, filter);
+ ret = copy;
+ }
+ }
+ LOG.debug("<== AuditMetricsDBStore.getRangerAuditMetricsByDays() ret:{}", ret);
+ return ret;
+ }
+
+ @Override
+ public void deleteRangerAuditMetrics(Integer olderThanInDays, String serviceName, String serviceType) throws RuntimeException {
+ XXServiceDef xxServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
+ if (xxServiceDef == null) {
+ throw restErrorUtil.createRESTException("No ServiceDefinition found with Service Type :" + serviceType, MessageEnums.INVALID_INPUT_DATA);
+ }
+ Long svcType = xxServiceDef.getId();
+ daoMgr.getXXAuditMetricsDao().deleteRangerAuditMetrics(olderThanInDays, serviceName, svcType);
+ }
+
+ @PostConstruct
+ public void initStore() {
+ LOG.debug("==> AuditMetricsDBStore.initStore()");
+
+ config = RangerAdminConfig.getInstance();
+ rangerAuditMetricsService.setPopulateExistingBaseFields(populateExistingBaseFields);
+ predicateUtil = new AuditMetricsPredicateUtil();
+
+ LOG.debug("<== AuditMetricsDBStore.initStore()");
+ }
+
+ private boolean auditMetricsExistsForDeletion(Integer olderThanInDays, String serviceName, String serviceType) {
+ if (olderThanInDays == null) {
+ throw restErrorUtil.createRESTException("Retention Period cannot be null, hence older audit metrics not deleted...");
+ }
+ XXServiceDef xxServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
+ if (xxServiceDef == null) {
+ throw restErrorUtil.createRESTException("No ServiceDefinition found with Service Type :" + serviceType, MessageEnums.INVALID_INPUT_DATA);
+ }
+ Long svcType = xxServiceDef.getId();
+ return daoMgr.getXXAuditMetricsDao().getCountOfAuditMetrics(olderThanInDays, serviceName, svcType) > 0;
+ }
+
+ private Integer getIntegerValueFromObj(Object obj) {
+ Integer intVal;
+ if (obj instanceof Double) {
+ intVal = ((Double) obj).intValue();
+ } else if (obj instanceof BigDecimal) {
+ intVal = ((BigDecimal) obj).intValue();
+ } else {
+ intVal = (Integer) obj;
+ }
+ return intVal;
+ }
+
+ private Long getLongValueFromObj(Object obj) {
+ Long longVal;
+ if (obj instanceof Double) {
+ longVal = ((Double) obj).longValue();
+ } else if (obj instanceof BigDecimal) {
+ longVal = ((BigDecimal) obj).longValue();
+ } else {
+ longVal = (Long) obj;
+ }
+ return longVal;
+ }
+
+ public void validateRetentionDays(Integer days) {
+ Integer maxAllowedDays = Math.max(config.getInt(PROP_AUDIT_METRICS_RETENTION_PERIOD_IN_DAYS, PROP_AUDIT_METRICS_RETENTION_PERIOD_IN_DAYS_DEFAULT),
+ config.getInt(PROP_AUDIT_METRICS_MAX_SUPPORTED_DAYS, PROP_AUDIT_METRICS_MAX_SUPPORTED_DAYS_DEFAULT));
+
+ if (days == null || days <= 0 || days > maxAllowedDays) {
+ throw restErrorUtil.createRESTException(String.format("Supported days must be between 1 and %d (provided: %s)", maxAllowedDays, days), MessageEnums.INVALID_INPUT_DATA);
+ }
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java b/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
index 4a69b57707..67e1a4bc77 100755
--- a/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
@@ -97,6 +97,8 @@ public SearchFilter getSearchFilter(@Nonnull HttpServletRequest request, List {
+ private static final Logger logger = LoggerFactory.getLogger(XXAuditMetricsDao.class);
+
+ public XXAuditMetricsDao(RangerDaoManagerBase daoManager) {
+ super(daoManager);
+ }
+
+ public XXAuditMetrics findLatestAuditMetricsByServiceTypeAndName(Long serviceType, String serviceName) {
+ XXAuditMetrics ret = null;
+ if (serviceType != null) {
+ try {
+ ret = getEntityManager()
+ .createNamedQuery("XXAuditMetrics.findLatestAuditMetricsByServiceTypeAndName", XXAuditMetrics.class)
+ .setParameter("serviceType", serviceType)
+ .setParameter("serviceName", serviceName)
+ .getSingleResult();
+ } catch (NoResultException e) {
+ logger.debug(e.getMessage());
+ }
+ } else {
+ logger.debug("Query XXAuditMetricsDao.findLatestAuditMetricsByServiceTypeAndName() failed...ServiceType or ServiceName not provided.");
+ }
+
+ return ret;
+ }
+
+ public XXAuditMetrics findById(Long id) {
+ XXAuditMetrics ret = null;
+ if (id != null) {
+ try {
+ ret = getEntityManager()
+ .createNamedQuery("XXAuditMetrics.findById", XXAuditMetrics.class)
+ .setParameter("id", id)
+ .getSingleResult();
+ } catch (NoResultException e) {
+ logger.debug(e.getMessage());
+ }
+ } else {
+ logger.debug("Query XXAuditMetricsDao.findById() failed...ServiceType not provided.");
+ }
+
+ return ret;
+ }
+
+ public List findAllLatestAuditMetrics() {
+ List ret;
+ try {
+ ret = getEntityManager()
+ .createNamedQuery("XXAuditMetrics.findAllLatestAuditMetrics", tClass)
+ .getResultList();
+ } catch (NoResultException e) {
+ ret = ListUtils.EMPTY_LIST;
+ }
+ return ret;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRangerAuditMetricsByHours() {
+ List ret;
+ try {
+ String sqlStr;
+ sqlStr = "select service_type, service_name, app_id, cluster_name, client_ip, hours, numberOfAudits from vx_audit_metrics_by_hours ";
+ ret = getEntityManager().createNativeQuery(sqlStr).getResultList();
+ } catch (NoResultException e) {
+ ret = ListUtils.EMPTY_LIST;
+ }
+ return ret;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getRangerAuditMetricsByDays(Integer olderThanInDays) {
+ List ret;
+ Date since = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(olderThanInDays));
+
+ try {
+ StringBuilder sqlStr = new StringBuilder();
+ sqlStr.append("select service_type, service_name, app_id, cluster_name, client_ip, days, numberOfAudits, auditDate from vx_audit_metrics_by_days ");
+ if (olderThanInDays != null) {
+ sqlStr.append(" where auditDate >= ?1");
+ }
+ ret = getEntityManager().createNativeQuery(sqlStr.toString()).setParameter(1, since).getResultList();
+ } catch (NoResultException e) {
+ ret = ListUtils.EMPTY_LIST;
+ }
+ return ret;
+ }
+
+ public void deleteRangerAuditMetrics(Integer olderThanInDays, String serviceName, Long serviceType) {
+ Date since = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(olderThanInDays));
+
+ logger.debug("Deleting records from x_audit_metrics that are older than {} days, that is, older than {}", olderThanInDays, since);
+
+ getEntityManager().createNamedQuery("XXAuditMetrics.deleteOlderThan")
+ .setParameter("olderThanInDays", since)
+ .setParameter("serviceName", serviceName)
+ .setParameter("serviceType", serviceType)
+ .executeUpdate();
+ }
+
+ public long getCountOfAuditMetrics(Integer olderThanInDays, String serviceName, Long serviceType) {
+ Date since = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(olderThanInDays));
+
+ logger.debug("No of records from x_audit_metrics that are older than {} days, that is, older than {}", olderThanInDays, since);
+
+ return getEntityManager().createNamedQuery("XXAuditMetrics.getCountOfAuditMetrics", Long.class)
+ .setParameter("olderThanInDays", since)
+ .setParameter("serviceName", serviceName)
+ .setParameter("serviceType", serviceType)
+ .getSingleResult();
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXAuditMetrics.java b/security-admin/src/main/java/org/apache/ranger/entity/XXAuditMetrics.java
new file mode 100644
index 0000000000..89582d0682
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXAuditMetrics.java
@@ -0,0 +1,182 @@
+/*
+ * 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.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.persistence.Version;
+
+import java.util.Objects;
+
+@Entity
+@Table(name = "x_audit_metrics")
+public class XXAuditMetrics extends XXDBBase implements java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @SequenceGenerator(name = "X_AUDIT_METRICS_SEQ", sequenceName = "X_AUDIT_METRICS_SEQ", allocationSize = 1)
+ @GeneratedValue(strategy = GenerationType.AUTO, generator = "X_AUDIT_METRICS_SEQ")
+ @Column(name = "id")
+ protected Long id;
+ @Version
+ @Column(name = "version")
+ protected Long version;
+ @Column(name = "service_type")
+ protected Long serviceType;
+ @Column(name = "service_name")
+ protected String serviceName;
+ @Column(name = "app_id")
+ protected String appId;
+ @Column(name = "cluster_name")
+ protected String clusterName;
+ @Column(name = "client_ip")
+ protected String clientIP;
+ @Column(name = "metrics_text")
+ protected String metricsText;
+ @Column(name = "throughput_unit")
+ protected String throughPutUnit;
+ @Column(name = "number_of_audits")
+ protected int numberOfAudits;
+
+ @Override
+ public Long getId() {
+ return id;
+ }
+
+ @Override
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), serviceType, serviceName, throughPutUnit, numberOfAudits, metricsText);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+
+ XXAuditMetrics other = (XXAuditMetrics) obj;
+
+ return Objects.equals(serviceType, other.serviceType) &&
+ Objects.equals(serviceName, other.serviceName) &&
+ Objects.equals(appId, other.appId) &&
+ Objects.equals(clusterName, other.clusterName) &&
+ Objects.equals(clientIP, other.clientIP) &&
+ Objects.equals(throughPutUnit, other.throughPutUnit) &&
+ Objects.equals(numberOfAudits, other.numberOfAudits) &&
+ Objects.equals(metricsText, other.metricsText);
+ }
+
+ @Override
+ public String toString() {
+ String sb = "XXAuditMetrics={" +
+ super.toString() +
+ "{[" +
+ "serviceType=" + serviceType + ", " +
+ "serviceName=" + serviceType + ", " +
+ "appId=" + appId + ", " +
+ "clusterName=" + clusterName + ", " +
+ "clientIP=" + clientIP + ", " +
+ "throughput unit=" + throughPutUnit + ", " +
+ "numberOfAudits=" + numberOfAudits + ", " +
+ "metricsText=" + metricsText + ", " +
+ "]}";
+ return sb;
+ }
+
+ public Long getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(Long serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public String getAppID() {
+ return appId;
+ }
+
+ public void setAppID(String appId) {
+ this.appId = appId;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getClientIP() {
+ return clientIP;
+ }
+
+ public void setClientIP(String clientIP) {
+ this.clientIP = clientIP;
+ }
+
+ public String getMetricsText() {
+ return metricsText;
+ }
+
+ public void setMetricsText(String metricsText) {
+ this.metricsText = metricsText;
+ }
+
+ public String getThroughPutUnit() {
+ return throughPutUnit;
+ }
+
+ public void setThroughPutUnit(String throughPutUnit) {
+ this.throughPutUnit = throughPutUnit;
+ }
+
+ public int getNumberOfAudits() {
+ return numberOfAudits;
+ }
+
+ public void setNumberOfAudits(int numberOfAudits) {
+ this.numberOfAudits = numberOfAudits;
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/AuditMetricsREST.java b/security-admin/src/main/java/org/apache/ranger/rest/AuditMetricsREST.java
new file mode 100644
index 0000000000..9d200b90d6
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/rest/AuditMetricsREST.java
@@ -0,0 +1,244 @@
+/*
+ * 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.rest;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.ranger.biz.AuditMetricsDBStore;
+import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.common.RangerSearchUtil;
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByDays;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByHours;
+import org.apache.ranger.plugin.util.SearchFilter;
+import org.apache.ranger.security.context.RangerAPIList;
+import org.apache.ranger.service.RangerAuditMetricsService;
+import org.apache.ranger.view.RangerAuditMetricsList;
+import org.apache.ranger.view.RangerAuditMetricsListByDays;
+import org.apache.ranger.view.RangerAuditMetricsListByHours;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+
+import java.util.List;
+
+@Path("audit")
+@Component
+@Scope("request")
+@Transactional(propagation = Propagation.REQUIRES_NEW)
+public class AuditMetricsREST {
+ private static final Logger LOG = LoggerFactory.getLogger(AuditMetricsREST.class);
+
+ @Autowired
+ RESTErrorUtil restErrorUtil;
+
+ @Autowired
+ AuditMetricsDBStore auditMetricsDBStore;
+
+ @Autowired
+ RangerSearchUtil searchUtil;
+
+ @Autowired
+ RangerAuditMetricsService rangerAuditMetricsService;
+
+ @POST
+ @Path("/metrics")
+ @Produces("application/json")
+ public RangerAuditMetrics createAuditMetrics(RangerAuditMetrics rangerAuditMetrics) {
+ LOG.debug("==> AuditMetricsREST.createAuditMetrics({})", rangerAuditMetrics);
+
+ if (rangerAuditMetrics == null) {
+ // send error message with response code 400
+ throw restErrorUtil.createRESTException("Can not create RangerAuditMetrics for null.");
+ }
+
+ RangerAuditMetrics ret;
+ try {
+ ret = auditMetricsDBStore.createRangerAuditMetrics(rangerAuditMetrics);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Throwable excp) {
+ LOG.error("createRangerAuditMetrics({}) failed", rangerAuditMetrics, excp);
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ }
+ LOG.debug("<== AuditMetricsREST.createRangerAuditMetrics({}):{}", rangerAuditMetrics, ret);
+ return ret;
+ }
+
+ @GET
+ @Path("/metrics/servicetype/{servicetype}/servicename/{servicename}")
+ @Produces("application/json")
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_LATEST_AUDIT_METRICS + "\")")
+ public RangerAuditMetrics getLatestAuditMetrics(@PathParam("servicetype") String serviceType, @PathParam("servicename") String serviceName) {
+ LOG.debug("==> AuditMetricsREST.getAuditMetrics(serviceType={} serviceName={})", serviceType, serviceName);
+ RangerAuditMetrics ret;
+ try {
+ ret = auditMetricsDBStore.getLatestRangerAuditMetrics(serviceType, serviceName);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Throwable excp) {
+ LOG.error("getAuditMetrics for serviceType={}, ServiceName={} failed", serviceType, serviceName, excp);
+
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ }
+ LOG.debug("<== AuditMetricsREST.getAuditMetrics(serviceType= \" + serviceType + \"serviceName=\" + serviceName + \")\"):{}", ret);
+ return ret;
+ }
+
+ @GET
+ @Path("/metrics/{id}")
+ @Produces("application/json")
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_AUDIT_METRICS + "\")")
+ public RangerAuditMetrics getAuditMetrics(@PathParam("id") Long id) {
+ LOG.debug("==> AuditMetricsREST.getAuditMetrics(id={})", id);
+ RangerAuditMetrics ret;
+ try {
+ ret = auditMetricsDBStore.getRangerAuditMetrics(id);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Throwable excp) {
+ LOG.error("getAuditMetrics({}) failed", id, excp);
+
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ }
+ LOG.debug("<== AuditMetricsREST.getAuditMetrics(id={}):{}", id, ret);
+ return ret;
+ }
+
+ @GET
+ @Path("/metrics")
+ @Produces("application/json")
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_ALL_LATEST_AUDIT_METRICS + "\")")
+ public RangerAuditMetricsList getAllLatestRangerAuditMetrics(@Context HttpServletRequest request) {
+ LOG.debug("==> AuditMetricsREST.getAllLatestAuditMetrics()");
+ RangerAuditMetricsList ret = new RangerAuditMetricsList();
+ List rangerAuditMetrics;
+
+ SearchFilter filter = searchUtil.getSearchFilter(request, rangerAuditMetricsService.sortFields);
+
+ try {
+ rangerAuditMetrics = auditMetricsDBStore.getAllLatestRangerAuditMetrics(filter);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Throwable excp) {
+ LOG.error("Error getting all latest audit metrics..", excp);
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ }
+
+ if (CollectionUtils.isNotEmpty(rangerAuditMetrics)) {
+ ret = new RangerAuditMetricsList(rangerAuditMetrics);
+ }
+
+ LOG.debug("<== AuditMetricsREST.getAllLatestRangerAuditMetrics()");
+
+ return ret;
+ }
+
+ @GET
+ @Path("/dailymetrics")
+ @Produces("application/json")
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_DAILY_AUDIT_METRICS + "\")")
+ public RangerAuditMetricsListByHours getDailyAuditMetrics(@Context HttpServletRequest request) {
+ LOG.debug("==> AuditMetricsREST.getRangerAuditMetricsByHours()");
+ RangerAuditMetricsListByHours ret = new RangerAuditMetricsListByHours();
+ List rangerAuditMetricsByHours;
+
+ SearchFilter filter = searchUtil.getSearchFilter(request, rangerAuditMetricsService.sortFields);
+ try {
+ rangerAuditMetricsByHours = auditMetricsDBStore.getRangerAuditMetricsByHours(filter);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Throwable excp) {
+ LOG.error("Error getting all latest audit metrics..", excp);
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ }
+
+ if (CollectionUtils.isNotEmpty(rangerAuditMetricsByHours)) {
+ ret = new RangerAuditMetricsListByHours(rangerAuditMetricsByHours);
+ }
+
+ LOG.debug("<== AuditMetricsREST.getRangerAuditMetricsByHours()");
+
+ return ret;
+ }
+
+ @GET
+ @Path("/daysmetrics")
+ @Produces("application/json")
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_DAYS_AUDIT_METRICS + "\")")
+ public RangerAuditMetricsListByDays getDaysAuditMetrics(@Context HttpServletRequest request, @DefaultValue("7") @QueryParam("olderThanInDays") Integer olderThanInDays) {
+ LOG.debug("==> AuditMetricsREST.getDaysAuditMetrics()");
+ auditMetricsDBStore.validateRetentionDays(olderThanInDays);
+
+ RangerAuditMetricsListByDays ret = new RangerAuditMetricsListByDays();
+ List rangerAuditMetricsByDays;
+ SearchFilter filter = searchUtil.getSearchFilter(request, rangerAuditMetricsService.sortFields);
+ try {
+ rangerAuditMetricsByDays = auditMetricsDBStore.getRangerAuditMetricsByDays(olderThanInDays, filter);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Throwable excp) {
+ LOG.error("Error getting all latest audit metrics..", excp);
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ }
+
+ if (CollectionUtils.isNotEmpty(rangerAuditMetricsByDays)) {
+ ret = new RangerAuditMetricsListByDays(rangerAuditMetricsByDays);
+ }
+
+ LOG.debug("<== AuditMetricsREST.getDaysAuditMetrics()");
+
+ return ret;
+ }
+
+ @DELETE
+ @Path("/metrics")
+ @Produces("application/json")
+ public void deleteRangerAuditMetrics(@DefaultValue("7") @QueryParam("retentionPeriod") Integer olderThanInDays, @DefaultValue("") @QueryParam("serviceType") String serviceType, @DefaultValue("") @QueryParam("serviceName") String serviceName, @Context HttpServletRequest request) {
+ LOG.debug("==> AuditMetricsREST.deleteRangerAuditMetrics({})", olderThanInDays);
+ auditMetricsDBStore.validateRetentionDays(olderThanInDays);
+
+ try {
+ auditMetricsDBStore.deleteRangerAuditMetrics(olderThanInDays, serviceName, serviceType);
+ } catch (WebApplicationException excp) {
+ throw excp;
+ } catch (Exception e) {
+ LOG.error("Error deleting Ranger Audit Metrics older than: {}", olderThanInDays, e);
+ throw restErrorUtil.createRESTException(e.getMessage());
+ }
+ LOG.debug("<== AuditMetricsREST.deleteRangerAuditMetrics({})", olderThanInDays);
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
index 27d076a480..ae210322a9 100755
--- a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
@@ -258,6 +258,15 @@ public class RangerAPIList {
public static final String UPDATE_DATASET_GRANTS = "GdsREST.updateDataSetGrants";
public static final String EVALUATE_SHARED_RESOURCES = "GdsREST.evaluateSharedResources";
+ /**
+ * List of APIs for AuditMetricsREST
+ */
+ public static final String GET_LATEST_AUDIT_METRICS = "AuditMetricsREST.getLatestAuditMetrics";
+ public static final String GET_AUDIT_METRICS = "AuditMetricsREST.getAuditMetrics";
+ public static final String GET_ALL_LATEST_AUDIT_METRICS = "AuditMetricsREST.getAllLatestRangerAuditMetrics";
+ public static final String GET_DAILY_AUDIT_METRICS = "AuditMetricsREST.getDailyAuditMetrics";
+ public static final String GET_DAYS_AUDIT_METRICS = "AuditMetricsREST.getDaysAuditMetrics";
+
/**
* List of APIs for PublicAPIsv2
*/
diff --git a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
index 1c4ee11837..ef22ea5673 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
@@ -426,6 +426,12 @@ private void mapAuditWithAPIs() {
apiAssociatedWithAudit.add(RangerAPIList.GET_AUTH_SESSION);
apiAssociatedWithAudit.add(RangerAPIList.GET_AUTH_SESSIONS);
+ apiAssociatedWithAudit.add(RangerAPIList.GET_LATEST_AUDIT_METRICS);
+ apiAssociatedWithAudit.add(RangerAPIList.GET_AUDIT_METRICS);
+ apiAssociatedWithAudit.add(RangerAPIList.GET_ALL_LATEST_AUDIT_METRICS);
+ apiAssociatedWithAudit.add(RangerAPIList.GET_DAILY_AUDIT_METRICS);
+ apiAssociatedWithAudit.add(RangerAPIList.GET_DAYS_AUDIT_METRICS);
+
rangerAPIMappingWithUI.put(TAB_AUDIT, apiAssociatedWithAudit);
for (String api : apiAssociatedWithAudit) {
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerAuditMetricsService.java b/security-admin/src/main/java/org/apache/ranger/service/RangerAuditMetricsService.java
new file mode 100644
index 0000000000..8aab101c25
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerAuditMetricsService.java
@@ -0,0 +1,51 @@
+/*
+ * 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.service;
+
+import org.apache.ranger.entity.XXAuditMetrics;
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+@Service
+@Scope("singleton")
+public class RangerAuditMetricsService extends RangerAuditMetricsServiceBase {
+ public RangerAuditMetricsService() {
+ super();
+ }
+
+ @Override
+ protected void validateForCreate(RangerAuditMetrics vObj) {
+ }
+
+ @Override
+ protected void validateForUpdate(RangerAuditMetrics vObj, XXAuditMetrics entityObj) {
+ }
+
+ @Override
+ protected XXAuditMetrics mapViewToEntityBean(RangerAuditMetrics rangerAuditMetrics, XXAuditMetrics xxAuditMetrics, int operationContext) {
+ XXAuditMetrics ret = super.mapViewToEntityBean(rangerAuditMetrics, xxAuditMetrics, operationContext);
+ return ret;
+ }
+
+ @Override
+ protected RangerAuditMetrics mapEntityToViewBean(RangerAuditMetrics rangerAuditMetrics, XXAuditMetrics xxAuditMetrics) {
+ RangerAuditMetrics ret = super.mapEntityToViewBean(rangerAuditMetrics, xxAuditMetrics);
+ return ret;
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerAuditMetricsServiceBase.java b/security-admin/src/main/java/org/apache/ranger/service/RangerAuditMetricsServiceBase.java
new file mode 100644
index 0000000000..4e15204472
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerAuditMetricsServiceBase.java
@@ -0,0 +1,74 @@
+/*
+ * 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.service;
+
+import org.apache.ranger.authorization.utils.JsonUtils;
+import org.apache.ranger.common.MessageEnums;
+import org.apache.ranger.common.SearchField;
+import org.apache.ranger.common.SortField;
+import org.apache.ranger.entity.XXAuditMetrics;
+import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+import org.apache.ranger.plugin.model.RangerAuditMetricsText;
+import org.apache.ranger.plugin.util.SearchFilter;
+
+public abstract class RangerAuditMetricsServiceBase extends RangerBaseModelService {
+ public RangerAuditMetricsServiceBase() {
+ super();
+
+ searchFields.add(new SearchField(SearchFilter.SERVICE_TYPE, "obj.serviceType", SearchField.DATA_TYPE.INTEGER, SearchField.SEARCH_TYPE.FULL));
+ searchFields.add(new SearchField(SearchFilter.SERVICE_NAME, "obj.serviceName", SearchField.DATA_TYPE.STRING, SearchField.SEARCH_TYPE.FULL));
+
+ sortFields.add(new SortField(SearchFilter.CREATE_TIME, "obj.createTime"));
+ sortFields.add(new SortField(SearchFilter.UPDATE_TIME, "obj.updateTime"));
+ sortFields.add(new SortField(SearchFilter.AUDIT_METRICS_ID, "obj.id", true, SortField.SORT_ORDER.ASC));
+ }
+
+ @Override
+ protected T mapViewToEntityBean(V vObj, T xObj, int operationContext) {
+ XXServiceDef xServiceDef = daoMgr.getXXServiceDef().findByName(vObj.getServiceType());
+ if (xServiceDef == null) {
+ throw restErrorUtil.createRESTException("No ServiceDefinition found with name :" + vObj.getServiceName(), MessageEnums.INVALID_INPUT_DATA);
+ }
+ xObj.setServiceType(xServiceDef.getId());
+ xObj.setServiceName(vObj.getServiceName());
+ xObj.setAppID(vObj.getAppId());
+ xObj.setClusterName(vObj.getClusterName());
+ xObj.setClientIP(vObj.getclientIP());
+ xObj.setThroughPutUnit(vObj.getThroughPutUnit());
+ xObj.setNumberOfAudits(vObj.getNumberOfAudits());
+ xObj.setMetricsText(JsonUtils.objectToJson(vObj.getMetricsText()));
+ return xObj;
+ }
+
+ @Override
+ protected V mapEntityToViewBean(V vObj, T xObj) {
+ XXServiceDef xServiceDef = daoMgr.getXXServiceDef().getById(xObj.getServiceType());
+ vObj.setServiceType(xServiceDef.getName());
+ vObj.setServiceName(xObj.getServiceName());
+ vObj.setAppId(xObj.getAppID());
+ vObj.setClusterName(xObj.getClusterName());
+ vObj.setclientIP(xObj.getClientIP());
+ vObj.setThroughPutUnit(xObj.getThroughPutUnit());
+ vObj.setNumberOfAudits(xObj.getNumberOfAudits());
+ String metricsText = xObj.getMetricsText();
+ RangerAuditMetricsText rangerAuditMetricsText = JsonUtils.jsonToObject(metricsText, RangerAuditMetricsText.class);
+ vObj.setMetricsText(rangerAuditMetricsText);
+ return vObj;
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsList.java b/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsList.java
new file mode 100644
index 0000000000..b63e61e586
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsList.java
@@ -0,0 +1,65 @@
+/*
+ * 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.view;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.ranger.common.view.VList;
+import org.apache.ranger.plugin.model.RangerAuditMetrics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RangerAuditMetricsList extends VList {
+ private static final long serialVersionUID = 1L;
+
+ List rangerAuditMetricsList = new ArrayList<>();
+
+ public RangerAuditMetricsList() {
+ super();
+ }
+
+ public RangerAuditMetricsList(List objList) {
+ super(objList);
+ this.rangerAuditMetricsList = objList;
+ }
+
+ public List getRangerAuditMetricsList() {
+ return rangerAuditMetricsList;
+ }
+
+ public void setRangerAuditMetricsList(List auditMetrics) {
+ this.rangerAuditMetricsList = auditMetrics;
+ }
+
+ @Override
+ public int getListSize() {
+ if (rangerAuditMetricsList != null) {
+ return rangerAuditMetricsList.size();
+ }
+ return 0;
+ }
+
+ @Override
+ public List> getList() {
+ return rangerAuditMetricsList;
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByDays.java b/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByDays.java
new file mode 100644
index 0000000000..1bf3b8b71c
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByDays.java
@@ -0,0 +1,65 @@
+/*
+ * 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.view;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.ranger.common.view.VList;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByDays;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RangerAuditMetricsListByDays extends VList {
+ private static final long serialVersionUID = 1L;
+
+ List auditMetricsByDays = new ArrayList<>();
+
+ public RangerAuditMetricsListByDays() {
+ super();
+ }
+
+ public RangerAuditMetricsListByDays(List objList) {
+ super(objList);
+ this.auditMetricsByDays = objList;
+ }
+
+ public List getAuditMetricsListByUnit() {
+ return auditMetricsByDays;
+ }
+
+ public void setAuditMetricsListByDays(List auditMetricsByDays) {
+ this.auditMetricsByDays = auditMetricsByDays;
+ }
+
+ @Override
+ public int getListSize() {
+ if (auditMetricsByDays != null) {
+ return auditMetricsByDays.size();
+ }
+ return 0;
+ }
+
+ @Override
+ public List> getList() {
+ return auditMetricsByDays;
+ }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByHours.java b/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByHours.java
new file mode 100644
index 0000000000..e729ca6ec3
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByHours.java
@@ -0,0 +1,65 @@
+/*
+ * 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.view;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.ranger.common.view.VList;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByHours;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RangerAuditMetricsListByHours extends VList {
+ private static final long serialVersionUID = 1L;
+
+ List auditMetricsByHours = new ArrayList<>();
+
+ public RangerAuditMetricsListByHours() {
+ super();
+ }
+
+ public RangerAuditMetricsListByHours(List objList) {
+ super(objList);
+ this.auditMetricsByHours = objList;
+ }
+
+ public List getAuditMetricsListByHours() {
+ return auditMetricsByHours;
+ }
+
+ public void setAuditMetricsListByHours(List auditMetricsByHours) {
+ this.auditMetricsByHours = auditMetricsByHours;
+ }
+
+ @Override
+ public int getListSize() {
+ if (auditMetricsByHours != null) {
+ return auditMetricsByHours.size();
+ }
+ return 0;
+ }
+
+ @Override
+ public List> getList() {
+ return auditMetricsByHours;
+ }
+}
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index 7ae05973de..2d0dffd28f 100755
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -2197,6 +2197,43 @@
+
+
+ select obj from XXAuditMetrics obj where obj.serviceType = :serviceType and obj.serviceName = :serviceName
+ and obj.id = (select max(auditMetrics.id) from XXAuditMetrics auditMetrics where auditMetrics.serviceType = :serviceType
+ and auditMetrics.serviceName = :serviceName)
+
+
+
+
+ select obj from XXAuditMetrics obj where obj.id = :id
+
+
+
+ select obj from XXAuditMetrics obj
+ where obj.id in (select max(auditMetrics.id) from XXAuditMetrics auditMetrics
+ where auditMetrics.serviceType in (select service.type from XXService service )
+ group by auditMetrics.serviceType, auditMetrics.serviceName, auditMetrics.appId, auditMetrics.clusterName, auditMetrics.clientIP)
+
+
+
+
+ delete from XXAuditMetrics obj where obj.createTime < :olderThanInDays
+ and obj.serviceName = :serviceName
+ and obj.serviceType = :serviceType
+
+
+
+
+
+
+ select count(obj.id) from XXAuditMetrics obj
+ where obj.createTime < :olderThanInDays
+ and obj.serviceType = :serviceType
+ and obj.serviceName = :serviceName
+
+
+
select obj from XXPolicy obj where obj.zoneId = :zoneId
diff --git a/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml b/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml
index 1af3390103..449702e133 100644
--- a/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml
+++ b/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml
@@ -675,4 +675,8 @@
ranger.allow.kerberos.auth.login.browser
false
+
+ ranger.audit.metrics.max.supported.days
+ 90
+