All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.am.gateway.handler.common.policy.DefaultRulesEngine Maven / Gradle / Ivy

/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed 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.
 */
package io.gravitee.am.gateway.handler.common.policy;

import io.gravitee.am.common.policy.ExtensionPoint;
import io.gravitee.am.common.utils.ConstantKeys;
import io.gravitee.am.gateway.handler.common.flow.ExecutionPredicate;
import io.gravitee.am.gateway.handler.common.flow.FlowManager;
import io.gravitee.am.gateway.handler.common.http.NoOpResponse;
import io.gravitee.am.gateway.handler.context.ExecutionContextFactory;
import io.gravitee.am.gateway.policy.Policy;
import io.gravitee.am.gateway.policy.PolicyChainException;
import io.gravitee.am.gateway.policy.PolicyChainProcessorFactory;
import io.gravitee.am.model.User;
import io.gravitee.am.model.oidc.Client;
import io.gravitee.am.plugins.policy.core.PolicyPluginManager;
import io.gravitee.gateway.api.ExecutionContext;
import io.gravitee.gateway.api.Request;
import io.gravitee.gateway.api.context.SimpleExecutionContext;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Single;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.rxjava3.impl.AsyncResultSingle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Titouan COMPIEGNE (titouan.compiegne at graviteesource.com)
 * @author GraviteeSource Team
 */
public class DefaultRulesEngine implements RulesEngine {

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRulesEngine.class);

    @Autowired
    private PolicyChainProcessorFactory policyChainProcessorFactory;

    @Autowired
    private PolicyPluginManager policyPluginManager;

    @Autowired
    private FlowManager flowManager;

    @Autowired
    private ExecutionContextFactory executionContextFactory;

    @Override
    public Completable fire(List rules, ExecutionContext executionContext) {
        if (rules.isEmpty()) {
            LOGGER.debug("No rules registered!");
            return Completable.complete();
        }

        return rxExecutePolicyChain(resolve(rules), executionContext)
                .ignoreElement();
    }

    @Override
    public Single fire(ExtensionPoint extensionPoint,
                                         Request request,
                                         Client client,
                                         User user) {
        return prepareContext(request, client, user)
                .flatMap(executionContext -> {
                    return flowManager.findByExtensionPoint(extensionPoint, client, ExecutionPredicate.from(executionContext))
                            .flatMap(policies -> {
                                if (policies.isEmpty()) {
                                    LOGGER.debug("No policies registered for flow {}", extensionPoint.toString());
                                    return Single.just(executionContext);
                                }
                                return rxExecutePolicyChain(policies, executionContext);
                            });
                });
    }

    private Single prepareContext(Request request,
                                                    Client client,
                                                    User user) {
        return Single.fromCallable(() -> {
            ExecutionContext simpleExecutionContext = new SimpleExecutionContext(request, new NoOpResponse());
            ExecutionContext executionContext = executionContextFactory.create(simpleExecutionContext);
            // add current context attributes
            executionContext.getAttributes().put(ConstantKeys.CLIENT_CONTEXT_KEY, client);
            // user can be null for flow such as client_credentials
            if (user != null) {
                executionContext.getAttributes().put(ConstantKeys.USER_CONTEXT_KEY, user);
            }
            return executionContext;
        });
    }

    private Single rxExecutePolicyChain(List policies, ExecutionContext executionContext) {
        return AsyncResultSingle.toSingle(resultHandler -> {
            executePolicyChain(policies, executionContext, new io.vertx.lang.rx.DelegatingHandler<>(resultHandler, ar -> ar.map(event -> {
                ExecutionContext enhancedContext = new SimpleExecutionContext(event.request(), event.response());
                enhancedContext.getAttributes().putAll(event.getAttributes());
                return enhancedContext;
            })));
        });
    }

    private void executePolicyChain(List policies, ExecutionContext executionContext, Handler> handler) {
        policyChainProcessorFactory
                .create(policies, executionContext)
                .handler(executionContext1 -> handler.handle(Future.succeededFuture(executionContext1)))
                .errorHandler(processorFailure -> handler.handle(Future.failedFuture(new PolicyChainException(processorFailure.message(), processorFailure.statusCode(), processorFailure.key(), processorFailure.parameters(), processorFailure.contentType()))))
                .handle(executionContext);
    }

    private List resolve(List rules) {
        if (rules != null && ! rules.isEmpty()) {
            return rules.stream()
                    .filter(Rule::enabled)
                    .map(rule -> {
                        Policy policy = policyPluginManager.create(rule.type(), rule.condition());
                        policy.setMetadata(rule.metadata());

                        return policy;
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }

        return Collections.emptyList();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy