Access Keys:
Skip to content (Access Key - 0)

CSM

Simplified CSM View Developer Guide

There are a variety of situations in which you may need to write custom code to integrate instance-level security based on the CSM authorization model with a caGrid service. These situations include:

  • A data service based on a non-relational data store with CQL processor that only supports a subset of CQL.
  • A service that needs instance-level authorizations for operations other than READ.

The CQL_CSM library includes some Java code to help with these situations by providing easy access to information in the CSM authorization model. This code is built to use a simplified view of the authorization model. There are also some things to help manage PostgreSQL database tables that contain the CSM authorization model.

Contents

The Simplified Database View

Determining what, if any, privileges a user has on a protection element involves a query that uses data from eight different tables. Organizing the data in this way provides some ease and flexibility for administering the authorization model. However, when determining what privileges a user has on a protection element, this complexity is not helpful. All that is needed to determine authorizations is valid combinations of users, privileges and protection elements.

To hide this complexity, the CQL_CSM library provides a single view that contains just the needed columns. The name of this view is CSM_USER_PROTECTION_ELEMENTS. The CSM_USER_PROTECTION_ELEMENTS view has these columns:

Column Description
LOGIN_NAME The identity of the user that this row is for.
PRIVILEGE_NAME The name of the privilege that this row is for.
APPLICATION_ID The numeric ID of the application that the protection element belongs to.
OBJECT_ID The OBJECT_ID column of the protection element.
ATTRIBUTE The ATTRIBUTE column of the protection element.
ATTRIBUTE_VALUE The ATTRIBUTE_VALUE column of the protection element.
PROTECTION_ELEMENT_TYPE The PROTECTION_ELEMENT_TYPE column of the protection element.

To get the definition of this view and the rest of the CQL_CSM library, you will need to download the library.

Creating and Managing the CSM Database

This discussion assumes that you have downloaded and unpacked the library. It also assumes that an environment variable named CSM_CQL_LOCATION is defined with a value that is the absolute path of the root directory of the library's directory structure.

The SQL script that creates the CSM_USER_PROTECTION_ELEMENTS view is in the file $CSM_CQL_LOCATION//CSM_pg/UserProtectionElements.sql. You can use PostgreSQL's psql or another interactive SQL tool to run this script. Using this script in this stand-alone way is most useful if you want to add the view to an existing database. However if you want to create an entire set of CSM tables or create an new database with a set of CSM tables, then there is an ant script that will do all of these things and create the CSM_USER_PROTECTION_ELEMENTS view.

There are a few things you must do to prepare before running the ant script:

  • You will need to make sure that PosegreSQL is installed. The ant script was tested with PostgreSQL 8.1, but more recent versions should work.
  • You will need to create some user IDs (described below).
  • You will need to download and prepare the CQL_CSM library (described below).
  • You will need to modify the script with the name of the database to be created (described below).

The ant script assumes these three user IDs are defined in the PostgreSQL instance:

  • One user must be have the ID csm. This user must be created with CREATEDB. The csm user is the user will own the CSM tables. The csm user ID will not be used for any runtime or production purposes.
  • One user must have the ID csm_adm. This user ID will be granted permissions needed to modify the contents of the CSM tables. The CSM service should be configured to use the csm_adm ID for connecting to the database.
  • The other user must have the ID csm_app. This user ID will be granted read-only access to the CSM tables. Your data service should use the csm_app ID for connecting to the database.

Download the CQL_CSM library, if you have not already done so. Unpack the .zip file. For the convenience of these instructions, define an environment variable named CQL_CSM_LOCATION whose value is the absolute path of the root directory of the CQL_CSM library directory structure.

To ensure that drivers and any other needed externally supplied files are available to the ant script, issue these commands:

Linux &
Macintosh
 cd $CQL_CSM_LOCATION 
 ant resolve 
Windows  cd %CQL_CSM_LOCATION% 
 ant resolve 

In the CQL_CSM_LOCATION directory is a file named build.xml. Change the line in the file that looks like

<property name="csm.postgresql.csm.dbname" value="ivi_csm"/>

so that the value of the property is the name of the database your data service will be using. For example, if the name of the database is snpdb, then change the line to look like

<property name="csm.postgresql.csm.dbname" value="snpdb"/>

To create or replace the CSM database, issue these commands:

Linux &
Macintosh
 cd $CQL_CSM_LOCATION 
 ant createPostgresqlCsmDatabase 
Windows  cd %CQL_CSM_LOCATION% 
 ant createPostgresqlCsmDatabase 

To create or replace just the CSM tables in an existing database, issue these commands:

