Package org.teiid.dqp.internal.process

Source Code of org.teiid.dqp.internal.process.AuthorizationValidationVisitor

/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library 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.1 of the License, or (at your option) any later version.
*
* This library 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 Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/

package org.teiid.dqp.internal.process;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.teiid.adminapi.DataPolicy;
import org.teiid.adminapi.DataPolicy.PermissionType;
import org.teiid.adminapi.impl.DataPolicyMetadata;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.core.CoreConstants;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.dqp.internal.process.multisource.MultiSourceElement;
import org.teiid.logging.AuditMessage;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.MessageLevel;
import org.teiid.query.QueryPlugin;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.lang.AlterProcedure;
import org.teiid.query.sql.lang.AlterTrigger;
import org.teiid.query.sql.lang.AlterView;
import org.teiid.query.sql.lang.Create;
import org.teiid.query.sql.lang.Delete;
import org.teiid.query.sql.lang.Drop;
import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.Into;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Function;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.Symbol;
import org.teiid.query.sql.visitor.ElementCollectorVisitor;
import org.teiid.query.sql.visitor.GroupCollectorVisitor;
import org.teiid.query.validator.AbstractValidationVisitor;


public class AuthorizationValidationVisitor extends AbstractValidationVisitor {
   
  public enum Context {
    CREATE,
    DROP,
    QUERY,
    INSERT,
    UPDATE,
    DELETE,
    FUNCTION,
    ALTER,
    STORED_PROCEDURE;
    }
   
    private HashMap<String, DataPolicy> allowedPolicies;
    private String userName;
    private boolean allowCreateTemporaryTablesDefault = true;
    private boolean allowFunctionCallsByDefault = true;

    public AuthorizationValidationVisitor(HashMap<String, DataPolicy> policies, String user) {
        this.allowedPolicies = policies;
        this.userName = user;
    }
   
    public void setAllowCreateTemporaryTablesDefault(
      boolean allowCreateTemporaryTablesDefault) {
    this.allowCreateTemporaryTablesDefault = allowCreateTemporaryTablesDefault;
  }
   
    public void setAllowFunctionCallsByDefault(boolean allowFunctionCallsDefault) {
    this.allowFunctionCallsByDefault = allowFunctionCallsDefault;
  }

    // ############### Visitor methods for language objects ##################
   
    @Override
    public void visit(Create obj) {
      Set<String> resources = Collections.singleton(obj.getTable().getName());
      Collection<GroupSymbol> symbols = Arrays.asList(obj.getTable());
      validateTemp(resources, symbols, Context.CREATE);
    }
   
    @Override
    public void visit(AlterProcedure obj) {
      validateEntitlements(Arrays.asList(obj.getTarget()), DataPolicy.PermissionType.ALTER, Context.ALTER);
    }
   
    @Override
    public void visit(AlterTrigger obj) {
      validateEntitlements(Arrays.asList(obj.getTarget()), DataPolicy.PermissionType.ALTER, obj.isCreate()?Context.CREATE:Context.ALTER);
    }
   
    @Override
    public void visit(AlterView obj) {
      validateEntitlements(Arrays.asList(obj.getTarget()), DataPolicy.PermissionType.ALTER, Context.ALTER);
    }

  private void validateTemp(Set<String> resources,
      Collection<GroupSymbol> symbols, Context context) {
    logRequest(resources, context);
       
      boolean allowed = false;
      for(DataPolicy p:this.allowedPolicies.values()) {
      DataPolicyMetadata policy = (DataPolicyMetadata)p;
     
      if (policy.isAllowCreateTemporaryTables() == null) {
        if (allowCreateTemporaryTablesDefault) {
          allowed = true;
          break;
        }
      } else if (policy.isAllowCreateTemporaryTables()) {
        allowed = true;
        break;
      }
    }
     
      logResult(resources, context, allowed);
      if (!allowed) {
        handleValidationError(
              QueryPlugin.Util.getString("ERR.018.005.0095", userName, "CREATE_TEMPORARY_TABLES"), //$NON-NLS-1$  //$NON-NLS-2$
              symbols);
      }
  }

  private void logRequest(Set<String> resources, Context context) {
    if (LogManager.isMessageToBeRecorded(LogConstants.CTX_AUDITLOGGING, MessageLevel.DETAIL)) {
          // Audit - request
        AuditMessage msg = new AuditMessage(context.name(), "getInaccessibleResources-request", this.userName, resources.toArray(new String[resources.size()])); //$NON-NLS-1$
        LogManager.logDetail(LogConstants.CTX_AUDITLOGGING, msg);
        }
  }
   
