Skip to content

Commit

Permalink
TEIID-2844 adding the ability to filter unauthorized columns from select
Browse files Browse the repository at this point in the history
*
  • Loading branch information
shawkins committed Feb 10, 2014
1 parent 6b95798 commit 67bc5ff
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 23 deletions.
4 changes: 2 additions & 2 deletions build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
Expand Up @@ -26,11 +26,11 @@ <H2>Overview</H2>
</UL>
<H2><A NAME="Highlights"></A>Highlights</H2>
<ul>
<<<<<<< HEAD
<li>TEIID-1070 <b>Amazon SimpleDB</b> support has been contributed by Radim Hopp. See the Admin and Reference Guides for more.
<li>TEIID-2761 <b>Security Enhancements</b> added support for a grant-all attribute on a role. Also added the ability to specify the security domain for a VDB. See the reference guide for more.
<li>TEIID-2780 <b>Apache Solr</b> Translator has been added. See the Admin and Reference Guides for more.
<li><b>TEIID-2809</b> Pattern based system property substitution has been added to VDB.XML files. Only supported if the DVB is being deployed JBoss EAP.
<li>TEIID-2809 <b>Pattern based system property substitution</b> has been added to VDB.XML files. Only supported if the DVB is being deployed JBoss EAP.
<li>TEIID-2844 <b>Removsl og unauthorized columns</b> from SELECT * can be enabled via the session property ignore_unauthorized_asterisk. See the Reference for more.
</ul>

