Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java
38853 views
1
/*
2
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @bug 6578647 6829283
27
* @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock HttpNegotiateServer
28
* @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
29
* @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one
30
*/
31
32
import com.sun.net.httpserver.Headers;
33
import com.sun.net.httpserver.HttpContext;
34
import com.sun.net.httpserver.HttpExchange;
35
import com.sun.net.httpserver.HttpHandler;
36
import com.sun.net.httpserver.HttpServer;
37
import com.sun.net.httpserver.HttpPrincipal;
38
import com.sun.security.auth.module.Krb5LoginModule;
39
import java.io.BufferedReader;
40
import java.io.File;
41
import java.io.FileOutputStream;
42
import java.io.IOException;
43
import java.io.InputStream;
44
import java.io.InputStreamReader;
45
import java.net.HttpURLConnection;
46
import java.net.InetSocketAddress;
47
import java.net.PasswordAuthentication;
48
import java.net.Proxy;
49
import java.net.URL;
50
import java.net.URLConnection;
51
import java.security.*;
52
import java.util.HashMap;
53
import java.util.Map;
54
import javax.security.auth.Subject;
55
import javax.security.auth.callback.Callback;
56
import javax.security.auth.callback.CallbackHandler;
57
import javax.security.auth.callback.NameCallback;
58
import javax.security.auth.callback.PasswordCallback;
59
import javax.security.auth.callback.UnsupportedCallbackException;
60
import javax.security.auth.login.AppConfigurationEntry;
61
import javax.security.auth.login.Configuration;
62
import javax.security.auth.login.LoginContext;
63
import javax.security.auth.login.LoginException;
64
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
65
import org.ietf.jgss.GSSContext;
66
import org.ietf.jgss.GSSCredential;
67
import org.ietf.jgss.GSSManager;
68
import sun.security.jgss.GSSUtil;
69
import sun.security.krb5.Config;
70
import java.util.Base64;
71
72
/**
73
* Basic JGSS/krb5 test with 3 parties: client, server, backend server. Each
74
* party uses JAAS login to get subjects and executes JGSS calls using
75
* Subject.doAs.
76
*/
77
public class HttpNegotiateServer {
78
79
// Two realm, web server in one, proxy server in another
80
final static String REALM_WEB = "WEB.DOMAIN";
81
final static String REALM_PROXY = "PROXY.DOMAIN";
82
final static String KRB5_CONF = "web.conf";
83
final static String KRB5_TAB = "web.ktab";
84
85
// user principals
86
final static String WEB_USER = "web";
87
final static char[] WEB_PASS = "webby".toCharArray();
88
final static String PROXY_USER = "pro";
89
final static char[] PROXY_PASS = "proxy".toCharArray();
90
91
92
final static String WEB_HOST = "host.web.domain";
93
final static String PROXY_HOST = "host.proxy.domain";
94
95
// web page content
96
final static String CONTENT = "Hello, World!";
97
98
// For 6829283, count how many times the Authenticator is called.
99
static int count = 0;
100
101
static int webPort, proxyPort;
102
103
// URLs for web test, proxy test. The proxy server is not a real proxy
104
// since it fakes the same content for any URL. :)
105
static URL webUrl, proxyUrl;
106
107
/**
108
* This Authenticator checks everything:
109
* scheme, protocol, requestor type, host, port, and url
110
*/
111
static class KnowAllAuthenticator extends java.net.Authenticator {
112
public PasswordAuthentication getPasswordAuthentication () {
113
if (!getRequestingScheme().equalsIgnoreCase("Negotiate")) {
114
throw new RuntimeException("Bad scheme");
115
}
116
if (!getRequestingProtocol().equalsIgnoreCase("HTTP")) {
117
throw new RuntimeException("Bad protocol");
118
}
119
if (getRequestorType() == RequestorType.SERVER) {
120
if (!this.getRequestingHost().equalsIgnoreCase(webUrl.getHost())) {
121
throw new RuntimeException("Bad host");
122
}
123
if (this.getRequestingPort() != webUrl.getPort()) {
124
throw new RuntimeException("Bad port");
125
}
126
if (!this.getRequestingURL().equals(webUrl)) {
127
throw new RuntimeException("Bad url");
128
}
129
return new PasswordAuthentication(
130
WEB_USER+"@"+REALM_WEB, WEB_PASS);
131
} else if (getRequestorType() == RequestorType.PROXY) {
132
if (!this.getRequestingHost().equalsIgnoreCase(PROXY_HOST)) {
133
throw new RuntimeException("Bad host");
134
}
135
if (this.getRequestingPort() != proxyPort) {
136
throw new RuntimeException("Bad port");
137
}
138
if (!this.getRequestingURL().equals(proxyUrl)) {
139
throw new RuntimeException("Bad url");
140
}
141
return new PasswordAuthentication(
142
PROXY_USER+"@"+REALM_PROXY, PROXY_PASS);
143
} else {
144
throw new RuntimeException("Bad requster type");
145
}
146
}
147
}
148
149
/**
150
* This Authenticator knows nothing
151
*/
152
static class KnowNothingAuthenticator extends java.net.Authenticator {
153
@Override
154
public PasswordAuthentication getPasswordAuthentication () {
155
HttpNegotiateServer.count++;
156
return null;
157
}
158
}
159
160
public static void main(String[] args)
161
throws Exception {
162
163
KDC kdcw = KDC.create(REALM_WEB);
164
kdcw.addPrincipal(WEB_USER, WEB_PASS);
165
kdcw.addPrincipalRandKey("krbtgt/" + REALM_WEB);
166
kdcw.addPrincipalRandKey("HTTP/" + WEB_HOST);
167
168
KDC kdcp = KDC.create(REALM_PROXY);
169
kdcp.addPrincipal(PROXY_USER, PROXY_PASS);
170
kdcp.addPrincipalRandKey("krbtgt/" + REALM_PROXY);
171
kdcp.addPrincipalRandKey("HTTP/" + PROXY_HOST);
172
173
KDC.saveConfig(KRB5_CONF, kdcw, kdcp,
174
"default_keytab_name = " + KRB5_TAB,
175
"[domain_realm]",
176
"",
177
".web.domain="+REALM_WEB,
178
".proxy.domain="+REALM_PROXY);
179
180
System.setProperty("java.security.krb5.conf", KRB5_CONF);
181
Config.refresh();
182
KDC.writeMultiKtab(KRB5_TAB, kdcw, kdcp);
183
184
// Write a customized JAAS conf file, so that any kinit cache
185
// will be ignored.
186
System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF);
187
File f = new File(OneKDC.JAAS_CONF);
188
FileOutputStream fos = new FileOutputStream(f);
189
fos.write((
190
"com.sun.security.jgss.krb5.initiate {\n" +
191
" com.sun.security.auth.module.Krb5LoginModule required;\n};\n"
192
).getBytes());
193
fos.close();
194
195
HttpServer h1 = httpd("Negotiate", false,
196
"HTTP/" + WEB_HOST + "@" + REALM_WEB, KRB5_TAB);
197
webPort = h1.getAddress().getPort();
198
HttpServer h2 = httpd("Negotiate", true,
199
"HTTP/" + PROXY_HOST + "@" + REALM_PROXY, KRB5_TAB);
200
proxyPort = h2.getAddress().getPort();
201
202
webUrl = new URL("http://" + WEB_HOST +":" + webPort + "/a/b/c");
203
proxyUrl = new URL("http://nosuchplace/a/b/c");
204
205
try {
206
Exception e1 = null, e2 = null, e3 = null;
207
try {
208
test6578647();
209
} catch (Exception e) {
210
e1 = e;
211
e.printStackTrace();
212
}
213
try {
214
test6829283();
215
} catch (Exception e) {
216
e2 = e;
217
e.printStackTrace();
218
}
219
try {
220
test8077155();
221
} catch (Exception e) {
222
e3 = e;
223
e.printStackTrace();
224
}
225
226
if (e1 != null || e2 != null || e3 != null) {
227
throw new RuntimeException("Test error");
228
}
229
} finally {
230
// Must stop. Seems there's no HttpServer.startAsDaemon()
231
if (h1 != null) h1.stop(0);
232
if (h2 != null) h2.stop(0);
233
}
234
}
235
236
static void test6578647() throws Exception {
237
BufferedReader reader;
238
java.net.Authenticator.setDefault(new KnowAllAuthenticator());
239
240
reader = new BufferedReader(new InputStreamReader(
241
webUrl.openConnection().getInputStream()));
242
if (!reader.readLine().equals(CONTENT)) {
243
throw new RuntimeException("Bad content");
244
}
245
246
reader = new BufferedReader(new InputStreamReader(
247
proxyUrl.openConnection(
248
new Proxy(Proxy.Type.HTTP,
249
new InetSocketAddress(PROXY_HOST, proxyPort)))
250
.getInputStream()));
251
if (!reader.readLine().equals(CONTENT)) {
252
throw new RuntimeException("Bad content");
253
}
254
}
255
256
static void test6829283() throws Exception {
257
BufferedReader reader;
258
java.net.Authenticator.setDefault(new KnowNothingAuthenticator());
259
try {
260
new BufferedReader(new InputStreamReader(
261
webUrl.openConnection().getInputStream()));
262
} catch (IOException ioe) {
263
// Will fail since no username and password is provided.
264
}
265
if (count > 1) {
266
throw new RuntimeException("Authenticator called twice");
267
}
268
}
269
270
static void testConnect() {
271
InputStream inputStream = null;
272
try {
273
URL url = webUrl;
274
275
URLConnection conn = url.openConnection();
276
conn.connect();
277
inputStream = conn.getInputStream();
278
byte[] b = new byte[inputStream.available()];
279
for (int j = 0; j < b.length; j++) {
280
b[j] = (byte) inputStream.read();
281
}
282
String s = new String(b);
283
System.out.println("Length: " + s.length());
284
System.out.println(s);
285
} catch (Exception ex) {
286
throw new RuntimeException(ex);
287
} finally {
288
if (inputStream != null) {
289
try {
290
inputStream.close();
291
} catch (IOException e) {
292
e.printStackTrace();
293
}
294
}
295
}
296
}
297
298
static void test8077155() throws Exception {
299
final String username = WEB_USER;
300
final char[] password = WEB_PASS;
301
302
SecurityManager security = new SecurityManager();
303
Policy.setPolicy(new SecurityPolicy());
304
System.setSecurityManager(security);
305
306
CallbackHandler callback = new CallbackHandler() {
307
@Override
308
public void handle(Callback[] pCallbacks) throws IOException, UnsupportedCallbackException {
309
for (Callback cb : pCallbacks) {
310
if (cb instanceof NameCallback) {
311
NameCallback ncb = (NameCallback)cb;
312
ncb.setName(username);
313
314
} else if (cb instanceof PasswordCallback) {
315
PasswordCallback pwdcb = (PasswordCallback) cb;
316
pwdcb.setPassword(password);
317
}
318
}
319
}
320
321
};
322
323
final String jaasConfigName = "oracle.test.kerberos.login";
324
final String krb5LoginModule = "com.sun.security.auth.module.Krb5LoginModule";
325
326
Configuration loginConfig = new Configuration() {
327
@Override
328
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
329
if (! jaasConfigName.equals(name)) {
330
return new AppConfigurationEntry[0];
331
}
332
333
Map<String, String> options = new HashMap<String, String>();
334
options.put("useTicketCache", Boolean.FALSE.toString());
335
options.put("useKeyTab", Boolean.FALSE.toString());
336
337
return new AppConfigurationEntry[] {
338
new AppConfigurationEntry(krb5LoginModule,
339
LoginModuleControlFlag.REQUIRED,
340
options)
341
};
342
}
343
};
344
345
// oracle context/subject/login
346
LoginContext context = null;
347
try {
348
context = new LoginContext("oracle.test.kerberos.login", null, callback, loginConfig);
349
context.login();
350
351
} catch (LoginException ex) {
352
ex.printStackTrace();
353
throw new RuntimeException(ex);
354
}
355
356
357
Subject subject = context.getSubject();
358
359
final PrivilegedExceptionAction<Object> test_action = new PrivilegedExceptionAction<Object>() {
360
public Object run() throws Exception {
361
testConnect();
362
return null;
363
}
364
};
365
366
System.err.println("\n\nExpecting to succeed when executing with the the logged in subject.");
367
368
try {
369
Subject.doAs(subject, test_action);
370
System.err.println("\n\nConnection succeed when executing with the the logged in subject.");
371
} catch (PrivilegedActionException e) {
372
System.err.println("\n\nFailure unexpected when executing with the the logged in subject.");
373
e.printStackTrace();
374
throw new RuntimeException("Failed to login as subject");
375
}
376
377
try {
378
System.err.println("\n\nExpecting to fail when running with the current user's login.");
379
testConnect();
380
} catch (Exception ex) {
381
System.err.println("\nConnect failed when running with the current user's login:\n" + ex.getMessage());
382
}
383
}
384
385
/**
386
* Creates and starts an HTTP or proxy server that requires
387
* Negotiate authentication.
388
* @param scheme "Negotiate" or "Kerberos"
389
* @param principal the krb5 service principal the server runs with
390
* @return the server
391
*/
392
public static HttpServer httpd(String scheme, boolean proxy,
393
String principal, String ktab) throws Exception {
394
MyHttpHandler h = new MyHttpHandler();
395
HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
396
HttpContext hc = server.createContext("/", h);
397
hc.setAuthenticator(new MyServerAuthenticator(
398
proxy, scheme, principal, ktab));
399
server.start();
400
return server;
401
}
402
403
static class MyHttpHandler implements HttpHandler {
404
public void handle(HttpExchange t) throws IOException {
405
t.sendResponseHeaders(200, 0);
406
t.getResponseBody().write(CONTENT.getBytes());
407
t.close();
408
}
409
}
410
411
static class MyServerAuthenticator
412
extends com.sun.net.httpserver.Authenticator {
413
Subject s = new Subject();
414
GSSManager m = null;
415
GSSCredential cred = null;
416
String scheme = null;
417
String reqHdr = "WWW-Authenticate";
418
String respHdr = "Authorization";
419
int err = HttpURLConnection.HTTP_UNAUTHORIZED;
420
421
public MyServerAuthenticator(boolean proxy, String scheme,
422
String principal, String ktab) throws Exception {
423
424
this.scheme = scheme;
425
if (proxy) {
426
reqHdr = "Proxy-Authenticate";
427
respHdr = "Proxy-Authorization";
428
err = HttpURLConnection.HTTP_PROXY_AUTH;
429
}
430
431
Krb5LoginModule krb5 = new Krb5LoginModule();
432
Map<String, String> map = new HashMap<>();
433
Map<String, Object> shared = new HashMap<>();
434
435
map.put("storeKey", "true");
436
map.put("isInitiator", "false");
437
map.put("useKeyTab", "true");
438
map.put("keyTab", ktab);
439
map.put("principal", principal);
440
krb5.initialize(s, null, shared, map);
441
krb5.login();
442
krb5.commit();
443
m = GSSManager.getInstance();
444
cred = Subject.doAs(s, new PrivilegedExceptionAction<GSSCredential>() {
445
@Override
446
public GSSCredential run() throws Exception {
447
System.err.println("Creating GSSCredential");
448
return m.createCredential(
449
null,
450
GSSCredential.INDEFINITE_LIFETIME,
451
MyServerAuthenticator.this.scheme.equalsIgnoreCase("Negotiate")?
452
GSSUtil.GSS_SPNEGO_MECH_OID:
453
GSSUtil.GSS_KRB5_MECH_OID,
454
GSSCredential.ACCEPT_ONLY);
455
}
456
});
457
}
458
459
@Override
460
public Result authenticate(HttpExchange exch) {
461
// The GSContext is stored in an HttpContext attribute named
462
// "GSSContext" and is created at the first request.
463
GSSContext c = null;
464
String auth = exch.getRequestHeaders().getFirst(respHdr);
465
try {
466
c = (GSSContext)exch.getHttpContext().getAttributes().get("GSSContext");
467
if (auth == null) { // First request
468
Headers map = exch.getResponseHeaders();
469
map.set (reqHdr, scheme); // Challenge!
470
c = Subject.doAs(s, new PrivilegedExceptionAction<GSSContext>() {
471
@Override
472
public GSSContext run() throws Exception {
473
return m.createContext(cred);
474
}
475
});
476
exch.getHttpContext().getAttributes().put("GSSContext", c);
477
return new com.sun.net.httpserver.Authenticator.Retry(err);
478
} else { // Later requests
479
byte[] token = Base64.getMimeDecoder().decode(auth.split(" ")[1]);
480
token = c.acceptSecContext(token, 0, token.length);
481
Headers map = exch.getResponseHeaders();
482
map.set (reqHdr, scheme + " " + Base64.getMimeEncoder()
483
.encodeToString(token).replaceAll("\\s", ""));
484
if (c.isEstablished()) {
485
return new com.sun.net.httpserver.Authenticator.Success(
486
new HttpPrincipal(c.getSrcName().toString(), ""));
487
} else {
488
return new com.sun.net.httpserver.Authenticator.Retry(err);
489
}
490
}
491
} catch (Exception e) {
492
throw new RuntimeException(e);
493
}
494
}
495
}
496
}
497
498
class SecurityPolicy extends Policy {
499
500
private static Permissions perms;
501
502
public SecurityPolicy() {
503
super();
504
if (perms == null) {
505
perms = new Permissions();
506
perms.add(new AllPermission());
507
}
508
}
509
510
@Override
511
public PermissionCollection getPermissions(CodeSource codesource) {
512
return perms;
513
}
514
515
}
516
517