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.eclipse.aether.transport.http;
20  
21  import java.net.InetAddress;
22  import java.net.UnknownHostException;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Map;
26  
27  import org.apache.http.auth.AuthScope;
28  import org.apache.http.auth.Credentials;
29  import org.apache.http.auth.NTCredentials;
30  import org.apache.http.auth.UsernamePasswordCredentials;
31  import org.apache.http.client.CredentialsProvider;
32  import org.apache.http.impl.client.BasicCredentialsProvider;
33  import org.eclipse.aether.repository.AuthenticationContext;
34  
35  /**
36   * Credentials provider that defers calls into the auth context until authentication is actually requested.
37   */
38  final class DeferredCredentialsProvider implements CredentialsProvider {
39  
40      private final CredentialsProvider delegate;
41  
42      private final Map<AuthScope, Factory> factories;
43  
44      DeferredCredentialsProvider() {
45          delegate = new BasicCredentialsProvider();
46          factories = new HashMap<>();
47      }
48  
49      public void setCredentials(AuthScope authScope, Factory factory) {
50          factories.put(authScope, factory);
51      }
52  
53      @Override
54      public void setCredentials(AuthScope authScope, Credentials credentials) {
55          delegate.setCredentials(authScope, credentials);
56      }
57  
58      @Override
59      public Credentials getCredentials(AuthScope authScope) {
60          synchronized (factories) {
61              for (Iterator<Map.Entry<AuthScope, Factory>> it =
62                              factories.entrySet().iterator();
63                      it.hasNext(); ) {
64                  Map.Entry<AuthScope, Factory> entry = it.next();
65                  if (authScope.match(entry.getKey()) >= 0) {
66                      it.remove();
67                      delegate.setCredentials(entry.getKey(), entry.getValue().newCredentials());
68                  }
69              }
70          }
71          return delegate.getCredentials(authScope);
72      }
73  
74      @Override
75      public void clear() {
76          delegate.clear();
77      }
78  
79      interface Factory {
80  
81          Credentials newCredentials();
82      }
83  
84      static class BasicFactory implements Factory {
85  
86          private final AuthenticationContext authContext;
87  
88          BasicFactory(AuthenticationContext authContext) {
89              this.authContext = authContext;
90          }
91  
92          @Override
93          public Credentials newCredentials() {
94              String username = authContext.get(AuthenticationContext.USERNAME);
95              if (username == null) {
96                  return null;
97              }
98              String password = authContext.get(AuthenticationContext.PASSWORD);
99              return new UsernamePasswordCredentials(username, password);
100         }
101     }
102 
103     static class NtlmFactory implements Factory {
104 
105         private final AuthenticationContext authContext;
106 
107         NtlmFactory(AuthenticationContext authContext) {
108             this.authContext = authContext;
109         }
110 
111         @Override
112         public Credentials newCredentials() {
113             String username = authContext.get(AuthenticationContext.USERNAME);
114             if (username == null) {
115                 return null;
116             }
117             String password = authContext.get(AuthenticationContext.PASSWORD);
118             String domain = authContext.get(AuthenticationContext.NTLM_DOMAIN);
119             String workstation = authContext.get(AuthenticationContext.NTLM_WORKSTATION);
120 
121             if (domain == null) {
122                 int backslash = username.indexOf('\\');
123                 if (backslash < 0) {
124                     domain = guessDomain();
125                 } else {
126                     domain = username.substring(0, backslash);
127                     username = username.substring(backslash + 1);
128                 }
129             }
130             if (workstation == null) {
131                 workstation = guessWorkstation();
132             }
133 
134             return new NTCredentials(username, password, workstation, domain);
135         }
136 
137         private static String guessDomain() {
138             return safeNtlmString(System.getProperty("http.auth.ntlm.domain"), System.getenv("USERDOMAIN"));
139         }
140 
141         private static String guessWorkstation() {
142             String localHost = null;
143             try {
144                 localHost = InetAddress.getLocalHost().getHostName();
145             } catch (UnknownHostException e) {
146                 // well, we have other options to try
147             }
148             return safeNtlmString(System.getProperty("http.auth.ntlm.host"), System.getenv("COMPUTERNAME"), localHost);
149         }
150 
151         private static String safeNtlmString(String... strings) {
152             for (String string : strings) {
153                 if (string != null) {
154                     return string;
155                 }
156             }
157             // avoid NPE from httpclient and trigger proper auth failure instead
158             return "";
159         }
160     }
161 }