| /* |
| * 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 |
| * |
| * https://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.ivy.util.url; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.net.Authenticator; |
| import java.net.PasswordAuthentication; |
| |
| import org.apache.ivy.util.Credentials; |
| import org.apache.ivy.util.Message; |
| |
| import static org.apache.ivy.util.StringUtils.isNullOrEmpty; |
| |
| /** |
| * |
| */ |
| public final class IvyAuthenticator extends Authenticator { |
| |
| private Authenticator original; |
| |
| private static boolean securityWarningLogged = false; |
| |
| /** |
| * Private c'tor to prevent instantiation. |
| */ |
| private IvyAuthenticator(Authenticator original) { |
| this.original = original; |
| } |
| |
| /** |
| * Installs an <tt>IvyAuthenticator</tt> as default <tt>Authenticator</tt>. Call this method |
| * before opening HTTP(S) connections to enable Ivy authentication. |
| */ |
| public static void install() { |
| // We will try to use the original authenticator as backup authenticator. |
| // Since there is no getter available, so try to use some reflection to |
| // obtain it. If that doesn't work, assume there is no original authenticator |
| Authenticator original = getCurrentAuthenticator(); |
| |
| if (original instanceof IvyAuthenticator) { |
| return; |
| } |
| |
| try { |
| Authenticator.setDefault(new IvyAuthenticator(original)); |
| } catch (SecurityException e) { |
| if (!securityWarningLogged) { |
| securityWarningLogged = true; |
| Message.warn("Not enough permissions to set the IvyAuthenticator. " |
| + "HTTP(S) authentication will be disabled!"); |
| } |
| } |
| } |
| |
| // API ****************************************************************** |
| |
| // Overriding Authenticator ********************************************* |
| |
| protected PasswordAuthentication getPasswordAuthentication() { |
| PasswordAuthentication result = null; |
| |
| if (isProxyAuthentication()) { |
| String proxyUser = System.getProperty("http.proxyUser"); |
| if (!isNullOrEmpty(proxyUser)) { |
| String proxyPass = System.getProperty("http.proxyPassword", ""); |
| Message.debug("authenticating to proxy server with username [" + proxyUser + "]"); |
| result = new PasswordAuthentication(proxyUser, proxyPass.toCharArray()); |
| } |
| } else { |
| Credentials c = CredentialsStore.INSTANCE.getCredentials(getRequestingPrompt(), |
| getRequestingHost()); |
| Message.debug("authentication: k='" |
| + Credentials.buildKey(getRequestingPrompt(), getRequestingHost()) + "' c='" |
| + c + "'"); |
| if (c != null) { |
| final String password = c.getPasswd() == null ? "" : c.getPasswd(); |
| result = new PasswordAuthentication(c.getUserName(), password.toCharArray()); |
| } |
| } |
| |
| if (result == null && original != null) { |
| Authenticator.setDefault(original); |
| try { |
| result = Authenticator.requestPasswordAuthentication(getRequestingHost(), |
| getRequestingSite(), getRequestingPort(), getRequestingProtocol(), |
| getRequestingPrompt(), getRequestingScheme(), getRequestingURL(), getRequestorType()); |
| } finally { |
| Authenticator.setDefault(this); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * The {@link Authenticator} doesn't have API before Java 9 to get hold of the current system |
| * level {@link Authenticator}. This method does a best-effort attempt to try and get hold of |
| * the current {@link Authenticator} in a way that's specific to the implementation of this |
| * method. There's no guarantee that this method will return the current authenticator. |
| * <strong>Note: this method is intended to be used exclusively by tests.</strong> |
| * |
| * @return Returns the currently setup system level {@link Authenticator}. In cases where this |
| * method isn't able to get the current authenticator, this method returns null |
| */ |
| static Authenticator getCurrentAuthenticator() { |
| return (getJavaVersion() < 9) ? getTheAuthenticator() : getDefaultAuthenticator(); |
| } |
| |
| /** |
| * Checks if the current authentication request is for the proxy server. |
| */ |
| private boolean isProxyAuthentication() { |
| return RequestorType.PROXY.equals(getRequestorType()); |
| } |
| |
| private static Authenticator getDefaultAuthenticator() { |
| try { |
| final Method m = Authenticator.class.getDeclaredMethod("getDefault"); |
| return (Authenticator) m.invoke(null); |
| } catch (final Throwable t) { |
| handleReflectionException(t); |
| } |
| return null; |
| } |
| |
| private static Authenticator getTheAuthenticator() { |
| try { |
| Field f = Authenticator.class.getDeclaredField("theAuthenticator"); |
| f.setAccessible(true); |
| return (Authenticator) f.get(null); |
| } catch (final Throwable t) { |
| handleReflectionException(t); |
| } |
| return null; |
| } |
| |
| private static void handleReflectionException(final Throwable t) { |
| Message.debug("Error occurred while getting the original authenticator: " |
| + t.getMessage()); |
| } |
| |
| private static int getJavaVersion() { |
| // See https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90002 |
| final String[] version = System.getProperty("java.specification.version").split("\\."); |
| final int major = Integer.parseInt(version[0]); |
| return major == 1 ? Integer.parseInt(version[1]) : major; |
| } |
| } |