Package org.exist.security.xacml

Source Code of org.exist.security.xacml.RequestHelper

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2001-06 The eXist Project
*  http://exist-db.org
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*
*  $Id$
*/

package org.exist.security.xacml;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.exist.dom.QName;
import org.exist.security.Account;
import org.exist.xquery.ExternalModule;
import org.exist.xquery.Module;
import org.exist.xquery.XQueryContext;

import com.sun.xacml.attr.AnyURIAttribute;
import com.sun.xacml.attr.AttributeValue;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.ctx.Attribute;
import com.sun.xacml.ctx.RequestCtx;
import com.sun.xacml.ctx.Subject;

/*
* Source.getKey().toString() needs to be unique:
*  potential collision between FileSource and DBSource ??
*/
/**
* This class provides methods for creating an XACML request.  The main methods
* are those that return a <code>RequestCtx</code>.  Links are provided to the
* relevant constants in <code>XACMLConstants</code> to facilitate policy
* writing.
*
* @see XACMLConstants
*/
public class RequestHelper
{
  /**
   * Creates an XACML request for permission to execute an XQuery main module.
   * The subjects section will contain a subject for the user obtained from the
   * specified context.  The resource section will be created by the
   * createQueryResource method.  The action-id will be
   * {@link XACMLConstants#EXECUTE_QUERY_ACTION execute query}.  The environment
   * section will be created by createEnvironment, using the access context
   * of the query context.
   * 
   * @param context The context for this query
   * @param source The source of this query
   * @return A <code>RequestCtx</code> that may be evaluated by the PDP to
   * determine whether the specified user may execute the query represented by
   * <code>source</code>.
   */
  public RequestCtx createQueryRequest(XQueryContext context, XACMLSource source)
  {
    final Set<Subject> subjects = createQuerySubjects(context.getUser(), null);
    final Set<Attribute> resourceAttributes = createQueryResource(source);
    final Set<Attribute> actionAttributes = createBasicAction(XACMLConstants.EXECUTE_QUERY_ACTION);
    final Set<Attribute> environmentAttributes = createEnvironment(context.getAccessContext());

    return new RequestCtx(subjects, resourceAttributes, actionAttributes, environmentAttributes);
  }
 
  /**
  * Creates a <code>RequestCtx</code> for a request concerning reflective
  * access to Java code from an XQuery.  This handles occurs when a method
  * is being invoked on the class in question. This method creates a
  * request with the following content:
  * <ul>
  *
  *  <li>Subjects for the contextModule and user are created with the
  * createQuerySubjects method.</li>
  *
  *  <li>Resource attributes are created with the
  * <code>createReflectionResource</code> method.</li>
  *
  *  <li>Action attributes are created with the
  * <code>createBasicAction</code> method.  The action-id is
  * {@link XACMLConstants#INVOKE_METHOD_ACTION invoke method}.</li>
  *
  *  <li>The {@link XACMLConstants#ACCESS_CONTEXT_ATTRIBUTE} access context
  * attribute is generated for the environment section.</li>
  *
  * </ul>
  *
  * @param context The <code>XQueryContext</code> for the module making the
  * request.
  * @param contextModule The query containing the reflection.
  * @param className The name of the class that is being accessed or loaded.
  * @param methodName The name of the method that is being invoked
  * @return A <code>RequestCtx</code> that represents the access in question.
  */
  public RequestCtx createReflectionRequest(XQueryContext context, Module contextModule, String className, String methodName)
  {
    final Account user = context.getUser();
    final Set<Subject> subjects = createQuerySubjects(user, contextModule);
    final Set<Attribute> resourceAttributes = createReflectionResource(className, methodName);
    final Set<Attribute> actionAttributes = createBasicAction(XACMLConstants.INVOKE_METHOD_ACTION);
    final Set<Attribute> environmentAttributes = createEnvironment(context.getAccessContext());

    return new RequestCtx(subjects, resourceAttributes, actionAttributes, environmentAttributes);
  }
 