<h2><a name="Compatibility">Compatibility Issues</a></h2>
Expand Down
Expand Up @@ -40,6 +40,7 @@
import org.teiid.logging.MessageLevel;
import org.teiid.query.QueryPlugin;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.LanguageObject;
Expand Down Expand Up @@ -295,15 +296,15 @@ protected void validateEntitlements(Collection<? extends LanguageObject> symbols
if (metadataID instanceof TempMetadataID) {
if (group.isProcedure()) {
Map<String, LanguageObject> procMap = new LinkedHashMap<String, LanguageObject>();
addToNameMap(((TempMetadataID)metadataID).getOriginalMetadataID(), symbol, procMap);
addToNameMap(((TempMetadataID)metadataID).getOriginalMetadataID(), symbol, procMap, getMetadata());
validateEntitlements(PermissionType.EXECUTE, auditContext, procMap);
} else if (group.isTempTable() && group.isImplicitTempGroupSymbol()) {
validateTemp(actionCode, group.getNonCorrelationName(), false, group, auditContext);
}
continue;
}
}
addToNameMap(metadataID, symbol, nameToSymbolMap);
addToNameMap(metadataID, symbol, nameToSymbolMap, getMetadata());
} catch(QueryMetadataException e) {
handleException(e);
} catch(TeiidComponentException e) {
Expand All @@ -314,16 +315,16 @@ protected void validateEntitlements(Collection<? extends LanguageObject> symbols
validateEntitlements(actionCode, auditContext, nameToSymbolMap);
}

private void addToNameMap(Object metadataID, LanguageObject symbol, Map<String, LanguageObject> nameToSymbolMap) throws QueryMetadataException, TeiidComponentException {
String fullName = getMetadata().getFullName(metadataID);
Object modelId = getMetadata().getModelID(metadataID);
String modelName = getMetadata().getFullName(modelId);
static void addToNameMap(Object metadataID, LanguageObject symbol, Map<String, LanguageObject> nameToSymbolMap, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
String fullName = metadata.getFullName(metadataID);
Object modelId = metadata.getModelID(metadataID);
String modelName = metadata.getFullName(modelId);
if (!isSystemSchema(modelName)) {
nameToSymbolMap.put(fullName, symbol);
}
}

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

Expand Down
Expand Up @@ -22,19 +22,38 @@

package org.teiid.dqp.internal.process;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import org.teiid.PolicyDecider;
import org.teiid.adminapi.DataPolicy.Context;
import org.teiid.adminapi.DataPolicy.PermissionType;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.types.TransformationException;
import org.teiid.core.util.PropertiesUtils;
import org.teiid.dqp.internal.process.multisource.MultiSourceElement;
import org.teiid.query.QueryPlugin;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.MultipleElementSymbol;
import org.teiid.query.util.CommandContext;

/**
* The default Teiid authorization validator
*/
public class DefaultAuthorizationValidator implements AuthorizationValidator {

public static final String IGNORE_UNAUTHORIZED_ASTERISK = "ignore_unauthorized_asterisk"; //$NON-NLS-1$
private PolicyDecider policyDecider;
private boolean ignoreUnauthorizedAsteriskDefault = PropertiesUtils.getBooleanProperty(System.getProperties(), "org.teiid.ignoreUnauthorizedAsterisk", false); //$NON-NLS-1$

public DefaultAuthorizationValidator() {
}
Expand All @@ -44,10 +63,61 @@ public boolean validate(String[] originalSql, Command command,
QueryMetadataInterface metadata, CommandContext commandContext,
CommandType commandType) throws QueryValidatorException,
TeiidComponentException {
boolean modified = false;
if (policyDecider != null && policyDecider.validateCommand(commandContext)) {
if (ignoreUnathorizedInAsterisk(command, commandContext)) {
Query query = (Query)command;
HashMap<String, LanguageObject> map = null;
for (Expression ex : query.getSelect().getSymbols()) {
if (ex instanceof MultipleElementSymbol) {
MultipleElementSymbol mes = (MultipleElementSymbol)ex;
if (map == null) {
map = new HashMap<String, LanguageObject>();
}
for (Iterator<ElementSymbol> iter = mes.getElementSymbols().iterator(); iter.hasNext();) {
ElementSymbol es = iter.next();
Object metadataObject = es.getMetadataID();
if (metadataObject instanceof MultiSourceElement || metadataObject instanceof TempMetadataID) {
continue;
}
map.clear();
AuthorizationValidationVisitor.addToNameMap(metadataObject, es, map, commandContext.getMetadata());
Set<String> results = this.policyDecider.getInaccessibleResources(PermissionType.READ, map.keySet(), Context.QUERY, commandContext);
if (!results.isEmpty()) {
iter.remove(); //remove from the select
modified = true;
}
}
}
}
if (query.getProjectedSymbols().isEmpty()) {
throw new QueryValidatorException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31151));
}
}
AuthorizationValidationVisitor visitor = new AuthorizationValidationVisitor(this.policyDecider, commandContext);
Request.validateWithVisitor(visitor, metadata, command);
}
return modified;
}

private boolean ignoreUnathorizedInAsterisk(Command command, CommandContext commandContext) {
if (!(command instanceof Query)) {
return false;
}
Query query = (Query)command;
if (query.getIsXML() || query.getInto() != null) {
return false;
}
if (ignoreUnauthorizedAsteriskDefault) {
return true;
}
Object value = commandContext.getSessionVariable(IGNORE_UNAUTHORIZED_ASTERISK);
if (value != null) {
try {
return Boolean.TRUE.equals(DataTypeManager.transformValue(value, DataTypeManager.DefaultDataClasses.BOOLEAN));
} catch (TransformationException e) {
}
}
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion engine/src/main/java/org/teiid/query/QueryPlugin.java
Expand Up @@ -562,6 +562,7 @@ public static enum Event implements BundleUtil.Event{
TEIID31147,
TEIID31148,
TEIID31149,
TEIID31150
TEIID31150,
TEIID31151
}
}
Expand Up @@ -170,7 +170,6 @@ private static GroupSymbol resolveAllInGroup(MultipleElementSymbol allInGroupSym
qre.addUnresolvedSymbol(new UnresolvedSymbolDescription(allInGroupSymbol.toString(), msg));
throw qre;
}
GroupSymbol gs = allInGroupSymbol.getGroup();
allInGroupSymbol.setGroup(groupSymbols.get(0).clone());
return groupSymbols.get(0);
}
Expand Down
4 changes: 3 additions & 1 deletion engine/src/main/resources/org/teiid/query/i18n.properties
Expand Up @@ -1119,4 +1119,6 @@ TEIID31146=Translator {2} not found for vdb {0} {1}
TEIID31144=One or more of required properties for materialization management is missing. Required properties are teiid_rel:MATVIEW_STATUS_TABLE, teiid_rel:MATVIEW_BEFORE_LOAD_SCRIPT, teiid_rel:MATVIEW_AFTER_LOAD_SCRIPT, teiid_rel:MATVIEW_LOAD_SCRIPT, teiid_rel:MATERIALIZED_STAGE_TABLE
TEIID31147=The materialized view {0}.{1} materialization table is currently not in valid state.
TEIID31148=Invalid virtual model {0} specified in conformed sources for {1}.
TEIID31149=No columns are specified on key {1} for table {0}.
TEIID31149=No columns are specified on key {1} for table {0}.

