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

Java tutorial

Introduction

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

Source

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