diff --git a/agents-audit/core/pom.xml b/agents-audit/core/pom.xml index 79eedbe60c..ee2f7471a3 100644 --- a/agents-audit/core/pom.xml +++ b/agents-audit/core/pom.xml @@ -47,6 +47,15 @@ jackson-databind ${fasterxml.jackson.databind.version} + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${fasterxml.jackson.databind.version} + + + com.google.code.gson + gson + commons-collections commons-collections @@ -88,6 +97,11 @@ ranger-plugins-cred ${project.version} + + org.glassfish.jersey.core + jersey-client + ${jersey-client.version} + 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: + *

+ * + *

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 +