View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.settings.validation;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Set;
27  import java.util.regex.Pattern;
28  
29  import org.apache.maven.settings.Mirror;
30  import org.apache.maven.settings.Profile;
31  import org.apache.maven.settings.Proxy;
32  import org.apache.maven.settings.Repository;
33  import org.apache.maven.settings.Server;
34  import org.apache.maven.settings.Settings;
35  import org.apache.maven.settings.building.SettingsProblem.Severity;
36  import org.apache.maven.settings.building.SettingsProblemCollector;
37  
38  /**
39   */
40  @Named
41  @Singleton
42  public class DefaultSettingsValidator implements SettingsValidator {
43  
44      private static final String ID = "[\\w.-]+";
45      private static final Pattern ID_REGEX = Pattern.compile(ID);
46  
47      private static final String ILLEGAL_REPO_ID_CHARS = "\\/:\"<>|?*"; // ILLEGAL_FS_CHARS
48  
49      @Override
50      public void validate(Settings settings, SettingsProblemCollector problems) {
51          validate(settings, false, problems);
52      }
53  
54      @Override
55      public void validate(Settings settings, boolean isProjectSettings, SettingsProblemCollector problems) {
56          if (isProjectSettings) {
57              String msgS = "is not supported on project settings.";
58              String msgP = "are not supported on project settings.";
59              if (settings.getLocalRepository() != null
60                      && !settings.getLocalRepository().isEmpty()) {
61                  addViolation(problems, Severity.WARNING, "localRepository", null, msgS);
62              }
63              if (settings.getInteractiveMode() != null && !settings.getInteractiveMode()) {
64                  addViolation(problems, Severity.WARNING, "interactiveMode", null, msgS);
65              }
66              if (settings.isOffline()) {
67                  addViolation(problems, Severity.WARNING, "offline", null, msgS);
68              }
69              if (!settings.getProxies().isEmpty()) {
70                  addViolation(problems, Severity.WARNING, "proxies", null, msgP);
71              }
72              if (settings.isUsePluginRegistry()) {
73                  addViolation(problems, Severity.WARNING, "usePluginRegistry", null, msgS);
74              }
75              List<Server> servers = settings.getServers();
76              for (int i = 0; i < servers.size(); i++) {
77                  Server server = servers.get(i);
78                  String serverField = "servers.server[" + i + "]";
79                  validateStringEmpty(problems, serverField + ".username", server.getUsername(), msgS);
80                  validateStringEmpty(problems, serverField + ".password", server.getPassword(), msgS);
81                  validateStringEmpty(problems, serverField + ".privateKey", server.getPrivateKey(), msgS);
82                  validateStringEmpty(problems, serverField + ".passphrase", server.getPassphrase(), msgS);
83                  validateStringEmpty(problems, serverField + ".filePermissions", server.getFilePermissions(), msgS);
84                  validateStringEmpty(
85                          problems, serverField + ".directoryPermissions", server.getDirectoryPermissions(), msgS);
86              }
87          }
88  
89          if (settings.isUsePluginRegistry()) {
90              addViolation(problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect.");
91          }
92  
93          List<String> pluginGroups = settings.getPluginGroups();
94  
95          if (pluginGroups != null) {
96              for (int i = 0; i < pluginGroups.size(); i++) {
97                  String pluginGroup = pluginGroups.get(i);
98  
99                  validateStringNotEmpty(problems, "pluginGroups.pluginGroup[" + i + "]", pluginGroup, null);
100 
101                 if (!ID_REGEX.matcher(pluginGroup).matches()) {
102                     addViolation(
103                             problems,
104                             Severity.ERROR,
105                             "pluginGroups.pluginGroup[" + i + "]",
106                             null,
107                             "must denote a valid group id and match the pattern " + ID);
108                 }
109             }
110         }
111 
112         List<Server> servers = settings.getServers();
113 
114         if (servers != null) {
115             Set<String> serverIds = new HashSet<>();
116 
117             for (int i = 0; i < servers.size(); i++) {
118                 Server server = servers.get(i);
119 
120                 validateStringNotEmpty(problems, "servers.server[" + i + "].id", server.getId(), null);
121 
122                 if (!serverIds.add(server.getId())) {
123                     addViolation(
124                             problems,
125                             Severity.WARNING,
126                             "servers.server.id",
127                             null,
128                             "must be unique but found duplicate server with id " + server.getId());
129                 }
130             }
131         }
132 
133         List<Mirror> mirrors = settings.getMirrors();
134 
135         if (mirrors != null) {
136             for (Mirror mirror : mirrors) {
137                 validateStringNotEmpty(problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl());
138 
139                 validateBannedCharacters(
140                         problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null, ILLEGAL_REPO_ID_CHARS);
141 
142                 if ("local".equals(mirror.getId())) {
143                     addViolation(
144                             problems,
145                             Severity.WARNING,
146                             "mirrors.mirror.id",
147                             null,
148                             "must not be 'local'"
149                                     + ", this identifier is reserved for the local repository"
150                                     + ", using it for other repositories will corrupt your repository metadata.");
151                 }
152 
153                 validateStringNotEmpty(problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId());
154 
155                 validateStringNotEmpty(problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId());
156             }
157         }
158 
159         List<Profile> profiles = settings.getProfiles();
160 
161         if (profiles != null) {
162             Set<String> profileIds = new HashSet<>();
163 
164             for (Profile profile : profiles) {
165                 if (!profileIds.add(profile.getId())) {
166                     addViolation(
167                             problems,
168                             Severity.WARNING,
169                             "profiles.profile.id",
170                             null,
171                             "must be unique but found duplicate profile with id " + profile.getId());
172                 }
173 
174                 String prefix = "profiles.profile[" + profile.getId() + "].";
175 
176                 validateRepositories(problems, profile.getRepositories(), prefix + "repositories.repository");
177                 validateRepositories(
178                         problems, profile.getPluginRepositories(), prefix + "pluginRepositories.pluginRepository");
179             }
180         }
181 
182         List<Proxy> proxies = settings.getProxies();
183 
184         if (proxies != null) {
185             Set<String> proxyIds = new HashSet<>();
186 
187             for (Proxy proxy : proxies) {
188                 if (!proxyIds.add(proxy.getId())) {
189                     addViolation(
190                             problems,
191                             Severity.WARNING,
192                             "proxies.proxy.id",
193                             null,
194                             "must be unique but found duplicate proxy with id " + proxy.getId());
195                 }
196                 validateStringNotEmpty(problems, "proxies.proxy.host", proxy.getHost(), proxy.getId());
197 
198                 try {
199                     Integer.parseInt(proxy.getPortString());
200                 } catch (NumberFormatException e) {
201                     addViolation(
202                             problems,
203                             Severity.ERROR,
204                             "proxies.proxy[" + proxy.getId() + "].port",
205                             null,
206                             "must be a valid integer but found '" + proxy.getPortString() + "'");
207                 }
208             }
209         }
210     }
211 
212     private void validateRepositories(SettingsProblemCollector problems, List<Repository> repositories, String prefix) {
213         Set<String> repoIds = new HashSet<>();
214 
215         for (Repository repository : repositories) {
216             validateStringNotEmpty(problems, prefix + ".id", repository.getId(), repository.getUrl());
217 
218             validateBannedCharacters(
219                     problems, prefix + ".id", Severity.WARNING, repository.getId(), null, ILLEGAL_REPO_ID_CHARS);
220 
221             if ("local".equals(repository.getId())) {
222                 addViolation(
223                         problems,
224                         Severity.WARNING,
225                         prefix + ".id",
226                         null,
227                         "must not be 'local'"
228                                 + ", this identifier is reserved for the local repository"
229                                 + ", using it for other repositories will corrupt your repository metadata.");
230             }
231 
232             if (!repoIds.add(repository.getId())) {
233                 addViolation(
234                         problems,
235                         Severity.WARNING,
236                         prefix + ".id",
237                         null,
238                         "must be unique but found duplicate repository with id " + repository.getId());
239             }
240 
241             validateStringNotEmpty(problems, prefix + ".url", repository.getUrl(), repository.getId());
242 
243             if ("legacy".equals(repository.getLayout())) {
244                 addViolation(
245                         problems,
246                         Severity.WARNING,
247                         prefix + ".layout",
248                         repository.getId(),
249                         "uses the unsupported value 'legacy', artifact resolution might fail.");
250             }
251         }
252     }
253 
254     // ----------------------------------------------------------------------
255     // Field validation
256     // ----------------------------------------------------------------------
257 
258     /**
259      * Asserts:
260      * <p/>
261      * <ul>
262      * <li><code>string.length == null</code>
263      * <li><code>string.length == 0</code>
264      * </ul>
265      */
266     private static boolean validateStringEmpty(
267             SettingsProblemCollector problems, String fieldName, String string, String message) {
268         if (string == null || string.length() == 0) {
269             return true;
270         }
271 
272         addViolation(problems, Severity.WARNING, fieldName, null, message);
273 
274         return false;
275     }
276 
277     /**
278      * Asserts:
279      * <p/>
280      * <ul>
281      * <li><code>string.length != null</code>
282      * <li><code>string.length > 0</code>
283      * </ul>
284      */
285     private static boolean validateStringNotEmpty(
286             SettingsProblemCollector problems, String fieldName, String string, String sourceHint) {
287         if (!validateNotNull(problems, fieldName, string, sourceHint)) {
288             return false;
289         }
290 
291         if (string.length() > 0) {
292             return true;
293         }
294 
295         addViolation(problems, Severity.ERROR, fieldName, sourceHint, "is missing");
296 
297         return false;
298     }
299 
300     /**
301      * Asserts:
302      * <p/>
303      * <ul>
304      * <li><code>string != null</code>
305      * </ul>
306      */
307     private static boolean validateNotNull(
308             SettingsProblemCollector problems, String fieldName, Object object, String sourceHint) {
309         if (object != null) {
310             return true;
311         }
312 
313         addViolation(problems, Severity.ERROR, fieldName, sourceHint, "is missing");
314 
315         return false;
316     }
317 
318     private static boolean validateBannedCharacters(
319             SettingsProblemCollector problems,
320             String fieldName,
321             Severity severity,
322             String string,
323             String sourceHint,
324             String banned) {
325         if (string != null) {
326             for (int i = string.length() - 1; i >= 0; i--) {
327                 if (banned.indexOf(string.charAt(i)) >= 0) {
328                     addViolation(
329                             problems,
330                             severity,
331                             fieldName,
332                             sourceHint,
333                             "must not contain any of these characters " + banned + " but found " + string.charAt(i));
334                     return false;
335                 }
336             }
337         }
338 
339         return true;
340     }
341 
342     private static void addViolation(
343             SettingsProblemCollector problems, Severity severity, String fieldName, String sourceHint, String message) {
344         StringBuilder buffer = new StringBuilder(256);
345         buffer.append('\'').append(fieldName).append('\'');
346 
347         if (sourceHint != null) {
348             buffer.append(" for ").append(sourceHint);
349         }
350 
351         buffer.append(' ').append(message);
352 
353         problems.add(severity, buffer.toString(), -1, -1, null);
354     }
355 }