Skip to content

Conversation

@CalvinKirs
Copy link
Member

AccessControllerFactory Interface

Overview

The AccessControllerFactory interface is responsible for creating and managing CatalogAccessController instances. The interface includes the following methods:

  • default String factoryIdentifier(): Returns the identifier for the factory, defaulting to the simple name of the implementing class. To maintain compatibility with user-defined plugins from older versions, the factoryIdentifier method provides a default implementation that returns the simple name of the current implementation class, ensuring that each factory has a unique identifier.

  • CatalogAccessController createAccessController(Map<String, String> prop): Creates a new instance of CatalogAccessController and initializes it with the provided properties.

Factory Identifier

Each class implementing AccessControllerFactory will automatically use its class name as the factory identifier. This helps in identifying different factory instances during plugin loading and selection.

Instance Creation

The createAccessController method allows you to create and initialize CatalogAccessController instances. The prop parameter provides the configuration properties needed for initialization.

Compatibility

  • If you are using the previously built-in range-dorir authentication plugin, no configuration changes are required; it will continue to function as before.
  • For custom plugins, configuration information should be defined in conf/access.conf. Then, in fe.conf, specify the access_controller_type as the identifier for the custom plugin.

How to Extend

  • Add the fe-core dependency to your Maven pom.xml file.
        <dependency>
            <groupId>org.apache.doris</groupId>
            <artifactId>fe-core</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>

Then, implement the AccessControllerFactory interface to create your own plugin factory class as follows:

public class SimpleAccessControllerFactory implements AccessControllerFactory {
    @Override
    public String factoryIdentifier() {
        return "local-simple";
    }

    @Override
    public CatalogAccessController createAccessController(Map<String, String> map) {
        return new SimpleAccessController(map);
    }
}

package org.example.access;

import org.apache.doris.analysis.ResourceTypeEnum;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.AuthorizationException;
import org.apache.doris.mysql.privilege.CatalogAccessController;
import org.apache.doris.mysql.privilege.DataMaskPolicy;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.RowFilterPolicy;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public class SimpleAccessController implements CatalogAccessController {

    private HashMap<String, Boolean> databasePrivs = new HashMap<>();
    // just for test
    public SimpleAccessController(Map<String, String> prop) {
        prop.forEach((k, v) -> {
            databasePrivs.put(k, Boolean.parseBoolean(v));
        });
    }

    @Override
    public boolean checkGlobalPriv(UserIdentity userIdentity, PrivPredicate privPredicate) {
        return false;
    }

    @Override
    public boolean checkCtlPriv(UserIdentity userIdentity, String s, PrivPredicate privPredicate) {
        return true;
    }
    ...

Add a new folder named META-INF/services under the resources directory, Create a new file named org.apache.doris.mysql.privilege.AccessControllerFactory. with a file containing org.apache.doris.mysql.privilege.AccessControllerFactory.

How to Use

  • In fe.conf, specify the access_controller_type=local-simple
  • Put the jar file containing the custom plugin in the fe/custom_lib directory.

# AccessControllerFactory Interface

## Overview

The `AccessControllerFactory` interface is responsible for creating and managing `CatalogAccessController` instances. The interface includes the following methods:

- **`default String factoryIdentifier()`**: Returns the identifier for the factory, defaulting to the simple name of the implementing class. To maintain compatibility with user-defined plugins from older versions, the `factoryIdentifier` method provides a default implementation that returns the simple name of the current implementation class, ensuring that each factory has a unique identifier.

- **`CatalogAccessController createAccessController(Map<String, String> prop)`**: Creates a new instance of `CatalogAccessController` and initializes it with the provided properties.

## Factory Identifier

Each class implementing `AccessControllerFactory` will automatically use its class name as the factory identifier. This helps in identifying different factory instances during plugin loading and selection.

## Instance Creation

The `createAccessController` method allows you to create and initialize `CatalogAccessController` instances. The `prop` parameter provides the configuration properties needed for initialization.

## Compatibility

- If you are using the previously built-in `range-dorir` authentication plugin, no configuration changes are required; it will continue to function as before.
- For custom plugins, configuration information should be defined in `conf/access.conf`. Then, in `fe.conf`, specify the `access_controller_type` as the identifier for the custom plugin.

## How to Extend

- Add the `fe-core` dependency to your Maven `pom.xml` file.

```xml
        <dependency>
            <groupId>org.apache.doris</groupId>
            <artifactId>fe-core</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>
```
Then, implement the AccessControllerFactory interface to create your own plugin factory class as follows:
```java

public class SimpleAccessControllerFactory implements AccessControllerFactory {
    @OverRide
    public String factoryIdentifier() {
        return "local-simple";
    }

    @OverRide
    public CatalogAccessController createAccessController(Map<String, String> map) {
        return new SimpleAccessController(map);
    }
}

package org.example.access;

import org.apache.doris.analysis.ResourceTypeEnum;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.AuthorizationException;
import org.apache.doris.mysql.privilege.CatalogAccessController;
import org.apache.doris.mysql.privilege.DataMaskPolicy;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.RowFilterPolicy;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public class SimpleAccessController implements CatalogAccessController {

    private HashMap<String, Boolean> databasePrivs = new HashMap<>();
    // just for test
    public SimpleAccessController(Map<String, String> prop) {
        prop.forEach((k, v) -> {
            databasePrivs.put(k, Boolean.parseBoolean(v));
        });
    }

    @OverRide
    public boolean checkGlobalPriv(UserIdentity userIdentity, PrivPredicate privPredicate) {
        return false;
    }

    @OverRide
    public boolean checkCtlPriv(UserIdentity userIdentity, String s, PrivPredicate privPredicate) {
        return true;
    }
    ...

```
Add a new folder named **META-INF/services** under the resources directory, Create a new file named **org.apache.doris.mysql.privilege.AccessControllerFactory.**
with a file containing **org.apache.doris.mysql.privilege.AccessControllerFactory.**

## How to Use
- In `fe.conf`, specify the **access_controller_type=local-simple**
- Put the jar file containing the custom plugin in the **fe/custom_lib** directory.
@doris-robot
Copy link

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR

Since 2024-03-18, the Document has been moved to doris-website.
See Doris Document.

@CalvinKirs CalvinKirs changed the title (feat)[Authentication]Authentication framework modularization (feat)[Authorization-plugin]Authorization framework modularization Sep 12, 2024
@CalvinKirs CalvinKirs changed the title (feat)[Authorization-plugin]Authorization framework modularization [feat](Authorization-plugin)Authorization framework modularization Sep 12, 2024
@CalvinKirs
Copy link
Member Author

run buildall

@doris-robot
Copy link

TPC-H: Total hot run time: 42976 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit f27c60e1232c1a4ba72e8e461669e5f828131043, data reload: false

------ Round 1 ----------------------------------
q1	17600	7397	7301	7301
q2	2033	188	184	184
q3	10460	1265	1401	1265
q4	10517	969	1052	969
q5	7722	3220	3139	3139
q6	239	150	150	150
q7	1049	634	630	630
q8	9465	2013	2069	2013
q9	6842	6310	6334	6310
q10	7023	2509	2492	2492
q11	436	250	249	249
q12	409	226	229	226
q13	17769	3003	3020	3003
q14	283	253	251	251
q15	582	536	529	529
q16	523	429	433	429
q17	983	947	946	946
q18	7320	6859	6798	6798
q19	1385	1239	1233	1233
q20	611	338	335	335
q21	3892	3592	3530	3530
q22	1074	1013	994	994
Total cold run time: 108217 ms
Total hot run time: 42976 ms

----- Round 2, with runtime_filter_mode=off -----
q1	7223	7161	7199	7161
q2	352	247	240	240
q3	3058	3127	3076	3076
q4	2060	2126	2039	2039
q5	5733	5602	5716	5602
q6	240	149	151	149
q7	2154	1825	1799	1799
q8	3382	3423	3381	3381
q9	8876	8834	8817	8817
q10	3455	3597	3599	3597
q11	594	502	487	487
q12	821	641	603	603
q13	8381	3203	3178	3178
q14	312	305	293	293
q15	592	545	543	543
q16	501	456	462	456
q17	1791	1760	1721	1721
q18	8495	8165	8164	8164
q19	1774	1744	1730	1730
q20	2106	1867	1872	1867
q21	5908	5575	5785	5575
q22	1151	1047	1029	1029
Total cold run time: 68959 ms
Total hot run time: 61507 ms

@CalvinKirs
Copy link
Member Author

run performance

private Auth auth;
private CatalogAccessController defaultAccessController;
private Map<String, CatalogAccessController> ctlToCtlAccessController = Maps.newConcurrentMap();
private ConcurrentHashMap<String, AccessControllerFactory> accessControllerFactoriesCache
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment to explain key and value of the map

prop = PropertiesUtils.loadAccessControllerPropertiesOrNull();
} catch (IOException e) {
LOG.warn("Failed to load access controller properties,Using default access controller plugin", e);
return new InternalAccessController(auth);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should stop process if user specified access controller is not found

import java.util.Properties;

public class PropertiesUtils {
public static final String ACCESS_PROPERTIES_FILE_DIR = "/conf/access.conf";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better be a FE config

 When the configuration plugin name cannot be found, an error is reported.
morningman
morningman previously approved these changes Sep 23, 2024
Copy link
Contributor

@morningman morningman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-actions github-actions bot added the approved Indicates a PR has been approved by one committer. label Sep 23, 2024
@github-actions
Copy link
Contributor

PR approved by at least one committer and no changes requested.

@github-actions
Copy link
Contributor

PR approved by anyone and no changes requested.

return accessControllerFactoriesCache.get(accessControllerName).createAccessController(prop);
}
throw new RuntimeException("No authorization plugin factory found for " + accessControllerName
+ "Please confirm that your plugin is placed in the correct location.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
+ "Please confirm that your plugin is placed in the correct location.");
+ ". Please confirm that your plugin is placed in the correct location.");

