diff --git a/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java b/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java index c0539cf..a39cede 100644 --- a/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java +++ b/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java @@ -274,9 +274,11 @@ public void init(AdaptorContext context) throws Exception { if (!isNullOrEmptyString(cfg.getValue("db.aclSql"))) { aclSql = cfg.getValue("db.aclSql"); log.config("acl sql: " + aclSql); - aclPrincipalDelimiter = cfg.getValue("db.aclPrincipalDelimiter"); - log.config("aclPrincipalDelimiter: '" + aclPrincipalDelimiter + "'"); } + // May have delimiter and no aclSql as ACLs might come from + // singleDocContentSql rather than aclSql. + aclPrincipalDelimiter = cfg.getValue("db.aclPrincipalDelimiter"); + log.config("aclPrincipalDelimiter: '" + aclPrincipalDelimiter + "'"); disableStreaming = Boolean.parseBoolean(cfg.getValue("db.disableStreaming")); @@ -291,11 +293,7 @@ public void init(AdaptorContext context) throws Exception { ignored.add("db.updateTimestampTimezone"); } - if (aclSql == null) { - context.setAuthzAuthority(new AllPublic()); - } else { - context.setAuthzAuthority(new AccessChecker()); - } + context.setAuthzAuthority(new AccessChecker()); aclNamespace = cfg.getValue("adaptor.namespace"); log.config("namespace: " + aclNamespace); @@ -675,10 +673,8 @@ public void getDocContent(Request req, Response resp) throws IOException { } // Generate response metadata first. addMetadataToResponse(resp, rs); - // Generate Acl if aclSql is provided. - if (aclSql != null) { - resp.setAcl(getAcl(conn, id.getUniqueId())); - } + // Generate Acl. + resp.setAcl(getAcl(conn, rs, id.getUniqueId())); // Generate response body. // In database adaptor's case, we almost never want to follow the URLs. // One record means one document. @@ -693,22 +689,34 @@ public static void main(String[] args) { AbstractAdaptor.main(new DatabaseAdaptor(), args); } - private Acl getAcl(Connection conn, String uniqueId) throws SQLException { - try (PreparedStatement stmt = getAclFromDb(conn, uniqueId); - ResultSet rs = stmt.executeQuery()) { - log.finer("got acl"); - return buildAcl(rs, aclPrincipalDelimiter, aclNamespace); + private Acl getAcl(Connection conn, ResultSet contentRs, String uniqueId) + throws SQLException { + if (aclSql != null || contentRs == null) { + try (PreparedStatement stmt = getAclFromDb(conn, uniqueId); + ResultSet rs = stmt.executeQuery()) { + log.finer("got acl"); + boolean hasResult = rs.next(); + if (!hasResult) { + // empty Acl ensures adaptor will mark this document as secure + return Acl.EMPTY; + } else if (aclSql != null) { + return buildAcl(rs, aclPrincipalDelimiter, aclNamespace, + ResultSetNext.PROCESS_ALL_ROWS, Acl.EMPTY); + } else { + return buildAcl(rs, aclPrincipalDelimiter, aclNamespace, + ResultSetNext.PROCESS_ONE_ROW, null); + } + } + } else { + // Generate ACL if it came as part of result to singleDocContentSql. + return buildAcl(contentRs, aclPrincipalDelimiter, aclNamespace, + ResultSetNext.PROCESS_ONE_ROW, null); } } @VisibleForTesting - static Acl buildAcl(ResultSet rs, String delim, String namespace) - throws SQLException { - boolean hasResult = rs.next(); - if (!hasResult) { - // empty Acl ensures adaptor will mark this document as secure - return Acl.EMPTY; - } + static Acl buildAcl(ResultSet rs, String delim, String namespace, + ResultSetNext rsNext, Acl defaultAcl) throws SQLException { ResultSetMetaData metadata = rs.getMetaData(); Acl.Builder builder = new Acl.Builder(); ArrayList permitUsers = new ArrayList(); @@ -723,6 +731,12 @@ static Acl buildAcl(ResultSet rs, String delim, String namespace) hasColumn(metadata, GsaSpecialColumns.GSA_PERMIT_GROUPS); boolean hasDenyGroups = hasColumn(metadata, GsaSpecialColumns.GSA_DENY_GROUPS); + + if (!hasPermitUsers && !hasDenyUsers + && !hasPermitGroups && !hasDenyGroups) { + return defaultAcl; + } + do { if (hasPermitUsers) { permitUsers.addAll(getUserPrincipalsFromResultSet(rs, @@ -740,7 +754,7 @@ static Acl buildAcl(ResultSet rs, String delim, String namespace) denyGroups.addAll(getGroupPrincipalsFromResultSet(rs, GsaSpecialColumns.GSA_DENY_GROUPS, delim, namespace)); } - } while (rs.next()); + } while (rsNext == ResultSetNext.PROCESS_ALL_ROWS && rs.next()); return builder .setPermitUsers(permitUsers) .setDenyUsers(denyUsers) @@ -817,8 +831,15 @@ private PreparedStatement getDocFromDb(Connection conn, private PreparedStatement getAclFromDb(Connection conn, String uniqueId) throws SQLException { - PreparedStatement st = conn.prepareStatement(aclSql); - uniqueKey.setAclSqlValues(st, uniqueId); + PreparedStatement st; + // aclSql will only be null when called from isUserAuthorized. + if (aclSql == null) { + st = conn.prepareStatement(singleDocContentSql); + uniqueKey.setContentSqlValues(st, uniqueId); + } else { + st = conn.prepareStatement(aclSql); + uniqueKey.setAclSqlValues(st, uniqueId); + } log.log(Level.FINER, "about to get acl: {0}", uniqueId); return st; } @@ -1085,16 +1106,9 @@ enum GsaSpecialColumns { GSA_TIMESTAMP; } - private static class AllPublic implements AuthzAuthority { - public Map isUserAuthorized(AuthnIdentity userIdentity, - Collection ids) throws IOException { - Map result = - new HashMap(ids.size() * 2); - for (DocId docId : ids) { - result.put(docId, AuthzStatus.PERMIT); - } - return Collections.unmodifiableMap(result); - } + enum ResultSetNext { + PROCESS_ALL_ROWS, + PROCESS_ONE_ROW, } private static Map allDeny(Collection ids) { @@ -1109,32 +1123,29 @@ private static Map allDeny(Collection ids) { private class AccessChecker implements AuthzAuthority { public Map isUserAuthorized(AuthnIdentity userIdentity, Collection ids) throws IOException { - if (null == userIdentity) { - log.info("null identity to authorize"); - return allDeny(ids); // TODO: consider way to permit public - } - UserPrincipal user = userIdentity.getUser(); - if (null == user) { - log.info("null user to authorize"); - return allDeny(ids); // TODO: consider way to permit public - } - log.log(Level.INFO, "about to authorize {0} {1}", - new Object[]{user, userIdentity.getGroups()}); Map result = new HashMap(ids.size() * 2); try (Connection conn = makeNewConnection()) { for (DocId id : ids) { log.log(Level.FINE, "about to get acl of doc {0}", id); - Acl acl = getAcl(conn, id.getUniqueId()); - List aclChain = Arrays.asList(acl); - log.log(Level.FINE, - "about to authorize user {0} for doc {1} and acl {2}", - new Object[]{user, id, acl}); - AuthzStatus decision = Acl.isAuthorized(userIdentity, aclChain); - log.log(Level.FINE, - "authorization decision {0} for user {1} and doc {2}", - new Object[]{decision, user, id}); - result.put(id, decision); + Acl acl = getAcl(conn, null, id.getUniqueId()); + if (acl == null) { + result.put(id, AuthzStatus.PERMIT); + } else if (userIdentity == null || userIdentity.getUser() == null) { + result.put(id, AuthzStatus.DENY); + } else { + log.log(Level.FINE, "about to authorize {0} {1}", + new Object[] {user, userIdentity.getGroups()}); + List aclChain = Arrays.asList(acl); + log.log(Level.FINE, + "about to authorize user {0} for doc {1} and acl {2}", + new Object[] {user, id, acl}); + AuthzStatus decision = Acl.isAuthorized(userIdentity, aclChain); + log.log(Level.FINE, + "authorization decision {0} for user {1} and doc {2}", + new Object[] {decision, user, id}); + result.put(id, decision); + } } } catch (SQLException ex) { throw new IOException("authz retrieval error", ex); diff --git a/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java b/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java index d297e84..924daab 100644 --- a/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java +++ b/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java @@ -60,6 +60,7 @@ import com.google.enterprise.adaptor.StartupException; import com.google.enterprise.adaptor.UserPrincipal; import com.google.enterprise.adaptor.database.DatabaseAdaptor.GsaSpecialColumns; +import com.google.enterprise.adaptor.database.DatabaseAdaptor.ResultSetNext; import com.google.enterprise.adaptor.testing.RecordingDocIdPusher; import com.google.enterprise.adaptor.testing.RecordingResponse; import com.google.enterprise.adaptor.testing.UnsupportedAdaptorContext; @@ -365,6 +366,13 @@ public void testHasColumn() throws Exception { GsaSpecialColumns.GSA_TIMESTAMP)); } + private Acl buildAcl(ResultSet rs, String delim, String namespace) + throws SQLException { + rs.next(); + return DatabaseAdaptor.buildAcl(rs, delim, namespace, + ResultSetNext.PROCESS_ALL_ROWS, Acl.EMPTY); + } + @Test public void testAclSqlResultSetHasNoAclColumns() throws SQLException { Acl golden = Acl.EMPTY; @@ -372,7 +380,7 @@ public void testAclSqlResultSetHasNoAclColumns() throws SQLException { executeUpdate("create table acl(id integer)"); executeUpdate("insert into acl(id) values(1)"); ResultSet rs = executeQuery("select * from acl"); - Acl acl = DatabaseAdaptor.buildAcl(rs, ",", DEFAULT_NAMESPACE); + Acl acl = buildAcl(rs, ",", DEFAULT_NAMESPACE); assertEquals(golden, acl); } @@ -382,7 +390,7 @@ public void testAclSqlResultSetHasNoRecord() throws SQLException { executeUpdate("create table acl(id integer)"); ResultSet rs = executeQuery("select * from acl"); - Acl acl = DatabaseAdaptor.buildAcl(rs, ",", DEFAULT_NAMESPACE); + Acl acl = buildAcl(rs, ",", DEFAULT_NAMESPACE); assertEquals(golden, acl); } @@ -415,10 +423,88 @@ public void testAclSqlResultSetHasOneRecord() throws SQLException { new GroupPrincipal("dgroup1"))) .build(); ResultSet rs = executeQuery("select * from acl"); - Acl acl = DatabaseAdaptor.buildAcl(rs, ",", DEFAULT_NAMESPACE); + Acl acl = buildAcl(rs, ",", DEFAULT_NAMESPACE); assertEquals(golden, acl); } + @Test + public void testSingleDocSqlResultSetHasTwoRecords() throws Exception { + executeUpdate("create table data(" + + "id int, col1 varchar(20)," + + GsaSpecialColumns.GSA_PERMIT_GROUPS + " varchar(20)," + + GsaSpecialColumns.GSA_PERMIT_USERS + " varchar(20)," + + GsaSpecialColumns.GSA_DENY_GROUPS + " varchar(20)," + + GsaSpecialColumns.GSA_DENY_USERS + " varchar(20))"); + executeUpdate("insert into data(" + + "id, col1," + + GsaSpecialColumns.GSA_PERMIT_GROUPS + "," + + GsaSpecialColumns.GSA_PERMIT_USERS + "," + + GsaSpecialColumns.GSA_DENY_GROUPS + "," + + GsaSpecialColumns.GSA_DENY_USERS + ") values (" + + "1, 'test', " + + "'pgroup1, pgroup2', 'puser1, puser2', " + + "'dgroup1, dgroup2', 'duser1, duser2')"); + executeUpdate("insert into data(" + + "id, col1," + + GsaSpecialColumns.GSA_PERMIT_GROUPS + "," + + GsaSpecialColumns.GSA_PERMIT_USERS + "," + + GsaSpecialColumns.GSA_DENY_GROUPS + "," + + GsaSpecialColumns.GSA_DENY_USERS + ") values (" + + "1, 'test2', " + + "'pgroup3, pgroup4', 'puser3, puser4', " + + "'dgroup3, dgroup4', 'duser3, duser4')"); + Acl golden = new Acl.Builder() + .setPermitUsers(Arrays.asList( + new UserPrincipal("puser2"), + new UserPrincipal("puser1"))) + .setDenyUsers(Arrays.asList( + new UserPrincipal("duser1"), + new UserPrincipal("duser2"))) + .setPermitGroups(Arrays.asList( + new GroupPrincipal("pgroup1"), + new GroupPrincipal("pgroup2"))) + .setDenyGroups(Arrays.asList( + new GroupPrincipal("dgroup2"), + new GroupPrincipal("dgroup1"))) + .build(); + + Map configEntries = new HashMap(); + configEntries.put("db.uniqueKey", "id:int"); + configEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); + configEntries.put("db.modeOfOperation", "rowToText"); + // Required for validation, but not specific to this test. + configEntries.put("db.everyDocIdSql", "select id from data"); + + DatabaseAdaptor adaptor = getObjectUnderTest(configEntries); + MockRequest request = new MockRequest(new DocId("1")); + RecordingResponse response = new RecordingResponse(); + adaptor.getDocContent(request, response); + + assertEquals(golden, response.getAcl()); + } + + @Test + public void testSingleDocSqlHasNoAcl() throws Exception { + executeUpdate("create table data(id int, col1 varchar(20))"); + executeUpdate("insert into data(id, col1) values (1, 'test')"); + + Map configEntries = new HashMap(); + configEntries.put("db.uniqueKey", "id:int"); + configEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); + configEntries.put("db.modeOfOperation", "rowToText"); + // Required for validation, but not specific to this test. + configEntries.put("db.everyDocIdSql", "select id from data"); + + DatabaseAdaptor adaptor = getObjectUnderTest(configEntries); + MockRequest request = new MockRequest(new DocId("1")); + RecordingResponse response = new RecordingResponse(); + adaptor.getDocContent(request, response); + + assertNull(response.getAcl()); + } + @Test public void testAclSqlResultSetHasNonOverlappingTwoRecord() throws SQLException { @@ -464,7 +550,7 @@ public void testAclSqlResultSetHasNonOverlappingTwoRecord() new GroupPrincipal("dgroup2"))) .build(); ResultSet rs = executeQuery("select * from acl"); - Acl acl = DatabaseAdaptor.buildAcl(rs, ",", DEFAULT_NAMESPACE); + Acl acl = buildAcl(rs, ",", DEFAULT_NAMESPACE); assertEquals(golden, acl); } @@ -505,7 +591,7 @@ public void testAclSqlResultSetHasOverlappingTwoRecord() new GroupPrincipal("dgroup2"))) .build(); ResultSet rs = executeQuery("select * from acl"); - Acl acl = DatabaseAdaptor.buildAcl(rs, ",", DEFAULT_NAMESPACE); + Acl acl = buildAcl(rs, ",", DEFAULT_NAMESPACE); assertEquals(golden, acl); } @@ -539,7 +625,7 @@ public void testAclSqlResultSetOneColumnPerRow() throws SQLException { new UserPrincipal("duser2"))) .build(); ResultSet rs = executeQuery("select * from acl"); - Acl acl = DatabaseAdaptor.buildAcl(rs, ",", DEFAULT_NAMESPACE); + Acl acl = buildAcl(rs, ",", DEFAULT_NAMESPACE); assertEquals(golden, acl); } @@ -2760,18 +2846,46 @@ private AuthnIdentity getAuthnIdentity(final UserPrincipal user) { @Test public void testAuthzAuthority_public() throws Exception { + executeUpdate("create table data(id int)"); + executeUpdate("insert into data(id) values (1)"); + executeUpdate("insert into data(id) values (2)"); + Map moreEntries = new HashMap(); + moreEntries.put("db.uniqueKey", "id:int"); + moreEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); // Required for validation, but not specific to this test. - executeUpdate("create table data(id int)"); moreEntries.put("db.modeOfOperation", "rowToText"); - moreEntries.put("db.uniqueKey", "id:int"); moreEntries.put("db.everyDocIdSql", "select id from data"); + + AuthzAuthority authority = getAuthzAuthority(moreEntries); + Map answers = authority.isUserAuthorized( + getAuthnIdentity(new UserPrincipal("alice")), + Arrays.asList(new DocId("1"), new DocId("2"))); + + HashMap golden = new HashMap<>(); + golden.put(new DocId("1"), AuthzStatus.PERMIT); + golden.put(new DocId("2"), AuthzStatus.PERMIT); + assertEquals(golden, answers); + } + + @Test + public void testAuthzAuthority_publicNullIdentity() throws Exception { + executeUpdate("create table data(id int)"); + executeUpdate("insert into data(id) values (1)"); + executeUpdate("insert into data(id) values (2)"); + + Map moreEntries = new HashMap(); + moreEntries.put("db.uniqueKey", "id:int"); moreEntries.put("db.singleDocContentSql", "select * from data where id = ?"); + // Required for validation, but not specific to this test. + moreEntries.put("db.modeOfOperation", "rowToText"); + moreEntries.put("db.everyDocIdSql", "select id from data"); AuthzAuthority authority = getAuthzAuthority(moreEntries); Map answers = authority.isUserAuthorized( - getAuthnIdentity(new UserPrincipal("alice")), + null, Arrays.asList(new DocId("1"), new DocId("2"))); HashMap golden = new HashMap<>(); @@ -2863,22 +2977,24 @@ public void testAuthzAuthorityAcl_permit() throws Exception { Map moreEntries = new HashMap(); moreEntries.put("db.aclSql", "select * from acl where id = ?"); + moreEntries.put("db.aclSqlParameters", "id"); + moreEntries.put("db.singleDocContentSqlParameters", "author"); // Required for validation, but not specific to this test. - executeUpdate("create table data(id int)"); + executeUpdate("create table data(id integer, author varchar(20))"); moreEntries.put("db.modeOfOperation", "rowToText"); - moreEntries.put("db.uniqueKey", "id:int"); - moreEntries.put("db.everyDocIdSql", "select id from data"); + moreEntries.put("db.uniqueKey", "id:int,author:string"); + moreEntries.put("db.everyDocIdSql", "select id, author from data"); moreEntries.put("db.singleDocContentSql", - "select * from data where id = ?"); + "select * from data where author = ?"); AuthzAuthority authority = getAuthzAuthority(moreEntries); Map answers = authority.isUserAuthorized( getAuthnIdentity(new UserPrincipal("alice")), - Arrays.asList(new DocId("1"), new DocId("2"))); + Arrays.asList(new DocId("1/tom"), new DocId("2/alice"))); HashMap golden = new HashMap<>(); - golden.put(new DocId("1"), AuthzStatus.INDETERMINATE); - golden.put(new DocId("2"), AuthzStatus.PERMIT); + golden.put(new DocId("1/tom"), AuthzStatus.INDETERMINATE); + golden.put(new DocId("2/alice"), AuthzStatus.PERMIT); assertEquals(golden, answers); } @@ -2909,4 +3025,135 @@ public void testAuthzAuthorityAcl_sqlException() throws Exception { getAuthnIdentity(new UserPrincipal("alice")), Arrays.asList(new DocId("1"), new DocId("2"))); } + + @Test + public void testAuthzAuthoritySingleDocContentSql_noResults() + throws Exception { + executeUpdate("create table data(id integer)"); + + Map moreEntries = new HashMap(); + moreEntries.put("db.uniqueKey", "id:int"); + moreEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); + // Required for validation, but not specific to this test. + moreEntries.put("db.modeOfOperation", "rowToText"); + moreEntries.put("db.everyDocIdSql", "select id from data"); + + AuthzAuthority authority = getAuthzAuthority(moreEntries); + Map answers = authority.isUserAuthorized( + getAuthnIdentity(new UserPrincipal("alice")), + Arrays.asList(new DocId("1"), new DocId("2"))); + + HashMap golden = new HashMap<>(); + golden.put(new DocId("1"), AuthzStatus.INDETERMINATE); + golden.put(new DocId("2"), AuthzStatus.INDETERMINATE); + assertEquals(golden, answers); + } + + @Test + public void testAuthzAuthoritySingleDocContentSql_permit() throws Exception { + executeUpdate("create table data(id integer, author varchar(20), " + + "gsa_permit_users varchar(20), gsa_deny_users varchar(20))"); + executeUpdate("insert into data(id, author, gsa_deny_users) values " + + "(1, 'tom', 'alice')"); + executeUpdate("insert into data(id, author, gsa_permit_users) values " + + "(2, 'alice', 'alice')"); + + Map moreEntries = new HashMap(); + moreEntries.put("db.aclSqlParameters", "author"); + moreEntries.put("db.singleDocContentSqlParameters", "id, author"); + moreEntries.put("db.uniqueKey", "id:int,author:string"); + moreEntries.put("db.singleDocContentSql", + "select * from data where id = ? and author = ?"); + // Required for validation, but not specific to this test. + moreEntries.put("db.modeOfOperation", "rowToText"); + moreEntries.put("db.everyDocIdSql", "select id, author from data"); + + AuthzAuthority authority = getAuthzAuthority(moreEntries); + Map answers = authority.isUserAuthorized( + getAuthnIdentity(new UserPrincipal("alice")), + Arrays.asList(new DocId("1/tom"), new DocId("2/alice"))); + + HashMap golden = new HashMap<>(); + golden.put(new DocId("1/tom"), AuthzStatus.DENY); + golden.put(new DocId("2/alice"), AuthzStatus.PERMIT); + assertEquals(golden, answers); + } + + @Test + public void testAuthzAuthoritySingleDocContentSql_muiltiRowAcl() + throws Exception { + executeUpdate("create table data(id integer, " + + "gsa_permit_users varchar(20), gsa_deny_users varchar(20))"); + executeUpdate("insert into data(id, gsa_deny_users) values (1, 'tom')"); + executeUpdate("insert into data(id, gsa_permit_users) values (1, 'alice')"); + + Map moreEntries = new HashMap(); + moreEntries.put("db.uniqueKey", "id:int"); + moreEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); + // Required for validation, but not specific to this test. + moreEntries.put("db.modeOfOperation", "rowToText"); + moreEntries.put("db.everyDocIdSql", "select id from data"); + + AuthzAuthority authority = getAuthzAuthority(moreEntries); + Map answers = authority.isUserAuthorized( + getAuthnIdentity(new UserPrincipal("alice")), + Arrays.asList(new DocId("1"))); + + HashMap golden = new HashMap<>(); + golden.put(new DocId("1"), AuthzStatus.DENY); + assertEquals(golden, answers); + } + + @Test + public void testAuthzAuthoritySingleDocContentSql_noAclColumns() + throws Exception { + executeUpdate("create table data(id integer)"); + executeUpdate("insert into data(id) values (2)"); + + Map moreEntries = new HashMap(); + moreEntries.put("db.uniqueKey", "id:int"); + moreEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); + // Required for validation, but not specific to this test. + moreEntries.put("db.modeOfOperation", "rowToText"); + moreEntries.put("db.everyDocIdSql", "select id from data"); + + AuthzAuthority authority = getAuthzAuthority(moreEntries); + Map answers = authority.isUserAuthorized( + getAuthnIdentity(new UserPrincipal("alice")), + Arrays.asList(new DocId("1"), new DocId("2"))); + + HashMap golden = new HashMap<>(); + golden.put(new DocId("1"), AuthzStatus.INDETERMINATE); + golden.put(new DocId("2"), AuthzStatus.PERMIT); + assertEquals(golden, answers); + } + + @Test + public void testAuthzAuthoritySingleDocContentSql_noAclEntries() + throws Exception { + executeUpdate("create table data(id integer, " + + "gsa_permit_users varchar(20))"); + executeUpdate("insert into data(id) values (2)"); + + Map moreEntries = new HashMap(); + moreEntries.put("db.uniqueKey", "id:int"); + moreEntries.put("db.singleDocContentSql", + "select * from data where id = ?"); + // Required for validation, but not specific to this test. + moreEntries.put("db.modeOfOperation", "rowToText"); + moreEntries.put("db.everyDocIdSql", "select id from data"); + + AuthzAuthority authority = getAuthzAuthority(moreEntries); + Map answers = authority.isUserAuthorized( + getAuthnIdentity(new UserPrincipal("alice")), + Arrays.asList(new DocId("1"), new DocId("2"))); + + HashMap golden = new HashMap<>(); + golden.put(new DocId("1"), AuthzStatus.INDETERMINATE); + golden.put(new DocId("2"), AuthzStatus.INDETERMINATE); + assertEquals(golden, answers); + } }