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