@Override public QueryResponse processPostQuery(QueryResponse input) throws StopProcessingException { if (input.getRequest() == null || input.getRequest().getProperties() == null) { throw new StopProcessingException( "Unable to filter contents of current message, no user Subject available."); } Subject subject = getSubject(input); List<Result> results = input.getResults(); List<Result> newResults = new ArrayList<>(results.size()); Metacard metacard; KeyValueCollectionPermission securityPermission = new KeyValueCollectionPermission(CollectionPermission.READ_ACTION); int filteredMetacards = 0; for (Result result : results) { metacard = result.getMetacard(); Attribute attr = metacard.getAttribute(Metacard.SECURITY); if (!checkPermissions(attr, securityPermission, subject, CollectionPermission.READ_ACTION)) { for (FilterStrategy filterStrategy : filterStrategies.values()) { FilterResult filterResult = filterStrategy.process(input, metacard); if (filterResult.processed()) { if (filterResult.metacard() != null) { newResults.add(new ResultImpl(filterResult.metacard())); } break; // returned responses are ignored for queries } } filteredMetacards++; } else { newResults.add(result); } } LOGGER.info("Filtered {} metacards, returned {}", filteredMetacards, newResults.size()); SecurityLogger.logInfo( "Filtered " + filteredMetacards + " metacards, returned " + newResults.size()); input.getResults().clear(); input.getResults().addAll(newResults); newResults.clear(); return input; }
/** * Overrides the implies method to handle checking for the existence of one attribute - the "match * one" scenario rather than the "match all" behavior of the overridden classes. Specifically, * this permission will imply another permission if that permission matches at least one of our * permission attributes. * * @param p the permission to check for behavior/functionality comparison. * @return {@code true} if this current instance <em>implies</em> the specified {@code Permission} * argument, {@code false} otherwise. */ @Override public boolean implies(Permission p) { if (permissionList.isEmpty()) { SecurityLogger.logDebug( PERMISSION_START_MSG + toString() + PERMISSION_NOT_IMPLIES_MSG + p.toString() + PERMISSION_END_MSG); return false; } if (p instanceof CollectionPermission) { for (Permission perm : ((CollectionPermission) p).getPermissionList()) { boolean result = false; for (Permission ourPerm : permissionList) { // we only care about the key value permission here, because that one can have // multiple values // mapped to a single key. In the case of "match one" we only need one of those // values to satisfy // the permission. if (ourPerm instanceof KeyValuePermission) { for (String value : ((KeyValuePermission) ourPerm).getValues()) { // Since this is "match one" we know that only one of these values needs // to match in order // for the entire permission at that key to be implied // So here we loop through all of the values assigned to that key and // create new // single valued key value permissions KeyValuePermission kvp = new KeyValuePermission(((KeyValuePermission) ourPerm).getKey()); kvp.addValue(value); if (perm.implies(kvp)) { result = true; break; } } // Currently we use key value permissions for everything. However, we still need // to be able to handle // permissions other than KV, so this else block will serve as the catch all for // everything else. } else { // Shiro permissions are always a "match all" condition so we need to flip // the implies to make it match one if (perm.implies(ourPerm)) { result = true; break; } } } if (!result) { SecurityLogger.logDebug( PERMISSION_START_MSG + toString() + PERMISSION_NOT_IMPLIES_MSG + p.toString() + PERMISSION_END_MSG); return false; } } SecurityLogger.logDebug( PERMISSION_START_MSG + toString() + PERMISSION_IMPLIES_MSG + p.toString() + PERMISSION_END_MSG); return true; } // default catch all permission check for (Permission permission : permissionList) { // Shiro permissions are always a "match all" condition so we need to flip the implies // to make it match one if (p.implies(permission)) { SecurityLogger.logDebug( PERMISSION_START_MSG + toString() + PERMISSION_IMPLIES_MSG + p.toString() + PERMISSION_END_MSG); return true; } } SecurityLogger.logDebug( PERMISSION_START_MSG + toString() + PERMISSION_NOT_IMPLIES_MSG + p.toString() + PERMISSION_END_MSG); return false; }
@Override public boolean[] isPermitted(PrincipalCollection subjectPrincipal, List<Permission> permissions) { boolean[] results = new boolean[permissions.size()]; AuthorizationInfo info = getAuthorizationInfo(subjectPrincipal); Permission curPermission; boolean curResponse; String curAction; for (int i = 0; i < permissions.size(); i++) { curPermission = permissions.get(i); if (curPermission instanceof ActionPermission) { curAction = ((ActionPermission) curPermission).getAction(); logger.debug( "Checking if {} has access to perform a {} action", subjectPrincipal.getPrimaryPrincipal(), curAction); SecurityLogger.logInfo( "Checking if [" + subjectPrincipal.getPrimaryPrincipal() + "] has access to perform a [" + curAction + "] action"); logger.debug("Received authZ info, creating XACML request."); RequestType curRequest = createActionXACMLRequest( (String) subjectPrincipal.getPrimaryPrincipal(), info, curAction); logger.debug("Created XACML request, calling PDP."); curResponse = isPermitted(curRequest); logger.debug("Received response from PDP, returning {}.", curResponse); results[i] = curResponse; } else if (curPermission instanceof KeyValueCollectionPermission) { logger.debug( "Checking if {} has access to current metacard", subjectPrincipal.getPrimaryPrincipal()); SecurityLogger.logInfo( "Checking if [" + subjectPrincipal.getPrimaryPrincipal() + "] has access to view current metacard"); logger.debug("Received authZ info, creating XACML request."); RequestType curRequest = createRedactXACMLRequest( (String) subjectPrincipal.getPrimaryPrincipal(), info, (KeyValueCollectionPermission) curPermission); logger.debug("Created XACML request, calling PDP."); curResponse = isPermitted(curRequest); logger.debug("Received response from PDP, returning {}.", curResponse); results[i] = curResponse; } else if (curPermission instanceof KeyValuePermission) { // Need to refactor this into a private method with the above condition // This is to handle the case where there is a single KeyValuePermission logger.debug( "Checking if {} has access to current metacard", subjectPrincipal.getPrimaryPrincipal()); SecurityLogger.logInfo( "Checking if [" + subjectPrincipal.getPrimaryPrincipal() + "] has access to view current metacard"); KeyValueCollectionPermission keyValueCollectionPermission = new KeyValueCollectionPermission((KeyValuePermission) curPermission); logger.debug("Received authZ info, creating XACML request."); RequestType curRequest = createRedactXACMLRequest( (String) subjectPrincipal.getPrimaryPrincipal(), info, keyValueCollectionPermission); logger.debug("Created XACML request, calling PDP."); curResponse = isPermitted(curRequest); logger.debug("Received response from PDP, returning {}.", curResponse); results[i] = curResponse; } else { logger.warn( "Could not check permissions with {}, permission being requested MUST be an ActionPermission or RedactionPermission", curPermission); results[i] = false; } } return results; }
QuerySources initializeSources( QueryOperations queryOps, QueryRequest queryRequest, Set<String> sourceIds) { if (queryRequest.isEnterprise()) { // Check if it's an enterprise query addConnectedSources = true; addCatalogProvider = queryOps.hasCatalogProvider(); if (sourceIds != null && !sourceIds.isEmpty()) { LOGGER.debug("Enterprise Query also included specific sites which will now be ignored"); sourceIds.clear(); } // add all the federated sources Set<String> notPermittedSources = new HashSet<>(); for (FederatedSource source : frameworkProperties.getFederatedSources().values()) { boolean canAccessSource = queryOps.canAccessSource(source, queryRequest); if (!canAccessSource) { notPermittedSources.add(source.getId()); } if (queryOps.sourceOperations.isSourceAvailable(source) && canAccessSource) { sourcesToQuery.add(source); } else { exceptions.add(queryOps.createUnavailableProcessingDetails(source)); } } if (!notPermittedSources.isEmpty()) { SecurityLogger.audit( "Subject is not permitted to access sources {}", notPermittedSources); } } else if (CollectionUtils.isNotEmpty(sourceIds)) { // it's a targeted federated query if (queryOps.includesLocalSources(sourceIds)) { LOGGER.debug("Local source is included in sourceIds"); addConnectedSources = CollectionUtils.isNotEmpty(frameworkProperties.getConnectedSources()); addCatalogProvider = queryOps.hasCatalogProvider(); sourceIds.remove(queryOps.getId()); sourceIds.remove(null); sourceIds.remove(""); } // See if we still have sources to look up by name if (!sourceIds.isEmpty()) { Set<String> notPermittedSources = new HashSet<>(); for (String id : sourceIds) { LOGGER.debug("Looking up source ID = {}", id); boolean sourceFound = false; if (frameworkProperties.getFederatedSources().containsKey(id)) { sourceFound = true; boolean canAccessSource = queryOps.canAccessSource( frameworkProperties.getFederatedSources().get(id), queryRequest); if (!canAccessSource) { notPermittedSources.add(frameworkProperties.getFederatedSources().get(id).getId()); } if (frameworkProperties.getFederatedSources().get(id).isAvailable() && canAccessSource) { sourcesToQuery.add(frameworkProperties.getFederatedSources().get(id)); } else { exceptions.add( queryOps.createUnavailableProcessingDetails( frameworkProperties.getFederatedSources().get(id))); } } if (!sourceFound) { exceptions.add( new ProcessingDetailsImpl( id, new SourceUnavailableException("Source id is not found"))); } } if (!notPermittedSources.isEmpty()) { SecurityLogger.audit( "Subject is not permitted to access sources {}", notPermittedSources); } } } else { // default to local sources addConnectedSources = CollectionUtils.isNotEmpty(frameworkProperties.getConnectedSources()); addCatalogProvider = queryOps.hasCatalogProvider(); } return this; }