提交 384b18f5 authored 作者: noelgrandin's avatar noelgrandin

Adding support for "GRANT ALTER ANY SCHEMA TO <user>", patch by John Yates

上级 e67580d7
......@@ -902,6 +902,17 @@ This command commits an open transaction.
GRANT SELECT ON TEST TO READONLY
"
"Commands (Other)","GRANT ALTER ANY SCHEMA","
GRANT ALTER ANY SCHEMA TO userName
","
Grant schema altering rights to a user.
Admin rights are required to execute this command.
This command commits an open transaction.
","
GRANT ALTER ANY SCHEMA TO Bob
"
"Commands (Other)","GRANT ROLE","
GRANT roleName TO { PUBLIC | userName | roleName }
","
......
......@@ -88,6 +88,7 @@ Change Log
Add optional export to MANIFEST.MF for JTS Geometry classes
Validate that geometry values can be represented in WKB.
</li><li>Issue 506: RFE: Include Thread.getName() in case of a deadlock
</li><li>Adding support for "GRANT ALTER ANY SCHEMA TO <user>", patch by John Yates
</li></ul>
<h2>Version 1.3.173 (2013-07-28)</h2>
......
......@@ -3942,45 +3942,54 @@ public class Parser {
}
}
/**
* @return true if we expect to see a TABLE clause
*/
private boolean addRoleOrRight(GrantRevoke command) {
if (readIf("SELECT")) {
command.addRight(Right.SELECT);
return false;
return true;
} else if (readIf("DELETE")) {
command.addRight(Right.DELETE);
return false;
return true;
} else if (readIf("INSERT")) {
command.addRight(Right.INSERT);
return false;
return true;
} else if (readIf("UPDATE")) {
command.addRight(Right.UPDATE);
return false;
return true;
} else if (readIf("ALL")) {
command.addRight(Right.ALL);
return true;
} else if (readIf("ALTER")) {
read("ANY");
read("SCHEMA");
command.addRight(Right.ALTER_ANY_SCHEMA);
command.addTable(null);
return false;
} else if (readIf("CONNECT")) {
// ignore this right
return false;
return true;
} else if (readIf("RESOURCE")) {
// ignore this right
return false;
return true;
} else {
command.addRoleName(readUniqueIdentifier());
return true;
return false;
}
}
private GrantRevoke parseGrantRevoke(int operationType) {
GrantRevoke command = new GrantRevoke(session);
command.setOperationType(operationType);
boolean isRoleBased = addRoleOrRight(command);
boolean tableClauseExpected = addRoleOrRight(command);
while (readIf(",")) {
boolean next = addRoleOrRight(command);
if (next != isRoleBased) {
addRoleOrRight(command);
if (command.isRightMode() && command.isRoleMode()) {
throw DbException.get(ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED);
}
}
if (!isRoleBased) {
if (tableClauseExpected) {
if (readIf("ON")) {
do {
Table table = readTableOrView();
......
......@@ -47,7 +47,7 @@ public class AlterSchemaRename extends DefineCommand {
if (db.findSchema(newSchemaName) != null || newSchemaName.equals(oldSchema.getName())) {
throw DbException.get(ErrorCode.SCHEMA_ALREADY_EXISTS_1, newSchemaName);
}
session.getUser().checkAdmin();
session.getUser().checkSchemaAdmin();
db.renameDatabaseObject(session, oldSchema, newSchemaName);
ArrayList<SchemaObject> all = db.getAllSchemaObjects();
for (SchemaObject schemaObject : all) {
......
......@@ -34,11 +34,14 @@ public class CreateSchema extends DefineCommand {
@Override
public int update() {
session.getUser().checkAdmin();
session.getUser().checkSchemaAdmin();
session.commit(true);
Database db = session.getDatabase();
User user = db.getUser(authorization);
user.checkAdmin();
// during DB startup, the Right/Role records have not yet been loaded
if (!db.isStarting()) {
user.checkSchemaAdmin();
}
if (db.findSchema(schemaName) != null) {
if (ifNotExists) {
return 0;
......
......@@ -32,7 +32,7 @@ public class DropSchema extends DefineCommand {
@Override
public int update() {
session.getUser().checkAdmin();
session.getUser().checkSchemaAdmin();
session.commit(true);
Database db = session.getDatabase();
Schema schema = db.findSchema(schemaName);
......
......@@ -183,4 +183,17 @@ public class GrantRevoke extends DefineCommand {
return operationType;
}
/**
* @return true if this command is using Roles
*/
public boolean isRoleMode() {
return roleNames != null;
}
/**
* @return true if this command is using Rights
*/
public boolean isRightMode() {
return rightMask != 0;
}
}
......@@ -36,6 +36,11 @@ public class Right extends DbObjectBase {
*/
public static final int UPDATE = 8;
/**
* The right bit mask that means: create/alter/drop schema is allowed.
*/
public static final int ALTER_ANY_SCHEMA = 16;
/**
* The right bit mask that means: select, insert, update, delete, and update
* for this object is allowed.
......@@ -80,6 +85,7 @@ public class Right extends DbObjectBase {
comma = appendRight(buff, grantedRight, SELECT, "SELECT", comma);
comma = appendRight(buff, grantedRight, DELETE, "DELETE", comma);
comma = appendRight(buff, grantedRight, INSERT, "INSERT", comma);
comma = appendRight(buff, grantedRight, ALTER_ANY_SCHEMA, "ALTER ANY SCHEMA", comma);
appendRight(buff, grantedRight, UPDATE, "UPDATE", comma);
}
return buff.toString();
......@@ -109,7 +115,10 @@ public class Right extends DbObjectBase {
if (grantedRole != null) {
buff.append(grantedRole.getSQL());
} else {
buff.append(getRights()).append(" ON ").append(table.getSQL());
buff.append(getRights());
if (table != null) {
buff.append(" ON ").append(table.getSQL());
}
}
buff.append(" TO ").append(grantee.getSQL());
return buff.toString();
......
......@@ -105,12 +105,12 @@ public class User extends RightOwner {
/**
* See if this user has the given rights for this database object.
*
* @param table the database object
* @param table the database object, or null for schema-only check
* @param rightMask the rights required
* @return true if the user has the rights
*/
public boolean hasRight(Table table, int rightMask) {
if (rightMask != Right.SELECT && !systemUser) {
if (rightMask != Right.SELECT && !systemUser && table != null) {
table.checkWritingAllowed();
}
if (admin) {
......@@ -124,6 +124,7 @@ public class User extends RightOwner {
// everybody has access to the metadata information
return true;
}
if (table != null) {
String tableType = table.getTableType();
if (Table.VIEW.equals(tableType)) {
TableView v = (TableView) table;
......@@ -140,6 +141,7 @@ public class User extends RightOwner {
// the owner has all rights on local temporary tables
return true;
}
}
if (isRightGrantedRecursive(table, rightMask)) {
return true;
}
......@@ -203,6 +205,18 @@ public class User extends RightOwner {
}
}
/**
* Check if this user has schema admin rights. An exception is thrown if he does
* not have them.
*
* @throws DbException if this user is not a schema admin
*/
public void checkSchemaAdmin() {
if (!admin && !hasRight(null, Right.ALTER_ANY_SCHEMA)) {
throw DbException.get(ErrorCode.ADMIN_RIGHTS_REQUIRED);
}
}
@Override
public int getType() {
return DbObject.USER;
......
......@@ -43,6 +43,7 @@ public class TestRights extends TestBase {
// testLowerCaseUser();
testSchemaRenameUser();
testAccessRights();
testSchemaAdminRole();
deleteDb("rights");
}
......@@ -199,6 +200,71 @@ public class TestRights extends TestBase {
conn.close();
}
private void testSchemaAdminRole() throws SQLException {
if (config.memory) {
return;
}
deleteDb("rights");
Connection conn = getConnection("rights");
stat = conn.createStatement();
// default table type
testTableType(conn, "MEMORY");
testTableType(conn, "CACHED");
executeSuccess("CREATE USER SCHEMA_CREATOR PASSWORD 'xyz'");
executeSuccess("CREATE SCHEMA SCHEMA_RIGHT_TEST");
executeSuccess("ALTER SCHEMA SCHEMA_RIGHT_TEST RENAME TO SCHEMA_RIGHT_TEST_RENAMED");
executeSuccess("DROP SCHEMA SCHEMA_RIGHT_TEST_RENAMED");
executeSuccess("CREATE SCHEMA SCHEMA_RIGHT_TEST_EXISTS");
conn.close();
/* try and fail */
conn = getConnection("rights;LOG=2", "SCHEMA_CREATOR", getPassword("xyz"));
stat = conn.createStatement();
assertThrows(ErrorCode.ADMIN_RIGHTS_REQUIRED, stat).
execute("CREATE SCHEMA SCHEMA_RIGHT_TEST_WILL_FAIL");
assertThrows(ErrorCode.ADMIN_RIGHTS_REQUIRED, stat).
execute("ALTER SCHEMA SCHEMA_RIGHT_TEST_EXISTS RENAME TO SCHEMA_RIGHT_TEST_WILL_FAIL");
assertThrows(ErrorCode.ADMIN_RIGHTS_REQUIRED, stat).
execute("DROP SCHEMA SCHEMA_RIGHT_TEST_EXISTS");
conn.close();
/* give them */
conn = getConnection("rights");
stat = conn.createStatement();
executeSuccess("DROP SCHEMA SCHEMA_RIGHT_TEST_EXISTS");
executeSuccess("GRANT ALTER ANY SCHEMA TO SCHEMA_CREATOR");
conn.close();
/* try and succeed */
conn = getConnection("rights;LOG=2", "SCHEMA_CREATOR", getPassword("xyz"));
stat = conn.createStatement();
executeSuccess("CREATE SCHEMA SCHEMA_RIGHT_TEST");
executeSuccess("ALTER SCHEMA SCHEMA_RIGHT_TEST RENAME TO SCHEMA_RIGHT_TEST_RENAMED");
executeSuccess("DROP SCHEMA SCHEMA_RIGHT_TEST_RENAMED");
executeSuccess("CREATE SCHEMA SCHEMA_RIGHT_TEST_EXISTS");
conn.close();
/* revoke them */
conn = getConnection("rights");
stat = conn.createStatement();
executeSuccess("REVOKE ALTER ANY SCHEMA FROM SCHEMA_CREATOR");
conn.close();
/* try and fail */
conn = getConnection("rights;LOG=2", "SCHEMA_CREATOR", getPassword("xyz"));
stat = conn.createStatement();
assertThrows(ErrorCode.ADMIN_RIGHTS_REQUIRED, stat).
execute("CREATE SCHEMA SCHEMA_RIGHT_TEST");
assertThrows(ErrorCode.ADMIN_RIGHTS_REQUIRED, stat).
execute("ALTER SCHEMA SCHEMA_RIGHT_TEST_EXISTS RENAME TO SCHEMA_RIGHT_TEST_RENAMED");
assertThrows(ErrorCode.ADMIN_RIGHTS_REQUIRED, stat).
execute("DROP SCHEMA SCHEMA_RIGHT_TEST_EXISTS");
conn.close();
}
private void testAccessRights() throws SQLException {
if (config.memory) {
return;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论