  /**
  * Creates a <code>RequestCtx</code> for a request concerning access
  * to a function in an XQuery library module.  If the function is
  * from a main module, this method returns null to indicate that.
  * The client should interpret this to mean that the request is
  * granted because access to a main module implies access to its
  * functions.
  *
  * <p>
  * This method creates a request with the following content:
  * <ul>
  *
  *  <li>Subjects for the contextModule and user (obtained from the
  * XQueryContext) are created with the createQuerySubjects method.</li>
  *
  *  <li>The specified functionModule parameter is used to generate the
  * {@link XACMLConstants#SOURCE_KEY_ATTRIBUTE source-key},
  * {@link XACMLConstants#SOURCE_TYPE_ATTRIBUTE source-type}, and
  * {@link XACMLConstants#MODULE_CATEGORY_ATTRIBUTE module category}
  * attributes. The functionName parameter is the value of the
  * {@link XACMLConstants#RESOURCE_ID_ATTRIBUTE subject-id} attribute
  * (the local part) and of the
  * {@link XACMLConstants#MODULE_NS_ATTRIBUTE module namespace}
  *  attribute (the namespace URI part).  The
  * {@link XACMLConstants#RESOURCE_CATEGORY_ATTRIBUTE resource-category}
  * attribute is {@link XACMLConstants#FUNCTION_RESOURCE function}.
  *
  *  <li>Action attributes are created with the
  * <code>createBasicAction</code> method.  The action is
  * {@link XACMLConstants#CALL_FUNCTION_ACTION call function}.
  *
  *  <li>The {@link XACMLConstants#ACCESS_CONTEXT_ATTRIBUTE} access context
  * attribute is generated for the environment section.</li>
  *
  * </ul>
  *
  * @param context The query context.
  * @param contextModule The query making the access.
  * @param functionName The <code>QName</code> of the function being called.
  * @return A <code>RequestCtx</code> that represents the access in question
  *  or <code>null</code> if the function belongs to a main module and
  *  not a library module.
  */
  public RequestCtx createFunctionRequest(XQueryContext context, Module contextModule, QName functionName)
  {
    final String namespaceURI = functionName.getNamespaceURI();
    final Module functionModule = context.getModule(namespaceURI);
    if(functionModule == null)
    {
      //main module, not a library module, so access to function is always allowed
      return null;
    }
   
    final Account user = context.getUser();
    final Set<Subject> subjects = createQuerySubjects(user, contextModule);

    final Set<Attribute> resourceAttributes = new HashSet<Attribute>(8);
    addStringAttribute(resourceAttributes, XACMLConstants.MODULE_CATEGORY_ATTRIBUTE, getModuleCategory(functionModule));
    final XACMLSource moduleSrc = generateModuleSource(functionModule);
    addSourceAttributes(resourceAttributes, moduleSrc);
    addValidURIAttribute(resourceAttributes, XACMLConstants.MODULE_NS_ATTRIBUTE, namespaceURI);
    addStringAttribute(resourceAttributes, XACMLConstants.RESOURCE_CATEGORY_ATTRIBUTE, XACMLConstants.FUNCTION_RESOURCE);
    addStringAttribute(resourceAttributes, XACMLConstants.RESOURCE_ID_ATTRIBUTE, functionName.getLocalName());

    final Set<Attribute> actionAttributes = createBasicAction(XACMLConstants.CALL_FUNCTION_ACTION);
    final Set<Attribute> environmentAttributes = createEnvironment(context.getAccessContext());

    return new RequestCtx(subjects, resourceAttributes, actionAttributes, environmentAttributes);
  }
 
