Search in sources :

Example 16 with AuthzAuditEvent

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);
    }
}
Also used : AuthzAuditEvent(org.apache.ranger.audit.model.AuthzAuditEvent) RangerAccessResult(org.apache.ranger.plugin.policyengine.RangerAccessResult)

Example 17 with AuthzAuditEvent

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()");
    }
}
Also used : AuthzAuditEvent(org.apache.ranger.audit.model.AuthzAuditEvent) AccessDeniedException(org.apache.hadoop.hbase.security.AccessDeniedException)

Example 18 with AuthzAuditEvent

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;
}
Also used : AccessDeniedException(org.apache.hadoop.hbase.security.AccessDeniedException) User(org.apache.hadoop.hbase.security.User) Set(java.util.Set) NavigableSet(java.util.NavigableSet) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AuthzAuditEvent(org.apache.ranger.audit.model.AuthzAuditEvent) Map(java.util.Map) HashMap(java.util.HashMap) HashSet(java.util.HashSet)

Example 19 with AuthzAuditEvent

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;
}
Also used : AuthzAuditEvent(org.apache.ranger.audit.model.AuthzAuditEvent)

Example 20 with AuthzAuditEvent

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;
}
Also used : AuthzAuditEvent(org.apache.ranger.audit.model.AuthzAuditEvent) UpdateResponse(org.apache.solr.client.solrj.response.UpdateResponse) SolrInputDocument(org.apache.solr.common.SolrInputDocument)

Aggregations

AuthzAuditEvent (org.apache.ranger.audit.model.AuthzAuditEvent)23 ArrayList (java.util.ArrayList)3 AccessDeniedException (org.apache.hadoop.hbase.security.AccessDeniedException)2 User (org.apache.hadoop.hbase.security.User)2 RangerAccessRequest (org.apache.ranger.plugin.policyengine.RangerAccessRequest)2 RangerAccessResource (org.apache.ranger.plugin.policyengine.RangerAccessResource)2 RangerAccessResult (org.apache.ranger.plugin.policyengine.RangerAccessResult)2 UpdateResponse (org.apache.solr.client.solrj.response.UpdateResponse)2 SolrInputDocument (org.apache.solr.common.SolrInputDocument)2 BufferedReader (java.io.BufferedReader)1 File (java.io.File)1 FileReader (java.io.FileReader)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 NavigableSet (java.util.NavigableSet)1 Properties (java.util.Properties)1 Set (java.util.Set)1 HTableDescriptor (org.apache.hadoop.hbase.HTableDescriptor)1