Linux &
Macintosh
 cd $CQL_CSM_LOCATION 
 ant createPostgresqlTables 
Windows  cd %CQL_CSM_LOCATION% 
 ant createPostgresqlTables 

The first time that you issue either of these commands, it will prompt you for some information about your database. It collects this information in the file $CQL_CSM_LOCATION/CSM_pg/csm.properties. Subsequent times that you issue these commands they will not prompt you for this information. Instead, they will read the stored information from the file. If you want to enter different information, then edit or delete the file.

The $CQL_CSM_LOCATION/CSM_pg/csm.properties file created by the ant script can be useful for configuring the data service you are working on. It can also be used to configure the CSM service (discussed below).

The csm.properties file can be useful for configuring your data service to access the database that contains the CSM tables. The properties given values in this file include:

Property Typical Value Description
csm.database.driver org.postgresql.Driver The class to use for the JDBC driver.
csm.database.host localhost The name of the database host
csm.database.port 5432 The port number that the database server uses.
csm.database.dbname csm The name of the database to use.
csm.database.url jdbc:postgresql://localhost:5432/csm The URL to use for JDBC connections
csm.database.user csm_app The user ID that the data service will use to connect to the CSM database.
csm.database.password   The password that the data service will use to connect to the CSM database.
csm.dbadmin.user csm_adm The user ID that will be used by an administration tool such as the CSM service to connect to the CSM database.
csm.dbadmin.password   The password that will be used by an administration tool such as the CSM service to connect to the CSM database.
csm.dbowner.user csm The user ID that owns the CSM tables.
csm.dbowner.password   The password for the user ID that will own the CSM tables.
csm.appName   The name that will be used to identify the data service that consumes the authorization model in the authorization model

To administer the CSM authorization model contained in the CSM tables, we recommend that you use the CSM Service and its GAARDS-based client UI. You should install version 1.3.1 of the CSM service on the same host as your data service. You can download the CSM service and its client UI from the Inventrio downloads page.

The csm.properties file you created in the previous step can be used to configure the CSM service. When you get to the place in the CSM service installation instructions where it tells you to edit a file named csm.properties, just copy $CSM_CQL_LOCATION/CSM_pg/csm.properties over that file.

The installation instructions for the CSM service describe a step titled, "Step 6: Initialize CSM database or tables (optional)". You should skip this step, as you have already created the database.

A Small API

A small API is provided use the CSM authorization model information in the database to perform instance-level authorization. The following paragraphs describe how to use this API. Before reading this description, it will be helpful for you to be familiar with the CSM authorization model.

If you are not already familiar with the CSM authorization model it is recommended that you first read a high-level description of the model. To become more familiar with the details of the model, read the description of how to configure instance-level authorization.

The main class that you will be using to access the authorization model is edu.emory.cci.cqlCsm.CsmDatabaseAccess. In any class that will be using the authorization model you should have an import like this:

import edu.emory.cci.cqlCsm.CsmDatabaseAccess;

There is just one instance of the CsmDatabaseAccess class. You access the instance of the CsmDatabaseAccess by calling its getInstance method like this:

CsmDatabaseAccess csm = CsmDatabaseAccess.getInstance();

The first time that you call this getInstance method, it will access some information in the CSM database. The way that the CsmDatabaseAccess class knows how to access the database is by reading the csm.properties file whose creation is described in the preceding section of this page. In order for the CsmDatabaseAccess class to find the csm.properties file, you will need to copy it to the etc directory in your data service's build tree. Once you have copied the csm.properties file to that directory, you can deploy your service to its container and the csm.properties file will be where it will be found.

If you are planning to access the authorization model by directly querying the database, you will need to know the correct numeric application ID to use to identify which portions of the data model apply to your data service. You can get this application ID by first calling the CsmDatabaseAccess object's fetchApplicationId method like this:

long appId = csm.fetchApplicationId();

In addition to getting the application ID from the database, it also registers the data service in the database if it does not already have an application ID.

If you will be accessing in the authorization model only though the CsmDatabaseAccess object's other methods and not by directly querying the database, then you will not need to get the application ID.

Something that you will want to do before you query the authorization model is determine the identity of the user whose authorization is to be determined. We can get that information from globus like this:

import org.globus.wsrf.security.SecurityManager;
...
String userId = SecurityManager.getManager().getCaller();
if (userId==null || userId.length()==0) {
    throw new MalformedQueryException("Cannot authorize query for anonymous user.");
}

If you want to access the authorization model through the CsmDatabaseAccess object, you will use the getFiltersForClass method to find filters and the getAuthorizedAttributeValues to determine the authorized values for each filter's attribute.