  /**
  * Creates a <code>Subject</code> for a <code>User</code>.
  * The user's name is the value of the
  * {@link XACMLConstants#SUBJECT_ID_ATTRIBUTE subject-id} attribute.  The
  * subject-category is {@link XACMLConstants#ACCESS_SUBJECT access-subject}.
  * The {@link XACMLConstants#GROUP_ATTRIBUTE group} attribute is a bag
  * containing the name of each group of which the user is a member.
  *
  * @param user The user making the request
  * @return A <code>Subject</code> for use in a <code>RequestCtx</code>
  */
  public Subject createUserSubject(Account user)
  {
    final AttributeValue value = new StringAttribute(user.getName());
    final Attribute attr = new Attribute(XACMLConstants.SUBJECT_ID_ATTRIBUTE, null, null, value);
    return new Subject(XACMLConstants.ACCESS_SUBJECT, Collections.singleton(attr));
  }
  /**
  * Creates the basic attributes needed to describe a simple action
  * in a request.  The <code>action</code> parameter is the value of
  * the {@link XACMLConstants#ACTION_ID_ATTRIBUTE action-id} attribute and the
  * {@link XACMLConstants#ACTION_NS_ATTRIBUTE namespace} attribute for the
  * action-id is eXist's XACML
  * {@link XACMLConstants#ACTION_NS action namespace}.
  *
  * @param action The {@link XACMLConstants#ACTION_ID_ATTRIBUTE action-id}
  *  of the action.
  * @return A <code>Set</code> that contains attributes describing the
  *  action for use in a <code>RequestCtx</code>
  */
  public Set<Attribute> createBasicAction(String action)
  {
    if(action == null)
      {return null;}

    final Set<Attribute> attributes = new HashSet<Attribute>(4);
    addStringAttribute(attributes, XACMLConstants.ACTION_ID_ATTRIBUTE, action);
    addValidURIAttribute(attributes, XACMLConstants.ACTION_NS_ATTRIBUTE, XACMLConstants.ACTION_NS);

    return attributes;
  }

  /**
  * Creates a <code>Subject</code> for a <code>Module</code>.
  * If the module is external, its <code>Source</code> is the value of the
  * {@link XACMLConstants#SUBJECT_ID_ATTRIBUTE subject-id} attribute, otherwise,
  * the name of the implementing class is used.  The subject-category is
  * {@link XACMLConstants#CODEBASE_SUBJECT codebase}.  The value of the
  * {@link XACMLConstants#SUBJECT_NS_ATTRIBUTE module namespace} attribute
  * is the namespace URI of the module.  The
  * {@link XACMLConstants#MODULE_CATEGORY_ATTRIBUTE module category}
  * attribute is the type of module, either
  * {@link XACMLConstants#INTERNAL_LIBRARY_MODULE internal} or
  * {@link XACMLConstants#EXTERNAL_LIBRARY_MODULE external}.
  *
  * @param module A query module involved in making the request
  * @return A <code>Subject</code> for use in a <code>RequestCtx</code>
  */
  public Subject createModuleSubject(Module module)
  {
    if(module == null)
      {return null;}

    final Set<Attribute> attributes = new HashSet<Attribute>(8);
    addValidURIAttribute(attributes, XACMLConstants.SUBJECT_NS_ATTRIBUTE, module.getNamespaceURI());
    addStringAttribute(attributes, XACMLConstants.MODULE_CATEGORY_ATTRIBUTE, getModuleCategory(module));
    final XACMLSource moduleSrc = generateModuleSource(module);
    addSourceAttributes(attributes, moduleSrc);
    addStringAttribute(attributes, XACMLConstants.SUBJECT_ID_ATTRIBUTE, moduleSrc.createId());

    return new Subject(XACMLConstants.CODEBASE_SUBJECT, attributes);
  }


  /**
  * Creates a <code>Set</code> of <code>Attribute</code>s for a resource
  * representing Java reflection in an XQuery.
  * The {@link XACMLConstants#RESOURCE_CATEGORY_ATTRIBUTE resource-category}
  * attribute is {@link XACMLConstants#METHOD_RESOURCE method}.
  * The {@link XACMLConstants#SOURCE_TYPE_ATTRIBUTE source-type} attribute is
  * {@link XACMLConstants#CLASS_SOURCE_TYPE class} and the
  * {@link XACMLConstants#SOURCE_KEY_ATTRIBUTE source-key} attribute is the
  * name of the class.  The
  * {@link XACMLConstants#RESOURCE_ID_ATTRIBUTE resource-id} attribute is the
  * method name.
  *
  * @param className The name of the Java class
  * @param methodName The name of the method being invoked
  * @return A <code>Set</code> containing the <code>Attribute</code>s
  * describing access to Java code by reflection.
  */
  public Set<Attribute> createReflectionResource(String className, String methodName)
  {
    if(className == null)
      {throw new NullPointerException("Class name cannot be null");}
    if(methodName == null)
      {throw new NullPointerException("Method name cannot be null");}
   
    final Set<Attribute> resourceAttributes = new HashSet<Attribute>(8);

    addStringAttribute(resourceAttributes, XACMLConstants.RESOURCE_CATEGORY_ATTRIBUTE, XACMLConstants.METHOD_RESOURCE);
    final XACMLSource source = XACMLSource.getInstance(className);
    addSourceAttributes(resourceAttributes, source);
    addStringAttribute(resourceAttributes, XACMLConstants.RESOURCE_ID_ATTRIBUTE, methodName);

    return resourceAttributes;
  }
 
