blob: 3c6d875918ef6a9f96f2c266720bab155a2148ef [file] [log] [blame]
/*
* 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
*
* 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.apache.syncope.core.provisioning.java;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
import org.apache.syncope.core.provisioning.api.utils.URIUtils;
import org.identityconnectors.common.IOUtil;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.api.APIConfiguration;
import org.identityconnectors.framework.api.ConfigurationProperties;
import org.identityconnectors.framework.api.ConnectorInfo;
import org.identityconnectors.framework.api.ConnectorInfoManager;
import org.identityconnectors.framework.api.ConnectorInfoManagerFactory;
import org.identityconnectors.framework.api.ConnectorKey;
import org.identityconnectors.framework.api.RemoteFrameworkConnectionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DefaultConnIdBundleManager implements ConnIdBundleManager {
protected static final Logger LOG = LoggerFactory.getLogger(ConnIdBundleManager.class);
/**
* ConnId Locations.
*/
protected final List<URI> locations;
/**
* ConnectorInfoManager instances.
*/
protected final Map<URI, ConnectorInfoManager> connInfoManagers =
Collections.synchronizedMap(new LinkedHashMap<>());
public DefaultConnIdBundleManager(final List<String> stringLocations) {
locations = new ArrayList<>();
stringLocations.forEach(location -> {
try {
locations.add(URIUtils.buildForConnId(location));
LOG.info("Valid ConnId location: {}", location.trim());
} catch (Exception e) {
LOG.error("Invalid ConnId location: {}", location.trim(), e);
}
});
}
@Override
public List<URI> getLocations() {
return locations;
}
protected void initLocal(final URI location) {
// 1. Find bundles inside local directory
File bundleDirectory = new File(location);
String[] bundleFiles = bundleDirectory.list();
if (bundleFiles == null) {
throw new NotFoundException("Local bundles directory " + location);
}
List<URL> bundleFileURLs = new ArrayList<>();
for (String file : bundleFiles) {
try {
bundleFileURLs.add(IOUtil.makeURL(bundleDirectory, file));
} catch (IOException ignore) {
// ignore exception and don't add bundle
LOG.debug("{}/{} is not a valid connector bundle", bundleDirectory.toString(), file, ignore);
}
}
if (bundleFileURLs.isEmpty()) {
LOG.warn("No connector bundles found in {}", location);
}
LOG.debug("Configuring local connector server:"
+ "\n\tFiles: {}", bundleFileURLs);
// 2. Get connector info manager
ConnectorInfoManager manager = ConnectorInfoManagerFactory.getInstance().getLocalManager(
bundleFileURLs.toArray(new URL[bundleFileURLs.size()]));
if (manager == null) {
throw new NotFoundException("Local ConnectorInfoManager");
}
connInfoManagers.put(location, manager);
}
protected void initRemote(final URI location) {
// 1. Extract conf params for remote connection from given URI
String host = location.getHost();
int port = location.getPort();
GuardedString key = new GuardedString(location.getUserInfo().toCharArray());
boolean useSSL = location.getScheme().equals("connids");
List<TrustManager> trustManagers = new ArrayList<>();
String[] params = StringUtils.isBlank(location.getQuery()) ? null : location.getQuery().split("&");
if (params != null && params.length > 0) {
final String[] trustAllCerts = params[0].split("=");
if (trustAllCerts.length > 1
&& "trustAllCerts".equalsIgnoreCase(trustAllCerts[0])
&& "true".equalsIgnoreCase(trustAllCerts[1])) {
trustManagers.add(new X509TrustManager() {
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException {
// no checks, trust all
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException {
// no checks, trust all
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
});
}
}
LOG.debug("Configuring remote connector server:"
+ "\n\tHost: {}"
+ "\n\tPort: {}"
+ "\n\tKey: {}"
+ "\n\tUseSSL: {}"
+ "\n\tTrustAllCerts: {}",
host, port, key, useSSL, !trustManagers.isEmpty());
RemoteFrameworkConnectionInfo info =
new RemoteFrameworkConnectionInfo(host, port, key, useSSL, trustManagers, 60 * 1000);
LOG.debug("Remote connection info: {}", info);
// 2. Get connector info manager
ConnectorInfoManager manager = ConnectorInfoManagerFactory.getInstance().getRemoteManager(info);
if (manager == null) {
throw new NotFoundException("Remote ConnectorInfoManager");
}
connInfoManagers.put(location, manager);
}
@Override
public void resetConnManagers() {
connInfoManagers.clear();
}
@Override
public Map<URI, ConnectorInfoManager> getConnManagers() {
if (connInfoManagers.isEmpty()) {
locations.forEach(location -> {
try {
if ("file".equals(location.getScheme())) {
LOG.debug("Local initialization: {}", location);
initLocal(location);
} else if (location.getScheme().startsWith("connid")) {
LOG.debug("Remote initialization: {}", location);
initRemote(location);
} else {
LOG.warn("Unsupported scheme: {}", location);
}
} catch (Exception e) {
LOG.error("Could not process {}", location, e);
}
});
}
if (LOG.isDebugEnabled()) {
connInfoManagers.entrySet().stream().map(entry -> {
LOG.debug("Connector bundles found at {}", entry.getKey());
return entry;
}).forEach(entry -> entry.getValue().getConnectorInfos().forEach(
connInfo -> LOG.debug("\t{}", connInfo.getConnectorDisplayName())));
}
return connInfoManagers;
}
@Override
public Pair<URI, ConnectorInfo> getConnectorInfo(final ConnInstance connInstance) {
// check ConnIdLocation
URI uriLocation = null;
try {
uriLocation = URIUtils.buildForConnId(connInstance.getLocation());
} catch (Exception e) {
throw new IllegalArgumentException("Invalid ConnId location " + connInstance.getLocation(), e);
}
// create key for search all properties
ConnectorKey key = new ConnectorKey(
connInstance.getBundleName(), connInstance.getVersion(), connInstance.getConnectorName());
if (LOG.isDebugEnabled()) {
LOG.debug("\nBundle name: " + key.getBundleName()
+ "\nBundle version: " + key.getBundleVersion()
+ "\nBundle class: " + key.getConnectorName());
}
// get the specified connector
ConnectorInfo info = null;
if (getConnManagers().containsKey(uriLocation)) {
info = getConnManagers().get(uriLocation).findConnectorInfo(key);
}
if (info == null) {
throw new NotFoundException("ConnectorInfo for location " + connInstance.getLocation() + " and key " + key);
}
return Pair.of(uriLocation, info);
}
@Override
public Map<URI, ConnectorInfoManager> getConnInfoManagers() {
return connInfoManagers;
}
@Override
public ConfigurationProperties getConfigurationProperties(final ConnectorInfo info) {
if (info == null) {
throw new NotFoundException("Invalid: connector info is null");
}
// create default configuration
APIConfiguration apiConfig = info.createDefaultAPIConfiguration();
// retrieve the ConfigurationProperties.
ConfigurationProperties properties = apiConfig.getConfigurationProperties();
if (properties == null) {
throw new NotFoundException("Configuration properties");
}
if (LOG.isDebugEnabled()) {
properties.getPropertyNames().forEach(propName -> LOG.debug("Property Name: {}"
+ "\nProperty Type: {}",
properties.getProperty(propName).getName(),
properties.getProperty(propName).getType()));
}
return properties;
}
}