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

org.wildfly.security.ssl.ProtocolSelector Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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 org.wildfly.security.ssl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * An immutable filter for SSL/TLS protocols.
 *
 * @author David M. Lloyd
 */
public abstract class ProtocolSelector {

    final ProtocolSelector prev;

    ProtocolSelector(final ProtocolSelector prev) {
        this.prev = prev;
    }

    /* -- predicates -- */

    private static final ProtocolSelector EMPTY = new ProtocolSelector(null) {
        void applyFilter(final Set enabled, final EnumMap supported) {
        }

        void toString(final StringBuilder b) {
            b.append("(empty)");
        }
    };

    public final String toString() {
        final StringBuilder b = new StringBuilder();
        toString(b);
        return b.toString();
    }

    abstract void toString(final StringBuilder b);

    /**
     * Get the basic empty SSL protocol selector.
     *
     * @return the empty selector
     */
    public static ProtocolSelector empty() {
        return EMPTY;
    }

    /**
     * Get the default SSL protocol selector.
     *
     * @return the default selector
     */
    public static ProtocolSelector defaultProtocols() {
        return DEFAULT_SELECTOR;
    }


    /* -- Put this after the EMPTY selector for proper static ordering -- */
    static final ProtocolSelector DEFAULT_SELECTOR = empty().add(Protocol.TLSv1, Protocol.TLSv1_1, Protocol.TLSv1_2, Protocol.TLSv1_3);


    /* -- delete -- */

    /**
     * Permanently delete the given protocol.  Matching protocols cannot
     * be re-added by a later rule (such rules will be ignored).
     *
     * @param protocolName the name of the protocol to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector deleteFully(final String protocolName) {
        return deleteFully(Protocol.forName(protocolName));
    }

    /**
     * Permanently delete the given protocol.  Matching protocols cannot
     * be re-added by a later rule (such rules will be ignored).
     *
     * @param protocol the protocol to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector deleteFully(final Protocol protocol) {
        return protocol == null ? this : new FullyDeletingProtocolSelector(this, EnumSet.of(protocol));
    }

    /**
     * Permanently delete all of the given protocols.  Matching protocols cannot
     * be re-added by a later rule (such rules will be ignored).
     *
     * @param protocols the protocols to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector deleteFully(final Protocol... protocols) {
        return protocols == null || protocols.length == 0 ? this : new FullyDeletingProtocolSelector(this, EnumSet.of(protocols[0], protocols));
    }

    /**
     * Permanently delete all of the given protocols.  Matching protocols cannot
     * be re-added by a later rule (such rules will be ignored).
     *
     * @param protocols the protocols to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector deleteFully(final EnumSet protocols) {
        return protocols == null || protocols.isEmpty() ? this : new FullyDeletingProtocolSelector(this, protocols);
    }

    /* -- remove -- */

    /**
     * Remove the given protocol.  Matching protocols may be re-added by a later rule.
     *
     * @param protocolName the name of the protocol to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector remove(final String protocolName) {
        return remove(Protocol.forName(protocolName));
    }

    /**
     * Remove the given protocol.  Matching protocols may be re-added by a later rule.
     *
     * @param protocol the protocol to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector remove(final Protocol protocol) {
        return protocol == null ? this : new RemovingProtocolSelector(this, EnumSet.of(protocol));
    }

    /**
     * Remove the given protocols.  Matching protocols may be re-added by a later rule.
     *
     * @param protocols the protocols to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector remove(final Protocol... protocols) {
        return protocols == null || protocols.length == 0 ? this : new RemovingProtocolSelector(this, EnumSet.of(protocols[0], protocols));
    }

    /**
     * Remove the given protocols.  Matching protocols may be re-added by a later rule.
     *
     * @param protocols the protocols to remove
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector remove(final EnumSet protocols) {
        return protocols == null || protocols.isEmpty() ? this : new RemovingProtocolSelector(this, protocols);
    }

    /* -- add -- */

    /**
     * Add the given protocol.
     *
     * @param protocolName the name of the protocol to add
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector add(final String protocolName) {
        return add(Protocol.forName(protocolName));
    }

    /**
     * Add the given protocol.
     *
     * @param protocol the protocol to add
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector add(final Protocol protocol) {
        return protocol == null ? this : new AddingProtocolSelector(this, EnumSet.of(protocol));
    }

    /**
     * Add the given protocols.
     *
     * @param protocols the protocols to add
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector add(final Protocol... protocols) {
        return protocols == null || protocols.length == 0 ? this : new AddingProtocolSelector(this, EnumSet.of(protocols[0], protocols));
    }

    /**
     * Add the given protocols.
     *
     * @param protocols the protocols to add
     * @return a new selector which includes the new rule
     */
    public ProtocolSelector add(final EnumSet protocols) {
        return protocols == null || protocols.isEmpty() ? this : new AddingProtocolSelector(this, protocols);
    }

