1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.wrapper;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.lang.reflect.Method;
24 import java.net.Authenticator;
25 import java.net.PasswordAuthentication;
26 import java.net.URI;
27 import java.net.URL;
28 import java.net.URLConnection;
29 import java.nio.charset.StandardCharsets;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.StandardCopyOption;
33 import java.util.Locale;
34 import java.util.concurrent.ThreadLocalRandom;
35
36 import static org.apache.maven.wrapper.MavenWrapperMain.MVNW_PASSWORD;
37 import static org.apache.maven.wrapper.MavenWrapperMain.MVNW_USERNAME;
38
39
40
41
42 public class DefaultDownloader implements Downloader {
43 private final String applicationName;
44
45 private final String applicationVersion;
46
47 public DefaultDownloader(String applicationName, String applicationVersion) {
48 this.applicationName = applicationName;
49 this.applicationVersion = applicationVersion;
50 configureProxyAuthentication();
51 configureAuthentication();
52 }
53
54 private void configureProxyAuthentication() {
55 if (System.getProperty("http.proxyUser") != null) {
56 Authenticator.setDefault(new SystemPropertiesProxyAuthenticator());
57 }
58 }
59
60 private void configureAuthentication() {
61 if (System.getenv(MVNW_USERNAME) != null
62 && System.getenv(MVNW_PASSWORD) != null
63 && System.getProperty("http.proxyUser") == null) {
64 Authenticator.setDefault(new Authenticator() {
65 @Override
66 protected PasswordAuthentication getPasswordAuthentication() {
67 return new PasswordAuthentication(
68 System.getenv(MVNW_USERNAME),
69 System.getenv(MVNW_PASSWORD).toCharArray());
70 }
71 });
72 }
73 }
74
75 @Override
76 public void download(URI address, Path destination) throws Exception {
77 if (Files.exists(destination)) {
78 return;
79 }
80 Files.createDirectories(destination.getParent());
81
82 if (!"https".equals(address.getScheme())) {
83 Logger.warn("Using an insecure connection to download the Maven distribution."
84 + " Please consider using HTTPS.");
85 }
86 downloadInternal(address, destination);
87 }
88
89 private void downloadInternal(URI address, Path destination) throws IOException {
90 URL url = address.toURL();
91 URLConnection conn = url.openConnection();
92 addBasicAuthentication(address, conn);
93 final String userAgentValue = calculateUserAgent();
94 conn.setRequestProperty("User-Agent", userAgentValue);
95
96 Path temp = destination
97 .getParent()
98 .resolve(destination.getFileName() + "."
99 + Long.toUnsignedString(ThreadLocalRandom.current().nextLong()) + ".tmp");
100 try (InputStream inStream = conn.getInputStream()) {
101 Files.copy(inStream, temp, StandardCopyOption.REPLACE_EXISTING);
102 Files.move(temp, destination, StandardCopyOption.REPLACE_EXISTING);
103 } finally {
104 Files.deleteIfExists(temp);
105 }
106 }
107
108 private void addBasicAuthentication(URI address, URLConnection connection) {
109 String userInfo = calculateUserInfo(address);
110 if (userInfo == null) {
111 return;
112 }
113 connection.setRequestProperty("Authorization", "Basic " + base64Encode(userInfo));
114 }
115
116
117
118
119
120
121
122
123
124
125
126 private String base64Encode(String userInfo) {
127 ClassLoader loader = getClass().getClassLoader();
128 try {
129 Method getEncoderMethod = loader.loadClass("java.util.Base64").getMethod("getEncoder");
130 Method encodeMethod =
131 loader.loadClass("java.util.Base64$Encoder").getMethod("encodeToString", byte[].class);
132 Object encoder = getEncoderMethod.invoke(null);
133 return (String) encodeMethod.invoke(encoder, new Object[] {userInfo.getBytes(StandardCharsets.UTF_8)});
134 } catch (Exception java7OrEarlier) {
135 try {
136 Method encodeMethod = loader.loadClass("javax.xml.bind.DatatypeConverter")
137 .getMethod("printBase64Binary", byte[].class);
138 return (String) encodeMethod.invoke(null, new Object[] {userInfo.getBytes(StandardCharsets.UTF_8)});
139 } catch (Exception java5OrEarlier) {
140 throw new RuntimeException(
141 "Downloading Maven distributions with HTTP Basic Authentication"
142 + " is not supported on your JVM.",
143 java5OrEarlier);
144 }
145 }
146 }
147
148 private String calculateUserInfo(URI uri) {
149 String username = System.getenv(MVNW_USERNAME);
150 String password = System.getenv(MVNW_PASSWORD);
151 if (username != null && password != null) {
152 return username + ':' + password;
153 }
154 return uri.getUserInfo();
155 }
156
157 private String calculateUserAgent() {
158 String appVersion = applicationVersion;
159
160 String javaVendor = System.getProperty("java.vendor");
161 String javaVersion = System.getProperty("java.version");
162 String javaVendorVersion = System.getProperty("java.vm.version");
163 String osName = System.getProperty("os.name");
164 String osVersion = System.getProperty("os.version");
165 String osArch = System.getProperty("os.arch");
166 return String.format(
167 Locale.ROOT,
168 "%s/%s (%s;%s;%s) (%s;%s;%s)",
169 applicationName,
170 appVersion,
171 osName,
172 osVersion,
173 osArch,
174 javaVendor,
175 javaVersion,
176 javaVendorVersion);
177 }
178
179 private static class SystemPropertiesProxyAuthenticator extends Authenticator {
180 @Override
181 protected PasswordAuthentication getPasswordAuthentication() {
182 return new PasswordAuthentication(
183 System.getProperty("http.proxyUser"),
184 System.getProperty("http.proxyPassword", "").toCharArray());
185 }
186 }
187 }