Elasticsearch 内核研发 - 如何给引擎加上权限保护

实现思路

ACL权限策略表 : 通过扩展Elasticsearch 元数据(cluster_state metadata) 实现ACL规则的注册与管理维护机制。
引擎权限检测钩子: 实现自定义引擎,通过钩子从ACL表获取当前索引权限,检测引擎操作是否被允许。

Engine Plugin

Elasticsearch的Engine Plugin是一种插件,它允许开发人员通过自定义索引内核引擎来扩展Elasticsearch的核心功能。Engine Plugin允许你以更底层的方式介入Elasticsearch的索引和搜索过程。

public interface EnginePlugin {

    Optional<EngineFactory> getEngineFactory(IndexSettings indexSettings);

}

实现自己的Elasticsearch 引擎插件

public class MyEnginePlugin extends Plugin implements EnginePlugin {

    public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {
        return Optional.of(config -> new PermissionInternalEngine(config);
    }

}

自定义引擎,放置钩子,添加权限检测

通过覆盖索引策略和删除策略,增加Checker拦截机制

public class PermissionInternalEngine extends InternalEngine {

    /**
     * 返回 EngineOperation 是否被允许
     */
    Function<EngineOperation, Boolean> checker;

    public PermissionInternalEngine(EngineConfig engineConfig, Function<EngineOperation, Boolean> checker) {
        super(engineConfig);
        this.checker = checker;
    }

    /**
     * 索引策略
     */
    @Override
    protected IndexingStrategy indexingStrategyForOperation(final Index index) throws IOException {
        boolean allowed = checker.apply(new EngineOperation(shardId.getIndexName(), index.version(), index));
        if (allowed == false) {
            final PermissionEngineException error = new PermissionEngineException(shardId, index.seqNo(), lookupPrimaryTerm(index.seqNo()));
            return IndexingStrategy.skipDueToVersionConflict(error, false, index.version());
        } else {
            return super.indexingStrategyForOperation(index);
        }
    }

    /**
     * 删除策略
     */
    protected InternalEngine.DeletionStrategy deletionStrategyForOperation(final Delete delete) throws IOException {
        boolean allowed = checker.apply(new EngineOperation(shardId.getIndexName(), Versions.MATCH_DELETED, delete));
        if (allowed == false) {
            final PermissionEngineException error = new PermissionEngineException(shardId, delete.seqNo(), lookupPrimaryTerm(delete.seqNo()));
            return DeletionStrategy.skipDueToVersionConflict(error, delete.version(), false);
        } else {
            return super.deletionStrategyForOperation(delete);
        }
    }
...
}

ACL 权限策略设计

这里设计一种枚举类型,代表是否能创建、更新、删除文档,然后通过组合构建不同的权限策略

public enum PermissionPolicy {

    /*
     * 不允许新增、修改、删除
     */
    STRICT(false, false, false),
    /*
     * 仅允许新增,不允许更新、删除
     */
    ALLOW_APPEND_ONLY(true, false, false),
    /*
     * 允许新增、更新,不允许删除
     */
    ALLOW_CREATE_UPDATE(true, true, false),
    /*
     * 仅允许更新,不允许新增、删除
     */
    ALLOW_UPDATE_ONLY(false, true, false),
    /**
     * 仅允许删除,不允许新增、更新
     */
    ALLOW_DELETE_ONLY(false, false, true);

    private final boolean create;
    private final boolean update;
    private final boolean delete;

    PermissionPolicy(boolean create, boolean update, boolean delete) {
        this.create = create;
        this.update = update;
        this.delete = delete;
    }

    public boolean canCreate() {
        return create;
    }

    public boolean canUpdate() {
        return update;
    }

    public boolean canDelete() {
        return delete;
    }

    public static PermissionPolicy fromString(String str) {
        if ("STRICT".equalsIgnoreCase(str)) {
            return STRICT;
        } else if ("ALLOW_APPEND_ONLY".equalsIgnoreCase(str)) {
            return ALLOW_APPEND_ONLY;
        } else if ("ALLOW_UPDATE_ONLY".equalsIgnoreCase(str)) {
            return ALLOW_UPDATE_ONLY;
        } else if ("ALLOW_CREATE_UPDATE".equalsIgnoreCase(str)) {
            return ALLOW_CREATE_UPDATE;
        } else if ("ALLOW_DELETE_ONLY".equalsIgnoreCase(str)) {
            return ALLOW_DELETE_ONLY;
        }
        throw new IllegalArgumentException("unkonw operation policy : " + str);
    }

}

索引权限策略

通过定义索引名或索引模式挂接到策略

/**
 * 索引权限策略
 */

public class IndexPermissionPolicy {

    private final PermissionPolicy policy;
    private final String pattern;

    public IndexPermissionPolicy(PermissionPolicy policy, String pattern) {
        this.policy = policy;
        this.pattern = pattern;
    }

    public boolean isEmpty() {
        return policy == null && pattern == null;
    }

    public static IndexPermissionPolicy EMPTY = new IndexPermissionPolicy(null, null);

    /**
     * 引擎层权限检查
     *
     * @param index     index
     * @param version   version
     * @param operation operation
     * @return allowed
     */
    public boolean canEngineOperation(String index, long version, Engine.Operation operation) {
        if (Regex.simpleMatch(pattern, index) == false) {
            return true;
        }
        switch (operation.operationType()) {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值