    /* -- selector implementation -- */

    abstract void applyFilter(Set enabled, EnumMap supported);

    private void doEvaluate(Set enabled, EnumMap supported) {
        if (prev != null) {
            prev.doEvaluate(enabled, supported);
        }
        applyFilter(enabled, supported);
    }

    /**
     * Evaluate this selector against the given list of JSSE supported protocols.
     *
     * @param supportedProtocols the supported protocols
     * @return the enabled protocols (not {@code null})
     */
    public final String[] evaluate(String[] supportedProtocols) {
        final EnumMap supported = new EnumMap(Protocol.class);
        for (String protocolName : supportedProtocols) {
            final Protocol protocol = Protocol.forName(protocolName);
            if (protocol != null) {
                supported.put(protocol, protocolName);
            }
        }
        final LinkedHashSet enabledSet = new LinkedHashSet<>(supported.size());
        doEvaluate(enabledSet, supported);
        final ArrayList list = new ArrayList<>(enabledSet.size());
        for (Protocol protocol : enabledSet) {
            list.add(supported.get(protocol));
        }
        return list.toArray(new String[enabledSet.size()]);
    }

    /* -- selector impls -- */

    static final class AddingProtocolSelector extends ProtocolSelector {
        private final EnumSet protocols;

        AddingProtocolSelector(final ProtocolSelector prev, final EnumSet protocols) {
            super(prev);
            this.protocols = protocols;
        }

        void toString(final StringBuilder b) {
            if (prev != null && prev != EMPTY) {
                prev.toString(b);
                b.append(", then ");
            }
            b.append("add protocols (");
            Iterator iterator = protocols.iterator();
            Protocol protocol;
            if (iterator.hasNext()) {
                protocol = iterator.next();
                b.append(protocol);
                while (iterator.hasNext()) {
                    protocol = iterator.next();
                    b.append(", ");
                    b.append(protocol);
                }
            }
            b.append(")");
        }

        void applyFilter(final Set enabled, final EnumMap supported) {
            final List clone = new ArrayList<>(supported.keySet());
            clone.retainAll(protocols);
            // it will be in reverse-preference order due to the ordering of the enum
            Collections.reverse(clone);
            enabled.addAll(clone);
        }
    }

    static final class RemovingProtocolSelector extends ProtocolSelector {
        private final EnumSet protocols;

        RemovingProtocolSelector(final ProtocolSelector prev, final EnumSet protocols) {
            super(prev);
            this.protocols = protocols;
        }

        void toString(final StringBuilder b) {
            if (prev != null && prev != EMPTY) {
                prev.toString(b);
                b.append(", then ");
            }
            b.append("remove protocols (");
            Iterator iterator = protocols.iterator();
            Protocol protocol;
            if (iterator.hasNext()) {
                protocol = iterator.next();
                b.append(protocol);
                while (iterator.hasNext()) {
                    protocol = iterator.next();
                    b.append(", ");
                    b.append(protocol);
                }
            }
            b.append(")");
        }

        void applyFilter(final Set enabled, final EnumMap supported) {
            enabled.removeAll(protocols);
        }
    }

    static class FullyDeletingProtocolSelector extends ProtocolSelector {
        private final EnumSet protocols;

        FullyDeletingProtocolSelector(final ProtocolSelector prev, final EnumSet protocols) {
            super(prev);
            this.protocols = protocols;
        }

        void toString(final StringBuilder b) {
            if (prev != null && prev != EMPTY) {
                prev.toString(b);
                b.append(", then ");
            }
            b.append("fully remove protocols (");
            Iterator iterator = protocols.iterator();
            Protocol protocol;
            if (iterator.hasNext()) {
                protocol = iterator.next();
                b.append(protocol);
                while (iterator.hasNext()) {
                    protocol = iterator.next();
                    b.append(", ");
                    b.append(protocol);
                }
            }
            b.append(")");
        }

        void applyFilter(final Set enabled, final EnumMap supported) {
            enabled.removeAll(protocols);
            for (Protocol protocol : protocols) {
                supported.remove(protocol);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy