blob: cb85c7d62bcf98888d75fe041b4a95077934e5a6 [file] [log] [blame]
/***********************************************************************************************************************
* Copyright (c) 2008, 2011 Attensity Europe GmbH and brox IT Solutions GmbH. All rights reserved.
* This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: Daniel Stucky (empolis GmbH) - initial API and implementation
**********************************************************************************************************************/
package org.eclipse.smila.security.processing;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.smila.blackboard.Blackboard;
import org.eclipse.smila.blackboard.BlackboardAccessException;
import org.eclipse.smila.datamodel.Any;
import org.eclipse.smila.datamodel.AnyMap;
import org.eclipse.smila.datamodel.AnySeq;
import org.eclipse.smila.datamodel.Value;
import org.eclipse.smila.processing.Pipelet;
import org.eclipse.smila.processing.ProcessingException;
import org.eclipse.smila.search.api.QueryConstants;
import org.eclipse.smila.security.SecurityAttribute;
import org.eclipse.smila.security.SecurityAttributes.AccessRightType;
import org.eclipse.smila.security.SecurityAttributes.EntityType;
import org.eclipse.smila.security.SecurityException;
import org.eclipse.smila.security.SecurityResolver;
import org.eclipse.smila.utils.service.ServiceUtils;
/**
* Sample Security Converter Pipelet.
*/
public class SampleSecurityConverterPipelet implements Pipelet {
/**
* Constant for the property readUsersAttributeName.
*/
public static final String PROP_READ_USERS_ATTRIBUTE_NAME = "readUsersAttributeName";
/**
* Constant for the property resolveGroups.
*/
public static final String PROP_RESOLVE_GROUPS = "resolveGroups";
/**
* Constant for the property resolveUserNames.
*/
public static final String PROP_RESOLVE_USER_NAMES = "resolveUserNames";
/**
* Constant for the property resolvedUserNamePropertyName.
*/
public static final String PROP_RESOLVED_USER_NAME_PROPERTY_NAME = "resolvedUserNamePropertyName";
/**
* name of annotation configuring the type of execution.
*/
public static final String EXECUTION_MODE = "_executionMode";
/**
* Types of execution modes this service supports.
*/
public enum ExecutionMode {
/**
* Add the record to the index.
*/
INDEX,
/**
* Delete the id from the index.
*/
SEARCH
};
/**
* local logger.
*/
private final Log _log = LogFactory.getLog(SampleSecurityConverterPipelet.class);
/**
* The configuration.
*/
private AnyMap _configuration;
/**
* Name of the attribute to store the users with read access in.
*/
private String _readUsersAttributeName;
/**
* Boolean flag if to resolve groups to users.
*/
private boolean _resolveGroups;
/**
* Boolean flag if to resolver users to display names.
*/
private boolean _resolveUserNames;
/**
* The property to retrieve for a user as display name.
*/
private String _resolvedUserNameProperty;
/**
* The SecurityResolver to use (optional).
*/
private SecurityResolver _securityResolver;
/**
* Reads the configuration.
*
* {@inheritDoc}
*/
@Override
public void configure(final AnyMap configuration) throws ProcessingException {
_configuration = configuration;
if (_configuration != null) {
_readUsersAttributeName = (String) _configuration.getStringValue(PROP_READ_USERS_ATTRIBUTE_NAME);
_resolveGroups = _configuration.getBooleanValue(PROP_RESOLVE_GROUPS) == null ? false : true;
_resolveUserNames = _configuration.getBooleanValue(PROP_RESOLVE_USER_NAMES) == null ? false : true;
_resolvedUserNameProperty = _configuration.getStringValue(PROP_RESOLVED_USER_NAME_PROPERTY_NAME);
} else {
_readUsersAttributeName = null;
_resolveGroups = false;
_resolvedUserNameProperty = null;
_resolveUserNames = false;
}
}
/**
* {@inheritDoc}
*/
@Override
public String[] process(Blackboard blackboard, String[] recordIds) throws ProcessingException {
for (int i = 0; i < recordIds.length; i++) {
try {
final String executionModeValue = blackboard.getMetadata(recordIds[i]).getStringValue(EXECUTION_MODE);
if (executionModeValue != null) {
final ExecutionMode executionMode = ExecutionMode.valueOf(executionModeValue);
switch (executionMode) {
case INDEX:
convertToAttributes(blackboard, recordIds[i]);
break;
case SEARCH:
convertToFilter(blackboard, recordIds[i]);
break;
default:
break;
}
}
} catch (final Exception ex) {
if (_log.isErrorEnabled()) {
_log.error("error processing record " + recordIds[i], ex);
}
}
} // for
return recordIds;
}
/**
* gets the SecurityResolver service.
*
* @return the SecurityResolver.
*/
private synchronized SecurityResolver getSecurityResolver() {
if (_securityResolver == null) {
try {
_securityResolver = ServiceUtils.getService(SecurityResolver.class);
} catch (final InterruptedException e) {
if (_log.isWarnEnabled()) {
_log.warn("Interrupted while getting SecurityResolver service.");
}
}
}
return _securityResolver;
}
/**
* Converts the security attributes into record metadata values for indexing.
*
* @param blackboard
* the BlackboardService
* @param id
* the record Id
* @throws BlackboardAccessException
* if any error occurs
* @throws SecurityException
* if any security error occurs
*/
private void convertToAttributes(final Blackboard blackboard, final String id) throws BlackboardAccessException,
SecurityException {
final SecurityAttribute sa = new SecurityAttribute(blackboard.getRecord(id));
final Set<String> readAccessRights = getReadAccessRights(sa);
if (!readAccessRights.isEmpty()) {
// create attribute and add values
final AnySeq values = blackboard.getDataFactory().createAnySeq();
for (final String value : readAccessRights) {
values.add(value);
}
blackboard.getMetadata(id).put(_readUsersAttributeName, values);
}
if (_log.isTraceEnabled()) {
_log.trace("converted security information for id " + id + " into attribute values");
}
}
/**
* Converts the security information of a record into a query filter and appends it to the query.
*
* @param blackboard
* the BlackboardService
* @param id
* the record Id
* @throws BlackboardAccessException
* if any error occurs
* @throws SecurityException
* if any security error occurs
*/
private void convertToFilter(final Blackboard blackboard, final String id) throws BlackboardAccessException,
SecurityException {
final SecurityAttribute sa = new SecurityAttribute(blackboard.getRecord(id));
final Set<String> readAccessRights = getReadAccessRights(sa);
if (!readAccessRights.isEmpty()) {
/* filter structure in search request record:
<Seq key="filter">
<Map>
<Val key="attribute">_readUsersAttributeName</Val>
<Seq key="oneOf">
<Val>pratchett</Val>
<Val>adams</Val>
</Seq>
</Map>
<Map>
<Val key="attribute">...</Val>
...
</Map>
</Seq>
*/
// get filter section (create filter section if it doesn't exist)
AnySeq filterSection = (AnySeq) blackboard.getRecord(id).getMetadata().get(QueryConstants.FILTER);
if (filterSection == null) {
filterSection = blackboard.getDataFactory().createAnySeq();
blackboard.getRecord(id).getMetadata().put(QueryConstants.FILTER, filterSection);
}
// find filter section for attribute (create if it doesn't exist)
AnyMap filterSectionForAttribute = null;
for (final Any filterSectionEntry : filterSection) {
if (_readUsersAttributeName.equals(((AnyMap) filterSectionEntry).getStringValue(QueryConstants.ATTRIBUTE))) {
filterSectionForAttribute = (AnyMap) filterSectionEntry;
}
}
if (filterSectionForAttribute == null) {
filterSectionForAttribute = blackboard.getDataFactory().createAnyMap();
filterSectionForAttribute.put(QueryConstants.ATTRIBUTE, _readUsersAttributeName);
filterSection.add(filterSectionForAttribute);
}
// create security "oneOf" filter and put new filter in attribute's filter section
final AnySeq oneOfFilter = blackboard.getDataFactory().createAnySeq();
for (final String value : readAccessRights) {
oneOfFilter.add(value);
}
filterSectionForAttribute.put(QueryConstants.FILTER_ONEOF, oneOfFilter);
// ensure that the attribute exists (some search engines need attribute value when applying filters)
if (!blackboard.getMetadata(id).containsKey(_readUsersAttributeName)) {
blackboard.getMetadata(id).put(_readUsersAttributeName, "dummy");
}
}
if (_log.isTraceEnabled()) {
_log.trace("converted security information for id " + id + " into query filter");
}
}
/**
* Gets the access rights values from the security information. Depending on the configuration the return values are
* the plain values provided by a crawler/search client or are resolved against a SecurityResolver.
*
* @param sa
* the SecurityAnnotation
* @return a Set of Strings containing the values
* @throws BlackboardAccessException
* if any error occurs
* @throws SecurityException
* if any security error occurs
*/
private Set<String> getReadAccessRights(final SecurityAttribute sa) throws BlackboardAccessException,
SecurityException {
final HashSet<String> accessRights = new HashSet<String>();
final AnySeq users = sa.getAccessRights(AccessRightType.READ, EntityType.PRINCIPALS);
final SecurityResolver securityResolver = getSecurityResolver();
// check if there was a security resolver set, else skip any resolving
if (securityResolver != null) {
if (users != null) {
for (final Any user : users) {
final String userDN = securityResolver.resolvePrincipal(((Value) user).asString());
accessRights.add(userDN);
}
}
// check if to resolve members of groups
if (_resolveGroups) {
final AnySeq groups = sa.getAccessRights(AccessRightType.READ, EntityType.GROUPS);
if (groups != null) {
for (final Any group : groups) {
final String groupDN = securityResolver.resolvePrincipal(((Value) group).asString());
final Set<String> groupMembers = securityResolver.resolveGroupMembers(groupDN);
accessRights.addAll(groupMembers);
} // for
} // if
} // if
// check if to resolve user names to some display name
final Set<String> displayNames;
if (_resolveUserNames) {
displayNames = new HashSet<String>();
for (final String principalDN : accessRights) {
final Map<String, Collection<String>> properties = securityResolver.getProperties(principalDN);
final Collection<String> resolvedUserNames = properties.get(_resolvedUserNameProperty);
if (resolvedUserNames != null && !resolvedUserNames.isEmpty()) {
displayNames.add(resolvedUserNames.iterator().next());
}
} // for
} else {
displayNames = accessRights;
}
return displayNames;
} else {
if (users != null) {
for (final Any user : users) {
accessRights.add(((Value) user).asString());
}
}
return accessRights;
}
}
}