  /**
   * Creates the Resource section of a request for a main module.
   *
   * @param source The source of the query.
   * @return A <code>Set</code> containing attributes for the specified
   * query.
   */
  public Set<Attribute> createQueryResource(XACMLSource source)
  {
    if(source == null)
      {throw new NullPointerException("Query source cannot be null");}
   
    final Set<Attribute> resourceAttributes = new HashSet<Attribute>(4);
    addSourceAttributes(resourceAttributes, source);
    addStringAttribute(resourceAttributes, XACMLConstants.RESOURCE_ID_ATTRIBUTE, source.createId());
    addStringAttribute(resourceAttributes, XACMLConstants.RESOURCE_CATEGORY_ATTRIBUTE, XACMLConstants.MAIN_MODULE_RESOURCE);
    return resourceAttributes;
  }
 
  /**
  * Creates <code>Subject</code>s for the specified user and module.  This is
  * equivalent to putting the <code>Subject</code>s created by the
  * <code>createUserSubject(User user)</code> and
  * <code>createModuleSubject(Module contextModule)</code> methods.  The
  * context module may be null if there is no context module.
  *
  * @param user The user making the access
  * @param contextModule The module involved in the access, if any.  It may
  * be null to indicate the is not an intermediary XQuery module.
  * @return A <code>Set</code> containing a <code>Subject</code> for each
  * the context module if there is one and the user.
  */
  public Set<Subject> createQuerySubjects(Account user, Module contextModule)
  {
    if(user == null)
      {throw new NullPointerException("User cannot be null");}
    final Set<Subject> subjects = new HashSet<Subject>(4);

    final Subject userSubject = createUserSubject(user);
    subjects.add(userSubject);

    if(contextModule != null)
    {
      final Subject moduleSubject = createModuleSubject(contextModule);
      subjects.add(moduleSubject);
    }
    return subjects;
  }
 
  /**
   * Creates the environment section of a request for the given
   * <code>AccessContext</code>.
   *
   * @param accessCtx The context
   * @return A <code>Set</code> containing one attribute, the
   * {@link XACMLConstants#ACCESS_CONTEXT_ATTRIBUTE access context}
   * attribute with the value of the specified access context.
   */
  public Set<Attribute> createEnvironment(AccessContext accessCtx)
  {
    if(accessCtx == null)
      {throw new NullAccessContextException();}
    final Set<Attribute> environment = new HashSet<Attribute>(4);
    addStringAttribute(environment, XACMLConstants.ACCESS_CONTEXT_ATTRIBUTE, accessCtx.toString());
    return environment;
  }
   
  /**
  * Generates an <code>XACMLSource</code> for a <code>Module</code>
  * based on its implementing class name (if it is an
  * <code>InternalModule</code>) or its <code>Source</code>
  * (if it is an <code>ExternalModule</code>).
  *
  * @param module the module for which the source should be generated
  * @return an <code>XACMLSource</code> that uniquely defines the source
  * of the given module
  */
  public static XACMLSource generateModuleSource(Module module)
  {
    if(module == null)
      {throw new NullPointerException("Module cannot be null");}
    if(module.isInternalModule())
      {return XACMLSource.getInstance(module.getClass());}
    return XACMLSource.getInstance(((ExternalModule)module).getSource());
  }

