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

org.codehaus.plexus.components.secdispatcher.internal.DefaultSecDispatcher Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008 Sonatype, Inc. All rights reserved.
 *
 * This program is licensed to you under the Apache License Version 2.0,
 * and you may not use this file except in compliance with the Apache License Version 2.0.
 * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Apache License Version 2.0 is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 */

package org.codehaus.plexus.components.secdispatcher.internal;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.stream.Collectors;

import org.codehaus.plexus.components.secdispatcher.Dispatcher;
import org.codehaus.plexus.components.secdispatcher.DispatcherMeta;
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
import org.codehaus.plexus.components.secdispatcher.SecDispatcherException;
import org.codehaus.plexus.components.secdispatcher.internal.dispatchers.LegacyDispatcher;
import org.codehaus.plexus.components.secdispatcher.model.SettingsSecurity;

import static java.util.Objects.requireNonNull;

/**
 * Note: this implementation is NOT a JSR330 component. Integrating apps anyway want to customize it (at least
 * the name and location of configuration file), so instead as before (providing "bad" configuration file just
 * to have one), it is the duty of integrator to wrap and "finish" the implementation in a way it suits the
 * integrator. Also, using "globals" like Java System Properties are bad thing, and it is integrator who knows
 * what is needed anyway.
 * 

* Recommended way for integration is to create JSR330 {@link javax.inject.Provider}. * * @author Oleg Gusakov */ public class DefaultSecDispatcher implements SecDispatcher { public static final String SHIELD_BEGIN = "{"; public static final String SHIELD_END = "}"; public static final String ATTR_START = "["; public static final String ATTR_STOP = "]"; protected final Map dispatchers; protected final Path configurationFile; public DefaultSecDispatcher(Map dispatchers, Path configurationFile) { this.dispatchers = requireNonNull(dispatchers); this.configurationFile = requireNonNull(configurationFile); // file may or may not exist, but one thing is certain: it cannot be an exiting directory if (Files.isDirectory(configurationFile)) { throw new IllegalArgumentException("configurationFile cannot be a directory"); } } @Override public Set availableDispatchers() { return Set.copyOf( dispatchers.entrySet().stream().map(this::dispatcherMeta).collect(Collectors.toSet())); } private DispatcherMeta dispatcherMeta(Map.Entry dispatcher) { // sisu components are lazy! Dispatcher d = dispatcher.getValue(); if (d instanceof DispatcherMeta meta) { return meta; } else { return new DispatcherMeta() { @Override public String name() { return dispatcher.getKey(); } @Override public String displayName() { return dispatcher.getKey() + " (needs manual configuration)"; } @Override public Collection fields() { return List.of(); } }; } } @Override public String encrypt(String str, Map attr) throws SecDispatcherException, IOException { if (isEncryptedString(str)) return str; if (attr == null) { attr = new HashMap<>(); } else { attr = new HashMap<>(attr); } if (attr.get(DISPATCHER_NAME_ATTR) == null) { SettingsSecurity conf = readConfiguration(false); if (conf == null) { throw new SecDispatcherException("No configuration found"); } String defaultDispatcher = conf.getDefaultDispatcher(); if (defaultDispatcher == null) { throw new SecDispatcherException("No defaultDispatcher set in configuration"); } attr.put(DISPATCHER_NAME_ATTR, defaultDispatcher); } String name = attr.get(DISPATCHER_NAME_ATTR); Dispatcher dispatcher = dispatchers.get(name); if (dispatcher == null) throw new SecDispatcherException("No dispatcher exist with name " + name); Dispatcher.EncryptPayload payload = dispatcher.encrypt(str, attr, prepareDispatcherConfig(name)); HashMap resultAttributes = new HashMap<>(payload.getAttributes()); resultAttributes.put(SecDispatcher.DISPATCHER_NAME_ATTR, name); resultAttributes.put(SecDispatcher.DISPATCHER_VERSION_ATTR, SecUtil.specVersion()); return SHIELD_BEGIN + ATTR_START + resultAttributes.entrySet().stream() .map(e -> e.getKey() + "=" + e.getValue()) .collect(Collectors.joining(",")) + ATTR_STOP + payload.getEncrypted() + SHIELD_END; } @Override public String decrypt(String str) throws SecDispatcherException, IOException { if (!isAnyEncryptedString(str)) return str; String bare = unDecorate(str); Map attr = requireNonNull(stripAttributes(bare)); if (isLegacyEncryptedString(str)) { attr.put(DISPATCHER_NAME_ATTR, LegacyDispatcher.NAME); } String name = attr.get(DISPATCHER_NAME_ATTR); Dispatcher dispatcher = dispatchers.get(name); if (dispatcher == null) throw new SecDispatcherException("No dispatcher exist with name " + name); return dispatcher.decrypt(strip(bare), attr, prepareDispatcherConfig(name)); } /** *

    *
  • Current: {[name=master,cipher=AES/GCM/NoPadding,version=4.0]vvq66pZ7rkvzSPStGTI9q4QDnsmuDwo+LtjraRel2b0XpcGJFdXcYAHAS75HUA6GLpcVtEkmyQ==}
  • *
*/ @Override public boolean isEncryptedString(String str) { boolean looksLike = str != null && !str.isBlank() && str.startsWith(SHIELD_BEGIN) && str.endsWith(SHIELD_END) && !unDecorate(str).contains(SHIELD_BEGIN) && !unDecorate(str).contains(SHIELD_END); if (looksLike) { Map attributes = stripAttributes(unDecorate(str)); return attributes.containsKey(DISPATCHER_NAME_ATTR) && attributes.containsKey(DISPATCHER_VERSION_ATTR); } return false; } /** *
    *
  • Legacy: {jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}
  • *
*/ @Override public boolean isLegacyEncryptedString(String str) { boolean looksLike = str != null && !str.isBlank() && str.startsWith(SHIELD_BEGIN) && str.endsWith(SHIELD_END) && !unDecorate(str).contains(SHIELD_BEGIN) && !unDecorate(str).contains(SHIELD_END); if (looksLike) { return stripAttributes(unDecorate(str)).isEmpty(); } return false; } @Override public SettingsSecurity readConfiguration(boolean createIfMissing) throws IOException { SettingsSecurity configuration = SecUtil.read(configurationFile); if (configuration == null && createIfMissing) { configuration = new SettingsSecurity(); } return configuration; } @Override public void writeConfiguration(SettingsSecurity configuration) throws IOException { requireNonNull(configuration, "configuration is null"); SecUtil.write(configurationFile, configuration, true); } @Override public ValidationResponse validateConfiguration() { HashMap> report = new HashMap<>(); ArrayList subsystems = new ArrayList<>(); boolean valid = false; try { SettingsSecurity config = readConfiguration(false); if (config == null) { report.computeIfAbsent(ValidationResponse.Level.ERROR, k -> new ArrayList<>()) .add("No configuration file found on path " + configurationFile); } else { report.computeIfAbsent(ValidationResponse.Level.INFO, k -> new ArrayList<>()) .add("Configuration file present on path " + configurationFile); String defaultDispatcher = config.getDefaultDispatcher(); if (defaultDispatcher == null) { report.computeIfAbsent(ValidationResponse.Level.ERROR, k -> new ArrayList<>()) .add("No default dispatcher set in configuration"); } else { report.computeIfAbsent(ValidationResponse.Level.INFO, k -> new ArrayList<>()) .add("Default dispatcher configured"); Dispatcher dispatcher = dispatchers.get(defaultDispatcher); if (dispatcher == null) { report.computeIfAbsent(ValidationResponse.Level.ERROR, k -> new ArrayList<>()) .add("Configured default dispatcher not present in system"); } else { ValidationResponse dispatcherResponse = dispatcher.validateConfiguration(prepareDispatcherConfig(defaultDispatcher)); subsystems.add(dispatcherResponse); if (!dispatcherResponse.isValid()) { report.computeIfAbsent(ValidationResponse.Level.ERROR, k -> new ArrayList<>()) .add("Configured default dispatcher configuration is invalid"); } else { valid = true; report.computeIfAbsent(ValidationResponse.Level.INFO, k -> new ArrayList<>()) .add("Configured default dispatcher configuration is valid"); } } } } // below is legacy check, that does not affect validity of config, is merely informational Dispatcher legacy = dispatchers.get(LegacyDispatcher.NAME); if (legacy == null) { report.computeIfAbsent(ValidationResponse.Level.INFO, k -> new ArrayList<>()) .add("Legacy dispatcher not present in system"); } else { report.computeIfAbsent(ValidationResponse.Level.INFO, k -> new ArrayList<>()) .add("Legacy dispatcher present in system"); ValidationResponse legacyResponse = legacy.validateConfiguration(prepareDispatcherConfig(LegacyDispatcher.NAME)); subsystems.add(legacyResponse); if (!legacyResponse.isValid()) { report.computeIfAbsent(ValidationResponse.Level.WARNING, k -> new ArrayList<>()) .add("Legacy dispatcher not operational; transparent fallback not possible"); } else { report.computeIfAbsent(ValidationResponse.Level.INFO, k -> new ArrayList<>()) .add("Legacy dispatcher is operational; transparent fallback possible"); } } } catch (IOException e) { report.computeIfAbsent(ValidationResponse.Level.ERROR, k -> new ArrayList<>()) .add(e.getMessage()); } return new ValidationResponse(getClass().getSimpleName(), valid, report, subsystems); } protected Map prepareDispatcherConfig(String name) throws IOException { HashMap dispatcherConf = new HashMap<>(); Map conf = SecUtil.getConfig(SecUtil.read(configurationFile), name); if (conf != null) { dispatcherConf.putAll(conf); } return dispatcherConf; } protected String strip(String str) { int start = str.indexOf(ATTR_START); int stop = str.indexOf(ATTR_STOP); if (start != -1 && stop != -1 && stop > start) { return str.substring(stop + 1); } return str; } protected Map stripAttributes(String str) { HashMap result = new HashMap<>(); int start = str.indexOf(ATTR_START); int stop = str.indexOf(ATTR_STOP); if (start != -1 && stop != -1 && stop > start) { if (start != 0) throw new SecDispatcherException("Attributes can be prefix only"); if (stop == start + 1) return null; String attrs = str.substring(start + 1, stop).trim(); if (attrs.isEmpty()) return null; StringTokenizer st = new StringTokenizer(attrs, ","); while (st.hasMoreTokens()) { String pair = st.nextToken(); int pos = pair.indexOf('='); if (pos == -1) throw new SecDispatcherException("Attribute malformed: " + pair); String key = pair.substring(0, pos).trim(); String val = pair.substring(pos + 1).trim(); result.put(key, val); } } return result; } protected String unDecorate(String str) { return str.substring(SHIELD_BEGIN.length(), str.length() - SHIELD_END.length()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy