blob: 583a6c83590b811eee99238ec4f64dc057b168c3 [file] [log] [blame]
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* $Id$
*
* CAS-Browser Module
*
* This module provides applications a means for browsing a CAS File
* Manager catalog and obtaining products from a CAS File Manager repository.
*
* For complete functionality, the following configuration variables
* are expected to be present in the module's config.ini file:
*
* browser_filemgr_url - filemanager host (e.g.: http://somehost:9000)
* browser_filemgr_path - filemanager url on server (e.g.: /)
* browser_datadeliv_url - the base url to use when downloading products
*
* NOTE: This module has a dependency upon the CAS-Filemgr PHP classes
* (https://svn.apache.org/repos/asf/oodt/trunk/filemgr/src/main/php)
*
* To build this dependency, check out the above project and then:
* 1) cd into the checked out project (you should see a package.xml file)
* 2) pear package
* 3) (sudo) pear install --force CAS_Filemgr...tar.gz
*
* @author ahart
* @author resneck
*
*/
// Require CAS Filemgr Classes
require_once("CAS/Filemgr/BooleanQueryCriteria.class.php");
require_once("CAS/Filemgr/Element.class.php");
require_once("CAS/Filemgr/Metadata.class.php");
require_once("CAS/Filemgr/Product.class.php");
require_once("CAS/Filemgr/ProductType.class.php");
require_once("CAS/Filemgr/ProductPage.class.php");
require_once("CAS/Filemgr/Query.class.php");
require_once("CAS/Filemgr/RangeQueryCriteria.class.php");
require_once("CAS/Filemgr/TermQueryCriteria.class.php");
require_once("CAS/Filemgr/XmlRpcFilemgrClient.class.php");
require_once(dirname(__FILE__) . "/Utils.class.php");
class CasBrowser {
const VIS_INTERPRET_HIDE = 'hide';
const VIS_INTERPRET_SHOW = 'show';
const VIS_AUTH_ANONYMOUS = false;
const VIS_AUTH_AUTHENTICATED = true;
const VIS_ALL = 'all';
const VIS_LIMIT = 'limit';
const VIS_NONE = 'deny';
const VIS_DENY = 'deny';
public $client;
public function __construct() {
try {
$this->client = new CAS_Filemgr_XmlRpcFilemgrClient(
App::Get()->settings['browser_filemgr_url'],
App::Get()->settings['browser_filemgr_path']);
} catch (Exception $e) {
App::Get()->fatal("Unable to instantiate a connection to "
. App::Get()->settings['browser_filemgr_url']
. App::Get()->settings['browser_filemgr_path']);
}
}
public function getClient() {
return $this->client;
}
/**
* Use the rules in element-ordering.ini to determine the display order
* for product type metadata elements. See element-ordering.ini for more
* information on how to specify element order rules.
*
* @param integer $productTypeId The id of the product type to get met for
* @param array $metadataTouse An optional array of metadata key/vals to sort. If
* this is not provided, the product type metadata will be used.
*/
public function getSortedMetadata($productTypeId,$metadataToUse = null, $orderingAttribute) {
if (!is_array($metadataToUse)) {
$pt = $this->client
->getProductTypeById($productTypeId)
->toAssocArray();
$metadataAsArray = $pt['typeMetadata'];
} else {
$metadataAsArray = $metadataToUse;
}
$orderingPolicyFilePath = dirname(dirname(__FILE__)) . '/element-ordering.ini';
if (file_exists($orderingPolicyFilePath)) {
$orderPolicy = parse_ini_file($orderingPolicyFilePath,true);
$first = isset($orderPolicy[$productTypeId][$orderingAttribute . '.element.ordering.first'])
? $orderPolicy[$productTypeId][$orderingAttribute . '.element.ordering.first']
: $orderPolicy['*'][$orderingAttribute . '.element.ordering.first'];
$last = isset($orderPolicy[$productTypeId][$orderingAttribute . '.element.ordering.last'])
? $orderPolicy[$productTypeId][$orderingAttribute . '.element.ordering.last']
: $orderPolicy['*'][$orderingAttribute . '.element.ordering.last'];
// Using the odering policy, determine the order in which the metadata will be listed
return $this->sortMetadata($metadataAsArray,$first,$last);
} else {
return $metadataAsArray;
}
}
/**
* Retreives the set of metadata for the provided productTypeId that should be visible
* to the current user. This function also applies the sorting policy (if it is defined)
* specified in element.ordering.ini.
*
* @param string $productTypeId - the unique productType identifier
*/
public function getVisibleMetadataForProductType($productTypeId) {
// Get the metadata for the product type
$pt = $this->client
->getProductTypeById($productTypeId)
->toAssocArray();
// Determine which metadata should be visible to the current user
$visibleMetadata = $this->getVisibleMetadata($pt['typeMetadata'], $productTypeId);
// Sort the visible metadata according to the ordering policy
$result = $this->getSortedMetadata($productTypeId,$visibleMetadata, 'pt');
return $result;
}
/**
* Retrieves the set of metadata for the provided productId that should be visible to
* the current user
*
* @param string $productId - the unique product identifier
* @param boolean $authState - whether or not the current user is authenticated
*/
public function getVisibleMetadataForProduct($productId) {
$p = $this->client->getProductById($productId);
$productTypeInfo = $p->getType()->toAssocArray();
$productTypeId = $productTypeInfo[App::Get()->settings['browser_pt_id_key']];
$productMetadata = $this->client->getMetadata($p);
// Determine which metadata should be visible to the current user
$visibleMetadata = $this->getVisibleMetadata($productMetadata->toAssocArray(), $productTypeId);
// Sort the visible metadata according to the ordering policy
$result = $this->getSortedMetadata($productTypeId,$visibleMetadata, 'p');
return $result;
}
/**
* Determine the visibility level for the current product type and current user.
* The level returned is one of VIS_ALL,VIS_LIMIT,VIS_NONE
*
* @param string $productTypeId - the unique product type identifier
*/
public function getProductTypeVisibilityLevel( $productTypeId ) {
// If the configuration explicitly states that this dataset is to be ignored,
// ignore it:
if (in_array($productTypeId,App::Get()->settings['browser_dataset_ignores'])) {
return CasBrowser::VIS_NONE;
}
// Get the metadata for the product type
$typeInfo = $this->client
->getProductTypeById($productTypeId)
->toAssocArray();
if ( App::Get()->getAuthenticationProvider() ) {
// Does the product type define a metadata element matching
// the `browser_data_access_key` config setting?
$accessKeyExists = isset($typeInfo['typeMetadata'][App::Get()->settings['browser_data_access_key']]);
// Obtain the groups for the current resource
$resourceGroups = ($accessKeyExists)
? $typeInfo['typeMetadata'][App::Get()->settings['browser_data_access_key']]
: array();
return $this->getResourceVisibility($resourceGroups,
App::Get()->settings['browser_pt_auth_policy']);
} else {
// No authentication provider, everything is public
return CasBrowser::VIS_ALL;
}
}
public function getProductVisibilityLevel( $productId ) {
$product = $this->client->getProductById( $productId );
$productMetadata = $this->client->getMetadata($product);
// Get metadata for product and productType as associative arrays
$productTypeInfo = $product->getType()->toAssocArray();
$productInfo = $productMetadata->toAssocArray();
if ( App::Get()->getAuthenticationProvider() ) {
// Does the product type define a metadata element matching
// the `browser_data_access_key` config setting?
$accessKeyExists = isset($productInfo[App::Get()->settings['browser_data_access_key']]);
// Obtain the groups for the current resource
$resourceGroups = ($accessKeyExists)
? $productInfo[App::Get()->settings['browser_data_access_key']]
: array();
return $this->getResourceVisibility($resourceGroups,
App::Get()->settings['browser_p_auth_policy']);
} else {
// No authentication provider, everything is public
return CasBrowser::VIS_ALL;
}
}
/**
* Internal helper function for sorting(ordering) a metadata array according to policy.
*
* @param array $unsortedMetadata An associative array of unsorted metadta key/(multi)values
* @param array $sortFirst A scalar array of metadata keys that must be ordered first
* @param array $sortLast A scalar array of metadata keys that must be ordered last
* @returns array An associative array of sorted(ordered) metadata key/(multi)values
*/
protected function sortMetadata($unsortedMetadata,$sortFirst,$sortLast) {
$orderedMetadata = array();
foreach ($sortFirst as $key) {
if (isset($unsortedMetadata[$key])) {
$orderedMetadata[$key] = $unsortedMetadata[$key];
unset($unsortedMetadata[$key]);
}
}
$lastMetadata = array();
foreach ($sortLast as $key) {
if (isset($unsortedMetadata[$key])) {
$lastMetadata[$key] = $unsortedMetadata[$key];
unset($unsortedMetadata[$key]);
}
}
$orderedMetadata += $unsortedMetadata;
$orderedMetadata += $lastMetadata;
return $orderedMetadata;
}
/**
* Internal helper function for, given an array of metadata, a productTypeID, and an indication of whether or not the
* current user is authenticated, returning the subset of metadata that should be visible to
* the user.
*
* @param array $metadataAsArray
* @param string $productTypeId
* @param boolean $longinState - one of VIS_AUTH_AUTHENTICATED|VIS_AUTH_ANONYMOUS
*/
protected function getVisibleMetadata($metadataAsArray, $productTypeId) {
// Determine whether the user is authenticated
$authState = (($ap = App::Get()->getAuthenticationProvider()) && $ap->isLoggedIn());
$visibilityPolicyFilePath = dirname(dirname(__FILE__)) . '/element-visibility.ini';
if (file_exists($visibilityPolicyFilePath)) {
$visibilityPolicy = parse_ini_file($visibilityPolicyFilePath,true);
$interpretation = $visibilityPolicy['interpretation.policy'];
$globalVisibilityPolicy = $visibilityPolicy['*'];
$productTypeVisibilityPolicy = isset($visibilityPolicy[$productTypeId])
? $visibilityPolicy[$productTypeId]
: array("visibility.always" => array(),
"visibility.anonymous" => array(),
"visibility.authenticated" => array());
// The visibility of a given metadata element is dependent upon
// (1) the authentication status of the user (VIS_AUTH_AUTHENTICATED|VIS_AUTH_ANONYMOUS)
// (2) the interpretation of the visibility policy (VIS_INTERPRET_SHOW|VIS_INTERPRET_HIDE)
//
// Using these values, determine which metadata to display:
switch ($interpretation) {
// If the policy defines only those metadata which should be hidden:
case self::VIS_INTERPRET_HIDE:
$displayMet = $metadataAsArray; // everything is shown unless explicitly hidden via the policy
foreach ($globalVisibilityPolicy['visibility.always'] as $elm) // iterate through the global 'always hide' array...
unset($displayMet[$elm]); // and remove all listed elements
foreach ($productTypeVisibilityPolicy['visibility.always'] as $elm) // now iterate through the product-type 'always hide' array...
unset($displayMet[$elm]); // and remove all listed elements
// Determine what to hide given the user's login state
switch ($authState) { // check the login status of the user
case self::VIS_AUTH_ANONYMOUS: // if the user is anonymous...
foreach($globalVisibilityPolicy['visibility.anonymous'] as $elm) // iterate through the global 'anonymous hide' array...
unset($displayMet[$elm]); // and remove all listed elements
foreach ($productTypeVisibilityPolicy['visibility.anonymous'] as $elm) // now iterate through the product-type 'anonymous hide' array...
unset($displayMet[$elm]); // and remove all listed elements
break; // done.
case self::VIS_AUTH_AUTHENTICATED: // if the user is authenticated...
foreach($globalVisibilityPolicy['visibility.authenticated'] as $elm) // iterate through the global 'authenticated hide' array...
unset($displayMet[$elm]); // and remove all listed elements
foreach ($productTypeVisibilityPolicy['visibility.authenticated'] as $elm) // now iterate through the product-type 'authenticated hide' array...
unset($displayMet[$elm]); // and remove all listed elements
break; // done.
}
break;
// If the policy defines only those metadata which should be shown:
case self::VIS_INTERPRET_SHOW:
$displayMet = $globalVisibilityPolicy['visibility.always'] // merge the global 'always show' array
+ $productTypeVisibilityPolicy['visibility.always']; // with the product-type specific 'always show' array
switch ($authState) { // check the login status of the user
case self::VIS_AUTH_ANONYMOUS: // if the user is anonymous...
$displayMet += $globalVisibilityPolicy['visibility.anonymous']; // merge the global 'anonymous show' array
$displayMet += $productTypeVisibilityPolicy['visibility.anonymous']; // and the product-type specific 'anonymous show' array
break; // done.
case self::VIS_AUTH_AUTHENTICATED: // if the user is authenticated...
$displayMet += $globalVisibilityPolicy['visibility.authenticated']; // merge the global 'authenticated show' array
$displayMet += $productTypeVisibilityPolicy['visibility.authenticated']; // and the product-type specific 'authenticated show' array
break; // done.
}
}
return $displayMet;
} else {
return $metadataAsArray;
}
}
/**
* Internal helper function to determine the visibility level of a given resource given
* its array of security groups. The value returned is one of VIS_ALL,VIS_LIMIT,VIS_NONE.
*
* @param array $resourceGroups - an array of security groups for the resource
* @param string $policy - one of VIS_LIMIT or VIS_DENY
*/
protected function getResourceVisibility( $resourceGroups, $policy = CasBrowser::VIS_DENY ) {
// Is the resource considered "public"?
if (in_array(App::Get()->settings['browser_data_public_access'],$resourceGroups)) {
return CasBrowser::VIS_ALL;
}
// Get user authentication info
$authentication = App::Get()->getAuthenticationProvider();
$username = ($authentication)
? $authentication->getCurrentUsername()
: false; // no authentication info provided in config file
// Does the metadata visibility depend on an access element matching
// the `browser_data_access_key` in the config setting?
$accessKeyExists = isset(App::Get()->settings['browser_data_access_key']);
// If key is set then we look into what groups have access to metadata
if ( $accessKeyExists && !empty($resourceGroups) ) {
// Has authentication provider information been specified?
if ( $authentication ) {
// Is the user currently logged in?
if ( $username ) {
if ( $authorization = App::Get()->getAuthorizationProvider() ) {
// Obtain the groups for the current user
$userGroups = $authorization->retrieveGroupsForUser($username);
// Perform a comparison via array intersection to determine overlap
$x = array_intersect($userGroups,$resourceGroups);
if (empty($x)) { // No intersection found between user and resource groups
// Examine the policy to determine how to handle the failure
switch ($policy) {
case CasBrowser::VIS_LIMIT:
// Allow the user to proceed, the metadata visibility policy
// will be used to determine what is visible to non-authorized
// users.
return CasBrowser::VIS_LIMIT;
default:
// Kick the user out at this point, deny all access.
return CasBrowser::VIS_NONE;
}
} else {
// We have an authorized user
$authorizedUser = true;
}
} else {
// If no authorization provider information exists in the application
// configuration file, it is assumed that every user is authorized once
// logged in.
return CasBrowser::VIS_ALL;
}
} else {
// If no logged in user, and policy says DENY, kick the user
if ($policy == CasBrowser::VIS_DENY) {
return CasBrowser::VIS_NONE;
} else {
return CasBrowser::VIS_LIMIT;
}
}
} else {
// If no authentication provider information exists in the application
// configuration file, it is assumed that authentication and authorization
// are not needed for this application, and thus every user is authorized
// by default.
return CasBrowser::VIS_ALL;
}
} else {
// All data is visible to user if logged in
// Has authentication provider information been specified?
if ( $authentication ) {
// Is the user currently logged in?
if ( $username ) {
return CasBrowser::VIS_ALL; // We have an authorized user
} else {
// If no logged in user, and policy says DENY, kick the user
if ($policy == CasBrowser::VIS_DENY) {
return CasBrowser::VIS_NONE;
} else {
return CasBrowser::VIS_LIMIT;
}
}
} else {
// If no authentication provider information exists in the application
// configuration file, it is assumed that authentication and authorization
// are not needed for this application, and thus every user is authorized
// by default.
return CasBrowser::VIS_ALL;
}
}
}
}