-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add AuthAdmin #1318
Add AuthAdmin #1318
Conversation
* An interface for administrative operations for authentication and authorization. This interface | ||
* is used for creating and dropping users, and granting and revoking privileges. | ||
*/ | ||
public interface AuthAdmin { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added AuthAdmin
for administrative operations for ScalarDB Auth.
@@ -8,7 +8,7 @@ | |||
* An administrative interface for distributed transaction implementations. The user can execute | |||
* administrative operations with it like createNamespace/createTable/getTableMetadata. | |||
*/ | |||
public interface DistributedTransactionAdmin extends Admin { | |||
public interface DistributedTransactionAdmin extends Admin, AuthAdmin { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made DistributedTransactionAdmin
extend AuthAdmin
.
private final boolean authenticationError; | ||
private final boolean authorizationError; | ||
private final boolean superuserRequired; | ||
@Nullable private final AuthAdmin.Privilege requiredPrivilege; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added flags to the exceptions to indicate authentication and authorization errors. Initially, I considered introducing new exceptions for these errors, but to maintain backward compatibility, I opted for this approach.
@Override | ||
public void createUser(String username, @Nullable String password, UserOption... userOption) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public void alterUser(String username, @Nullable String password, UserOption... userOption) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public void dropUser(String username) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public void grant(String username, String namespaceName, Privilege... privileges) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public void grant( | ||
String username, String namespaceName, String tableName, Privilege... privileges) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public void revoke(String username, String namespaceName, Privilege... privileges) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public void revoke( | ||
String username, String namespaceName, String tableName, Privilege... privileges) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public List<User> getUsers() { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public EnumSet<Privilege> getPrivileges(String username, String namespaceName) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} | ||
|
||
@Override | ||
public EnumSet<Privilege> getPrivileges(String username, String namespaceName, String tableName) { | ||
throw new UnsupportedOperationException("Not supported in the community edition"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No implementations are added here as it's an enterprise feature.
d0a3149
to
d38d93f
Compare
@@ -240,6 +243,58 @@ public void upgrade(Map<String, String> options) throws ExecutionException { | |||
admin.upgrade(options); | |||
} | |||
|
|||
@Override | |||
public void createUser(String username, @Nullable String password, UserOption... userOption) { | |||
throw new UnsupportedOperationException("Not supported in the community edition"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about moving these default implementations throwing the exception to AuthAdmin
as default methods so that all classes which inherit AuthAdmin
don't need to implement these ones?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had the same thought, but I didn't do that because I was not sure for which methods we should add a default implementation. In other words, should we add default implementations for the existing methods (createTable()
, getTableMetadata()
, etc.) as well? What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think only the methods of AuthAdmin
should have default methods to throw the exception since those features aren't supported in the community edition. As for the existing methods coming from DistributedTransactionAdmin
, we should keep them available in the community edition and don't need default impl for them. But I might be missing something on the background of this auth feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I think that's reasonable. Let me add default implementations to the methods in AuthAdmin
. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in ca46a9d. Thanks.
|
||
@Override | ||
public void createUser(String username, @Nullable String password, UserOption... userOption) { | ||
throw new UnsupportedOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This exception should have the same error message as the exceptions ConsensusCommitAdmin's methods throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially, I didn't add any message here because we were going to remove the JDBC transaction and ScalarDB Server components. However, recent discussions have raised the possibility of retaining the JDBC transaction. Therefore, I will add a message depending on the outcome of this discussion:
#1318 (comment)
Thanks.
} | ||
|
||
/** The privileges for ScalarDB operations. */ | ||
enum Privilege { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like an union of privileges for user (admin) operations, namespace operations and table operations. For instance, GRANT is for user (admin) operations and TRUNCATE is for table operations. Another option is to separate this set of privileges into each type of operations like UserPrivilege, NamespacePrivilege and TablePrivilege. This option requires additional enum definitions, but it might beneficial in the long run to avoid wrong privilege usage (e.g, TRUNCATE for a user). What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me clarify the specification to ensure we are on the same page.
Currently, we can grant privileges to a user for either a specific namespace or a table. I think we can imagine the SQL GRANT
statement as follows:
For table privileges:
GRANT READ, WRITE, CREATE ON <TABLE> TO <USER> WITH GRANT OPTION
In this case, the user has READ
, WRITE
, CREATE
and GRANT
privileges for the specified table.
READ
: The user can read the table.WRITE
: The user can write the table.CREATE
: The user can create indexes on the table.GRANT
: The user can grant privileges on the table to other users.
For namespace privileges:
GRANT READ, WRITE, CREATE ON NAMESPACE <NAMESPACE> TO <USER> WITH GRANT OPTION
In this case, the user has READ
, WRITE
, CREATE
and GRANT
privileges for all tables in the namespace.
READ
: The user can read all tables in the namespace.WRITE
: The user can write all tables in the namespace.CREATE
: The user can create a table in the namespace or create indexes on all tables in the namespace.GRANT
: The user can grant privileges on all tables in the namespace to other users.
Given this, I believe the approach is consistent and there's no need for separate privilege types for tables, namespaces, and users. What are your thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clarifying the usage. I understand how to use GRANT.
GRANT privilege seems a bit different type (more metadata-like?) attribute to me from other privileges (e.g. CREATE). It's like between UserOption
and Privilege
? It might fit PrivilegeOption
.
In this case, the user has READ, WRITE, CREATE and GRANT privileges for all tables in the namespace.
Understood. So, the enum is like TablePrivilege
. BTW, we don't need to another type of privileges to allow or prohibit operations for namespaces like GRANT CREATE ON DATABASE
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry, the explanation of GRANT
for namespace privileges was wrong.
The correct explanation is as follows
GRANT
: The user can grant/revoke privileges on all tables in the namespace to/from other users. Also the user can grant/revoke privileges on the namespace to/from other users.
So for example, if a superuser issues the following:
GRANT ... ON NAMESPACE ns TO user1 WITH GRANT OPTION
Then user1
can issue GRANT... ON NAMESPACE ns to ...
for other users. Also, user1
can issue GRANT
on all tables in the ns
namespace for other users.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more thing, if a superuser issues the following GRANT
command:
GRANT DROP ON NAMESPACE ns TO user1
Then, user1
can drop the ns
namespace as well as all tables in the ns
namespace.
That sounds inconsistent to you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GRANT DROP ON NAMESPACE ns TO user1
As we talked offline, this semantics of dropping a specific namespace seems inconsistent with other GRANT statements that affect tables. Perhaps, we can defer considering how to permit/prohibit manipulation of namespace.
As for Privilege.GRANT
, I still think it might belong to a different layer, but I don't have a so strong opinion on it. Let's proceed with the current design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for summarizing the discussion. I've fixed the Javadoc slightly and renamed several methods.
I think we can support something like the following grammar in ScalarDB SQL:
GRANT { { SELECT | INSERT | UPDATE | DELETE | CREATE | DROP | TRUNCATE | ALTER } [, ...] | ALL [ PRIVILEGES ] }
ON { [ TABLE ] table_name [, ...] | ON NAMESPACE namespace_name [, ...] }
TO user_name [, ...] [ WITH GRANT OPTION ]
If a user specified ON [TABLE] table_name
in the GRANT
statement, we call the AuthAdmin.grant(String username, String namespaceName, String tableName, Privilege... privileges)
method. And if a user specified ON NAMESPACE namespace_name
in the GRANT
statement, we call the AuthAdmin.grant(String username, String namespaceName, Privilege... privileges)
method.
Also, if a user specified WITH GRANT OPTION
and ON [TABLE] table_name
in the GRANT statement, the granted user can issue GRANT statements, and they can grant privileges on the specified table to other users.
And if a user specified WITH GRANT OPTION
and ALL TABLES IN NAMESPACE namespace_name
in the GRANT
statement, they can grant privileges on all tables in the specified namespace to other users.
Note that users can only grant privileges that they have to other users.
Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The syntax of the GRANT statement and the behavior looks good 👍
As for Privilege.GRANT, I still think it might belong to a different layer, but I don't have a so strong opinion on it. Let's proceed with the current design.
This comment only considers the internal design and implementation since I still think WITH GRANT OPTION
is a sort of option not a normal privilege. The above GRANT statement syntax itself also seems to handle GRANT
option differently from other privileges (e.g., UPDATE
). I checked the PostgreSQL source code, and it doesn't handle GRANT OPTION as well as other privileges https://github.com/postgres/postgres/blob/5ad49322e50459444b201e624d5df706751c9d41/src/include/nodes/parsenodes.h#L74-L93. So, IMO, maybe Privilege.GRANT
should be removed from the enum and handled differently, although it might be a matter of taste.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline, we have reached a conclusion regarding the behavior mentioned in the following comment:
#1318 (comment)
I've also revised the Javadoc and revered the method names in ad52e62.
@komamitsu Can you please take a quick look at it? Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Looks good!
6345ceb
to
b8c724e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 👍
3485cd6
to
e43fc39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, looking good. Thank you!
I left one comment. PTAL!
String message, | ||
Throwable cause, | ||
@Nullable String transactionId, | ||
boolean authenticationError) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of adding an argument only for authentication, it might be better to define an error code and add it here or something?
Since we don't define error code yet, I understand it's hard to do so now...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, at the moment, it's hard to do so since we need to define error codes for all errors for that. Anyway, I think we can add error codes later on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thank you!
Description
This PR adds the
AuthAdmin
interface for administrative operations related to ScalarDB Auth (authentication and authorization). As ScalarDB Auth is an enterprise feature, this PR only introduces the interface without any implementations in this repository.Related issues and/or PRs
N/A
Changes made
AuthAdmin
interface for administrative operations for ScalarDBChecklist
Additional notes (optional)
Release notes
N/A