org.eclipse.smila.security.processing.SampleSecurityConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.smila.security.processing.SampleSecurityConverter.java

Source

/***********************************************************************************************************************
 * 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);
        }
    }
}