  /**
   * Returns the module type for the given XQuery library module.  This
   * is either
   * {@link XACMLConstants#INTERNAL_LIBRARY_MODULE internal} or
   * {@link XACMLConstants#EXTERNAL_LIBRARY_MODULE external}
   *
   * @param module The XQuery library module.  If it is null, this method
   * returns null.
   * @return null if module is null, the module's category (internal or external)
   * otherwise
   */
  public static String getModuleCategory(Module module)
  {
    if(module == null)
      {return null;}
    return module.isInternalModule() ? XACMLConstants.INTERNAL_LIBRARY_MODULE : XACMLConstants.EXTERNAL_LIBRARY_MODULE;
  }
 
  /**
   * Adds new attributes to the specified <code>Set</code> of attributes
   * that represent the specified source.  The added attributes are the
   * {@link XACMLConstants#SOURCE_KEY_ATTRIBUTE source's key} and the
   * {@link XACMLConstants#SOURCE_TYPE_ATTRIBUTE source's type}.
   *  
   * @param attributes The <code>Set</code> to which attributes will be
   * added.  If null, this method does nothing.
   * @param source The source for which attributes will be added.  It
   * cannot be null.
   */
  public static void addSourceAttributes(Set<Attribute> attributes, XACMLSource source)
  {
    if(source == null)
      {throw new NullPointerException("Source cannot be null");}
    addStringAttribute(attributes, XACMLConstants.SOURCE_KEY_ATTRIBUTE, source.getKey());
    addStringAttribute(attributes, XACMLConstants.SOURCE_TYPE_ATTRIBUTE, source.getType());
  }

  /**
   * Adds a new attribute of type string to the specified
   * <code>Set</code> of attributes.  The new attribute's value is
   * constructed from the attrValue parameter and is given the id
   * of the attrID parameter.
   *
   * @param attributes The <code>Set</code> to which the new attribute
   * should be added.  If it is null, this method does nothing.
   * @param attrID The ID of the new attribute, cannot be null
   * @param attrValue The value of the new attribute.  It cannot be null.
   */
  public static void addStringAttribute(Set<Attribute> attributes, URI attrID, String attrValue)
  {
    if(attributes == null)
      {return;}
    if(attrID == null)
      {throw new NullPointerException("Attribute ID cannot be null");}
    if(attrValue == null)
      {throw new NullPointerException("Attribute value cannot be null");}
    final AttributeValue value = new StringAttribute(attrValue);
    final Attribute attr = new Attribute(attrID, null, null, value);
    attributes.add(attr);
  }
 
  /**
   * Adds a new attribute of type anyURI to the specified
   * <code>Set</code> of attributes.  The new attribute's value is
   * constructed from the uriString parameter and is given the id
   * of the attrID parameter.
   *
   * @param attributes The <code>Set</code> to which the new attribute
   * should be added.  If it is null, this method does nothing.
   * @param attrID The ID of the new attribute, cannot be null
   * @param uriString The value of the new attribute.  It must parse into a
   * valid URI and cannot be null.
   * @throws URISyntaxException if the specified attribute value is not a
   * valid URI.
   */
  public static void addURIAttribute(Set<Attribute> attributes, URI attrID, String uriString) throws URISyntaxException
  {
    if(attributes == null)
      {return;}
    if(attrID == null)
      {throw new NullPointerException("Attribute ID cannot be null");}
    if(uriString == null)
      {throw new NullPointerException("Attribute value cannot be null");}
    final URI uri = new URI(uriString);
    final AttributeValue value = new AnyURIAttribute(uri);
    final Attribute attr = new Attribute(attrID, null, null, value);
    attributes.add(attr);
  }
 
  //wrapper for when the URI is known to be valid, such as when obtained from a source
  //that validates the URI or from a constant
  private static void addValidURIAttribute(Set<Attribute> attributes, URI attrID, String uriString)
  {
    try
    {
      addURIAttribute(attributes, attrID, uriString);
    }
    catch(final URISyntaxException e)
    {
      throw new RuntimeException("URI should never be invalid", e);
    }
  }

  RequestHelper() {}
}
TOP

Related Classes of org.exist.security.xacml.RequestHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.