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

io.vertx.up.uca.web.origin.WallInquirer Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
package io.vertx.up.uca.web.origin;

import io.reactivex.Observable;
import io.vertx.core.json.JsonObject;
import io.vertx.tp.error.WallDuplicatedException;
import io.vertx.tp.error.WallKeyMissingException;
import io.vertx.up.annotations.Wall;
import io.vertx.up.atom.secure.Cliff;
import io.vertx.up.exception.zero.DynamicKeyMissingException;
import io.vertx.up.fn.Fn;
import io.vertx.up.log.Annal;
import io.vertx.up.secure.Rampart;
import io.vertx.up.secure.inquire.OstiumAuth;
import io.vertx.up.secure.inquire.PhylumAuth;
import io.vertx.up.uca.marshal.Transformer;
import io.vertx.up.uca.yaml.Node;
import io.vertx.up.uca.yaml.ZeroUniform;
import io.vertx.up.util.Ut;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * This class is for @Wall of security here.
 */
public class WallInquirer implements Inquirer> {

    private static final Annal LOGGER = Annal.get(WallInquirer.class);

    private static final Node NODE =
            Ut.singleton(ZeroUniform.class);

    private static final String KEY = "secure";

    private transient final Transformer transformer =
            Ut.singleton(Rampart.class);

    @Override
    public Set scan(final Set> walls) {
        /* 1. Build result **/
        final Set wallSet = new TreeSet<>();
        final Set> wallClses = walls.stream()
                .filter((item) -> item.isAnnotationPresent(Wall.class))
                .collect(Collectors.toSet());
        if (!wallClses.isEmpty()) {
            /*
             * It means that you have set Wall and enable security configuration
             * wallClses verification
             */
            final ConcurrentMap> keys = new ConcurrentHashMap<>();
            final JsonObject config = verify(wallClses, keys);
            for (final String field : config.fieldNames()) {
                // Difference key setting
                final Class cls = keys.get(field);
                final Cliff cliff = transformer.transform(config.getJsonObject(field));
                // Set Information from class
                mountData(cliff, cls);
                wallSet.add(cliff);
            }
        }
        /* 3. Transfer **/
        return wallSet;
    }

    private void mountData(final Cliff cliff, final Class clazz) {
        /* Extract basic data **/
        mountAnno(cliff, clazz);
        /* Proxy **/
        if (cliff.isDefined()) {
            // Custom Workflow
            OstiumAuth.create(clazz)
                    .verify().mount(cliff);
        } else {
            // Standard Workflow
            PhylumAuth.create(clazz)
                    .verify().mount(cliff);
        }
    }

    private void mountAnno(final Cliff cliff, final Class clazz) {
        final Annotation annotation = clazz.getAnnotation(Wall.class);
        cliff.setOrder(Ut.invoke(annotation, "order"));
        cliff.setPath(Ut.invoke(annotation, "path"));
        cliff.setDefined(Ut.invoke(annotation, "define"));
    }

    /**
     * @param wallClses Security @Wall class
     * @param keysRef   critical class reference for security
     * @return valid configuration that will be used in @Wall class.
     */
    private JsonObject verify(final Set> wallClses,
                              final ConcurrentMap> keysRef) {
        /* Wall duplicated **/
        final Set hashs = new HashSet<>();
        Observable.fromIterable(wallClses)
                .filter(Objects::nonNull)
                .map(item -> {
                    final Annotation annotation = item.getAnnotation(Wall.class);
                    // Add configuration key into keys;
                    keysRef.put(Ut.invoke(annotation, "value"), item);
                    return hashPath(annotation);
                }).subscribe(hashs::add).dispose();

        // Duplicated adding.
        Fn.outUp(hashs.size() != wallClses.size(), LOGGER,
                WallDuplicatedException.class, getClass(),
                wallClses.stream().map(Class::getName).collect(Collectors.toSet()));

        /* Shared key does not existing **/
        final JsonObject config = NODE.read();
        Fn.outUp(!config.containsKey(KEY), LOGGER,
                DynamicKeyMissingException.class, getClass(),
                KEY, config);

        /* Wall key missing **/
        final JsonObject hitted = config.getJsonObject(KEY);
        for (final String key : keysRef.keySet()) {
            Fn.outUp(null == hitted || !hitted.containsKey(key), LOGGER,
                    WallKeyMissingException.class, getClass(),
                    key, keysRef.get(key));
        }
        return hitted;
    }

    /**
     * Path or Order must be not the same or duplicated.
     *
     * @param annotation annotation that contains `order` and `path`
     * @return Each @Wall should contain unique hash key here.
     */
    private String hashPath(final Annotation annotation) {
        final Integer order = Ut.invoke(annotation, "order");
        final String path = Ut.invoke(annotation, "path");
        return Ut.encryptSHA256(order + path);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy