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

org.ehrbase.tenant.DefaultTenantAspect Maven / Gradle / Ivy

There is a newer version: 2.12.0
Show newest version
/*
 * Copyright (c) 2019 vitasystems GmbH and Hannover Medical School.
 *
 * This file is part of project EHRbase
 *
 * 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
 *
 *     https://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 org.ehrbase.tenant;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.ehrbase.api.annotations.TenantAware;
import org.ehrbase.api.tenant.TenantAuthentication;
import org.ehrbase.api.tenant.TenantIdExtractionStrategy;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

@Aspect
public class DefaultTenantAspect implements org.ehrbase.api.aspect.TenantAspect {
    private static final List> MATCHED_ANNOTATIONS = List.of(TenantAware.class);
    private final List> extractionStrategies;

    public DefaultTenantAspect() {
        this(new ArrayList<>());
    }

    private static final Comparator> PRIORITY_SORT =
            Comparator.comparingInt(TenantIdExtractionStrategy::priority);

    public DefaultTenantAspect(List> extractionStrategies) {
        extractionStrategies.sort(PRIORITY_SORT);
        this.extractionStrategies = extractionStrategies;
    }

    public  void addExtractionStrategy(TenantIdExtractionStrategy strategy) {
        extractionStrategies.add(strategy);
        extractionStrategies.sort(PRIORITY_SORT);
    }

    @Pointcut(value = "@within(tenantAnnotation)")
    public void matchTenantAnnotation(org.ehrbase.api.annotations.TenantAware tenantAnnotation) {}

    private static final String ERR_NON_TENANT_ID = "Fatal error, no tenant id available";

    /*
     * currently we support only TenantAuthentication. when more
     * is needed we must implement a more sophisticated conversion.
     */
    @Around("matchTenantAnnotation(tenantAnnotation)")
    public Object action(ProceedingJoinPoint pjp, TenantAware tenantAnnotation) throws Throwable {
        return action(pjp, List.of(tenantAnnotation));
    }

    @Override
    public Object action(ProceedingJoinPoint pjp, List annotations) throws Throwable {
        annotations.stream()
                .filter(TenantAware.class::isInstance)
                .map(TenantAware.class::cast)
                .findFirst()
                .ifPresent(tenantAnnotation -> {
                    if (isMethodTenantAware(pjp, tenantAnnotation)) {
                        Object[] args = pjp.getArgs();
                        TenantAuthentication tenant = Objects.requireNonNull(extract(args), ERR_NON_TENANT_ID);
                        SecurityContext ctx = SecurityContextHolder.getContext();
                        ctx.setAuthentication(DefaultTenantAuthentication.of(tenant, Object::toString));
                    }
                });
        return pjp.proceed();
    }

    private boolean isMethodTenantAware(ProceedingJoinPoint pjp, TenantAware tenantAnnotation) {
        if (tenantAnnotation.exclude().length != 0
                && pjp instanceof MethodInvocationProceedingJoinPoint mijp
                && mijp.getSignature() instanceof MethodSignature signature) {

            List allVariants = List.of(
                    signature.getMethod().getName(),
                    signature.toShortString(),
                    signature.toLongString(),
                    signature.toString());

            for (String exclude : tenantAnnotation.exclude()) {
                if (allVariants.contains(exclude)) {
                    return false;
                }
            }
        }

        return true;
    }

    private TenantAuthentication extract(Object... args) {
        Optional> priorAuth = Optional.empty();

        for (TenantIdExtractionStrategy strg : extractionStrategies) {
            if (!strg.accept(args)) continue;

            Optional> extract = strg.extractWithPrior(priorAuth, args);
            if (!extract.isPresent()) continue;

            priorAuth = (Optional>) extract;
        }

        return priorAuth.get();
    }

    @Override
    public List> matchAnnotations() {
        return MATCHED_ANNOTATIONS;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy