| /* |
| * 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.ace.connectionfactory.impl; |
| |
| import java.io.IOException; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import javax.net.ssl.HttpsURLConnection; |
| import javax.net.ssl.SSLContext; |
| |
| import org.apache.ace.connectionfactory.ConnectionFactory; |
| import org.apache.ace.connectionfactory.impl.UrlCredentials.AuthType; |
| import org.apache.ace.connectionfactory.impl.UrlCredentialsFactory.MissingValueException; |
| import org.apache.commons.codec.binary.Base64; |
| import org.osgi.service.cm.ConfigurationException; |
| import org.osgi.service.cm.ManagedServiceFactory; |
| import org.osgi.service.useradmin.User; |
| |
| /** |
| * Provides a default implementation for {@link ConnectionFactory} based on the standard <code>java.net</code> |
| * implementation of {@link URLConnection}. |
| */ |
| public class ConnectionFactoryImpl implements ConnectionFactory, ManagedServiceFactory { |
| |
| public static final String FACTORY_PID = "org.apache.ace.connectionfactory"; |
| |
| private static final String HTTP_HEADER_AUTHORIZATION = "Authorization"; |
| |
| private final Map<String /* config PID */, UrlCredentials> m_credentialMapping; |
| |
| /** |
| * Creates a new {@link ConnectionFactoryImpl}. |
| */ |
| public ConnectionFactoryImpl() { |
| m_credentialMapping = new HashMap<>(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public URLConnection createConnection(URL url) throws IOException { |
| if (url == null) { |
| throw new IllegalArgumentException("URL cannot be null!"); |
| } |
| |
| URLConnection conn = url.openConnection(); |
| |
| UrlCredentials creds = getCredentials(url); |
| if (creds != null) { |
| supplyCredentials(conn, creds); |
| } |
| |
| return conn; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public URLConnection createConnection(URL url, User user) throws IOException { |
| if (url == null) { |
| throw new IllegalArgumentException("URL cannot be null!"); |
| } |
| if (user == null) { |
| throw new IllegalArgumentException("User cannot be null!"); |
| } |
| |
| URLConnection conn = url.openConnection(); |
| |
| UrlCredentials creds = getCredentials(url); |
| if (creds != null) { |
| // TODO apply user! |
| supplyCredentials(conn, creds); |
| } |
| |
| return conn; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void deleted(String pid) { |
| synchronized (m_credentialMapping) { |
| m_credentialMapping.remove(pid); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getName() { |
| return "HTTP Connection Factory"; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException { |
| UrlCredentials creds; |
| synchronized (m_credentialMapping) { |
| creds = m_credentialMapping.get(pid); |
| } |
| |
| try { |
| creds = UrlCredentialsFactory.getCredentials(properties); |
| |
| synchronized (m_credentialMapping) { |
| m_credentialMapping.put(pid, creds); |
| } |
| } |
| catch (MissingValueException e) { |
| throw new ConfigurationException(e.getProperty(), e.getMessage()); |
| } |
| } |
| |
| /** |
| * Returns the credentials to access the given URL. |
| * |
| * @param url |
| * the URL to find the credentials for, cannot be <code>null</code>. |
| * @return a {@link UrlCredentials} instance for the given URL, or <code>null</code> if none were found, or if none |
| * were necessary. |
| */ |
| final UrlCredentials getCredentials(URL url) { |
| Collection<UrlCredentials> creds; |
| synchronized (m_credentialMapping) { |
| creds = new ArrayList<>(m_credentialMapping.values()); |
| } |
| |
| for (UrlCredentials c : creds) { |
| if (c.matches(url)) { |
| return c; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the authorization header for HTTP Basic Authentication. |
| * |
| * @param values |
| * the credential values to supply, cannot be <code>null</code> and should be an array of two elements. |
| * @return a string that denotes the basic authentication header ("Basic " + encoded credentials), never |
| * <code>null</code>. |
| */ |
| final String getBasicAuthCredentials(Object[] values) { |
| if ((values == null) || values.length < 2) { |
| throw new IllegalArgumentException("Insufficient credentials passed: expected 2 values!"); |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| if (values[0] instanceof String) { |
| sb.append((String) values[0]); |
| } |
| else if (values[0] instanceof byte[]) { |
| sb.append(new String((byte[]) values[0])); |
| } |
| sb.append(':'); |
| if (values[1] instanceof String) { |
| sb.append((String) values[1]); |
| } |
| else if (values[1] instanceof byte[]) { |
| sb.append(new String((byte[]) values[1])); |
| } |
| |
| return "Basic " + new String(Base64.encodeBase64(sb.toString().getBytes())); |
| } |
| |
| /** |
| * Applies basic authentication to the given connection, if it is a {@link HttpURLConnection}. |
| * |
| * @param conn |
| * the connection to apply basic authentication to; |
| * @param values |
| * the credentials to apply. |
| */ |
| private void applyBasicAuthentication(URLConnection conn, Object[] values) { |
| if (conn instanceof HttpURLConnection) { |
| conn.setRequestProperty(HTTP_HEADER_AUTHORIZATION, getBasicAuthCredentials(values)); |
| } |
| } |
| |
| /** |
| * Applies the use of client certificates to the given connection, if it a {@link HttpsURLConnection}. |
| * |
| * @param conn |
| * the connection to apply client certs to; |
| * @param values |
| * the credentials to apply. |
| */ |
| private void applyClientCertificate(URLConnection conn, Object[] values) { |
| if (conn instanceof HttpsURLConnection) { |
| ((HttpsURLConnection) conn).setSSLSocketFactory(((SSLContext) values[0]).getSocketFactory()); |
| } |
| } |
| |
| /** |
| * Supplies the actual credentials to the given {@link URLConnection}. |
| * |
| * @param conn |
| * the connection to supply the credentials to, cannot be <code>null</code>; |
| * @param urlCreds |
| * the URL credentials to supply, cannot be <code>null</code>. |
| * @throws IOException |
| * in case of I/O problems. |
| */ |
| private void supplyCredentials(URLConnection conn, UrlCredentials urlCreds) throws IOException { |
| final AuthType type = urlCreds.getType(); |
| final Object[] creds = urlCreds.getCredentials(); |
| |
| if (AuthType.BASIC.equals(type)) { |
| applyBasicAuthentication(conn, creds); |
| } |
| else if (AuthType.CLIENT_CERT.equals(type)) { |
| applyClientCertificate(conn, creds); |
| } |
| else if (!AuthType.NONE.equals(type)) { |
| throw new IllegalArgumentException("Unknown authentication type: " + type); |
| } |
| } |
| } |