.createAccessController(prop);
if (!isDryRun) {
ctlToCtlAccessController.put(ctl, accessController);
LOG.info("create access controller {} for catalog {}", ctl, acFactoryClassName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LOG.info("create access controller {} for catalog {}", ctl, acFactoryClassName);
LOG.info("create access controller {} for catalog {}", acFactoryClassName, ctl);

prop = PropertiesUtils.loadAccessControllerPropertiesOrNull();
} catch (IOException e) {
throw new RuntimeException("Failed to load authorization properties,"
+ "please check the configuration file, authorization name is " + accessControllerName, e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
+ "please check the configuration file, authorization name is " + accessControllerName, e);
+ " Please check the configuration file, authorization name is " + accessControllerName, e);

try {
prop = PropertiesUtils.loadAccessControllerPropertiesOrNull();
} catch (IOException e) {
throw new RuntimeException("Failed to load authorization properties,"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw new RuntimeException("Failed to load authorization properties,"
throw new RuntimeException("Failed to load authorization properties."

@github-actions github-actions bot removed the approved Indicates a PR has been approved by one committer. label Sep 23, 2024
Copy link
Contributor

@morningman morningman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@morningman
Copy link
Contributor

run buildall

@github-actions github-actions bot added the approved Indicates a PR has been approved by one committer. label Sep 23, 2024
@github-actions
Copy link
Contributor

PR approved by at least one committer and no changes requested.

@CalvinKirs
Copy link
Member Author

run buildall

@CalvinKirs CalvinKirs merged commit dd5605e into apache:master Sep 24, 2024
@CalvinKirs CalvinKirs deleted the master-authentication branch September 24, 2024 04:37
bobhan1 pushed a commit to bobhan1/doris that referenced this pull request Oct 23, 2024
…pache#40750)

# AccessControllerFactory Interface

## Overview

The `AccessControllerFactory` interface is responsible for creating and
managing `CatalogAccessController` instances. The interface includes the
following methods:

- **`default String factoryIdentifier()`**: Returns the identifier for
the factory, defaulting to the simple name of the implementing class. To
maintain compatibility with user-defined plugins from older versions,
the `factoryIdentifier` method provides a default implementation that
returns the simple name of the current implementation class, ensuring
that each factory has a unique identifier.

- **`CatalogAccessController createAccessController(Map<String, String>
prop)`**: Creates a new instance of `CatalogAccessController` and
initializes it with the provided properties.

## Factory Identifier

Each class implementing `AccessControllerFactory` will automatically use
its class name as the factory identifier. This helps in identifying
different factory instances during plugin loading and selection.

## Instance Creation

The `createAccessController` method allows you to create and initialize
`CatalogAccessController` instances. The `prop` parameter provides the
configuration properties needed for initialization.

## Compatibility

- If you are using the previously built-in `range-dorir` authentication
plugin, no configuration changes are required; it will continue to
function as before.
- For custom plugins, configuration information should be defined in
`conf/access.conf`. Then, in `fe.conf`, specify the
`access_controller_type` as the identifier for the custom plugin.

## How to Extend

- Add the `fe-core` dependency to your Maven `pom.xml` file.

```xml
        <dependency>
            <groupId>org.apache.doris</groupId>
            <artifactId>fe-core</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>
```
Then, implement the AccessControllerFactory interface to create your own
plugin factory class as follows:
```java

public class SimpleAccessControllerFactory implements AccessControllerFactory {
    @OverRide
    public String factoryIdentifier() {
        return "local-simple";
    }

    @OverRide
    public CatalogAccessController createAccessController(Map<String, String> map) {
        return new SimpleAccessController(map);
    }
}

package org.example.access;

import org.apache.doris.analysis.ResourceTypeEnum;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.AuthorizationException;
import org.apache.doris.mysql.privilege.CatalogAccessController;
import org.apache.doris.mysql.privilege.DataMaskPolicy;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.RowFilterPolicy;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public class SimpleAccessController implements CatalogAccessController {

    private HashMap<String, Boolean> databasePrivs = new HashMap<>();
    // just for test
    public SimpleAccessController(Map<String, String> prop) {
        prop.forEach((k, v) -> {
            databasePrivs.put(k, Boolean.parseBoolean(v));
        });
    }

    @OverRide
    public boolean checkGlobalPriv(UserIdentity userIdentity, PrivPredicate privPredicate) {
        return false;
    }

    @OverRide
    public boolean checkCtlPriv(UserIdentity userIdentity, String s, PrivPredicate privPredicate) {
        return true;
    }
    ...

```
Add a new folder named **META-INF/services** under the resources
directory, Create a new file named
**org.apache.doris.mysql.privilege.AccessControllerFactory.** with a
file containing
**org.apache.doris.mysql.privilege.AccessControllerFactory.**

## How to Use
- In `fe.conf`, specify the **access_controller_type=local-simple**
- Put the jar file containing the custom plugin in the **fe/custom_lib**
directory.

(cherry picked from commit dd5605e)
morningman pushed a commit to morningman/doris that referenced this pull request Nov 21, 2024
…pache#40750)

The `AccessControllerFactory` interface is responsible for creating and
managing `CatalogAccessController` instances. The interface includes the
following methods:

- **`default String factoryIdentifier()`**: Returns the identifier for
the factory, defaulting to the simple name of the implementing class. To
maintain compatibility with user-defined plugins from older versions,
the `factoryIdentifier` method provides a default implementation that
returns the simple name of the current implementation class, ensuring
that each factory has a unique identifier.

- **`CatalogAccessController createAccessController(Map<String, String>
prop)`**: Creates a new instance of `CatalogAccessController` and
initializes it with the provided properties.

Each class implementing `AccessControllerFactory` will automatically use
its class name as the factory identifier. This helps in identifying
different factory instances during plugin loading and selection.

The `createAccessController` method allows you to create and initialize
`CatalogAccessController` instances. The `prop` parameter provides the
configuration properties needed for initialization.

- If you are using the previously built-in `range-dorir` authentication
plugin, no configuration changes are required; it will continue to
function as before.
- For custom plugins, configuration information should be defined in
`conf/access.conf`. Then, in `fe.conf`, specify the
`access_controller_type` as the identifier for the custom plugin.

- Add the `fe-core` dependency to your Maven `pom.xml` file.

```xml
        <dependency>
            <groupId>org.apache.doris</groupId>
            <artifactId>fe-core</artifactId>
            <version>1.2-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>
```
Then, implement the AccessControllerFactory interface to create your own
plugin factory class as follows:
```java

public class SimpleAccessControllerFactory implements AccessControllerFactory {
    @OverRide
    public String factoryIdentifier() {
        return "local-simple";
    }

    @OverRide
    public CatalogAccessController createAccessController(Map<String, String> map) {
        return new SimpleAccessController(map);
    }
}

package org.example.access;

import org.apache.doris.analysis.ResourceTypeEnum;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.AuthorizationException;
import org.apache.doris.mysql.privilege.CatalogAccessController;
import org.apache.doris.mysql.privilege.DataMaskPolicy;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.RowFilterPolicy;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public class SimpleAccessController implements CatalogAccessController {

    private HashMap<String, Boolean> databasePrivs = new HashMap<>();
    // just for test
    public SimpleAccessController(Map<String, String> prop) {
        prop.forEach((k, v) -> {
            databasePrivs.put(k, Boolean.parseBoolean(v));
        });
    }

    @OverRide
    public boolean checkGlobalPriv(UserIdentity userIdentity, PrivPredicate privPredicate) {
        return false;
    }

    @OverRide
    public boolean checkCtlPriv(UserIdentity userIdentity, String s, PrivPredicate privPredicate) {
        return true;
    }
    ...

```
Add a new folder named **META-INF/services** under the resources
directory, Create a new file named
**org.apache.doris.mysql.privilege.AccessControllerFactory.** with a
file containing
**org.apache.doris.mysql.privilege.AccessControllerFactory.**

- In `fe.conf`, specify the **access_controller_type=local-simple**
- Put the jar file containing the custom plugin in the **fe/custom_lib**
directory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/2.1.x-experimental dev/3.1.0-merged reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants