| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 |
| * <p> |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * <p> |
| * 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.apache.knox.gateway.services.security.impl; |
| |
| import org.apache.knox.gateway.GatewayMessages; |
| import org.apache.knox.gateway.config.GatewayConfig; |
| import org.apache.knox.gateway.i18n.messages.MessagesFactory; |
| import org.apache.knox.gateway.security.RemoteAliasServiceProvider; |
| import org.apache.knox.gateway.services.ServiceLifecycleException; |
| import org.apache.knox.gateway.services.security.AliasService; |
| import org.apache.knox.gateway.services.security.AliasServiceException; |
| import org.apache.knox.gateway.services.security.MasterService; |
| import org.apache.knox.gateway.util.PasswordUtils; |
| |
| import java.security.cert.Certificate; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.ServiceLoader; |
| import java.util.Set; |
| |
| /** |
| * An {@link AliasService} implementation based on remote service registry. |
| * <p> |
| * This class encapsulates the default AliasService implementation which uses |
| * local keystore to store the aliases. The order in which Aliases are stored are |
| * <ul> |
| * <li>Local Keystore</li> |
| * <li>Remote Registry</li> |
| * </ul> |
| * |
| * @since 1.1.0 |
| */ |
| public class RemoteAliasService implements AliasService { |
| public static final String REMOTE_ALIAS_SERVICE_TYPE = "type"; |
| |
| private static final GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class); |
| |
| private final AliasService localAliasService; |
| private final MasterService ms; |
| |
| private AliasService remoteAliasServiceImpl; |
| |
| public RemoteAliasService(AliasService localAliasService, MasterService ms) { |
| this.localAliasService = localAliasService; |
| this.ms = ms; |
| } |
| |
| /** |
| * Get a list of all aliases for a given cluster. |
| * Remote aliases are preferred over local. |
| * |
| * @param clusterName cluster name |
| * @return List of all the aliases |
| */ |
| @Override |
| public List<String> getAliasesForCluster(final String clusterName) throws AliasServiceException { |
| List<String> remoteAliases = new ArrayList<>(); |
| |
| /* If we have remote registry configured, query it */ |
| if (remoteAliasServiceImpl != null) { |
| remoteAliases = remoteAliasServiceImpl.getAliasesForCluster(clusterName); |
| } |
| |
| List<String> localAliases = localAliasService |
| .getAliasesForCluster(clusterName); |
| |
| if(localAliases != null) { |
| for (final String alias : localAliases) { |
| if (!remoteAliases.contains(alias.toLowerCase(Locale.ROOT))) { |
| remoteAliases.add(alias); |
| } |
| } |
| } |
| |
| return remoteAliases; |
| } |
| |
| @Override |
| public void addAliasForCluster(final String clusterName, |
| final String givenAlias, final String value) throws AliasServiceException { |
| addAliasesForCluster(clusterName, Collections.singletonMap(givenAlias, value)); |
| } |
| |
| @Override |
| public void addAliasesForCluster(String clusterName, Map<String, String> credentials) throws AliasServiceException { |
| // Convert all alias names to lower case since JDK expects the same behaviour |
| Map<String, String> loweredCredentials = new HashMap<>(); |
| for (Map.Entry<String, String> credential : credentials.entrySet()) { |
| loweredCredentials.put(credential.getKey().toLowerCase(Locale.ROOT), credential.getValue()); |
| } |
| |
| // First add the alias to the local keystore |
| localAliasService.addAliasesForCluster(clusterName, loweredCredentials); |
| |
| if (remoteAliasServiceImpl != null) { |
| remoteAliasServiceImpl.addAliasesForCluster(clusterName, loweredCredentials); |
| } |
| } |
| |
| @Override |
| public void removeAliasForCluster(final String clusterName, final String givenAlias) |
| throws AliasServiceException { |
| removeAliasesForCluster(clusterName, Collections.singleton(givenAlias)); |
| } |
| |
| @Override |
| public void removeAliasesForCluster(String clusterName, Set<String> aliases) throws AliasServiceException { |
| // Convert all alias names to lower case since JDK expects the same behavior |
| Set<String> loweredAliases = new HashSet<>(); |
| for (String alias : aliases) { |
| loweredAliases.add(alias.toLowerCase(Locale.ROOT)); |
| } |
| |
| // First, remove them from the local keystore |
| localAliasService.removeAliasesForCluster(clusterName, loweredAliases); |
| |
| // If we have remote registry configured, remove them there also |
| if (remoteAliasServiceImpl != null) { |
| remoteAliasServiceImpl.removeAliasesForCluster(clusterName, loweredAliases); |
| } |
| } |
| |
| @Override |
| public char[] getPasswordFromAliasForCluster(String clusterName, String alias) |
| throws AliasServiceException { |
| return getPasswordFromAliasForCluster(clusterName, alias, false); |
| } |
| |
| @Override |
| public char[] getPasswordFromAliasForCluster(String clusterName, |
| String givenAlias, boolean generate) throws AliasServiceException { |
| /* convert all alias names to lower case since JDK expects the same behaviour */ |
| final String alias = givenAlias.toLowerCase(Locale.ROOT); |
| |
| /* Generate a new password */ |
| if (generate) { |
| generateAliasForCluster(clusterName, alias); |
| } |
| |
| char[] password = null; |
| |
| /* try to get it from remote registry */ |
| if (remoteAliasServiceImpl != null) { |
| password = remoteAliasServiceImpl.getPasswordFromAliasForCluster(clusterName, alias); |
| } |
| |
| /* |
| * If |
| * 1. Remote registry not configured or |
| * 2. Password not found for given alias in remote registry, |
| * Then try local keystore |
| */ |
| if(password == null) { |
| /* try to get it from the local keystore, ignore generate flag. */ |
| password = localAliasService.getPasswordFromAliasForCluster(clusterName, alias); |
| } |
| |
| /* found nothing */ |
| return password; |
| } |
| |
| @Override |
| public void generateAliasForCluster(final String clusterName, final String alias) |
| throws AliasServiceException { |
| /* auto-generated password */ |
| final String passwordString = PasswordUtils.generatePassword(16); |
| addAliasForCluster(clusterName, alias, passwordString); |
| } |
| |
| @Override |
| public char[] getPasswordFromAliasForGateway(String alias) |
| throws AliasServiceException { |
| return getPasswordFromAliasForCluster(NO_CLUSTER_NAME, alias); |
| } |
| |
| @Override |
| public char[] getGatewayIdentityPassphrase() throws AliasServiceException { |
| char[] password = null; |
| if(remoteAliasServiceImpl != null) { |
| password = remoteAliasServiceImpl.getGatewayIdentityPassphrase(); |
| } |
| |
| if(password == null) { |
| password = localAliasService.getGatewayIdentityPassphrase(); |
| } |
| |
| return password; |
| } |
| |
| @Override |
| public char[] getGatewayIdentityKeystorePassword() throws AliasServiceException { |
| char[] password = null; |
| if(remoteAliasServiceImpl != null) { |
| password = remoteAliasServiceImpl.getGatewayIdentityKeystorePassword(); |
| } |
| |
| if(password == null) { |
| password = localAliasService.getGatewayIdentityKeystorePassword(); |
| } |
| |
| return password; |
| } |
| |
| @Override |
| public char[] getSigningKeyPassphrase() throws AliasServiceException { |
| char[] password = null; |
| if(remoteAliasServiceImpl != null) { |
| password = remoteAliasServiceImpl.getSigningKeyPassphrase(); |
| } |
| |
| if(password == null) { |
| password = localAliasService.getSigningKeyPassphrase(); |
| } |
| |
| return password; |
| } |
| |
| @Override |
| public char[] getSigningKeystorePassword() throws AliasServiceException { |
| char[] password = null; |
| if(remoteAliasServiceImpl != null) { |
| password = remoteAliasServiceImpl.getSigningKeystorePassword(); |
| } |
| |
| if(password == null) { |
| password = localAliasService.getSigningKeystorePassword(); |
| } |
| |
| return password; |
| } |
| |
| @Override |
| public void generateAliasForGateway(final String alias) |
| throws AliasServiceException { |
| generateAliasForCluster(NO_CLUSTER_NAME, alias); |
| } |
| |
| @Override |
| public Certificate getCertificateForGateway(final String alias) |
| throws AliasServiceException { |
| /* We don't store certs in remote registry so we just delegate certs to keystore (DefaultAliasService.getCertificateForGateway) */ |
| return localAliasService.getCertificateForGateway(alias); |
| } |
| |
| @Override |
| public void init(final GatewayConfig config, final Map<String, String> options) |
| throws ServiceLifecycleException { |
| Map<String, String> remoteAliasServiceConfigs = config.getRemoteAliasServiceConfiguration(); |
| |
| if(config.isRemoteAliasServiceEnabled() && remoteAliasServiceConfigs != null) { |
| String remoteAliasServiceType = remoteAliasServiceConfigs.get(REMOTE_ALIAS_SERVICE_TYPE); |
| ServiceLoader<RemoteAliasServiceProvider> providers = |
| ServiceLoader.load(RemoteAliasServiceProvider.class); |
| for (RemoteAliasServiceProvider provider : providers) { |
| if(provider.getType().equalsIgnoreCase(remoteAliasServiceType)) { |
| LOG.remoteAliasServiceEnabled(); |
| remoteAliasServiceImpl = provider.newInstance(localAliasService, ms); |
| remoteAliasServiceImpl.init(config, options); |
| break; |
| } |
| } |
| } else { |
| LOG.remoteAliasServiceDisabled(); |
| } |
| } |
| |
| @Override |
| public void start() throws ServiceLifecycleException { |
| if (remoteAliasServiceImpl != null) { |
| remoteAliasServiceImpl.start(); |
| } |
| } |
| |
| @Override |
| public void stop() throws ServiceLifecycleException { |
| if(remoteAliasServiceImpl != null) { |
| remoteAliasServiceImpl.stop(); |
| } |
| } |
| } |