Java tutorial
/*********************************************************************************************************************** * Copyright (c) 2008 empolis 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.io.InputStream; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.xml.bind.Unmarshaller; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.smila.blackboard.BlackboardAccessException; import org.eclipse.smila.blackboard.Blackboard; import org.eclipse.smila.blackboard.path.Path; import org.eclipse.smila.datamodel.id.Id; import org.eclipse.smila.datamodel.record.Annotation; import org.eclipse.smila.datamodel.record.Literal; import org.eclipse.smila.processing.ProcessingException; import org.eclipse.smila.processing.ProcessingService; import org.eclipse.smila.processing.configuration.PipeletConfiguration; import org.eclipse.smila.processing.configuration.PipeletConfigurationLoader; import org.eclipse.smila.processing.parameters.SearchAnnotations; import org.eclipse.smila.security.SecurityAnnotation; import org.eclipse.smila.security.SecurityException; import org.eclipse.smila.security.SecurityResolver; import org.eclipse.smila.security.SecurityAnnotations.AccessRightType; import org.eclipse.smila.security.SecurityAnnotations.EntityType; import org.eclipse.smila.utils.config.ConfigUtils; import org.osgi.service.component.ComponentContext; /** * Sample Security Converter Index Service. */ public class SampleSecurityConverter implements ProcessingService { /** * name of bundle. Used in configuration reading. */ public static final String BUNDLE_NAME = "org.eclipse.smila.security.processing"; /** * name of configuration file. Hardcoded for now (or fallback), configuration properties should be received from * configuration service later. */ public static final String CONFIG_FILE = "SampleSecurityConverter.xml"; /** * 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(SampleSecurityConverter.class); /** * The configuration. */ private PipeletConfiguration _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; /** * DS activate method. * * @param context * ComponentContext * * @throws Exception * if any error occurs */ protected void activate(final ComponentContext context) throws Exception { try { // load configuration if (_configuration == null) { readConfiguration(); _readUsersAttributeName = (String) _configuration .getPropertyFirstValueNotNull(PROP_READ_USERS_ATTRIBUTE_NAME); _resolveGroups = ((Boolean) _configuration.getPropertyFirstValueNotNull(PROP_RESOLVE_GROUPS)) .booleanValue(); _resolveUserNames = ((Boolean) _configuration.getPropertyFirstValueNotNull(PROP_RESOLVE_USER_NAMES)) .booleanValue(); _resolvedUserNameProperty = (String) _configuration .getPropertyFirstValueNotNull(PROP_RESOLVED_USER_NAME_PROPERTY_NAME); } } catch (final Exception e) { if (_log.isErrorEnabled()) { _log.error("error initializing SampleSecurityConverter", e); } throw e; } } /** * DS deactivate method. * * @param context * the ComponentContext * * @throws Exception * if any error occurs */ protected void deactivate(final ComponentContext context) throws Exception { try { _configuration = null; _readUsersAttributeName = null; _resolvedUserNameProperty = null; } catch (final Exception e) { if (_log.isErrorEnabled()) { _log.error("error deactivating SampleSecurityConverter", e); } throw e; } } /** * Sets the _securityResolver. Used by OSGi Declarative Services. * * @param securityResolver * the SecurityResolver to set */ public void setSecurityResolver(final SecurityResolver securityResolver) { _securityResolver = securityResolver; } /** * Set the _securityResolver to null. Used by OSGi Declarative Services. * * @param securityResolver * the SecurityResolver to unset */ public void unsetSecurityResolver(final SecurityResolver securityResolver) { if (_securityResolver == securityResolver) { _securityResolver = null; } } /** * {@inheritDoc} * * @see org.eclipse.smila.processing.ProcessingService#process(Blackboard, Id[]) */ public Id[] process(final Blackboard blackboard, final Id[] recordIds) throws ProcessingException { for (int i = 0; i < recordIds.length; i++) { try { final Annotation pipeletAnnotation = blackboard.getAnnotation(recordIds[i], null, getClass().getName()); if (pipeletAnnotation != null) { final String executionModeValue = pipeletAnnotation.getNamedValue(EXECUTION_MODE); final ExecutionMode executionMode = ExecutionMode.valueOf(executionModeValue); switch (executionMode) { case INDEX: convertToAttributes(blackboard, recordIds[i]); break; case SEARCH: converteToFilter(blackboard, recordIds[i]); break; default: break; } } } catch (final Exception ex) { if (_log.isErrorEnabled()) { _log.error("error processing record " + recordIds[i], ex); } } } // for return recordIds; } /** * Converts the security annotations of a record into an attribute with 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 Id id) throws BlackboardAccessException, SecurityException { final SecurityAnnotation sa = new SecurityAnnotation(blackboard.getRecord(id)); final Set<String> readAccessRights = getReadAccessRights(sa); if (!readAccessRights.isEmpty()) { // create attribute and add values final Path path = new Path(_readUsersAttributeName); for (String value : readAccessRights) { final Literal literal = blackboard.getRecord(id).getFactory().createLiteral(); literal.setStringValue(value); blackboard.addLiteral(id, path, literal); } } if (_log.isTraceEnabled()) { _log.trace("converted security annotations for id " + id + " into attribute values"); } } /** * Converts the security annotations 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 converteToFilter(final Blackboard blackboard, final Id id) throws BlackboardAccessException, SecurityException { final SecurityAnnotation sa = new SecurityAnnotation(blackboard.getRecord(id)); final Set<String> readAccessRights = getReadAccessRights(sa); if (!readAccessRights.isEmpty()) { // create enumeration filter and add it to the configured _readUsersAttributeName final Annotation filter = blackboard.getRecord(id).getFactory().createAnnotation(); filter.setNamedValue(SearchAnnotations.FILTER_TYPE, SearchAnnotations.FilterType.ENUMERATION.toString()); filter.setNamedValue(SearchAnnotations.FILTER_MODE, SearchAnnotations.FilterMode.ANY.name()); for (String value : readAccessRights) { filter.addAnonValue(value); } final Path readUsersAttributePath = new Path(_readUsersAttributeName); // ensure that the attribute exists if (!blackboard.hasAttribute(id, readUsersAttributePath)) { final Literal literal = blackboard.getRecord(id).getFactory().createLiteral(); literal.setStringValue("dummy"); blackboard.addLiteral(id, readUsersAttributePath, literal); } blackboard.getRecord(id).getMetadata().getAttribute(_readUsersAttributeName) .addAnnotation(SearchAnnotations.FACET_FILTER, filter); blackboard.addAnnotation(id, readUsersAttributePath, SearchAnnotations.FACET_FILTER, filter); } if (_log.isTraceEnabled()) { _log.trace("converted security annotations for id " + id + " into query filter"); } } /** * Gets the access rights values from the security annotations. 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(SecurityAnnotation sa) throws BlackboardAccessException, SecurityException { final HashSet<String> accessRights = new HashSet<String>(); final Collection<String> users = sa.getAccessRights(AccessRightType.READ, EntityType.PRINCIPALS) .getAnonValues(); // check if there was a security resolver set, else skip any resolving if (_securityResolver != null) { if (users != null) { for (String user : users) { final String userDN = _securityResolver.resolvePrincipal(user); accessRights.add(userDN); } } // check if to resolve members of groups if (_resolveGroups) { final Collection<String> groups = sa.getAccessRights(AccessRightType.READ, EntityType.GROUPS) .getAnonValues(); if (groups != null) { for (String group : groups) { final String groupDN = _securityResolver.resolvePrincipal(group); final Set<String> groupMembers = _securityResolver.resolveGroupMembers(groupDN); accessRights.addAll(groupMembers); } // for } // if } // if // check if to resolve user names to some display name Set<String> displayNames = new HashSet<String>(); if (_resolveUserNames) { for (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) { accessRights.addAll(users); } return accessRights; } } /** * Read configuration property file. * * @throws ProcessingException * error reading configuration file */ private void readConfiguration() throws ProcessingException { InputStream configurationFileStream = null; try { configurationFileStream = ConfigUtils.getConfigStream(BUNDLE_NAME, CONFIG_FILE); final Unmarshaller unmarshaller = PipeletConfigurationLoader.createPipeletConfigurationUnmarshaller(); _configuration = (PipeletConfiguration) unmarshaller.unmarshal(configurationFileStream); } catch (final Exception ex) { if (_log.isErrorEnabled()) { _log.error("Could not read configuration property file " + CONFIG_FILE, ex); } throw new ProcessingException("Could not read configuration property file " + CONFIG_FILE, ex); } finally { IOUtils.closeQuietly(configurationFileStream); } } }