To get the filters associated with a named class, we use code like this:

import java.util.List;
import edu.emory.cci.cqlCsm.Filter;
...
List<Filter> filterList = csm.getFiltersForClass("gov.nih.nci.ivi.genericimage.ImageDataItem");

Filter objects are just value objects that contain the values of a filter's fields as fetched from the database. If the list of filters for a class is empty, then there are no filters associated with the class and no authorizations are required to access the class. Otherwise, we need to see the the actual value we have from an instance is equal to an authorized value. This test can be done by including a test for authorized values in the query that the data service uses for its underlying data store. It can also be by filtering retrieved instances with code like this:

for (Filter thisFilter : filterList) {
    ...
    Set<String> authorizedValues = csm.getAuthorizedAttributeValues(userId,
                                                                    thisFilter.getTargetClassName(),
                                                                    thisFilter.getAttributeName());
    ...
}

We conclude this discussion of using the API with a larger example. This is from a very simple data service whose domain model is contains one class named gov.nih.nci.ivi.genericimage.ImageDataItem that has one atribute named path. The method shown in the following code is passed an actual value of the value of the path attribute from an instance of gov.nih.nci.ivi.genericimage.ImageDataItem. The method is supposed to throw an exception if the actual value of path is not an authorized value. Otherwise it returns normally.

private static void ensurePathIsAuthorized(String path) throws MalformedQueryException {
    String userId = SecurityManager.getManager().getCaller();
    if (userId == null || userId.length() == 0) {
        throw new MalformedQueryException("Cannot authorize query for anonymous user.");
    }
    CsmDatabaseAccess csm = CsmDatabaseAccess.getInstance();
    final String className = "gov.nih.nci.ivi.imagedataservice.ImageData";
    List<Filter> filterList = csm.getFiltersForClass(className);
    if (!filterList.isEmpty()) {
        for (Filter thisFilter : filterList) {
            if (!className.equals(thisFilter.getTargetClassName())) {
                String msg = "Misconfigured filter: Target class is " + thisFilter.getTargetClassName()
                        + " but the only class in the domain model is " + className;
                myLogger.error(msg);
                throw new RuntimeException(msg);
        }
        if (!className.equals(thisFilter.getAttributeName())) {
            String msg = "Misconfigured filter: Attribute is " + thisFilter.getAttributeName()
                   + " but the only attribute in the domain model is " + path;
            myLogger.error(msg);
            throw new RuntimeException(msg);
        }
        Set<String> authorizedValues = csm.getAuthorizedAttributeValues(userId, thisFilter.getTargetClassName(), thisFilter.getAttributeName());
        if (authorizedValues.contains(path)) {
            return;
        }
    }
    throw new MalformedQueryException(userId + " is not authorized to query with path " + path);
}

Including the API in your Data Service

The name of the .jar file that contains the API is cql_csm-1.3.1.jar.

There are two reasonable way to make this .jar file available to a data service. One way is to download the source, build the .jar file and then add the .jar file to the repository directory in the data service's build tree.

However, to avoid having to add the .jar file to the data service's source repository, the recommended way to include the .jar file in the data service's build is to add an ivy dependency that will copy it from CCI's repository.

Add this to the dependencies in the project's ivy.xml file:

<dependency org="edu.emory.cci" name="cql_csm" rev="1.3.1" />

Under the top-level directory of your tree, in the antfiles/ivy/ivysettings.xml file, as the last element in

<ivysettings>
  ...
  <resolvers>
    <chain>
      ...
    </chain>
  </resolvers>
</ivysettings>

add this

  <url name="cci-resolver" m2compatible="true">
    <artifact pattern="http://repo.cci.emory.edu:8081/artifactory/libs-releases-local/[organization]/[module]/[revision]/[artifact]-[revision].[ext]" />
    <artifact pattern="http://repo.cci.emory.edu:8081/artifactory/libs-releases-local/[organization]/[module]/[revision]/[artifact].[ext]" />
  </url>

The result should look like this:

<ivysettings>
  ...
  <resolvers>
    <chain>
      ...
      <url name="cci-resolver" m2compatible="true">
        <artifact pattern="http://repo.cci.emory.edu:8081/artifactory/libs-releases-local/[organization]/[module]/[revision]/[artifact]-[revision].[ext]" />
        <artifact pattern="http://repo.cci.emory.edu:8081/artifactory/libs-releases-local/[organization]/[module]/[revision]/[artifact].[ext]" />
      </url>
    </chain>
  </resolvers>
</ivysettings>
Last edited by
Mark Grand (585 days ago)
Adaptavist Theme Builder Powered by Atlassian Confluence