1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.auth;
28
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.io.Serializable;
33 import java.nio.charset.Charset;
34 import java.nio.charset.StandardCharsets;
35 import java.nio.charset.UnsupportedCharsetException;
36 import java.security.Principal;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Locale;
40 import java.util.Map;
41
42 import org.apache.commons.codec.binary.Base64;
43 import org.apache.hc.client5.http.auth.AuthChallenge;
44 import org.apache.hc.client5.http.auth.AuthScheme;
45 import org.apache.hc.client5.http.auth.StandardAuthScheme;
46 import org.apache.hc.client5.http.auth.AuthScope;
47 import org.apache.hc.client5.http.auth.AuthStateCacheable;
48 import org.apache.hc.client5.http.auth.AuthenticationException;
49 import org.apache.hc.client5.http.auth.Credentials;
50 import org.apache.hc.client5.http.auth.CredentialsProvider;
51 import org.apache.hc.client5.http.auth.MalformedChallengeException;
52 import org.apache.hc.client5.http.protocol.HttpClientContext;
53 import org.apache.hc.client5.http.utils.ByteArrayBuilder;
54 import org.apache.hc.core5.http.HttpHost;
55 import org.apache.hc.core5.http.HttpRequest;
56 import org.apache.hc.core5.http.NameValuePair;
57 import org.apache.hc.core5.http.protocol.HttpContext;
58 import org.apache.hc.core5.util.Args;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63
64
65
66
67 @AuthStateCacheable
68 public class BasicScheme implements AuthScheme, Serializable {
69
70 private static final long serialVersionUID = -1931571557597830536L;
71
72 private static final Logger LOG = LoggerFactory.getLogger(BasicScheme.class);
73
74 private final Map<String, String> paramMap;
75 private transient Charset charset;
76 private transient ByteArrayBuilder buffer;
77 private transient Base64 base64codec;
78 private boolean complete;
79
80 private String username;
81 private char[] password;
82
83
84
85
86 public BasicScheme(final Charset charset) {
87 this.paramMap = new HashMap<>();
88 this.charset = charset != null ? charset : StandardCharsets.US_ASCII;
89 this.complete = false;
90 }
91
92 public BasicScheme() {
93 this(StandardCharsets.US_ASCII);
94 }
95
96 public void initPreemptive(final Credentials credentials) {
97 if (credentials != null) {
98 this.username = credentials.getUserPrincipal().getName();
99 this.password = credentials.getPassword();
100 } else {
101 this.username = null;
102 this.password = null;
103 }
104 }
105
106 @Override
107 public String getName() {
108 return StandardAuthScheme.BASIC;
109 }
110
111 @Override
112 public boolean isConnectionBased() {
113 return false;
114 }
115
116 @Override
117 public String getRealm() {
118 return this.paramMap.get("realm");
119 }
120
121 @Override
122 public void processChallenge(
123 final AuthChallenge authChallenge,
124 final HttpContext context) throws MalformedChallengeException {
125 this.paramMap.clear();
126 final List<NameValuePair> params = authChallenge.getParams();
127 if (params != null) {
128 for (final NameValuePair param: params) {
129 this.paramMap.put(param.getName().toLowerCase(Locale.ROOT), param.getValue());
130 }
131 }
132 this.complete = true;
133 }
134
135 @Override
136 public boolean isChallengeComplete() {
137 return this.complete;
138 }
139
140 @Override
141 public boolean isResponseReady(
142 final HttpHost host,
143 final CredentialsProvider credentialsProvider,
144 final HttpContext context) throws AuthenticationException {
145
146 Args.notNull(host, "Auth host");
147 Args.notNull(credentialsProvider, "CredentialsProvider");
148
149 final AuthScopep/auth/AuthScope.html#AuthScope">AuthScope authScope = new AuthScope(host, getRealm(), getName());
150 final Credentials credentials = credentialsProvider.getCredentials(
151 authScope, context);
152 if (credentials != null) {
153 this.username = credentials.getUserPrincipal().getName();
154 this.password = credentials.getPassword();
155 return true;
156 }
157
158 if (LOG.isDebugEnabled()) {
159 final HttpClientContext clientContext = HttpClientContext.adapt(context);
160 final String exchangeId = clientContext.getExchangeId();
161 LOG.debug("{} No credentials found for auth scope [{}]", exchangeId, authScope);
162 }
163 this.username = null;
164 this.password = null;
165 return false;
166 }
167
168 @Override
169 public Principal getPrincipal() {
170 return null;
171 }
172
173 @Override
174 public String generateAuthResponse(
175 final HttpHost host,
176 final HttpRequest request,
177 final HttpContext context) throws AuthenticationException {
178 if (this.buffer == null) {
179 this.buffer = new ByteArrayBuilder(64).charset(this.charset);
180 } else {
181 this.buffer.reset();
182 }
183 this.buffer.append(this.username).append(":").append(this.password);
184 if (this.base64codec == null) {
185 this.base64codec = new Base64();
186 }
187 final byte[] encodedCreds = this.base64codec.encode(this.buffer.toByteArray());
188 this.buffer.reset();
189 return StandardAuthScheme.BASIC + " " + new String(encodedCreds, 0, encodedCreds.length, StandardCharsets.US_ASCII);
190 }
191
192 private void writeObject(final ObjectOutputStream out) throws IOException {
193 out.defaultWriteObject();
194 out.writeUTF(this.charset.name());
195 }
196
197 @SuppressWarnings("unchecked")
198 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
199 in.defaultReadObject();
200 try {
201 this.charset = Charset.forName(in.readUTF());
202 } catch (final UnsupportedCharsetException ex) {
203 this.charset = StandardCharsets.US_ASCII;
204 }
205 }
206
207 private void readObjectNoData() {
208 }
209
210 @Override
211 public String toString() {
212 return getName() + this.paramMap;
213 }
214
215 }