use of org.apache.ranger.audit.model.AuthzAuditEvent in project nifi by apache.
the class RangerNiFiAuthorizer method auditAccessAttempt.
@Override
public void auditAccessAttempt(final AuthorizationRequest request, final AuthorizationResult result) {
final RangerAccessResult rangerResult;
synchronized (resultLookup) {
rangerResult = resultLookup.remove(request);
}
if (rangerResult != null && rangerResult.getIsAudited()) {
AuthzAuditEvent event = defaultAuditHandler.getAuthzEvents(rangerResult);
// update the event with the originally requested resource
event.setResourceType(RANGER_NIFI_RESOURCE_NAME);
event.setResourcePath(request.getRequestedResource().getIdentifier());
defaultAuditHandler.logAuthzAudit(event);
}
}
use of org.apache.ranger.audit.model.AuthzAuditEvent in project ranger by apache.
the class AuthorizationSession method publishResults.
void publishResults() throws AccessDeniedException {
if (LOG.isDebugEnabled()) {
LOG.debug("==> AuthorizationSession.publishResults()");
}
boolean authorized = isAuthorized();
if (_auditHandler != null) {
List<AuthzAuditEvent> events = null;
/*
* What we log to audit depends on authorization status. For success we log all accumulated events. In case of failure
* we log just the last set of audit messages as we only need to record the cause of overall denial.
*/
if (authorized) {
List<AuthzAuditEvent> theseEvents = _auditHandler.getCapturedEvents();
if (theseEvents != null && !theseEvents.isEmpty()) {
events = theseEvents;
}
} else {
AuthzAuditEvent event = _auditHandler.getAndDiscardMostRecentEvent();
if (event != null) {
events = Lists.newArrayList(event);
}
}
if (LOG.isDebugEnabled()) {
int size = events == null ? 0 : events.size();
String auditMessage = events == null ? "" : events.toString();
String message = String.format("Writing %d messages to audit: [%s]", size, auditMessage);
LOG.debug(message);
}
_auditHandler.logAuthzAudits(events);
}
if (!authorized) {
// and throw and exception... callers expect this behavior
String reason = getDenialReason();
String message = getLogMessage(false, reason);
if (LOG.isDebugEnabled()) {
LOG.debug("<== AuthorizationSession.publishResults: throwing exception: " + message);
}
throw new AccessDeniedException("Insufficient permissions for user '" + _user.getName() + "' (action=" + _access + ")");
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== AuthorizationSession.publishResults()");
}
}
use of org.apache.ranger.audit.model.AuthzAuditEvent in project ranger by apache.
the class RangerHBasePlugin method evaluateAccess.
ColumnFamilyAccessResult evaluateAccess(String operation, Action action, final RegionCoprocessorEnvironment env, final Map<byte[], ? extends Collection<?>> familyMap) throws AccessDeniedException {
String access = _authUtils.getAccess(action);
User user = getActiveUser();
String userName = _userUtils.getUserAsString(user);
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("evaluateAccess: entered: user[%s], Operation[%s], access[%s], families[%s]", userName, operation, access, getColumnFamilies(familyMap).toString()));
}
byte[] tableBytes = getTableName(env);
if (tableBytes == null || tableBytes.length == 0) {
String message = "evaluateAccess: Unexpected: Couldn't get table from RegionCoprocessorEnvironment. Access denied, not audited";
LOG.debug(message);
throw new AccessDeniedException("Insufficient permissions for operation '" + operation + "',action: " + action);
}
String table = Bytes.toString(tableBytes);
String clusterName = hbasePlugin.getClusterName();
final String messageTemplate = "evaluateAccess: exiting: user[%s], Operation[%s], access[%s], families[%s], verdict[%s]";
ColumnFamilyAccessResult result;
if (canSkipAccessCheck(operation, access, table) || canSkipAccessCheck(operation, access, env)) {
LOG.debug("evaluateAccess: exiting: isKnownAccessPattern returned true: access allowed, not audited");
result = new ColumnFamilyAccessResult(true, true, null, null, null, null, null, null);
if (LOG.isDebugEnabled()) {
Map<String, Set<String>> families = getColumnFamilies(familyMap);
String message = String.format(messageTemplate, userName, operation, access, families.toString(), result.toString());
LOG.debug(message);
}
return result;
}
// let's create a session that would be reused. Set things on it that won't change.
HbaseAuditHandler auditHandler = _factory.getAuditHandler();
AuthorizationSession session = new AuthorizationSession(hbasePlugin).operation(operation).remoteAddress(getRemoteAddress()).auditHandler(auditHandler).user(user).access(access).table(table).clusterName(clusterName);
Map<String, Set<String>> families = getColumnFamilies(familyMap);
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: families to process: " + families.toString());
}
if (families == null || families.isEmpty()) {
LOG.debug("evaluateAccess: Null or empty families collection, ok. Table level access is desired");
session.buildRequest().authorize();
boolean authorized = session.isAuthorized();
String reason = "";
if (authorized) {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: table level access granted [" + table + "]");
}
} else {
reason = String.format("Insufficient permissions for user ‘%s',action: %s, tableName:%s, no column families found.", user.getName(), operation, table);
}
// this could be null, of course, depending on audit settings of table.
AuthzAuditEvent event = auditHandler.getAndDiscardMostRecentEvent();
// if authorized then pass captured events as access allowed set else as access denied set.
result = new ColumnFamilyAccessResult(authorized, authorized, authorized ? Collections.singletonList(event) : null, null, authorized ? null : event, reason, null, clusterName);
if (LOG.isDebugEnabled()) {
String message = String.format(messageTemplate, userName, operation, access, families.toString(), result.toString());
LOG.debug(message);
}
return result;
} else {
LOG.debug("evaluateAccess: Families collection not null. Skipping table-level check, will do finer level check");
}
boolean everythingIsAccessible = true;
boolean somethingIsAccessible = false;
/*
* we would have to accumulate audits of all successful accesses and any one denial (which in our case ends up being the last denial)
* We need to keep audit events for family level access check seperate because we don't want them logged in some cases.
*/
List<AuthzAuditEvent> authorizedEvents = new ArrayList<AuthzAuditEvent>();
List<AuthzAuditEvent> familyLevelAccessEvents = new ArrayList<AuthzAuditEvent>();
AuthzAuditEvent deniedEvent = null;
String denialReason = null;
// we need to cache the auths results so that we can create a filter, if needed
Map<String, Set<String>> columnsAccessAllowed = new HashMap<String, Set<String>>();
Set<String> familesAccessAllowed = new HashSet<String>();
Set<String> familesAccessDenied = new HashSet<String>();
Set<String> familesAccessIndeterminate = new HashSet<String>();
for (Map.Entry<String, Set<String>> anEntry : families.entrySet()) {
String family = anEntry.getKey();
session.columnFamily(family);
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: Processing family: " + family);
}
Set<String> columns = anEntry.getValue();
if (columns == null || columns.isEmpty()) {
LOG.debug("evaluateAccess: columns collection null or empty, ok. Family level access is desired.");
// zap stale column from prior iteration of this loop, if any
session.column(null).buildRequest().authorize();
// capture it only for success
AuthzAuditEvent auditEvent = auditHandler.getAndDiscardMostRecentEvent();
if (session.isAuthorized()) {
somethingIsAccessible = true;
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: has family level access [" + family + "]. Checking if [" + family + "] descendants have access.");
}
session.resourceMatchingScope(RangerAccessRequest.ResourceMatchingScope.SELF_OR_DESCENDANTS).buildRequest().authorize();
// capture it only for failure
auditEvent = auditHandler.getAndDiscardMostRecentEvent();
if (session.isAuthorized()) {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: [" + family + "] descendants have access");
}
familesAccessAllowed.add(family);
if (auditEvent != null) {
LOG.debug("evaluateAccess: adding to family-level-access-granted-event-set");
familyLevelAccessEvents.add(auditEvent);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: has partial access (of some type) in family [" + family + "]");
}
everythingIsAccessible = false;
familesAccessIndeterminate.add(family);
if (auditEvent != null && deniedEvent == null) {
// we need to capture just one denial event
LOG.debug("evaluateAccess: Setting denied access audit event with last auth failure audit event.");
deniedEvent = auditEvent;
}
}
// Restore the headMatch setting
session.resourceMatchingScope(RangerAccessRequest.ResourceMatchingScope.SELF);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: has no access of [" + access + "] type in family [" + family + "]");
}
everythingIsAccessible = false;
familesAccessDenied.add(family);
denialReason = String.format("Insufficient permissions for user ‘%s',action: %s, tableName:%s, family:%s.", user.getName(), operation, table, family);
if (auditEvent != null && deniedEvent == null) {
// we need to capture just one denial event
LOG.debug("evaluateAccess: Setting denied access audit event with last auth failure audit event.");
deniedEvent = auditEvent;
}
}
} else {
LOG.debug("evaluateAccess: columns collection not empty. Skipping Family level check, will do finer level access check.");
// will be used in to populate our results cache for the filter
Set<String> accessibleColumns = new HashSet<String>();
for (String column : columns) {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: Processing column: " + column);
}
session.column(column).buildRequest().authorize();
AuthzAuditEvent auditEvent = auditHandler.getAndDiscardMostRecentEvent();
if (session.isAuthorized()) {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: has column level access [" + family + ", " + column + "]");
}
// we need to do 3 things: housekeeping, capturing audit events, building the results cache for filter
somethingIsAccessible = true;
accessibleColumns.add(column);
if (auditEvent != null) {
LOG.debug("evaluateAccess: adding to access-granted-audit-event-set");
authorizedEvents.add(auditEvent);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("evaluateAccess: no column level access [" + family + ", " + column + "]");
}
everythingIsAccessible = false;
denialReason = String.format("Insufficient permissions for user ‘%s',action: %s, tableName:%s, family:%s, column: %s", user.getName(), operation, table, family, column);
if (auditEvent != null && deniedEvent == null) {
// we need to capture just one denial event
LOG.debug("evaluateAccess: Setting denied access audit event with last auth failure audit event.");
deniedEvent = auditEvent;
}
}
if (!accessibleColumns.isEmpty()) {
columnsAccessAllowed.put(family, accessibleColumns);
}
}
}
}
// Cache of auth results are encapsulated the in the filter. Not every caller of the function uses it - only preGet and preOpt will.
RangerAuthorizationFilter filter = new RangerAuthorizationFilter(session, familesAccessAllowed, familesAccessDenied, familesAccessIndeterminate, columnsAccessAllowed);
result = new ColumnFamilyAccessResult(everythingIsAccessible, somethingIsAccessible, authorizedEvents, familyLevelAccessEvents, deniedEvent, denialReason, filter, clusterName);
if (LOG.isDebugEnabled()) {
String message = String.format(messageTemplate, userName, operation, access, families.toString(), result.toString());
LOG.debug(message);
}
return result;
}
use of org.apache.ranger.audit.model.AuthzAuditEvent in project ranger by apache.
the class RangerAuthorizationFilter method filterKeyValue.
@Override
public ReturnCode filterKeyValue(Cell kv) throws IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("==> filterKeyValue");
}
String family = null;
byte[] familyBytes = CellUtil.cloneFamily(kv);
if (familyBytes != null && familyBytes.length > 0) {
family = Bytes.toString(familyBytes);
if (LOG.isDebugEnabled()) {
LOG.debug("filterKeyValue: evaluating family[" + family + "].");
}
}
String column = null;
byte[] qualifier = CellUtil.cloneQualifier(kv);
if (qualifier != null && qualifier.length > 0) {
column = Bytes.toString(qualifier);
if (LOG.isDebugEnabled()) {
LOG.debug("filterKeyValue: evaluating column[" + column + "].");
}
} else {
LOG.warn("filterKeyValue: empty/null column set! Unexpected!");
}
ReturnCode result = ReturnCode.NEXT_COL;
boolean authCheckNeeded = false;
if (family == null) {
LOG.warn("filterKeyValue: Unexpected - null/empty family! Access denied!");
} else if (_familiesAccessDenied.contains(family)) {
LOG.debug("filterKeyValue: family found in access denied families cache. Access denied.");
} else if (_columnsAccessAllowed.containsKey(family)) {
LOG.debug("filterKeyValue: family found in column level access results cache.");
if (_columnsAccessAllowed.get(family).contains(column)) {
LOG.debug("filterKeyValue: family/column found in column level access results cache. Access allowed.");
result = ReturnCode.INCLUDE;
} else {
LOG.debug("filterKeyValue: family/column not in column level access results cache. Access denied.");
}
} else if (_familiesAccessAllowed.contains(family)) {
LOG.debug("filterKeyValue: family found in access allowed families cache. Must re-authorize for correct audit generation.");
authCheckNeeded = true;
} else if (_familiesAccessIndeterminate.contains(family)) {
LOG.debug("filterKeyValue: family found in indeterminate families cache. Evaluating access...");
authCheckNeeded = true;
} else {
LOG.warn("filterKeyValue: Unexpected - alien family encountered that wasn't seen by pre-hook! Access Denied.!");
}
if (authCheckNeeded) {
LOG.debug("filterKeyValue: Checking authorization...");
_session.columnFamily(family).column(column).buildRequest().authorize();
// must always purge the captured audit event out of the audit handler to avoid messing up the next check
AuthzAuditEvent auditEvent = _auditHandler.getAndDiscardMostRecentEvent();
if (_session.isAuthorized()) {
LOG.debug("filterKeyValue: Access granted.");
result = ReturnCode.INCLUDE;
if (auditEvent != null) {
LOG.debug("filterKeyValue: access is audited.");
_auditHandler.logAuthzAudits(Collections.singletonList(auditEvent));
} else {
LOG.debug("filterKeyValue: no audit event returned. Access not audited.");
}
} else {
LOG.debug("filterKeyValue: Access denied. Denial not audited.");
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("filterKeyValue: " + result);
}
return result;
}
use of org.apache.ranger.audit.model.AuthzAuditEvent in project ranger by apache.
the class SolrAuditProvider method log.
/*
* (non-Javadoc)
*
* @see
* org.apache.ranger.audit.provider.AuditProvider#log(org.apache.ranger.
* audit.model.AuditEventBase)
*/
@Override
public boolean log(AuditEventBase event) {
if (!(event instanceof AuthzAuditEvent)) {
LOG.error(event.getClass().getName() + " audit event class type is not supported");
return false;
}
AuthzAuditEvent authzEvent = (AuthzAuditEvent) event;
if (authzEvent.getAgentHostname() == null) {
authzEvent.setAgentHostname(MiscUtil.getHostname());
}
if (authzEvent.getLogType() == null) {
authzEvent.setLogType("RangerAudit");
}
if (authzEvent.getEventId() == null) {
authzEvent.setEventId(MiscUtil.generateUniqueId());
}
try {
if (solrClient == null) {
connect();
if (solrClient == null) {
// Solr is still not initialized. So need to throw error
return false;
}
}
if (lastFailTime > 0) {
long diff = System.currentTimeMillis() - lastFailTime;
if (diff < retryWaitTime) {
if (LOG.isDebugEnabled()) {
LOG.debug("Ignore sending audit. lastConnect=" + diff + " ms");
}
return false;
}
}
// Convert AuditEventBase to Solr document
final SolrInputDocument document = toSolrDoc(authzEvent);
final Collection<SolrInputDocument> docs = Collections.singletonList(document);
final UpdateResponse response = SolrAppUtil.addDocsToSolr(solrClient, docs);
if (response.getStatus() != 0) {
lastFailTime = System.currentTimeMillis();
// System.out.println("Response=" + response.toString()
// + ", status= " + response.getStatus() + ", event="
// + event);
// throw new Exception("Aborting. event=" + event +
// ", response="
// + response.toString());
} else {
lastFailTime = 0;
}
} catch (Throwable t) {
LOG.error("Error sending message to Solr", t);
return false;
}
return true;
}
Aggregations