    @Override
    public void visit(Drop obj) {
      Set<String> resources = Collections.singleton(obj.getTable().getName());
      Collection<GroupSymbol> symbols = Arrays.asList(obj.getTable());
      validateTemp(resources, symbols, Context.CREATE);
    }
   
    public void visit(Delete obj) {
      validateEntitlements(obj);
    }

    public void visit(Insert obj) {
      validateEntitlements(obj);
    }

    public void visit(Query obj) {
      validateEntitlements(obj);
    }

    public void visit(Update obj) {
      validateEntitlements(obj);
    }

    public void visit(StoredProcedure obj) {
      validateEntitlements(obj);
    }
   
    public void visit(Function obj) {
      if (FunctionLibrary.LOOKUP.equalsIgnoreCase(obj.getName())) {
        try {
        ResolverUtil.ResolvedLookup lookup = ResolverUtil.resolveLookup(obj, this.getMetadata());
          List<Symbol> symbols = new LinkedList<Symbol>();
        symbols.add(lookup.getGroup());
        symbols.add(lookup.getKeyElement());
        symbols.add(lookup.getReturnElement());
          validateEntitlements(symbols, DataPolicy.PermissionType.READ, Context.QUERY);
      } catch (TeiidComponentException e) {
        handleException(e, obj);
      } catch (TeiidProcessingException e) {
        handleException(e, obj);
      }
      } else if (!allowFunctionCallsByDefault) {
        String schema = obj.getFunctionDescriptor().getSchema();
        if (schema != null && !isSystemSchema(schema)) {
          Map<String, Function> map = new HashMap<String, Function>();
          map.put(schema + '.' + obj.getFunctionDescriptor().getName(), obj);
          validateEntitlements(PermissionType.EXECUTE, Context.FUNCTION, map);
        }
      }
    }

    // ######################### Validation methods #########################

    /**
     * Validate insert entitlements
     */
    protected void validateEntitlements(Insert obj) {
        validateEntitlements(
            obj.getVariables(),
            DataPolicy.PermissionType.CREATE,
            Context.INSERT);
    }

    /**
     * Validate update entitlements
     */
    protected void validateEntitlements(Update obj) {
        // Check that all elements used in criteria have read permission
      HashSet<ElementSymbol> elements = new HashSet<ElementSymbol>();
      ElementCollectorVisitor.getElements(obj.getChangeList().getClauseMap().values(), elements);
        if (obj.getCriteria() != null) {
            ElementCollectorVisitor.getElements(obj.getCriteria(), elements);
        }
        validateEntitlements(
            elements,
                DataPolicy.PermissionType.READ,
                Context.UPDATE);

        // The variables from the changes must be checked for UPDATE entitlement
        // validateEntitlements on all the variables used in the update.
        validateEntitlements(obj.getChangeList().getClauseMap().keySet(), DataPolicy.PermissionType.UPDATE, Context.UPDATE);
    }

    /**
     * Validate delete entitlements
     */
    protected void validateEntitlements(Delete obj) {
        // Check that all elements used in criteria have read permission
        if (obj.getCriteria() != null) {
            validateEntitlements(
                ElementCollectorVisitor.getElements(obj.getCriteria(), true),
                DataPolicy.PermissionType.READ,
                Context.DELETE);
        }

        // Check that all elements of group being deleted have delete permission
        validateEntitlements(Arrays.asList(obj.getGroup()), DataPolicy.PermissionType.DELETE, Context.DELETE);
    }

    /**
     * Validate query entitlements
     */
    protected void validateEntitlements(Query obj) {
        // If query contains SELECT INTO, validate INTO portion
        Into intoObj = obj.getInto();
        if ( intoObj != null ) {
            GroupSymbol intoGroup = intoObj.getGroup();
            List<ElementSymbol> intoElements = null;
            try {
                intoElements = ResolverUtil.resolveElementsInGroup(intoGroup, getMetadata());
            } catch (QueryMetadataException err) {
                handleException(err, intoGroup);
            } catch (TeiidComponentException err) {
                handleException(err, intoGroup);
            }
            validateEntitlements(intoElements,
                                 DataPolicy.PermissionType.CREATE,
                                 Context.INSERT);
        }

        // Validate this query's entitlements
        Collection entitledObjects = GroupCollectorVisitor.getGroups(obj, true);
        if (!isXMLCommand(obj)) {
            entitledObjects.addAll(ElementCollectorVisitor.getElements(obj, true));
        }

        if(entitledObjects.size() == 0) {
            return;
        }
       
        validateEntitlements(entitledObjects, DataPolicy.PermissionType.READ, Context.QUERY);
    }

