vtlim commented on code in PR #14009:
URL: https://github.com/apache/druid/pull/14009#discussion_r1156462105


##########
docs/operations/security-overview.md:
##########
@@ -176,70 +170,82 @@ An example configuration:
    druid.auth.authorizer.MyBasicMetadataAuthorizer.type=basic
    ```
 
-3. Restart the cluster. 
+3. Restart the cluster.
 
-See [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator, Escalator, and Authorizer concepts. See [Basic 
Security](../development/extensions-core/druid-basic-security.md) for more 
information about the extension used in the examples above, and 
[Kerberos](../development/extensions-core/druid-kerberos.md) for Kerberos 
authentication.
+See

Review Comment:
   ```suggestion
   See the following topics for more information:
   ```



##########
docs/operations/security-overview.md:
##########
@@ -176,70 +170,82 @@ An example configuration:
    druid.auth.authorizer.MyBasicMetadataAuthorizer.type=basic
    ```
 
-3. Restart the cluster. 
+3. Restart the cluster.
 
-See [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator, Escalator, and Authorizer concepts. See [Basic 
Security](../development/extensions-core/druid-basic-security.md) for more 
information about the extension used in the examples above, and 
[Kerberos](../development/extensions-core/druid-kerberos.md) for Kerberos 
authentication.
+See
 
+* [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator,
+Escalator, and Authorizer concepts.
+* [Basic Security](../development/extensions-core/druid-basic-security.md) for 
more information about
+the extension used in the examples above.
+* [Kerberos](../development/extensions-core/druid-kerberos.md) for Kerberos 
authentication.
+* [User authentication and authorization](security-user-auth.md) for details 
of permissions.
+* [SQL permissions](security-user-auth.md#sql-permissions) for permissions on 
SQL system tables.
+* The `druidapi` Python library, provided as part of the Druid tutorisls, for 
functions you can

Review Comment:
   ```suggestion
   * [The `druidapi` Python 
library](../tutorials/tutorial-jupyter-index.md#python-api-for-druid), provided 
as part of the Druid tutorials, for functions you can
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/druid.py:
##########
@@ -116,6 +117,33 @@ def datasources(self) -> DatasourceClient:
         if not self.datasource_client:
             self.datasource_client = DatasourceClient(self.rest_client)
         return self.datasource_client
+    
+    def basic_security(self, authenticator, authorizer=None):
+        '''
+        Returns a client to work with a basic authorization 
authenticator/authorizer pair.
+        This client assumes the typical case of one authenticator and one 
authorizer. If
+        you have more than one, create multiple clients.
+
+        The basic security API is not proxied through the router: it must work 
directly with
+        the coordinator. Create an ad-hoc Druid client for your coordinator. 
Because you have
+        Basic security enabled, you must specify the admin user and password:
+
+        ```
+        coord = druidapi.jupyter_client('http://localhost:8081', 
auth=('admin', 'admin-pwd'))
+        ac = coord.basic_security('yourAuthenticator', 'yourAuthorizer')
+        ```
+
+        Parameters
+        ----------
+        authenticator: str
+            Authenticator name as set in the `druid.auth.authenticatorChain`
+            runtime property.
+
+        authorizer: str, default = authenticator
+            Authorizor name as set in the `druid.auth.authorizers` runtime 
property.
+            Defaults to the same as `authenticator` for simple cases.

Review Comment:
   Is the default value of `authorizer` the string "authenticator", or is the 
default value the same value of what's assigned to `authenticator`?



##########
docs/operations/security-overview.md:
##########
@@ -176,70 +170,82 @@ An example configuration:
    druid.auth.authorizer.MyBasicMetadataAuthorizer.type=basic
    ```
 
-3. Restart the cluster. 
+3. Restart the cluster.
 
-See [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator, Escalator, and Authorizer concepts. See [Basic 
Security](../development/extensions-core/druid-basic-security.md) for more 
information about the extension used in the examples above, and 
[Kerberos](../development/extensions-core/druid-kerberos.md) for Kerberos 
authentication.
+See
 
+* [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator,
+Escalator, and Authorizer concepts.

Review Comment:
   ```suggestion
   Escalator, and Authorizer.
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/druid.py:
##########
@@ -116,6 +117,33 @@ def datasources(self) -> DatasourceClient:
         if not self.datasource_client:
             self.datasource_client = DatasourceClient(self.rest_client)
         return self.datasource_client
+    
+    def basic_security(self, authenticator, authorizer=None):
+        '''
+        Returns a client to work with a basic authorization 
authenticator/authorizer pair.
+        This client assumes the typical case of one authenticator and one 
authorizer. If
+        you have more than one, create multiple clients.
+
+        The basic security API is not proxied through the router: it must work 
directly with
+        the coordinator. Create an ad-hoc Druid client for your coordinator. 
Because you have
+        Basic security enabled, you must specify the admin user and password:
+
+        ```
+        coord = druidapi.jupyter_client('http://localhost:8081', 
auth=('admin', 'admin-pwd'))
+        ac = coord.basic_security('yourAuthenticator', 'yourAuthorizer')
+        ```
+
+        Parameters
+        ----------
+        authenticator: str
+            Authenticator name as set in the `druid.auth.authenticatorChain`
+            runtime property.
+
+        authorizer: str, default = authenticator
+            Authorizor name as set in the `druid.auth.authorizers` runtime 
property.

Review Comment:
   ```suggestion
               Authorizer name as set in the `druid.auth.authorizers` runtime 
property.
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/basic_auth.py:
##########
@@ -0,0 +1,238 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+BASIC_AUTH_BASE = '/druid-ext/basic-security'
+
+AUTHENTICATION_BASE = BASIC_AUTH_BASE + '/authentication'
+REQ_AUTHENTICATION_LOAD_STATUS = AUTHENTICATION_BASE + '/loadStatus'
+REQ_AUTHENTICATION_REFRESH_ALL = AUTHENTICATION_BASE + '/refreshAll'
+AUTHENTICATOR_BASE = AUTHENTICATION_BASE + '/db/{}'
+REQ_AUTHENTICATION_USERS = AUTHENTICATOR_BASE + '/users'
+REQ_AUTHENTICATION_USER = REQ_AUTHENTICATION_USERS + '/{}'
+REQ_AUTHENTICATION_CREDENTIALS = REQ_AUTHENTICATION_USER + '/credentials'
+
+AUTHORIZATION_BASE = BASIC_AUTH_BASE + '/authorization'
+REQ_AUTHORIZATION_LOAD_STATUS = AUTHORIZATION_BASE + '/loadStatus'
+REQ_AUTHORIZATION_REFRESH_ALL = AUTHORIZATION_BASE + '/refreshAll'
+AUTHORIZATION_BASE = AUTHORIZATION_BASE + '/db/{}'
+REQ_AUTHORIZATION_USERS = AUTHORIZATION_BASE + '/users'
+REQ_AUTHORIZATION_USER = REQ_AUTHORIZATION_USERS + '/{}'
+REQ_AUTHORIZATION_USER_ROLES = REQ_AUTHORIZATION_USER + '/roles'
+REQ_AUTHORIZATION_USER_ROLE = REQ_AUTHORIZATION_USER_ROLES + '/{}'
+REQ_AUTHORIZATION_GROUP_MAPPINGS = AUTHORIZATION_BASE + '/groupMappings'
+REQ_AUTHORIZATION_GROUP_MAPPING = AUTHORIZATION_BASE + '/groupMappings/{}'
+REQ_AUTHORIZATION_GROUP_ROLES = REQ_AUTHORIZATION_GROUP_MAPPING + '/roles'
+REQ_AUTHORIZATION_GROUP_ROLE = REQ_AUTHORIZATION_GROUP_ROLES + '/{}'
+REQ_AUTHORIZATION_ROLES = AUTHORIZATION_BASE + '/roles'
+REQ_AUTHORIZATION_ROLE = REQ_AUTHORIZATION_ROLES + '/{}'
+REQ_AUTHORIZATION_ROLE_PERMISSIONS = REQ_AUTHORIZATION_ROLE + '/permissions'
+REQ_USER_MAP = AUTHORIZATION_BASE + '/cachedSerializedUserMap'
+
+class BasicAuthClient:
+    '''
+    Manage Basic security. The Druid session must be logged in with the super
+    user, or some other user who has permission to modify user credentials.
+
+    Each client works with one authorizor/authenticator pair. Create multiple 
clients if you have to

Review Comment:
   ```suggestion
       Each client works with one authorizer/authenticator pair. Create 
multiple clients to
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/druid.py:
##########
@@ -116,6 +117,33 @@ def datasources(self) -> DatasourceClient:
         if not self.datasource_client:
             self.datasource_client = DatasourceClient(self.rest_client)
         return self.datasource_client
+    
+    def basic_security(self, authenticator, authorizer=None):
+        '''
+        Returns a client to work with a basic authorization 
authenticator/authorizer pair.
+        This client assumes the typical case of one authenticator and one 
authorizer. If
+        you have more than one, create multiple clients.
+
+        The basic security API is not proxied through the router: it must work 
directly with
+        the coordinator. Create an ad-hoc Druid client for your coordinator. 
Because you have

Review Comment:
   ```suggestion
           The basic security API is not proxied through the Router: it must 
work directly with
           the Coordinator. Create an ad hoc Druid client for your Coordinator. 
Because you have
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/rest.py:
##########
@@ -95,10 +95,27 @@ class DruidRestClient:
     concatenating the service endpoint with the request URL.
     '''
 
-    def __init__(self, endpoint):
+    def __init__(self, endpoint, auth=None):
+        '''
+        Creates a Druid rest client endpoint using the given endpoint URI and
+        optional authentication.
+
+        Parameters
+        ----------
+        endpoint: str
+            The Druid router endpoint of the form 'server:port'. Use
+            'localhost:8888' for a Druid running locally.
+
+        auth: str, defult = None
+            Optional authorization credentials in the format describd
+            by the Requets library. For Basic auth use

Review Comment:
   ```suggestion
               by the Requests library. For Basic auth use
   ```



##########
docs/operations/security-overview.md:
##########
@@ -176,70 +170,82 @@ An example configuration:
    druid.auth.authorizer.MyBasicMetadataAuthorizer.type=basic
    ```
 
-3. Restart the cluster. 
+3. Restart the cluster.
 
-See [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator, Escalator, and Authorizer concepts. See [Basic 
Security](../development/extensions-core/druid-basic-security.md) for more 
information about the extension used in the examples above, and 
[Kerberos](../development/extensions-core/druid-kerberos.md) for Kerberos 
authentication.
+See
 
+* [Authentication and Authorization](../design/auth.md) for more information 
about the Authenticator,
+Escalator, and Authorizer concepts.
+* [Basic Security](../development/extensions-core/druid-basic-security.md) for 
more information about
+the extension used in the examples above.
+* [Kerberos](../development/extensions-core/druid-kerberos.md) for Kerberos 
authentication.
+* [User authentication and authorization](security-user-auth.md) for details 
of permissions.

Review Comment:
   ```suggestion
   * [User authentication and authorization](security-user-auth.md) for details 
about permissions.
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/basic_auth.py:
##########
@@ -0,0 +1,238 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+BASIC_AUTH_BASE = '/druid-ext/basic-security'
+
+AUTHENTICATION_BASE = BASIC_AUTH_BASE + '/authentication'
+REQ_AUTHENTICATION_LOAD_STATUS = AUTHENTICATION_BASE + '/loadStatus'
+REQ_AUTHENTICATION_REFRESH_ALL = AUTHENTICATION_BASE + '/refreshAll'
+AUTHENTICATOR_BASE = AUTHENTICATION_BASE + '/db/{}'
+REQ_AUTHENTICATION_USERS = AUTHENTICATOR_BASE + '/users'
+REQ_AUTHENTICATION_USER = REQ_AUTHENTICATION_USERS + '/{}'
+REQ_AUTHENTICATION_CREDENTIALS = REQ_AUTHENTICATION_USER + '/credentials'
+
+AUTHORIZATION_BASE = BASIC_AUTH_BASE + '/authorization'
+REQ_AUTHORIZATION_LOAD_STATUS = AUTHORIZATION_BASE + '/loadStatus'
+REQ_AUTHORIZATION_REFRESH_ALL = AUTHORIZATION_BASE + '/refreshAll'
+AUTHORIZATION_BASE = AUTHORIZATION_BASE + '/db/{}'
+REQ_AUTHORIZATION_USERS = AUTHORIZATION_BASE + '/users'
+REQ_AUTHORIZATION_USER = REQ_AUTHORIZATION_USERS + '/{}'
+REQ_AUTHORIZATION_USER_ROLES = REQ_AUTHORIZATION_USER + '/roles'
+REQ_AUTHORIZATION_USER_ROLE = REQ_AUTHORIZATION_USER_ROLES + '/{}'
+REQ_AUTHORIZATION_GROUP_MAPPINGS = AUTHORIZATION_BASE + '/groupMappings'
+REQ_AUTHORIZATION_GROUP_MAPPING = AUTHORIZATION_BASE + '/groupMappings/{}'
+REQ_AUTHORIZATION_GROUP_ROLES = REQ_AUTHORIZATION_GROUP_MAPPING + '/roles'
+REQ_AUTHORIZATION_GROUP_ROLE = REQ_AUTHORIZATION_GROUP_ROLES + '/{}'
+REQ_AUTHORIZATION_ROLES = AUTHORIZATION_BASE + '/roles'
+REQ_AUTHORIZATION_ROLE = REQ_AUTHORIZATION_ROLES + '/{}'
+REQ_AUTHORIZATION_ROLE_PERMISSIONS = REQ_AUTHORIZATION_ROLE + '/permissions'
+REQ_USER_MAP = AUTHORIZATION_BASE + '/cachedSerializedUserMap'
+
+class BasicAuthClient:
+    '''
+    Manage Basic security. The Druid session must be logged in with the super
+    user, or some other user who has permission to modify user credentials.
+
+    Each client works with one authorizor/authenticator pair. Create multiple 
clients if you have to
+    work with multiple authenticators on a single server.
+
+    The basic pattern to add users and permissions is:
+
+    ```
+    # Create a client for your coordinator (Basic auth is not proxied through 
the router)
+    coord = druidapi.jupyter_client('http://localhost:8081', auth=('admin', 
'password'))
+
+    # Get a client for your authenticator and authorizer:
+    ac = coord.basic_security('yourAuthorizer', 'yourAuthenticator')
+
+    # Create a user in both the authenticator and authorizer
+    ac.add_user('bob', 'secret')
+
+    # Define a role
+    ac.add_role('myRole')
+
+    # Assign the role to the user
+    ac.assign_role_to_user('myRole', 'bob')
+
+    # Give the role some permissions
+    ac.grant_permissions('myRole', [[consts.DATASOURCE_RESOURCE, 'foo', 
consts.READ_ACTION]])
+    ```
+
+    Then use the various other methods to list users, roles and permissions to 
verify the
+    setup. You can now create a second Druid client that acts as the new user:

Review Comment:
   ```suggestion
       setup. You can then create a second Druid client that acts as the new 
user:
   ```



##########
examples/quickstart/jupyter-notebooks/druidapi/druidapi/basic_auth.py:
##########
@@ -0,0 +1,238 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+BASIC_AUTH_BASE = '/druid-ext/basic-security'
+
+AUTHENTICATION_BASE = BASIC_AUTH_BASE + '/authentication'
+REQ_AUTHENTICATION_LOAD_STATUS = AUTHENTICATION_BASE + '/loadStatus'
+REQ_AUTHENTICATION_REFRESH_ALL = AUTHENTICATION_BASE + '/refreshAll'
+AUTHENTICATOR_BASE = AUTHENTICATION_BASE + '/db/{}'
+REQ_AUTHENTICATION_USERS = AUTHENTICATOR_BASE + '/users'
+REQ_AUTHENTICATION_USER = REQ_AUTHENTICATION_USERS + '/{}'
+REQ_AUTHENTICATION_CREDENTIALS = REQ_AUTHENTICATION_USER + '/credentials'
+
+AUTHORIZATION_BASE = BASIC_AUTH_BASE + '/authorization'
+REQ_AUTHORIZATION_LOAD_STATUS = AUTHORIZATION_BASE + '/loadStatus'
+REQ_AUTHORIZATION_REFRESH_ALL = AUTHORIZATION_BASE + '/refreshAll'
+AUTHORIZATION_BASE = AUTHORIZATION_BASE + '/db/{}'
+REQ_AUTHORIZATION_USERS = AUTHORIZATION_BASE + '/users'
+REQ_AUTHORIZATION_USER = REQ_AUTHORIZATION_USERS + '/{}'
+REQ_AUTHORIZATION_USER_ROLES = REQ_AUTHORIZATION_USER + '/roles'
+REQ_AUTHORIZATION_USER_ROLE = REQ_AUTHORIZATION_USER_ROLES + '/{}'
+REQ_AUTHORIZATION_GROUP_MAPPINGS = AUTHORIZATION_BASE + '/groupMappings'
+REQ_AUTHORIZATION_GROUP_MAPPING = AUTHORIZATION_BASE + '/groupMappings/{}'
+REQ_AUTHORIZATION_GROUP_ROLES = REQ_AUTHORIZATION_GROUP_MAPPING + '/roles'
+REQ_AUTHORIZATION_GROUP_ROLE = REQ_AUTHORIZATION_GROUP_ROLES + '/{}'
+REQ_AUTHORIZATION_ROLES = AUTHORIZATION_BASE + '/roles'
+REQ_AUTHORIZATION_ROLE = REQ_AUTHORIZATION_ROLES + '/{}'
+REQ_AUTHORIZATION_ROLE_PERMISSIONS = REQ_AUTHORIZATION_ROLE + '/permissions'
+REQ_USER_MAP = AUTHORIZATION_BASE + '/cachedSerializedUserMap'
+
+class BasicAuthClient:
+    '''
+    Manage Basic security. The Druid session must be logged in with the super
+    user, or some other user who has permission to modify user credentials.
+
+    Each client works with one authorizor/authenticator pair. Create multiple 
clients if you have to
+    work with multiple authenticators on a single server.
+
+    The basic pattern to add users and permissions is:
+
+    ```
+    # Create a client for your coordinator (Basic auth is not proxied through 
the router)
+    coord = druidapi.jupyter_client('http://localhost:8081', auth=('admin', 
'password'))
+
+    # Get a client for your authenticator and authorizer:
+    ac = coord.basic_security('yourAuthorizer', 'yourAuthenticator')
+
+    # Create a user in both the authenticator and authorizer
+    ac.add_user('bob', 'secret')
+
+    # Define a role
+    ac.add_role('myRole')
+
+    # Assign the role to the user
+    ac.assign_role_to_user('myRole', 'bob')
+
+    # Give the role some permissions
+    ac.grant_permissions('myRole', [[consts.DATASOURCE_RESOURCE, 'foo', 
consts.READ_ACTION]])
+    ```
+
+    Then use the various other methods to list users, roles and permissions to 
verify the
+    setup. You can now create a second Druid client that acts as the new user:
+
+    ```
+    bob_client = druidapi.jupyter_client('http://localhost:8888', auth=('bob', 
'secret'))
+    ```
+
+    See 
https://druid.apache.org/docs/latest/operations/security-overview.html#enable-authorizers
+    '''
+
+    def __init__(self, rest_client, authenticator, authorizer=None):
+        self.rest_client = rest_client
+        self.authenticator = authenticator
+        self.authorizer = authorizer if authorizer else authenticator
+
+    # Authentication
+
+    def authentication_status(self) -> dict:
+        return self.rest_client.get_json(REQ_AUTHENTICATION_LOAD_STATUS)
+
+    def authentication_refresh(self) -> None:
+        self.rest_client.get(REQ_AUTHENTICATION_REFRESH_ALL)
+
+    def create_authentication_user(self, user) -> None:
+        self.rest_client.post(REQ_AUTHENTICATION_USER, None, 
args=[self.authenticator, user])
+
+    def set_password(self, user, password) -> None:
+        self.rest_client.post_only_json(REQ_AUTHENTICATION_CREDENTIALS, 
{'password': password}, args=[self.authenticator, user])
+
+    def drop_authentication_user(self, user) -> None:
+        self.rest_client.delete(REQ_AUTHENTICATION_USER, 
args=[self.authenticator, user])
+    
+    def authentication_user(self, user) -> dict:
+        return self.rest_client.get_json(REQ_AUTHENTICATION_USER, 
args=[self.authenticator, user])
+    
+    def authentication_users(self) -> list:
+        return self.rest_client.get_json(REQ_AUTHENTICATION_USERS, 
args=[self.authenticator])
+    
+    # Authorization
+    # Groups are not documented. Use at your own risk.
+
+    def authorization_status(self) -> dict:
+        return self.rest_client.get_json(REQ_AUTHORIZATION_LOAD_STATUS)
+
+    def authorization_refresh(self) -> None:
+        self.rest_client.get(REQ_AUTHORIZATION_REFRESH_ALL)
+
+    def create_authorization_user(self, user) -> None:
+        self.rest_client.post(REQ_AUTHORIZATION_USER, None, 
args=[self.authorizer, user])
+
+    def drop_authorization_user(self, user) -> None:
+        self.rest_client.delete(REQ_AUTHORIZATION_USER, 
args=[self.authenticator, user])
+    
+    def authorization_user(self, user) -> dict:
+        return self.rest_client.get_json(REQ_AUTHORIZATION_USER, 
args=[self.authorizer, user])
+    
+    def authorization_users(self) -> list:
+        return self.rest_client.get_json(REQ_AUTHORIZATION_USERS, 
args=[self.authorizer])
+    
+    def create_group(self, group, payload):
+        self.rest_client.post_json(REQ_AUTHORIZATION_GROUP_MAPPING, payload, 
args=[self.authorizer, group])
+
+    def drop_group(self, group):
+        self.rest_client.delete(REQ_AUTHORIZATION_GROUP_MAPPING, 
args=[self.authorizer, group])
+
+    def groups(self) -> dict:
+        return self.rest_client.get_json(REQ_AUTHORIZATION_GROUP_MAPPINGS, 
args=[self.authorizer])
+
+    def group(self, group) -> dict:
+        return self.rest_client.get_json(REQ_AUTHORIZATION_GROUP_MAPPING, 
args=[self.authorizer, group])
+    
+    def roles(self):
+        return self.rest_client.get_json(REQ_AUTHORIZATION_ROLES, 
args=[self.authenticator])
+ 
+    def add_role(self, role):
+        self.rest_client.post(REQ_AUTHORIZATION_ROLE, None, 
args=[self.authenticator, role])
+   
+    def drop_role(self, role):
+        self.rest_client.delete(REQ_AUTHORIZATION_ROLE, args=[self.authorizer, 
role])
+
+    def set_role_permissions(self, role, permissions):
+        self.rest_client.post_only_json(REQ_AUTHORIZATION_ROLE_PERMISSIONS, 
permissions, args=[self.authenticator, role])
+
+    def role_permissions(self, role):
+        return self.rest_client.get_json(REQ_AUTHORIZATION_ROLE_PERMISSIONS, 
args=[self.authenticator, role])
+    
+    def assign_role_to_user(self, role, user):
+        self.rest_client.post(REQ_AUTHORIZATION_USER_ROLE, None, 
args=[self.authenticator, user, role])
+
+    def revoke_role_from_user(self, role, user):
+        self.rest_client.delete(REQ_AUTHORIZATION_USER_ROLE, 
args=[self.authenticator, user, role])
+
+    def assign_role_to_group(self, group, role):
+        self.rest_client.post(REQ_AUTHORIZATION_GROUP_ROLE, None, 
args=[self.authenticator, group, role])
+
+    def revoke_role_from_group(self, group, role):
+        self.rest_client.delete(REQ_AUTHORIZATION_GROUP_ROLE, 
args=[self.authenticator, group, role])
+
+    def user_map(self):
+        # Result uses Smile encoding, not JSON. This is really just for sanity
+        # checks: a Python client can't make use of the info.
+        # To decode, see newsmile: https://pypi.org/project/newsmile/
+        # However, the format Druid returns is not quite compatible with 
newsmile
+        return self.rest_client.get(REQ_USER_MAP, args=[self.authenticator])
+
+    # Convenience methods
+
+    def add_user(self, user, password):
+        '''
+        Adds a user to both the authenticator and authorizer.
+        '''
+        self.create_authentication_user(user)
+        self.set_password(user, password)
+        self.create_authorization_user(user)
+
+    def drop_user(self, user):
+        '''
+        Drops a user from both the authenticator and authorizer.
+        '''
+        self.drop_authorization_user(user)
+        self.drop_authentication_user(user)
+
+    def users(self):
+        '''
+        Returns the list of authenticator and authorizer users.
+        '''
+        return {
+            "authenticator": self.authorization_users(),
+            "authorizer": self.authentication_users()
+        }
+
+    def status(self):
+        '''
+        Returns both the authenticator and authorizer status.
+        '''
+        return {
+            "authenticator": self.authorization_status(),
+            "authorizer": self.authentication_status()
+        }
+    
+    def resource(self, type, name):
+        return {
+            'type': type,
+            'name': name
+        }
+    
+    def action(self, resource, action):
+        return {
+            'resource': resource,
+            'action': action
+        }
+
+    def resource_action(self, type, name, action):
+        return self.action(self.resource(type, name), action)
+
+    def grant_permissions(self, role, triples):
+        '''
+        Set the permissions for a role given an array of triples of the form
+        [type, name, action].

Review Comment:
   May be helpful to add an example here. Is it an array or arrays or an array 
of tuples (or either)? Based on the loop, maybe something like this?
   ```
   [[type0, name0, action0], [type1, name1, action1]]
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to