Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

SMILA/Documentation/Security

Description

This page is about Security in SMILA (Authorization). Records may be associated with security information, services may use security information to restrict/grant access on data (records). The best known use case is indexing of documents with restricted access rights and filtering search results for users that have access rights on those documents. The basic idea is that a record created by either an Agent/Crawler or via the Search API can optionally contain "raw" security information. This "raw" security information is processed by special Pipelets in the executed pipeline that prepare the security information to be useable by some service (e.g. for the former mentioned use case the security information is stored with the record's metadata in a search index or a filter is created to restrict search results to those documents the user has access to).

Authentication (e.g. login to a SMILA based web application) is not in the scope of this document.

Datamodel

The datamodel is designed to be flexible by simply using record metadata, allowing many kinds of access rights types (e.g. Read, Write) for any kind of security principal (e.g. users, groups, roles). The name of the base metadata attribute containing security information is ACCESS_RIGHTS. It contains sub-elements for the various access right types. Currently the predefined types READ and WRITE are defined. These in turn contain sub-elements for entities for which these access right type apply. There are two entity types defined: PRINCIPALS and GROUPS. The elements contain the entity names as values. Here is the XML representation of the security metadata:

<Map key="ACCESS_RIGHTS">
    <Map key="%ACCESS_RIGHT_TYPE%">
        <Seq key="%ENTITY_TYPE%">
            <Val>%VALUE%</Val>
            ...
        </Map>
        ...
    </Map>
    ...
</Map>

For example

<Map key="ACCESS_RIGHTS">
    <Map key="READ">
        <Seq key="PRINCIPALS">
            <Val>0815</Val>
        </Seq>
        <Seq n="GROUPS">
            <Val>4711</Val>
            <Val>2525</Val>
        </Seq>
    </Map>
    <Map key="WRITE">
        <Seq key?"PRINCIPALS">
            <Val>0815</Val>
        </Seq>
    </Map>
</Map>


There are utility classes in bundle org.eclipse.smila.security that contain constant definitions for the metadata elements (class SecurityAnnotations) and a helper to create and access the security metadata (class SecurityAnnotation).


Processing of Security Annotations

During processing of records the security metadata has to be processed, too. In most cases the security information needs to be passed to other Pipelets and therefore the security information has to be converted. We distinguish between real conversion and resolving of security information (this list may not be complete):

  • Converters
    • preparations for Search Index (e.g. converting to an appropriate attribute representation)
    • combining data source and security information (like adding a domain or data source Id prefix to the security information)
  • Resolvers
    • resolve a Principals Sub-Principals (e.g. members of a group, subgroups of a group)
    • resolve a Principals Membership (e.g. get all groups the user is a member of)
    • resolve properties of a Principal (e.g. human readable names of Principal IDs)

Converters are implemented as Pipelets. They may be either generic or specific, usable in only indexing pipelines, search pipelines or both. There is a sample Converter SampleSecurityConverterPipelet available in bundle org.eclipse.smila.security.processing that is usable for indexing and search. It either converts security information into one attribute so that it's indexable by Lucene or into a filter for search. For more information check out the bundle documentation.

Resolvers are implemented as OSGi servces. They can be used by Converters or any other SMILA component (e.g. by some login component of a search application). Bundle org.eclipse.smila.security.ldap contains an LDAPSecurityResolver that offers the functionality to resolve principals against an LDAP directory. For more information see LDAPSecurityResolver.

Here is an illustration of the architecture of security resolvers and converters. Note that the usage of Converters and/or Resolvers is optional: architecture of security resolvers and converters


The interface for SecurityResolvers is also located in bunlde org.eclipse.smila.security.

public interface SecurityResolver {
 
  /**
   * Resolves a given name to a full form principal (e.g. a distinguished name).
   * @param name the name of the principal
   * @return the full form principal
   * @throws SecurityException if any error occurs
   */
  String resolvePrincipal(String name) throws SecurityException;
 
  /**
   * Returns all properties of the given principal. The properties are a map of attribute names (String) and attribute
   * values (Collection of Strings).
   * 
   * @param principal
   *          the principal
   * @return all properties if the principal
   * @throws SecurityException
   *           if any error occurs
   */
  Map<String, Collection<String>> getProperties(String principal) throws SecurityException;
 
  /**
   * Returns all principals that are member to the given group, including any subgroups.
   * 
   * @param group
   *          the group principal
   * @return a set of all principals that are members of this group
   * @throws SecurityException
   *           if any error occurs
   */
  Set<String> resolveGroupMembers(String group) throws SecurityException;
 
  /**
   * Returns all groups the given principal is member of.
   * 
   * @param principal
   *          the principal
   * @return a set of group principals the principal is member of
   * @throws SecurityException
   *           if any error occurs
   */
  Set<String> resolveMembership(String principal) throws SecurityException;
 
  /**
   * Checks if the given principal is a group.
   * 
   * @param principal
   *          the principal
   * @return true if the principal is a group, false otherwise
   * @throws SecurityException
   *           if any error occurs
   */
  boolean isGroup(String principal) throws SecurityException;
}


Here is a more detailed description of the security annotation processing for the use cases Indexing and Search. The samples make use the SampleSecurityProvider and LDAPSecurityResolver:

Indexing

During Indexing the security information for a record is read from the datasource by Crawlers/Agents, which create the ACCESS_RIGHTS metadata and store them in the record. Crawlers/Agents pass the security information as provided by the data source (at the moment no Crawler/Agent implementation supports this feature). All further processing of the security information is done by the Security Converters/Resolvers. Here is an example for the ACCESS_RIGHTS record metadata provided by a windows filesystem crawler:

<Map key="ACCESS_RIGHTS">
    <Map key="READ">
        <Map key="PRINCIPALS">
            <Val>0815</Val> <!-- an unmodified user id -->
        </Map>
        <Map n="GROUPS">
            <Val>4711</Val> <!-- an unmodified group id -->
            <Val>2525</Val> <!-- an unmodified group id -->
        </Map>
    </Map>
</Map>


Before storing a record in a search index, the security metadata has to be converted to metadata attributes that are indexable. The SampleSecurityConverterPipelet (used in index mode) will do this transformation. The basic result is just a conversion of the READ PRINCIPALS:

<Seq n="ReadUsers">
    <Val>0815</Val> <!-- an unmodified user id -->    
</Seq>

By using the LDAPSecurityResolver we could also resolve the group members, leading to a result like this:

<Seq n="ReadUsers">
    <Val>0815</Val> <!-- an unmodified user id -->
    <Val>666</Val> <!-- an resolved user id, member of group 4711 -->
    <Val>999</Val> <!-- an resolved user id, member of group 4711 -->
    <Val>1234</Val> <!-- an resolved user id, member of group 2525 -->
    <Val>6789</Val> <!-- an resolved user id, member of group 2525 -->
</Seq>

In addition the LDAPSecurityResolver could also replace the user ids with some human readable display name

<Seq n="ReadUsers">
    <Val>Doe, John</Val> <!-- a user id resolved to a a human readable display name  -->
    <Val>Regular, John</Val> <!-- a user id resolved to a a human readable display name  -->
    <Val>Becker, Heinz</Val> <!-- a user id resolved to a a human readable display name  -->
    <Val>Napp, Karl</Val> <!-- a user id resolved to a a human readable display name  -->
    <Val>Heinz, Karl</Val> <!-- a user id resolved to a a human readable display name  -->
</Seq>


Search

A search client also provides security informations for the query record. This is most likely just the user id of the user executing the search.

<Map key="ACCESS_RIGHTS">
    <Map key="READ">
        <Seq key="PRINCIPALS">
            <Val>0815</Val> <!-- an unmodified user id provided by a search client -->
        </Seq>
    </Map>
</Map>


The security metadata is processed by the SampleSecurityConverterPipelet (now in search mode) that transforms the security metadata into a filter for the security attributes in the Lucene index.

<Seq key="filter">
    <Map>
        <Val key="attribute">ReadUsers</Val>
        <Seq key="oneOf">
            <Val>0815</Val> <!-- an unmodified user id provided by a search client -->
        </Seq>
    </Map>
</Seq>


If the LDAPSecurityResolver was used during indexing it must be used during search, too, resolving the display name for the user id:

<Seq key="filter">
    <Map>
        <Val key="attribute">ReadUsers</Val>
        <Seq key="oneOf">
            <Val>Doe, John</Val> <!-- a user id resolved to a a human readable display name  -->
        </Seq>
    </Map>
</Seq>


It would also be possible to pass in just group ids

<Map key="ACCESS_RIGHTS">
    <Map key="READ">
         <Seq key="GROUPS">
            <Val>4711</Val> <!-- an unmodified group id -->
            <Val>2525</Val> <!-- an unmodified group id -->
        </Seq>
    </Map>
</Map>

and resolve their member user ids and display names for them:

<Seq key="filter">
    <Map>
        <Val key="attribute">ReadUsers</Val>
        <Seq key="oneOf">
            <Val>Regular, John</Val> <!-- a user id resolved to a a human readable display name  -->
            <Val>Becker, Heinz</Val> <!-- a user id resolved to a a human readable display name  -->
            <Val>Napp, Karl</Val> <!-- a user id resolved to a a human readable display name  -->
            <Val>Heinz, Karl</Val> <!-- a user id resolved to a a human readable display name  -->
        </Seq>
    </Map>
</Seq>

Back to the top