    /**
     * Validate query entitlements
     */
    protected void validateEntitlements(StoredProcedure obj) {
        validateEntitlements(Arrays.asList(obj.getGroup()), DataPolicy.PermissionType.EXECUTE, Context.STORED_PROCEDURE);
    }

    /**
     * Check that the user is entitled to access all data elements in the command.
     *
     * @param symbols The collection of <code>Symbol</code>s affected by these actions.
     * @param actionCode The actions to validate for
     * @param auditContext The {@link AuthorizationService} to use when resource auditing is done.
     */
    protected void validateEntitlements(Collection<? extends LanguageObject> symbols, DataPolicy.PermissionType actionCode, Context auditContext) {
        Map<String, LanguageObject> nameToSymbolMap = new HashMap<String, LanguageObject>();
        for (LanguageObject symbol : symbols) {
            try {
                String fullName = null;
                Object metadataID = null;
                if(symbol instanceof ElementSymbol) {                   
                    metadataID = ((ElementSymbol)symbol).getMetadataID();
                    if (metadataID instanceof MultiSourceElement || metadataID instanceof TempMetadataID) {
                        continue;
                    }
                } else if(symbol instanceof GroupSymbol) {
                    GroupSymbol group = (GroupSymbol)symbol;
                    metadataID = group.getMetadataID();
                    if (metadataID instanceof TempMetadataID && !group.isProcedure()) {
                        continue;
                    }
                }
                fullName = getMetadata().getFullName(metadataID);
                Object modelId = getMetadata().getModelID(metadataID);
                String modelName = getMetadata().getFullName(modelId);
                if (isSystemSchema(modelName)) {
                  continue;
                }
                nameToSymbolMap.put(fullName, symbol);
            } catch(QueryMetadataException e) {
                handleException(e);
            } catch(TeiidComponentException e) {
                handleException(e);
            }
        }

        validateEntitlements(actionCode, auditContext, nameToSymbolMap);
  }

  private boolean isSystemSchema(String modelName) {
    return CoreConstants.SYSTEM_MODEL.equalsIgnoreCase(modelName) || CoreConstants.ODBC_MODEL.equalsIgnoreCase(modelName);
  }

  private void validateEntitlements(DataPolicy.PermissionType actionCode,
      Context auditContext, Map<String, ? extends LanguageObject> nameToSymbolMap) {
    if (nameToSymbolMap.isEmpty()) {
      return;
    }
    Collection<String> inaccessibleResources = getInaccessibleResources(actionCode, nameToSymbolMap.keySet(), auditContext);
    if(inaccessibleResources.isEmpty()) {
      return;
    }
    List<LanguageObject> inaccessibleSymbols = new ArrayList<LanguageObject>(inaccessibleResources.size());
    for (String name : inaccessibleResources) {
          inaccessibleSymbols.add(nameToSymbolMap.get(name));
      }
     
      // CASE 2362 - do not include the names of the elements for which the user
      // is not authorized in the exception message
     
      handleValidationError(
          QueryPlugin.Util.getString("ERR.018.005.0095", userName, actionCode), //$NON-NLS-1$                   
          inaccessibleSymbols);
  }

    /**
     * Out of resources specified, return the subset for which the specified not have authorization to access.
     */
    public Set<String> getInaccessibleResources(DataPolicy.PermissionType action, Set<String> resources, Context context) {
        logRequest(resources, context);
       
        HashSet<String> results = new HashSet<String>(resources);
       
    for(DataPolicy p:this.allowedPolicies.values()) {
      DataPolicyMetadata policy = (DataPolicyMetadata)p;
     
      if (results.isEmpty()) {
        break;
      }
     
      Iterator<String> i = results.iterator();
      while (i.hasNext()) {       
        if (policy.allows(i.next(), action)) {
          i.remove();
        }
      }
    }

    logResult(resources, context, results.isEmpty());
        return results;
    }

  private void logResult(Set<String> resources, Context context,
      boolean granted) {
    if (LogManager.isMessageToBeRecorded(LogConstants.CTX_AUDITLOGGING, MessageLevel.DETAIL)) {
          if (granted) {
            AuditMessage msg = new AuditMessage(context.name(), "getInaccessibleResources-granted all", this.userName, resources.toArray(new String[resources.size()])); //$NON-NLS-1$
            LogManager.logDetail(LogConstants.CTX_AUDITLOGGING, msg);
          } else {
            AuditMessage msg = new AuditMessage(context.name(), "getInaccessibleResources-denied", this.userName, resources.toArray(new String[resources.size()])); //$NON-NLS-1$
            LogManager.logDetail(LogConstants.CTX_AUDITLOGGING, msg);
          }
    }
  }   
}
TOP

Related Classes of org.teiid.dqp.internal.process.AuthorizationValidationVisitor

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.