TEIID31151=After removing unauthorized columns from asterisk in select, no valid columns remain selected.
Expand Up @@ -24,6 +24,7 @@

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -36,11 +37,12 @@
import org.teiid.adminapi.DataPolicy.PermissionType;
import org.teiid.adminapi.impl.DataPolicyMetadata;
import org.teiid.adminapi.impl.DataPolicyMetadata.PermissionMetaData;
import org.teiid.adminapi.impl.SessionMetadata;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.api.exception.query.QueryParserException;
import org.teiid.api.exception.query.QueryResolverException;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.core.TeiidComponentException;
import org.teiid.dqp.internal.process.AuthorizationValidator.CommandType;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.resolver.QueryResolver;
Expand All @@ -63,8 +65,8 @@ public class TestAuthorizationValidationVisitor {

@Before public void setup() {
context = new CommandContext();
context.setSession(new SessionMetadata());
context.setDQPWorkContext(new DQPWorkContext());
context.setSession(context.getDQPWorkContext().getSession());
}

@BeforeClass static public void oneTimeSetup() {
Expand Down Expand Up @@ -189,15 +191,7 @@ private void helpTest(String sql, QueryMetadataInterface metadata, String[] expe
Command command = parser.parseCommand(sql);
QueryResolver.resolveCommand(command, metadata);

vdb.addAttchment(QueryMetadataInterface.class, metadata);

HashMap<String, DataPolicy> policies = new HashMap<String, DataPolicy>();
for (DataPolicyMetadata dataPolicyMetadata : roles) {
policies.put(dataPolicyMetadata.getName(), dataPolicyMetadata);
}
this.context.getDQPWorkContext().setPolicies(policies);
DataRolePolicyDecider dataRolePolicyDecider = new DataRolePolicyDecider();
dataRolePolicyDecider.setAllowFunctionCallsByDefault(false);
DataRolePolicyDecider dataRolePolicyDecider = createPolicyDecider(metadata, vdb, roles);
AuthorizationValidationVisitor visitor = new AuthorizationValidationVisitor(dataRolePolicyDecider, context); //$NON-NLS-1$
ValidatorReport report = Validator.validate(command, metadata, visitor);
if(report.hasItems()) {
Expand All @@ -219,6 +213,24 @@ private void helpTest(String sql, QueryMetadataInterface metadata, String[] expe
fail("Expected inaccessible objects, but got none."); //$NON-NLS-1$
}
}

private DataRolePolicyDecider createPolicyDecider(
QueryMetadataInterface metadata, VDBMetaData vdb,
DataPolicyMetadata... roles) {
vdb.addAttchment(QueryMetadataInterface.class, metadata);

HashMap<String, DataPolicy> policies = new HashMap<String, DataPolicy>();
for (DataPolicyMetadata dataPolicyMetadata : roles) {
policies.put(dataPolicyMetadata.getName(), dataPolicyMetadata);
}
vdb.setDataPolicies(new ArrayList<DataPolicy>(policies.values()));
this.context.getDQPWorkContext().setPolicies(policies);
this.context.getSession().setVdb(vdb);
this.context.setMetadata(metadata);
DataRolePolicyDecider dataRolePolicyDecider = new DataRolePolicyDecider();
dataRolePolicyDecider.setAllowFunctionCallsByDefault(false);
return dataRolePolicyDecider;
}

@Test public void testProcRelational() throws Exception {
helpTest("select * from sp1", RealMetadataFactory.example1Cached(), new String[] {}, RealMetadataFactory.example1VDB(), exampleAuthSvc1); //$NON-NLS-1$
Expand Down Expand Up @@ -393,4 +405,50 @@ private void helpTest(String sql, QueryMetadataInterface metadata, String[] expe
helpTest("create foreign temporary table x (id string) on bqt1", RealMetadataFactory.exampleBQTCached(), new String[] {}, RealMetadataFactory.exampleBQTVDB(), svc); //$NON-NLS-1$ //$NON-NLS-2$
helpTest("select * from xmltest.doc1", RealMetadataFactory.example1Cached(), new String[] {}, RealMetadataFactory.example1VDB(), svc); //$NON-NLS-1$ //$NON-NLS-2$
}

@Test public void testPruneSelectAll() throws Exception {
String sql = "select * from pm1.g1";
QueryMetadataInterface metadata = RealMetadataFactory.example1Cached();

DataPolicyMetadata svc = new DataPolicyMetadata();
svc.setName("test"); //$NON-NLS-1$

svc.addPermission(addResource(DataPolicy.PermissionType.READ, "pm1")); //$NON-NLS-1$
PermissionMetaData p = addResource(DataPolicy.PermissionType.READ, "pm1.g1.e1");
p.setAllowRead(false);
svc.addPermission(p); //$NON-NLS-1$

DataRolePolicyDecider dataRolePolicyDecider = createPolicyDecider(metadata, RealMetadataFactory.example1VDB(), svc);

DefaultAuthorizationValidator dav = new DefaultAuthorizationValidator();
dav.setPolicyDecider(dataRolePolicyDecider);
this.context.setSessionVariable(DefaultAuthorizationValidator.IGNORE_UNAUTHORIZED_ASTERISK, "true");

QueryParser parser = QueryParser.getQueryParser();
Command command = parser.parseCommand(sql);
QueryResolver.resolveCommand(command, metadata);

assertEquals(4, command.getProjectedSymbols().size());

boolean modified = dav.validate(new String[] {}, command, metadata, this.context, CommandType.USER);
assertTrue(modified);

assertEquals(3, command.getProjectedSymbols().size());

p = addResource(DataPolicy.PermissionType.READ, "pm1.g1");
p.setAllowRead(false);
svc.addPermission(p); //$NON-NLS-1$

command = parser.parseCommand(sql);
QueryResolver.resolveCommand(command, metadata);

assertEquals(4, command.getProjectedSymbols().size());

try {
dav.validate(new String[] {}, command, metadata, this.context, CommandType.USER);
fail();
} catch (QueryValidatorException e) {

}
}
}

0 comments on commit 67bc5ff

Please sign in to comment.