Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
30f766b9
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
30f766b9
编写于
1月 12, 2020
作者:
A
andrew
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8186884: Test native KDC, Java krb5 lib, and native krb5 lib in one test
Reviewed-by: mbalao
上级
15b81d15
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
844 addition
and
257 deletion
+844
-257
test/java/security/testlibrary/Proc.java
test/java/security/testlibrary/Proc.java
+13
-2
test/sun/security/krb5/auto/BasicProc.java
test/sun/security/krb5/auto/BasicProc.java
+293
-154
test/sun/security/krb5/auto/Context.java
test/sun/security/krb5/auto/Context.java
+74
-11
test/sun/security/krb5/auto/KDC.java
test/sun/security/krb5/auto/KDC.java
+464
-90
未找到文件。
test/java/security/testlibrary/Proc.java
浏览文件 @
30f766b9
...
...
@@ -235,6 +235,13 @@ public class Proc {
br
=
new
BufferedReader
(
new
InputStreamReader
(
p
.
getInputStream
()));
return
this
;
}
String
getId
(
String
suffix
)
{
if
(
debug
!=
null
)
{
return
debug
+
"."
+
suffix
;
}
else
{
return
System
.
identityHashCode
(
this
)
+
"."
+
suffix
;
}
}
// Reads a line from stdout of proc
public
String
readLine
()
throws
IOException
{
String
s
=
br
.
readLine
();
...
...
@@ -303,9 +310,13 @@ public class Proc {
boolean
isEmpty
=
true
;
while
(
true
)
{
int
i
=
System
.
in
.
read
();
if
(
i
==
-
1
)
break
;
if
(
i
==
-
1
)
{
break
;
}
isEmpty
=
false
;
if
(
i
==
'\n'
)
break
;
if
(
i
==
'\n'
)
{
break
;
}
if
(
i
!=
13
)
{
// Force it to a char, so only simple ASCII works.
sb
.
append
((
char
)
i
);
...
...
test/sun/security/krb5/auto/BasicProc.java
浏览文件 @
30f766b9
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013,
2017,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -23,180 +23,319 @@
/*
* @test
* @bug 8009977
* @summary A test library to launch multiple Java processes
* @bug 8009977 8186884
* @summary A test to launch multiple Java processes using either Java GSS
* or native GSS
* @library ../../../../java/security/testlibrary/
* @compile -XDignore.symbol.file BasicProc.java
* @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock BasicProc
* @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock BasicProc
launcher
*/
import
java.io.File
;
import
java.nio.file.Files
;
import
java.nio.file.Paths
;
import
java.nio.file.attribute.PosixFilePermission
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.PropertyPermission
;
import
java.util.Random
;
import
java.util.Set
;
import
org.ietf.jgss.Oid
;
import
sun.security.krb5.Config
;
import
javax.security.auth.PrivateCredentialPermission
;
/**
* Run this test automatically and test Java GSS with embedded KDC.
*
* Run with customized native.krb5.libs to test interop between Java GSS
* and native GSS, and native.kdc.path with a native KDC. For example,
* run the following command to test interop among Java, default native,
* MIT, and Heimdal krb5 libraries with the Heimdal KDC:
*
* jtreg -Dnative.krb5.libs=j=,
* n=,
* k=/usr/local/krb5/lib/libgssapi_krb5.so,
* h=/space/install/heimdal/lib/libgssapi.so \
* -Dnative.kdc.path=/usr/local/heimdal \
* BasicProc.java
*
* Note: The first 4 lines should be concatenated to make a long system
* property value with no blank around ",". This comma-separated value
* has each element being name=libpath. The special name "j" means the
* Java library and libpath is ignored. Otherwise it means a native library,
* and libpath (can be empty) will be the value for the sun.security.jgss.lib
* system property. If this system property is not set, only the Java
* library will be tested.
*/
public
class
BasicProc
{
static
String
CONF
=
"krb5.conf"
;
static
String
KTAB
=
"ktab"
;
private
static
final
String
CONF
=
"krb5.conf"
;
private
static
final
String
KTAB_S
=
"server.ktab"
;
private
static
final
String
KTAB_B
=
"backend.ktab"
;
private
static
final
String
HOST
=
"localhost"
;
private
static
final
String
SERVER
=
"server/"
+
HOST
;
private
static
final
String
BACKEND
=
"backend/"
+
HOST
;
private
static
final
String
USER
=
"user"
;
private
static
final
char
[]
PASS
=
"password"
.
toCharArray
();
private
static
final
String
REALM
=
"REALM"
;
private
static
final
int
MSGSIZE
=
1024
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
String
HOST
=
"localhost"
;
String
SERVER
=
"server/"
+
HOST
;
String
BACKEND
=
"backend/"
+
HOST
;
String
USER
=
"user"
;
char
[]
PASS
=
"password"
.
toCharArray
();
String
REALM
=
"REALM"
;
Oid
oid
=
new
Oid
(
"1.2.840.113554.1.2.2"
);
byte
[]
token
,
msg
;
if
(
args
.
length
==
0
)
{
System
.
setProperty
(
"java.security.krb5.conf"
,
CONF
);
KDC
kdc
=
KDC
.
create
(
REALM
,
HOST
,
0
,
true
);
kdc
.
addPrincipal
(
USER
,
PASS
);
kdc
.
addPrincipalRandKey
(
"krbtgt/"
+
REALM
);
kdc
.
addPrincipalRandKey
(
SERVER
);
kdc
.
addPrincipalRandKey
(
BACKEND
);
String
cwd
=
System
.
getProperty
(
"user.dir"
);
kdc
.
writeKtab
(
KTAB
);
KDC
.
saveConfig
(
CONF
,
kdc
,
"forwardable = true"
);
Proc
pc
=
Proc
.
create
(
"BasicProc"
)
.
args
(
"client"
)
.
prop
(
"java.security.krb5.conf"
,
CONF
)
.
prop
(
"java.security.manager"
,
""
)
.
prop
(
"sun.net.spi.nameservice.provider.1"
,
"ns,mock"
)
.
perm
(
new
java
.
lang
.
RuntimePermission
(
"accessClassInPackage.sun.net.spi.nameservice"
))
.
perm
(
new
java
.
util
.
PropertyPermission
(
"sun.security.krb5.principal"
,
"read"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"modifyPrincipals"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"modifyPrivateCredentials"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"doAs"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
"krbtgt/"
+
REALM
+
"@"
+
REALM
,
"initiate"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
"server/localhost@"
+
REALM
,
"initiate"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
DelegationPermission
(
"\"server/localhost@"
+
REALM
+
"\" "
+
"\"krbtgt/"
+
REALM
+
"@"
+
REALM
+
"\""
))
.
debug
(
"C"
)
.
start
();
Proc
ps
=
Proc
.
create
(
"BasicProc"
)
.
args
(
"server"
)
.
prop
(
"java.security.krb5.conf"
,
CONF
)
.
prop
(
"java.security.manager"
,
""
)
.
prop
(
"sun.net.spi.nameservice.provider.1"
,
"ns,mock"
)
.
perm
(
new
java
.
lang
.
RuntimePermission
(
"accessClassInPackage.sun.net.spi.nameservice"
))
.
perm
(
new
java
.
util
.
PropertyPermission
(
switch
(
args
[
0
])
{
case
"launcher"
:
KDC
kdc
=
KDC
.
create
(
REALM
,
HOST
,
0
,
true
);
try
{
kdc
.
addPrincipal
(
USER
,
PASS
);
kdc
.
addPrincipalRandKey
(
"krbtgt/"
+
REALM
);
kdc
.
addPrincipalRandKey
(
SERVER
);
kdc
.
addPrincipalRandKey
(
BACKEND
);
// Native lib might do some name lookup
KDC
.
saveConfig
(
CONF
,
kdc
,
"dns_lookup_kdc = no"
,
"ticket_lifetime = 1h"
,
"dns_lookup_realm = no"
,
"dns_canonicalize_hostname = false"
,
"forwardable = true"
);
System
.
setProperty
(
"java.security.krb5.conf"
,
CONF
);
Config
.
refresh
();
kdc
.
writeKtab
(
KTAB_S
,
false
,
SERVER
);
kdc
.
writeKtab
(
KTAB_B
,
false
,
BACKEND
);
String
[]
tmp
=
System
.
getProperty
(
"native.krb5.libs"
,
"j="
)
.
split
(
","
);
// Library paths. The 1st one is always null which means
// Java, "" means the default native lib.
String
[]
libs
=
new
String
[
tmp
.
length
];
// Names for each lib above. Use in file names.
String
[]
names
=
new
String
[
tmp
.
length
];
boolean
hasNative
=
false
;
for
(
int
i
=
0
;
i
<
tmp
.
length
;
i
++)
{
if
(
tmp
[
i
].
isEmpty
())
{
throw
new
Exception
(
"Invalid native.krb5.libs"
);
}
String
[]
pair
=
tmp
[
i
].
split
(
"="
,
2
);
names
[
i
]
=
pair
[
0
];
if
(!
pair
[
0
].
equals
(
"j"
))
{
libs
[
i
]
=
pair
.
length
>
1
?
pair
[
1
]
:
""
;
hasNative
=
true
;
}
}
if
(
hasNative
)
{
kdc
.
kinit
(
USER
,
"base.ccache"
);
}
// Try the same lib first
for
(
int
i
=
0
;
i
<
libs
.
length
;
i
++)
{
once
(
names
[
i
]
+
names
[
i
]
+
names
[
i
],
libs
[
i
],
libs
[
i
],
libs
[
i
]);
}
for
(
int
i
=
0
;
i
<
libs
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
libs
.
length
;
j
++)
{
for
(
int
k
=
0
;
k
<
libs
.
length
;
k
++)
{
if
(
i
!=
j
||
i
!=
k
)
{
once
(
names
[
i
]
+
names
[
j
]
+
names
[
k
],
libs
[
i
],
libs
[
j
],
libs
[
k
]);
}
}
}
}
}
finally
{
kdc
.
terminate
();
}
break
;
case
"client"
:
Context
c
=
args
[
1
].
equals
(
"n"
)
?
Context
.
fromThinAir
()
:
Context
.
fromUserPass
(
USER
,
PASS
,
false
);
c
.
startAsClient
(
SERVER
,
oid
);
c
.
x
().
requestCredDeleg
(
true
);
Proc
.
binOut
(
c
.
take
(
new
byte
[
0
]));
// AP-REQ
token
=
Proc
.
binIn
();
// AP-REP
c
.
take
(
token
);
break
;
case
"server"
:
Context
s
=
args
[
1
].
equals
(
"n"
)
?
Context
.
fromThinAir
()
:
Context
.
fromUserKtab
(
SERVER
,
KTAB_S
,
true
);
s
.
startAsServer
(
oid
);
token
=
Proc
.
binIn
();
// AP-REQ
token
=
s
.
take
(
token
);
Proc
.
binOut
(
token
);
// AP-REP
Context
s2
=
s
.
delegated
();
s2
.
startAsClient
(
BACKEND
,
oid
);
Proc
.
binOut
(
s2
.
take
(
new
byte
[
0
]));
// AP-REQ
token
=
Proc
.
binIn
();
s2
.
take
(
token
);
// AP-REP
Random
r
=
new
Random
();
msg
=
new
byte
[
MSGSIZE
];
r
.
nextBytes
(
msg
);
Proc
.
binOut
(
s2
.
wrap
(
msg
,
true
));
// enc1
Proc
.
binOut
(
s2
.
wrap
(
msg
,
true
));
// enc2
Proc
.
binOut
(
s2
.
wrap
(
msg
,
true
));
// enc3
s2
.
verifyMic
(
Proc
.
binIn
(),
msg
);
// mic
byte
[]
msg2
=
Proc
.
binIn
();
// msg
if
(!
Arrays
.
equals
(
msg
,
msg2
))
{
throw
new
Exception
(
"diff msg"
);
}
break
;
case
"backend"
:
Context
b
=
args
[
1
].
equals
(
"n"
)
?
Context
.
fromThinAir
()
:
Context
.
fromUserKtab
(
BACKEND
,
KTAB_B
,
true
);
b
.
startAsServer
(
oid
);
token
=
Proc
.
binIn
();
// AP-REQ
Proc
.
binOut
(
b
.
take
(
token
));
// AP-REP
msg
=
b
.
unwrap
(
Proc
.
binIn
(),
true
);
// enc1
if
(!
Arrays
.
equals
(
msg
,
b
.
unwrap
(
Proc
.
binIn
(),
true
)))
{
// enc2
throw
new
Exception
(
"diff msg"
);
}
if
(!
Arrays
.
equals
(
msg
,
b
.
unwrap
(
Proc
.
binIn
(),
true
)))
{
// enc3
throw
new
Exception
(
"diff msg"
);
}
Proc
.
binOut
(
b
.
getMic
(
msg
));
// mic
Proc
.
binOut
(
msg
);
// msg
break
;
}
}
/**
* One test run.
*
* @param label test label
* @param lc lib of client
* @param ls lib of server
* @param lb lib of backend
*/
private
static
void
once
(
String
label
,
String
lc
,
String
ls
,
String
lb
)
throws
Exception
{
Proc
pc
=
proc
(
lc
)
.
args
(
"client"
,
lc
==
null
?
"j"
:
"n"
)
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
"krbtgt/"
+
REALM
+
"@"
+
REALM
,
"initiate"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
SERVER
+
"@"
+
REALM
,
"initiate"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
DelegationPermission
(
"\""
+
SERVER
+
"@"
+
REALM
+
"\" "
+
"\"krbtgt/"
+
REALM
+
"@"
+
REALM
+
"\""
))
.
debug
(
label
+
"-C"
);
if
(
lc
==
null
)
{
// for Krb5LoginModule::promptForName
pc
.
perm
(
new
PropertyPermission
(
"user.name"
,
"read"
));
}
else
{
Files
.
copy
(
Paths
.
get
(
"base.ccache"
),
Paths
.
get
(
label
+
".ccache"
));
Set
<
PosixFilePermission
>
perms
=
new
HashSet
<>();
perms
.
add
(
PosixFilePermission
.
OWNER_READ
);
perms
.
add
(
PosixFilePermission
.
OWNER_WRITE
);
Files
.
setPosixFilePermissions
(
Paths
.
get
(
label
+
".ccache"
),
Collections
.
unmodifiableSet
(
perms
));
pc
.
env
(
"KRB5CCNAME"
,
label
+
".ccache"
);
// Do not try system ktab if ccache fails
pc
.
env
(
"KRB5_KTNAME"
,
"none"
);
}
pc
.
start
();
Proc
ps
=
proc
(
ls
)
.
args
(
"server"
,
ls
==
null
?
"j"
:
"n"
)
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
SERVER
+
"@"
+
REALM
,
"accept"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
BACKEND
+
"@"
+
REALM
,
"initiate"
))
.
debug
(
label
+
"-S"
);
if
(
ls
==
null
)
{
ps
.
perm
(
new
PrivateCredentialPermission
(
"javax.security.auth.kerberos.KeyTab * \"*\""
,
"read"
))
.
perm
(
new
java
.
io
.
FilePermission
(
KTAB_S
,
"read"
));
}
else
{
ps
.
env
(
"KRB5_KTNAME"
,
KTAB_S
);
}
ps
.
start
();
Proc
pb
=
proc
(
lb
)
.
args
(
"backend"
,
lb
==
null
?
"j"
:
"n"
)
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
BACKEND
+
"@"
+
REALM
,
"accept"
))
.
debug
(
label
+
"-B"
);
if
(
lb
==
null
)
{
pb
.
perm
(
new
PrivateCredentialPermission
(
"javax.security.auth.kerberos.KeyTab * \"*\""
,
"read"
))
.
perm
(
new
java
.
io
.
FilePermission
(
KTAB_B
,
"read"
));
}
else
{
pb
.
env
(
"KRB5_KTNAME"
,
KTAB_B
);
}
pb
.
start
();
// Client and server handshake
ps
.
println
(
pc
.
readData
());
pc
.
println
(
ps
.
readData
());
// Server and backend handshake
pb
.
println
(
ps
.
readData
());
ps
.
println
(
pb
.
readData
());
// wrap/unwrap/getMic/verifyMic and plain text
pb
.
println
(
ps
.
readData
());
pb
.
println
(
ps
.
readData
());
pb
.
println
(
ps
.
readData
());
ps
.
println
(
pb
.
readData
());
ps
.
println
(
pb
.
readData
());
if
((
pc
.
waitFor
()
|
ps
.
waitFor
()
|
pb
.
waitFor
())
!=
0
)
{
throw
new
Exception
(
"Process failed"
);
}
}
/**
* A Proc for a child process.
*
* @param lib the library. Null is Java. "" is default native lib.
*/
private
static
Proc
proc
(
String
lib
)
throws
Exception
{
Proc
p
=
Proc
.
create
(
"BasicProc"
)
.
prop
(
"java.security.manager"
,
""
)
.
prop
(
"sun.net.spi.nameservice.provider.1"
,
"ns,mock"
)
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"doAs"
));
if
(
lib
!=
null
)
{
p
.
env
(
"KRB5_CONFIG"
,
CONF
)
.
env
(
"KRB5_TRACE"
,
"/dev/stderr"
)
.
prop
(
"sun.security.jgss.native"
,
"true"
)
.
prop
(
"sun.security.jgss.lib"
,
lib
)
.
prop
(
"javax.security.auth.useSubjectCredsOnly"
,
"false"
)
.
prop
(
"sun.security.nativegss.debug"
,
"true"
);
int
pos
=
lib
.
lastIndexOf
(
'/'
);
if
(
pos
>
0
)
{
p
.
env
(
"LD_LIBRARY_PATH"
,
lib
.
substring
(
0
,
pos
));
p
.
env
(
"DYLD_LIBRARY_PATH"
,
lib
.
substring
(
0
,
pos
));
}
}
else
{
p
.
perm
(
new
java
.
util
.
PropertyPermission
(
"sun.security.krb5.principal"
,
"read"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"modifyPrincipals"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"modifyPrivateCredentials"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"doAs"
))
.
perm
(
new
PrivateCredentialPermission
(
"javax.security.auth.kerberos.KeyTab * \"*\""
,
"read"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
"server/localhost@"
+
REALM
,
"accept"
))
.
perm
(
new
java
.
io
.
FilePermission
(
cwd
+
File
.
separator
+
KTAB
,
"read"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
"backend/localhost@"
+
REALM
,
"initiate"
))
.
debug
(
"S"
)
.
start
();
Proc
pb
=
Proc
.
create
(
"BasicProc"
)
.
args
(
"backend"
)
.
prop
(
"java.security.krb5.conf"
,
CONF
)
.
prop
(
"java.security.manager"
,
""
)
.
prop
(
"sun.net.spi.nameservice.provider.1"
,
"ns,mock"
)
// For Krb5LoginModule::login.
.
perm
(
new
java
.
lang
.
RuntimePermission
(
"accessClassInPackage.sun.net.spi.nameservice"
))
.
perm
(
new
java
.
util
.
PropertyPermission
(
"sun.security.krb5.principal"
,
"read"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"modifyPrincipals"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"modifyPrivateCredentials"
))
.
perm
(
new
javax
.
security
.
auth
.
AuthPermission
(
"doAs"
))
.
perm
(
new
PrivateCredentialPermission
(
"javax.security.auth.kerberos.KeyTab * \"*\""
,
"read"
))
.
perm
(
new
javax
.
security
.
auth
.
kerberos
.
ServicePermission
(
"backend/localhost@"
+
REALM
,
"accept"
))
.
perm
(
new
java
.
io
.
FilePermission
(
cwd
+
File
.
separator
+
KTAB
,
"read"
))
.
debug
(
"B"
)
.
start
();
// Client and server handshake
String
token
=
pc
.
readData
();
ps
.
println
(
token
);
token
=
ps
.
readData
();
pc
.
println
(
token
);
// Server and backend handshake
token
=
ps
.
readData
();
pb
.
println
(
token
);
token
=
pb
.
readData
();
ps
.
println
(
token
);
// wrap/unwrap/getMic/verifyMic and plain text
token
=
ps
.
readData
();
pb
.
println
(
token
);
token
=
pb
.
readData
();
ps
.
println
(
token
);
token
=
pb
.
readData
();
ps
.
println
(
token
);
if
((
pc
.
waitFor
()
|
ps
.
waitFor
()
|
pb
.
waitFor
())
!=
0
)
{
throw
new
Exception
();
}
}
else
if
(
args
[
0
].
equals
(
"client"
))
{
Context
c
=
Context
.
fromUserPass
(
USER
,
PASS
,
false
);
c
.
startAsClient
(
SERVER
,
oid
);
c
.
x
().
requestCredDeleg
(
true
);
Proc
.
binOut
(
c
.
take
(
new
byte
[
0
]));
byte
[]
token
=
Proc
.
binIn
();
c
.
take
(
token
);
}
else
if
(
args
[
0
].
equals
(
"server"
))
{
Context
s
=
Context
.
fromUserKtab
(
SERVER
,
KTAB
,
true
);
s
.
startAsServer
(
oid
);
byte
[]
token
=
Proc
.
binIn
();
token
=
s
.
take
(
token
);
Proc
.
binOut
(
token
);
Context
s2
=
s
.
delegated
();
s2
.
startAsClient
(
BACKEND
,
oid
);
Proc
.
binOut
(
s2
.
take
(
new
byte
[
0
]));
token
=
Proc
.
binIn
();
s2
.
take
(
token
);
byte
[]
msg
=
"Hello"
.
getBytes
();
Proc
.
binOut
(
s2
.
wrap
(
msg
,
true
));
s2
.
verifyMic
(
Proc
.
binIn
(),
msg
);
String
in
=
Proc
.
textIn
();
if
(!
in
.
equals
(
"Hello"
))
{
throw
new
Exception
();
}
}
else
if
(
args
[
0
].
equals
(
"backend"
))
{
Context
b
=
Context
.
fromUserKtab
(
BACKEND
,
KTAB
,
true
);
b
.
startAsServer
(
oid
);
byte
[]
token
=
Proc
.
binIn
();
Proc
.
binOut
(
b
.
take
(
token
));
byte
[]
msg
=
b
.
unwrap
(
Proc
.
binIn
(),
true
);
Proc
.
binOut
(
b
.
getMic
(
msg
));
Proc
.
textOut
(
new
String
(
msg
));
.
prop
(
"sun.security.krb5.debug"
,
"true"
)
.
prop
(
"java.security.krb5.conf"
,
CONF
);
}
}
// create a native server
private
static
Proc
ns
(
Proc
p
)
throws
Exception
{
return
p
.
env
(
"KRB5_CONFIG"
,
CONF
)
.
env
(
"KRB5_KTNAME"
,
KTAB
)
.
prop
(
"sun.net.spi.nameservice.provider.1"
,
"ns,mock"
)
.
prop
(
"sun.security.jgss.native"
,
"true"
)
.
prop
(
"javax.security.auth.useSubjectCredsOnly"
,
"false"
)
.
prop
(
"sun.security.nativegss.debug"
,
"true"
);
return
p
;
}
}
test/sun/security/krb5/auto/Context.java
浏览文件 @
30f766b9
/*
* Copyright (c) 2008, 201
3
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 201
7
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -22,14 +22,21 @@
*/
import
com.sun.security.auth.module.Krb5LoginModule
;
import
java.
security.Key
;
import
java.
io.IOException
;
import
java.lang.reflect.InvocationTargetException
;
import
java.security.PrivilegedActionException
;
import
java.security.PrivilegedExceptionAction
;
import
java.security.Key
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.security.auth.Subject
;
import
javax.security.auth.callback.Callback
;
import
javax.security.auth.callback.CallbackHandler
;
import
javax.security.auth.callback.NameCallback
;
import
javax.security.auth.callback.PasswordCallback
;
import
javax.security.auth.callback.UnsupportedCallbackException
;
import
javax.security.auth.kerberos.KerberosKey
;
import
javax.security.auth.kerberos.KerberosTicket
;
import
javax.security.auth.login.LoginContext
;
...
...
@@ -40,6 +47,10 @@ import org.ietf.jgss.GSSManager;
import
org.ietf.jgss.GSSName
;
import
org.ietf.jgss.MessageProp
;
import
org.ietf.jgss.Oid
;
import
sun.security.jgss.krb5.Krb5Util
;
import
sun.security.krb5.Credentials
;
import
sun.security.krb5.internal.ccache.CredentialsCache
;
import
com.sun.security.jgss.ExtendedGSSContext
;
import
com.sun.security.jgss.InquireType
;
import
com.sun.security.jgss.AuthorizationDataEntry
;
...
...
@@ -154,24 +165,36 @@ public class Context {
Map
<
String
,
String
>
map
=
new
HashMap
<>();
Map
<
String
,
Object
>
shared
=
new
HashMap
<>();
if
(
storeKey
)
{
map
.
put
(
"storeKey"
,
"true"
);
}
if
(
pass
!=
null
)
{
map
.
put
(
"useFirstPass"
,
"true"
);
shared
.
put
(
"javax.security.auth.login.name"
,
user
);
shared
.
put
(
"javax.security.auth.login.password"
,
pass
);
krb5
.
initialize
(
out
.
s
,
new
CallbackHandler
()
{
@Override
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
((
NameCallback
)
cb
).
setName
(
user
);
}
else
if
(
cb
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
cb
).
setPassword
(
pass
);
}
}
}
},
shared
,
map
);
}
else
{
map
.
put
(
"doNotPrompt"
,
"true"
);
map
.
put
(
"useTicketCache"
,
"true"
);
if
(
user
!=
null
)
{
map
.
put
(
"principal"
,
user
);
}
}
if
(
storeKey
)
{
map
.
put
(
"storeKey"
,
"true"
);
krb5
.
initialize
(
out
.
s
,
null
,
shared
,
map
);
}
krb5
.
initialize
(
out
.
s
,
null
,
shared
,
map
);
krb5
.
login
();
krb5
.
commit
();
return
out
;
}
...
...
@@ -529,9 +552,23 @@ public class Context {
* @param s2 the receiver
* @throws java.lang.Exception If anything goes wrong
*/
static
public
void
transmit
(
final
String
message
,
final
Context
s1
,
static
public
void
transmit
(
String
message
,
final
Context
s1
,
final
Context
s2
)
throws
Exception
{
transmit
(
message
.
getBytes
(),
s1
,
s2
);
}
/**
* Transmits a message from one Context to another. The sender wraps the
* message and sends it to the receiver. The receiver unwraps it, creates
* a MIC of the clear text and sends it back to the sender. The sender
* verifies the MIC against the message sent earlier.
* @param messageBytes the message
* @param s1 the sender
* @param s2 the receiver
* @throws java.lang.Exception If anything goes wrong
*/
static
public
void
transmit
(
byte
[]
messageBytes
,
final
Context
s1
,
final
Context
s2
)
throws
Exception
{
final
byte
[]
messageBytes
=
message
.
getBytes
();
System
.
out
.
printf
(
"-------------------- TRANSMIT from %s to %s------------------------\n"
,
s1
.
name
,
s2
.
name
);
byte
[]
wrapped
=
s1
.
wrap
(
messageBytes
,
true
);
...
...
@@ -615,6 +652,32 @@ public class Context {
},
in
);
}
/**
* Saves the tickets to a ccache file.
*
* @param file pathname of the ccache file
* @return true if created, false otherwise.
*/
public
boolean
ccache
(
String
file
)
throws
Exception
{
Set
<
KerberosTicket
>
tickets
=
s
.
getPrivateCredentials
(
KerberosTicket
.
class
);
if
(
tickets
!=
null
&&
!
tickets
.
isEmpty
())
{
CredentialsCache
cc
=
null
;
for
(
KerberosTicket
t
:
tickets
)
{
Credentials
cred
=
Krb5Util
.
ticketToCreds
(
t
);
if
(
cc
==
null
)
{
cc
=
CredentialsCache
.
create
(
cred
.
getClient
(),
file
);
}
cc
.
update
(
cred
.
toCCacheCreds
());
}
if
(
cc
!=
null
)
{
cc
.
save
();
return
true
;
}
}
return
false
;
}
/**
* Handshake (security context establishment process) between two Contexts
* @param c the initiator
...
...
test/sun/security/krb5/auto/KDC.java
浏览文件 @
30f766b9
...
...
@@ -27,11 +27,12 @@ import java.lang.reflect.InvocationTargetException;
import
java.net.*
;
import
java.io.*
;
import
java.lang.reflect.Method
;
import
java.security.SecureRandom
;
import
java.time.Instant
;
import
java.time.temporal.ChronoUnit
;
import
java.nio.file.Files
;
import
java.nio.file.Paths
;
import
java.util.*
;
import
java.util.concurrent.*
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
sun.net.spi.nameservice.NameService
;
import
sun.net.spi.nameservice.NameServiceDescriptor
;
...
...
@@ -49,6 +50,11 @@ import java.util.regex.Pattern;
/**
* A KDC server.
*
* Note: By setting the system property native.kdc.path to a native
* krb5 installation, this class starts a native KDC with the
* given realm and host. It can also add new principals and save keytabs.
* Other features might not be available.
* <p>
* Features:
* <ol>
...
...
@@ -129,10 +135,18 @@ public class KDC {
public
static
final
int
DEFAULT_LIFETIME
=
39600
;
public
static
final
int
DEFAULT_RENEWTIME
=
86400
;
// Under the hood.
// What etypes the KDC supports. Comma-separated strings. Null for all.
// Please note native KDCs might use different names.
private
static
final
String
SUPPORTED_ETYPES
=
System
.
getProperty
(
"kdc.supported.enctypes"
);
// The native KDC
private
final
NativeKdc
nativeKdc
;
// The random generator to generate random keys (including session keys)
private
static
SecureRandom
secureRandom
=
new
SecureRandom
();
// The native KDC process
private
Process
kdcProc
=
null
;
// Under the hood.
// Principal db. principal -> pass. A case-insensitive TreeMap is used
// so that even if the client provides a name with different case, the KDC
...
...
@@ -140,14 +154,6 @@ public class KDC {
private
TreeMap
<
String
,
char
[]>
passwords
=
new
TreeMap
<>
(
String
.
CASE_INSENSITIVE_ORDER
);
// Alias for referrals.
private
TreeMap
<
String
,
KDC
>
aliasReferrals
=
new
TreeMap
<>
(
String
.
CASE_INSENSITIVE_ORDER
);
// Alias for local resolution.
private
TreeMap
<
String
,
PrincipalName
>
alias2Principals
=
new
TreeMap
<>
(
String
.
CASE_INSENSITIVE_ORDER
);
// Non default salts. Precisely, there should be different salts for
// different etypes, pretend they are the same at the moment.
private
TreeMap
<
String
,
String
>
salts
=
new
TreeMap
<>
...
...
@@ -159,6 +165,14 @@ public class KDC {
private
TreeMap
<
String
,
byte
[]>
s2kparamses
=
new
TreeMap
<>
(
String
.
CASE_INSENSITIVE_ORDER
);
// Alias for referrals.
private
TreeMap
<
String
,
KDC
>
aliasReferrals
=
new
TreeMap
<>
(
String
.
CASE_INSENSITIVE_ORDER
);
// Alias for local resolution.
private
TreeMap
<
String
,
PrincipalName
>
alias2Principals
=
new
TreeMap
<>
(
String
.
CASE_INSENSITIVE_ORDER
);
// Realm name
private
String
realm
;
// KDC
...
...
@@ -276,7 +290,8 @@ public class KDC {
* @return the running KDC instance
* @throws java.io.IOException for any socket creation error
*/
public
static
KDC
create
(
String
realm
,
String
kdc
,
int
port
,
boolean
asDaemon
)
throws
IOException
{
public
static
KDC
create
(
String
realm
,
String
kdc
,
int
port
,
boolean
asDaemon
)
throws
IOException
{
return
new
KDC
(
realm
,
kdc
,
port
,
asDaemon
);
}
...
...
@@ -316,26 +331,38 @@ public class KDC {
*/
public
void
writeKtab
(
String
tab
,
boolean
append
,
String
...
names
)
throws
IOException
,
KrbException
{
KeyTab
ktab
=
append
?
KeyTab
.
getInstance
(
tab
)
:
KeyTab
.
create
(
tab
);
KeyTab
ktab
=
null
;
if
(
nativeKdc
==
null
)
{
ktab
=
append
?
KeyTab
.
getInstance
(
tab
)
:
KeyTab
.
create
(
tab
);
}
Iterable
<
String
>
entries
=
(
names
.
length
!=
0
)
?
Arrays
.
asList
(
names
):
passwords
.
keySet
();
for
(
String
name
:
entries
)
{
char
[]
pass
=
passwords
.
get
(
name
);
int
kvno
=
0
;
if
(
Character
.
isDigit
(
pass
[
pass
.
length
-
1
]))
{
kvno
=
pass
[
pass
.
length
-
1
]
-
'0'
;
if
(
name
.
indexOf
(
'@'
)
<
0
)
{
name
=
name
+
"@"
+
realm
;
}
PrincipalName
pn
=
new
PrincipalName
(
name
,
if
(
nativeKdc
==
null
)
{
char
[]
pass
=
passwords
.
get
(
name
);
int
kvno
=
0
;
if
(
Character
.
isDigit
(
pass
[
pass
.
length
-
1
]))
{
kvno
=
pass
[
pass
.
length
-
1
]
-
'0'
;
}
PrincipalName
pn
=
new
PrincipalName
(
name
,
name
.
indexOf
(
'/'
)
<
0
?
PrincipalName
.
KRB_NT_UNKNOWN
:
PrincipalName
.
KRB_NT_SRV_HST
);
ktab
.
addEntry
(
pn
,
PrincipalName
.
KRB_NT_UNKNOWN
:
PrincipalName
.
KRB_NT_SRV_HST
);
ktab
.
addEntry
(
pn
,
getSalt
(
pn
),
pass
,
kvno
,
true
);
}
else
{
nativeKdc
.
ktadd
(
name
,
tab
);
}
}
if
(
nativeKdc
==
null
)
{
ktab
.
save
();
}
ktab
.
save
();
}
/**
...
...
@@ -392,16 +419,24 @@ public class KDC {
* @param salt the salt, or null if a default value will be used
* @param s2kparams the s2kparams, or null if a default value will be used
*/
public
void
addPrincipal
(
String
user
,
char
[]
pass
,
String
salt
,
byte
[]
s2kparams
)
{
public
void
addPrincipal
(
String
user
,
char
[]
pass
,
String
salt
,
byte
[]
s2kparams
)
{
if
(
user
.
indexOf
(
'@'
)
<
0
)
{
user
=
user
+
"@"
+
realm
;
}
passwords
.
put
(
user
,
pass
);
if
(
salt
!=
null
)
{
salts
.
put
(
user
,
salt
);
}
if
(
s2kparams
!=
null
)
{
s2kparamses
.
put
(
user
,
s2kparams
);
if
(
nativeKdc
!=
null
)
{
if
(!
user
.
equals
(
"krbtgt/"
+
realm
))
{
nativeKdc
.
addPrincipal
(
user
,
new
String
(
pass
));
}
passwords
.
put
(
user
,
new
char
[
0
]);
}
else
{
passwords
.
put
(
user
,
pass
);
if
(
salt
!=
null
)
{
salts
.
put
(
user
,
salt
);
}
if
(
s2kparams
!=
null
)
{
s2kparamses
.
put
(
user
,
s2kparams
);
}
}
}
...
...
@@ -498,12 +533,11 @@ public class KDC {
*/
public
static
void
saveConfig
(
String
file
,
KDC
kdc
,
Object
...
more
)
throws
IOException
{
File
f
=
new
File
(
file
);
StringBuffer
sb
=
new
StringBuffer
();
sb
.
append
(
"[libdefaults]\ndefault_realm = "
);
sb
.
append
(
kdc
.
realm
);
sb
.
append
(
"\n"
);
for
(
Object
o:
more
)
{
for
(
Object
o
:
more
)
{
if
(
o
instanceof
String
)
{
sb
.
append
(
o
);
sb
.
append
(
"\n"
);
...
...
@@ -511,14 +545,12 @@ public class KDC {
}
sb
.
append
(
"\n[realms]\n"
);
sb
.
append
(
kdc
.
realmLine
());
for
(
Object
o:
more
)
{
for
(
Object
o
:
more
)
{
if
(
o
instanceof
KDC
)
{
sb
.
append
(((
KDC
)
o
).
realmLine
());
sb
.
append
(((
KDC
)
o
).
realmLine
());
}
}
FileOutputStream
fos
=
new
FileOutputStream
(
f
);
fos
.
write
(
sb
.
toString
().
getBytes
());
fos
.
close
();
Files
.
write
(
Paths
.
get
(
file
),
sb
.
toString
().
getBytes
());
}
/**
...
...
@@ -561,6 +593,7 @@ public class KDC {
private
KDC
(
String
realm
,
String
kdc
)
{
this
.
realm
=
realm
;
this
.
kdc
=
kdc
;
this
.
nativeKdc
=
null
;
}
/**
...
...
@@ -568,7 +601,9 @@ public class KDC {
*/
protected
KDC
(
String
realm
,
String
kdc
,
int
port
,
boolean
asDaemon
)
throws
IOException
{
this
(
realm
,
kdc
);
this
.
realm
=
realm
;
this
.
kdc
=
kdc
;
this
.
nativeKdc
=
NativeKdc
.
get
(
this
);
startServer
(
port
,
asDaemon
);
}
/**
...
...
@@ -577,8 +612,9 @@ public class KDC {
*/
private
static
char
[]
randomPassword
()
{
char
[]
pass
=
new
char
[
32
];
Random
r
=
new
Random
();
for
(
int
i
=
0
;
i
<
31
;
i
++)
pass
[
i
]
=
(
char
)
secureRandom
.
nextInt
(
);
pass
[
i
]
=
(
char
)
(
'a'
+
r
.
nextInt
(
26
)
);
// The last char cannot be a number, otherwise, keyForUser()
// believes it's a sign of kvno
pass
[
31
]
=
'Z'
;
...
...
@@ -754,7 +790,10 @@ public class KDC {
" sends TGS-REQ for "
+
service
+
", "
+
tgsReq
.
reqBody
.
kdcOptions
);
KDCReqBody
body
=
tgsReq
.
reqBody
;
int
[]
eTypes
=
KDCReqBodyDotEType
(
body
);
int
[]
eTypes
=
filterSupported
(
KDCReqBodyDotEType
(
body
));
if
(
eTypes
.
length
==
0
)
{
throw
new
KrbException
(
Krb5
.
KDC_ERR_ETYPE_NOSUPP
);
}
int
e2
=
eTypes
[
0
];
// etype for outgoing session key
int
e3
=
eTypes
[
0
];
// etype for outgoing ticket
...
...
@@ -802,13 +841,14 @@ public class KDC {
PAForUserEnc
p4u
=
new
PAForUserEnc
(
new
DerValue
(
pa
.
getValue
()),
null
);
forUserCName
=
p4u
.
name
;
System
.
out
.
println
(
realm
+
">
presenting a
PA_FOR_USER "
System
.
out
.
println
(
realm
+
">
See
PA_FOR_USER "
+
" in the name of "
+
p4u
.
name
);
}
}
}
if
(
forUserCName
!=
null
)
{
List
<
String
>
names
=
(
List
<
String
>)
options
.
get
(
Option
.
ALLOW_S4U2SELF
);
List
<
String
>
names
=
(
List
<
String
>)
options
.
get
(
Option
.
ALLOW_S4U2SELF
);
if
(!
names
.
contains
(
cname
.
toString
()))
{
// Mimic the normal KDC behavior. When a server is not
// allowed to send S4U2self, do not send an error.
...
...
@@ -829,17 +869,19 @@ public class KDC {
EncryptionKey
key
=
generateRandomKey
(
e2
);
// Check time, TODO
KerberosTime
from
=
body
.
from
;
KerberosTime
till
=
body
.
till
;
if
(
from
==
null
||
from
.
isZero
())
{
from
=
timeAfter
(
0
);
}
KerberosTime
rtime
=
body
.
rtime
;
if
(
till
==
null
)
{
throw
new
KrbException
(
Krb5
.
KDC_ERR_NEVER_VALID
);
// TODO
}
else
if
(
till
.
isZero
())
{
till
=
new
KerberosTime
(
new
Date
().
getTime
()
+
1000
*
DEFAULT_LIFETIME
);
till
=
timeAfter
(
DEFAULT_LIFETIME
);
}
if
(
rtime
==
null
&&
body
.
kdcOptions
.
get
(
KDCOptions
.
RENEWABLE
))
{
rtime
=
new
KerberosTime
(
new
Date
().
getTime
()
+
1000
*
DEFAULT_RENEWTIME
);
rtime
=
timeAfter
(
DEFAULT_RENEWTIME
);
}
boolean
[]
bFlags
=
new
boolean
[
Krb5
.
TKT_OPTS_MAX
+
1
];
...
...
@@ -859,7 +901,7 @@ public class KDC {
}
if
(
body
.
kdcOptions
.
get
(
KDCOptions
.
RENEWABLE
))
{
bFlags
[
Krb5
.
TKT_OPTS_RENEWABLE
]
=
true
;
//renew =
new KerberosTime(new Date().getTime() + 1000 *
3600 * 24 * 7);
//renew =
timeAfter(
3600 * 24 * 7);
}
if
(
body
.
kdcOptions
.
get
(
KDCOptions
.
PROXIABLE
))
{
bFlags
[
Krb5
.
TKT_OPTS_PROXIABLE
]
=
true
;
...
...
@@ -878,7 +920,8 @@ public class KDC {
Map
<
String
,
List
<
String
>>
map
=
(
Map
<
String
,
List
<
String
>>)
options
.
get
(
Option
.
ALLOW_S4U2PROXY
);
Ticket
second
=
KDCReqBodyDotFirstAdditionalTicket
(
body
);
EncryptionKey
key2
=
keyForUser
(
second
.
sname
,
second
.
encPart
.
getEType
(),
true
);
EncryptionKey
key2
=
keyForUser
(
second
.
sname
,
second
.
encPart
.
getEType
(),
true
);
byte
[]
bb
=
second
.
encPart
.
decrypt
(
key2
,
KeyUsage
.
KU_TICKET
);
DerInputStream
derIn
=
new
DerInputStream
(
bb
);
DerValue
der
=
derIn
.
getDerValue
();
...
...
@@ -928,8 +971,8 @@ public class KDC {
key
,
cname
,
new
TransitedEncoding
(
1
,
new
byte
[
0
]),
// TODO
new
KerberosTime
(
new
Date
()
),
body
.
from
,
timeAfter
(
0
),
from
,
till
,
renewTill
,
body
.
addresses
!=
null
// always set caddr
?
body
.
addresses
...
...
@@ -948,15 +991,15 @@ public class KDC {
);
EncTGSRepPart
enc_part
=
new
EncTGSRepPart
(
key
,
new
LastReq
(
new
LastReqEntry
[]{
new
LastReqEntry
(
0
,
new
KerberosTime
(
new
Date
().
getTime
()
-
1000
0
))
new
LastReq
(
new
LastReqEntry
[]
{
new
LastReqEntry
(
0
,
timeAfter
(-
1
0
))
}),
body
.
getNonce
(),
// TODO: detect replay
new
KerberosTime
(
new
Date
().
getTime
()
+
1000
*
3600
*
24
),
timeAfter
(
3600
*
24
),
// Next 5 and last MUST be same with ticket
tFlags
,
new
KerberosTime
(
new
Date
()
),
body
.
from
,
timeAfter
(
0
),
from
,
till
,
renewTill
,
service
,
body
.
addresses
!=
null
// always set caddr
...
...
@@ -965,7 +1008,8 @@ public class KDC {
new
InetAddress
[]{
InetAddress
.
getLocalHost
()}),
null
);
EncryptedData
edata
=
new
EncryptedData
(
ckey
,
enc_part
.
asn1Encode
(),
KeyUsage
.
KU_ENC_TGS_REP_PART_SESSKEY
);
EncryptedData
edata
=
new
EncryptedData
(
ckey
,
enc_part
.
asn1Encode
(),
KeyUsage
.
KU_ENC_TGS_REP_PART_SESSKEY
);
TGSRep
tgsRep
=
new
TGSRep
(
null
,
cname
,
t
,
...
...
@@ -986,7 +1030,7 @@ public class KDC {
+
" "
+
ke
.
returnCodeMessage
());
if
(
kerr
==
null
)
{
kerr
=
new
KRBError
(
null
,
null
,
null
,
new
KerberosTime
(
new
Date
()
),
timeAfter
(
0
),
0
,
ke
.
returnCode
(),
body
.
cname
,
...
...
@@ -1023,16 +1067,11 @@ public class KDC {
KDCReqBody
body
=
asReq
.
reqBody
;
eTypes
=
KDCReqBodyDotEType
(
body
);
int
eType
=
eTypes
[
0
];
// Maybe server does not support aes256, but a kinit does
if
(!
EType
.
isSupported
(
eType
))
{
if
(
eTypes
.
length
<
2
)
{
throw
new
KrbException
(
Krb5
.
KDC_ERR_ETYPE_NOSUPP
);
}
eType
=
eTypes
[
1
];
eTypes
=
filterSupported
(
KDCReqBodyDotEType
(
body
));
if
(
eTypes
.
length
==
0
)
{
throw
new
KrbException
(
Krb5
.
KDC_ERR_ETYPE_NOSUPP
);
}
int
eType
=
eTypes
[
0
];
if
(
body
.
kdcOptions
.
get
(
KDCOptions
.
CANONICALIZE
)
&&
body
.
cname
.
getNameType
()
==
PrincipalName
.
KRB_NT_ENTERPRISE
)
{
...
...
@@ -1079,8 +1118,12 @@ public class KDC {
// Session key
EncryptionKey
key
=
generateRandomKey
(
eType
);
// Check time, TODO
KerberosTime
from
=
body
.
from
;
KerberosTime
till
=
body
.
till
;
KerberosTime
rtime
=
body
.
rtime
;
if
(
from
==
null
||
from
.
isZero
())
{
from
=
timeAfter
(
0
);
}
if
(
till
==
null
)
{
throw
new
KrbException
(
Krb5
.
KDC_ERR_NEVER_VALID
);
// TODO
}
else
if
(
till
.
isZero
())
{
...
...
@@ -1106,7 +1149,8 @@ public class KDC {
if
(
body
.
kdcOptions
.
get
(
KDCOptions
.
FORWARDABLE
))
{
List
<
String
>
sensitives
=
(
List
<
String
>)
options
.
get
(
Option
.
SENSITIVE_ACCOUNTS
);
if
(
sensitives
!=
null
&&
sensitives
.
contains
(
body
.
cname
.
toString
()))
{
if
(
sensitives
!=
null
&&
sensitives
.
contains
(
body
.
cname
.
toString
()))
{
// Cannot make FORWARDABLE
}
else
{
bFlags
[
Krb5
.
TKT_OPTS_FORWARDABLE
]
=
true
;
...
...
@@ -1114,7 +1158,7 @@ public class KDC {
}
if
(
body
.
kdcOptions
.
get
(
KDCOptions
.
RENEWABLE
))
{
bFlags
[
Krb5
.
TKT_OPTS_RENEWABLE
]
=
true
;
//renew =
new KerberosTime(new Date().getTime() + 1000 *
3600 * 24 * 7);
//renew =
timeAfter(
3600 * 24 * 7);
}
if
(
body
.
kdcOptions
.
get
(
KDCOptions
.
PROXIABLE
))
{
bFlags
[
Krb5
.
TKT_OPTS_PROXIABLE
]
=
true
;
...
...
@@ -1136,7 +1180,8 @@ public class KDC {
pas2
=
new
DerValue
[]
{
new
DerValue
(
new
ETypeInfo2
(
1
,
null
,
null
).
asn1Encode
()),
new
DerValue
(
new
ETypeInfo2
(
1
,
""
,
null
).
asn1Encode
()),
new
DerValue
(
new
ETypeInfo2
(
1
,
realm
,
new
byte
[]{
1
}).
asn1Encode
()),
new
DerValue
(
new
ETypeInfo2
(
1
,
realm
,
new
byte
[]{
1
}).
asn1Encode
()),
};
pas
=
new
DerValue
[]
{
new
DerValue
(
new
ETypeInfo
(
1
,
null
).
asn1Encode
()),
...
...
@@ -1146,7 +1191,8 @@ public class KDC {
break
;
case
2
:
// we still reject non-null s2kparams and prefer E2 over E
pas2
=
new
DerValue
[]
{
new
DerValue
(
new
ETypeInfo2
(
1
,
realm
,
new
byte
[]{
1
}).
asn1Encode
()),
new
DerValue
(
new
ETypeInfo2
(
1
,
realm
,
new
byte
[]{
1
}).
asn1Encode
()),
new
DerValue
(
new
ETypeInfo2
(
1
,
null
,
null
).
asn1Encode
()),
new
DerValue
(
new
ETypeInfo2
(
1
,
""
,
null
).
asn1Encode
()),
};
...
...
@@ -1241,11 +1287,14 @@ public class KDC {
}
else
{
EncryptionKey
pakey
=
null
;
try
{
EncryptedData
data
=
newEncryptedData
(
new
DerValue
(
inPAs
[
0
].
getValue
()));
EncryptedData
data
=
newEncryptedData
(
new
DerValue
(
inPAs
[
0
].
getValue
()));
pakey
=
keyForUser
(
body
.
cname
,
data
.
getEType
(),
false
);
data
.
decrypt
(
pakey
,
KeyUsage
.
KU_PA_ENC_TS
);
}
catch
(
Exception
e
)
{
throw
new
KrbException
(
Krb5
.
KDC_ERR_PREAUTH_FAILED
);
KrbException
ke
=
new
KrbException
(
Krb5
.
KDC_ERR_PREAUTH_FAILED
);
ke
.
initCause
(
e
);
throw
ke
;
}
bFlags
[
Krb5
.
TKT_OPTS_PRE_AUTHENT
]
=
true
;
for
(
PAData
pa
:
inPAs
)
{
...
...
@@ -1267,8 +1316,8 @@ public class KDC {
key
,
body
.
cname
,
new
TransitedEncoding
(
1
,
new
byte
[
0
]),
new
KerberosTime
(
new
Date
()
),
body
.
from
,
timeAfter
(
0
),
from
,
till
,
rtime
,
body
.
addresses
,
null
);
...
...
@@ -1279,20 +1328,21 @@ public class KDC {
EncASRepPart
enc_part
=
new
EncASRepPart
(
key
,
new
LastReq
(
new
LastReqEntry
[]{
new
LastReqEntry
(
0
,
new
KerberosTime
(
new
Date
().
getTime
()
-
1000
0
))
new
LastReqEntry
(
0
,
timeAfter
(-
1
0
))
}),
body
.
getNonce
(),
// TODO: detect replay?
new
KerberosTime
(
new
Date
().
getTime
()
+
1000
*
3600
*
24
),
timeAfter
(
3600
*
24
),
// Next 5 and last MUST be same with ticket
tFlags
,
new
KerberosTime
(
new
Date
()
),
body
.
from
,
timeAfter
(
0
),
from
,
till
,
rtime
,
service
,
body
.
addresses
,
enc_outPAs
.
toArray
(
new
PAData
[
enc_outPAs
.
size
()])
);
EncryptedData
edata
=
new
EncryptedData
(
ckey
,
enc_part
.
asn1Encode
(),
KeyUsage
.
KU_ENC_AS_REP_PART
);
EncryptedData
edata
=
new
EncryptedData
(
ckey
,
enc_part
.
asn1Encode
(),
KeyUsage
.
KU_ENC_AS_REP_PART
);
ASRep
asRep
=
new
ASRep
(
outPAs
.
toArray
(
new
PAData
[
outPAs
.
size
()]),
body
.
cname
,
...
...
@@ -1349,7 +1399,7 @@ public class KDC {
eData
=
temp
.
toByteArray
();
}
kerr
=
new
KRBError
(
null
,
null
,
null
,
new
KerberosTime
(
new
Date
()
),
timeAfter
(
0
),
0
,
ke
.
returnCode
(),
body
.
cname
,
...
...
@@ -1427,6 +1477,35 @@ public class KDC {
throw
new
KrbException
(
"Illegal duration format "
+
s
);
}
private
int
[]
filterSupported
(
int
[]
input
)
{
int
count
=
0
;
for
(
int
i
=
0
;
i
<
input
.
length
;
i
++)
{
if
(!
EType
.
isSupported
(
input
[
i
]))
{
continue
;
}
if
(
SUPPORTED_ETYPES
!=
null
)
{
boolean
supported
=
false
;
for
(
String
se
:
SUPPORTED_ETYPES
.
split
(
","
))
{
if
(
Config
.
getType
(
se
)
==
input
[
i
])
{
supported
=
true
;
break
;
}
}
if
(!
supported
)
{
continue
;
}
}
if
(
count
!=
i
)
{
input
[
count
]
=
input
[
i
];
}
count
++;
}
if
(
count
!=
input
.
length
)
{
input
=
Arrays
.
copyOf
(
input
,
count
);
}
return
input
;
}
/**
* Generates a line for a KDC to put inside [realms] of krb5.conf
* @return REALM.NAME = { kdc = host:port etc }
...
...
@@ -1451,6 +1530,20 @@ public class KDC {
* @throws java.io.IOException for any communication error
*/
protected
void
startServer
(
int
port
,
boolean
asDaemon
)
throws
IOException
{
if
(
nativeKdc
!=
null
)
{
startNativeServer
(
port
,
asDaemon
);
}
else
{
startJavaServer
(
port
,
asDaemon
);
}
}
private
void
startNativeServer
(
int
port
,
boolean
asDaemon
)
throws
IOException
{
nativeKdc
.
prepare
();
nativeKdc
.
init
();
kdcProc
=
nativeKdc
.
kdc
();
}
private
void
startJavaServer
(
int
port
,
boolean
asDaemon
)
throws
IOException
{
if
(
port
>
0
)
{
u1
=
new
DatagramSocket
(
port
,
InetAddress
.
getByName
(
"127.0.0.1"
));
t1
=
new
ServerSocket
(
port
);
...
...
@@ -1543,19 +1636,37 @@ public class KDC {
}
}
public
void
kinit
(
String
user
,
String
ccache
)
throws
Exception
{
if
(
user
.
indexOf
(
'@'
)
<
0
)
{
user
=
user
+
"@"
+
realm
;
}
if
(
nativeKdc
!=
null
)
{
nativeKdc
.
kinit
(
user
,
ccache
);
}
else
{
Context
.
fromUserPass
(
user
,
passwords
.
get
(
user
),
false
)
.
ccache
(
ccache
);
}
}
boolean
isReady
()
{
return
udpConsumerReady
&&
tcpConsumerReady
&&
dispatcherReady
;
}
public
void
terminate
()
{
try
{
thread1
.
stop
();
thread2
.
stop
();
thread3
.
stop
();
u1
.
close
();
t1
.
close
();
}
catch
(
Exception
e
)
{
// OK
if
(
nativeKdc
!=
null
)
{
System
.
out
.
println
(
"Killing kdc..."
);
kdcProc
.
destroyForcibly
();
System
.
out
.
println
(
"Done"
);
}
else
{
try
{
thread1
.
stop
();
thread2
.
stop
();
thread3
.
stop
();
u1
.
close
();
t1
.
close
();
}
catch
(
Exception
e
)
{
// OK
}
}
}
...
...
@@ -1710,6 +1821,269 @@ public class KDC {
}
}
/**
* A native KDC using the binaries in nativePath. Attention:
* this is using binaries, not an existing KDC instance.
* An implementation of this takes care of configuration,
* principal db managing and KDC startup.
*/
static
abstract
class
NativeKdc
{
protected
Map
<
String
,
String
>
env
;
protected
String
nativePath
;
protected
String
base
;
protected
String
realm
;
protected
int
port
;
NativeKdc
(
String
nativePath
,
KDC
kdc
)
{
if
(
kdc
.
port
==
0
)
{
kdc
.
port
=
8000
+
new
java
.
util
.
Random
().
nextInt
(
10000
);
}
this
.
nativePath
=
nativePath
;
this
.
realm
=
kdc
.
realm
;
this
.
port
=
kdc
.
port
;
this
.
base
=
Paths
.
get
(
""
+
port
).
toAbsolutePath
().
toString
();
}
// Add a new principal
abstract
void
addPrincipal
(
String
user
,
String
pass
);
// Add a keytab entry
abstract
void
ktadd
(
String
user
,
String
ktab
);
// Initialize KDC
abstract
void
init
();
// Start kdc
abstract
Process
kdc
();
// Configuration
abstract
void
prepare
();
// Fill ccache
abstract
void
kinit
(
String
user
,
String
ccache
);
static
NativeKdc
get
(
KDC
kdc
)
{
String
prop
=
System
.
getProperty
(
"native.kdc.path"
);
if
(
prop
==
null
)
{
return
null
;
}
else
if
(
Files
.
exists
(
Paths
.
get
(
prop
,
"sbin/krb5kdc"
)))
{
return
new
MIT
(
true
,
prop
,
kdc
);
}
else
if
(
Files
.
exists
(
Paths
.
get
(
prop
,
"kdc/krb5kdc"
)))
{
return
new
MIT
(
false
,
prop
,
kdc
);
}
else
if
(
Files
.
exists
(
Paths
.
get
(
prop
,
"libexec/kdc"
)))
{
return
new
Heimdal
(
prop
,
kdc
);
}
else
{
throw
new
IllegalArgumentException
(
"Strange "
+
prop
);
}
}
Process
run
(
boolean
wait
,
String
...
cmd
)
{
try
{
System
.
out
.
println
(
"Running "
+
cmd2str
(
env
,
cmd
));
ProcessBuilder
pb
=
new
ProcessBuilder
();
pb
.
inheritIO
();
pb
.
environment
().
putAll
(
env
);
Process
p
=
pb
.
command
(
cmd
).
start
();
if
(
wait
)
{
if
(
p
.
waitFor
()
<
0
)
{
throw
new
RuntimeException
(
"exit code is not null"
);
}
return
null
;
}
else
{
return
p
;
}
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
e
);
}
}
private
String
cmd2str
(
Map
<
String
,
String
>
env
,
String
...
cmd
)
{
return
env
.
entrySet
().
stream
().
map
(
e
->
e
.
getKey
()+
"="
+
e
.
getValue
())
.
collect
(
Collectors
.
joining
(
" "
))
+
" "
+
Stream
.
of
(
cmd
).
collect
(
Collectors
.
joining
(
" "
));
}
}
// Heimdal KDC. Build your own and run "make install" to nativePath.
static
class
Heimdal
extends
NativeKdc
{
Heimdal
(
String
nativePath
,
KDC
kdc
)
{
super
(
nativePath
,
kdc
);
Map
<
String
,
String
>
environment
=
new
HashMap
<>();
environment
.
put
(
"KRB5_CONFIG"
,
base
+
"/krb5.conf"
);
environment
.
put
(
"KRB5_TRACE"
,
"/dev/stderr"
);
environment
.
put
(
"DYLD_LIBRARY_PATH"
,
nativePath
+
"/lib"
);
environment
.
put
(
"LD_LIBRARY_PATH"
,
nativePath
+
"/lib"
);
this
.
env
=
Collections
.
unmodifiableMap
(
environment
);
}
@Override
public
void
addPrincipal
(
String
user
,
String
pass
)
{
run
(
true
,
nativePath
+
"/bin/kadmin"
,
"-l"
,
"-r"
,
realm
,
"add"
,
"-p"
,
pass
,
"--use-defaults"
,
user
);
}
@Override
public
void
ktadd
(
String
user
,
String
ktab
)
{
run
(
true
,
nativePath
+
"/bin/kadmin"
,
"-l"
,
"-r"
,
realm
,
"ext_keytab"
,
"-k"
,
ktab
,
user
);
}
@Override
public
void
init
()
{
run
(
true
,
nativePath
+
"/bin/kadmin"
,
"-l"
,
"-r"
,
realm
,
"init"
,
"--realm-max-ticket-life=1day"
,
"--realm-max-renewable-life=1month"
,
realm
);
}
@Override
public
Process
kdc
()
{
return
run
(
false
,
nativePath
+
"/libexec/kdc"
,
"--addresses=127.0.0.1"
,
"-P"
,
""
+
port
);
}
@Override
public
void
prepare
()
{
try
{
Files
.
createDirectory
(
Paths
.
get
(
base
));
Files
.
write
(
Paths
.
get
(
base
+
"/krb5.conf"
),
Arrays
.
asList
(
"[libdefaults]"
,
"default_realm = "
+
realm
,
"default_keytab_name = FILE:"
+
base
+
"/krb5.keytab"
,
"forwardable = true"
,
"dns_lookup_kdc = no"
,
"dns_lookup_realm = no"
,
"dns_canonicalize_hostname = false"
,
"\n[realms]"
,
realm
+
" = {"
,
" kdc = localhost:"
+
port
,
"}"
,
"\n[kdc]"
,
"db-dir = "
+
base
,
"database = {"
,
" label = {"
,
" dbname = "
+
base
+
"/current-db"
,
" realm = "
+
realm
,
" mkey_file = "
+
base
+
"/mkey.file"
,
" acl_file = "
+
base
+
"/heimdal.acl"
,
" log_file = "
+
base
+
"/current.log"
,
" }"
,
"}"
,
SUPPORTED_ETYPES
==
null
?
""
:
(
"\n[kadmin]\ndefault_keys = "
+
(
SUPPORTED_ETYPES
+
","
)
.
replaceAll
(
","
,
":pw-salt "
)),
"\n[logging]"
,
"kdc = 0-/FILE:"
+
base
+
"/messages.log"
,
"krb5 = 0-/FILE:"
+
base
+
"/messages.log"
,
"default = 0-/FILE:"
+
base
+
"/messages.log"
));
}
catch
(
IOException
e
)
{
throw
new
UncheckedIOException
(
e
);
}
}
@Override
void
kinit
(
String
user
,
String
ccache
)
{
String
tmpName
=
base
+
"/"
+
user
+
"."
+
System
.
identityHashCode
(
this
)
+
".keytab"
;
ktadd
(
user
,
tmpName
);
run
(
true
,
nativePath
+
"/bin/kinit"
,
"-f"
,
"-t"
,
tmpName
,
"-c"
,
ccache
,
user
);
}
}
// MIT krb5 KDC. Make your own exploded (install == false), or
// "make install" into nativePath (install == true).
static
class
MIT
extends
NativeKdc
{
private
boolean
install
;
// "make install" or "make"
MIT
(
boolean
install
,
String
nativePath
,
KDC
kdc
)
{
super
(
nativePath
,
kdc
);
this
.
install
=
install
;
Map
<
String
,
String
>
environment
=
new
HashMap
<>();
environment
.
put
(
"KRB5_KDC_PROFILE"
,
base
+
"/kdc.conf"
);
environment
.
put
(
"KRB5_CONFIG"
,
base
+
"/krb5.conf"
);
environment
.
put
(
"KRB5_TRACE"
,
"/dev/stderr"
);
environment
.
put
(
"DYLD_LIBRARY_PATH"
,
nativePath
+
"/lib"
);
environment
.
put
(
"LD_LIBRARY_PATH"
,
nativePath
+
"/lib"
);
this
.
env
=
Collections
.
unmodifiableMap
(
environment
);
}
@Override
public
void
addPrincipal
(
String
user
,
String
pass
)
{
run
(
true
,
nativePath
+
(
install
?
"/sbin/"
:
"/kadmin/cli/"
)
+
"kadmin.local"
,
"-q"
,
"addprinc -pw "
+
pass
+
" "
+
user
);
}
@Override
public
void
ktadd
(
String
user
,
String
ktab
)
{
run
(
true
,
nativePath
+
(
install
?
"/sbin/"
:
"/kadmin/cli/"
)
+
"kadmin.local"
,
"-q"
,
"ktadd -k "
+
ktab
+
" -norandkey "
+
user
);
}
@Override
public
void
init
()
{
run
(
true
,
nativePath
+
(
install
?
"/sbin/"
:
"/kadmin/dbutil/"
)
+
"kdb5_util"
,
"create"
,
"-s"
,
"-W"
,
"-P"
,
"olala"
);
}
@Override
public
Process
kdc
()
{
return
run
(
false
,
nativePath
+
(
install
?
"/sbin/"
:
"/kdc/"
)
+
"krb5kdc"
,
"-n"
);
}
@Override
public
void
prepare
()
{
try
{
Files
.
createDirectory
(
Paths
.
get
(
base
));
Files
.
write
(
Paths
.
get
(
base
+
"/kdc.conf"
),
Arrays
.
asList
(
"[kdcdefaults]"
,
"\n[realms]"
,
realm
+
"= {"
,
" kdc_listen = "
+
this
.
port
,
" kdc_tcp_listen = "
+
this
.
port
,
" database_name = "
+
base
+
"/principal"
,
" key_stash_file = "
+
base
+
"/.k5.ATHENA.MIT.EDU"
,
SUPPORTED_ETYPES
==
null
?
""
:
(
" supported_enctypes = "
+
(
SUPPORTED_ETYPES
+
","
)
.
replaceAll
(
","
,
":normal "
)),
"}"
));
Files
.
write
(
Paths
.
get
(
base
+
"/krb5.conf"
),
Arrays
.
asList
(
"[libdefaults]"
,
"default_realm = "
+
realm
,
"default_keytab_name = FILE:"
+
base
+
"/krb5.keytab"
,
"forwardable = true"
,
"dns_lookup_kdc = no"
,
"dns_lookup_realm = no"
,
"dns_canonicalize_hostname = false"
,
"\n[realms]"
,
realm
+
" = {"
,
" kdc = localhost:"
+
port
,
"}"
,
"\n[logging]"
,
"kdc = FILE:"
+
base
+
"/krb5kdc.log"
));
}
catch
(
IOException
e
)
{
throw
new
UncheckedIOException
(
e
);
}
}
@Override
void
kinit
(
String
user
,
String
ccache
)
{
String
tmpName
=
base
+
"/"
+
user
+
"."
+
System
.
identityHashCode
(
this
)
+
".keytab"
;
ktadd
(
user
,
tmpName
);
run
(
true
,
nativePath
+
(
install
?
"/bin/"
:
"/clients/kinit/"
)
+
"kinit"
,
"-f"
,
"-t"
,
tmpName
,
"-c"
,
ccache
,
user
);
}
}
// Calling private methods thru reflections
private
static
final
Field
getPADataField
;
private
static
final
Field
getEType
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录