Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
1f73cdd5
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看板
提交
1f73cdd5
编写于
11月 12, 2008
作者:
W
weijun
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
6765491: Krb5LoginModule a little too restrictive, and the doc is not clear.
Reviewed-by: valeriep
上级
fa1cfe5f
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
290 addition
and
52 deletion
+290
-52
src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
...classes/com/sun/security/auth/module/Krb5LoginModule.java
+69
-47
test/sun/security/krb5/auto/Context.java
test/sun/security/krb5/auto/Context.java
+13
-4
test/sun/security/krb5/auto/KDC.java
test/sun/security/krb5/auto/KDC.java
+24
-1
test/sun/security/krb5/auto/LoginModuleOptions.java
test/sun/security/krb5/auto/LoginModuleOptions.java
+184
-0
未找到文件。
src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
浏览文件 @
1f73cdd5
...
...
@@ -86,6 +86,8 @@ import sun.misc.HexDumpEncoder;
* the principal name from the configuration is used. In the
* case where the principal property is not set and the principal
* entry also does not exist, the user is prompted for the name.
* When this property of entry is set, and <code>useTicketCache</code>
* is set to true, only TGT belonging to this principal is used.
*
* <p> The following is a list of configuration options supported
* for <code>Krb5LoginModule</code>:
...
...
@@ -101,18 +103,19 @@ import sun.misc.HexDumpEncoder;
* to false if you do not want this module to use the ticket cache.
* (Default is False).
* This module will
* search for the ticke
c
t
* search for the ticket
* cache in the following locations:
* For Windows 2000, it will use Local Security Authority (LSA) API
* to get the TGT. On Solaris and Linux
* On Solaris and Linux
* it will look for the ticket cache in /tmp/krb5cc_<code>uid</code>
* where the uid is numeric user
* identifier. If the ticket cache is
* not available in
either of the above locations
, or if we are on a
*
different Windows platform,
it will look for the cache as
* not available in
the above location
, or if we are on a
*
Windows platform,
it will look for the cache as
* {user.home}{file.separator}krb5cc_{user.name}.
* You can override the ticket cache location by using
* <code>ticketCache</code>
* <code>ticketCache</code>.
* For Windows, if a ticket cannot be retrieved from the file ticket cache,
* it will use Local Security Authority (LSA) API to get the TGT.
* <P>
* <dt><b><code>ticketCache</code></b>:</dt>
* <dd>Set this to the name of the ticket
...
...
@@ -129,20 +132,20 @@ import sun.misc.HexDumpEncoder;
* <dt><b><code>doNotPrompt</code></b>:</dt>
* <dd>Set this to true if you do not want to be
* prompted for the password
* if credentials can
*
not be obtained from the cache or keytab
.(Default is false)
* If set to true
authentication will fail if credentials can
*
not be obtained from the cache or keytab
.</dd>
* if credentials can
not be obtained from the cache, the keytab,
*
or through shared state
.(Default is false)
* If set to true
, credential must be obtained through cache, keytab,
*
or shared state. Otherwise, authentication will fail
.</dd>
* <P>
* <dt><b><code>useKeyTab</code></b>:</dt>
* <dd>Set this to true if you
* want the module to get the principal's key from the
* the keytab.(default value is False)
* If <code>key
at
b</code>
* If <code>key
ta
b</code>
* is not set then
* the module will locate the keytab from the
* Kerberos configuration file.
</dd>
* If it is not specifed in the Kerberos configuration file
* Kerberos configuration file.
* If it is not specif
i
ed in the Kerberos configuration file
* then it will look for the file
* <code>{user.home}{file.separator}</code>krb5.keytab.</dd>
* <P>
...
...
@@ -210,20 +213,34 @@ import sun.misc.HexDumpEncoder;
* exist for the username and password in the shared
* state, or if authentication fails.
*
* clearPass
if, true, this <code>LoginModule</code>
clears the
* username and password stored in the module's shared
* state after both phases of authentication
*
(login and commit)
have completed.
* clearPass
if, true, this LoginModule
clears the
*
username and password stored in the module's shared
*
state after both phases of authentication
*
(login and commit)
have completed.
* </pre>
* <p>If the principal system property or key is already provided, the value of
* "javax.security.auth.login.name" in the shared state is ignored.
* <p>When multiple mechanisms to retrieve a ticket or key is provided, the
* preference order looks like this:
* <ol>
* <li>ticket cache
* <li>keytab
* <li>shared state
* <li>user prompt
* </ol>
* <p>Note that if any step fails, it will fallback to the next step.
* There's only one exception, it the shared state step fails and
* <code>useFirstPass</code>=true, no user prompt is made.
* <p>Examples of some configuration values for Krb5LoginModule in
* JAAS config file and the results are:
* <ul>
* <p> <code>doNotPrompt</code>=true;
* </ul>
* <p> This is an illegal combination since <code>useTicketCache</code>
* is not set and the user can not be prompted for the password.
* <p> This is an illegal combination since none of <code>useTicketCache</code>,
* <code>useKeyTab</code>, <code>useFirstPass</code> and <code>tryFirstPass</code>
* is set and the user can not be prompted for the password.
*<ul>
* <p> <code>ticketCache</code> =
< filename >
;
* <p> <code>ticketCache</code> =
<filename>
;
*</ul>
* <p> This is an illegal combination since <code>useTicketCache</code>
* is not set to true and the ticketCache is set. A configuration error
...
...
@@ -240,9 +257,9 @@ import sun.misc.HexDumpEncoder;
*</ul>
* <p> This is an illegal combination since <code>storeKey</code> is set to
* true but the key can not be obtained either by prompting the user or from
* the keytab
.
A configuration error will occur.
* the keytab
, or from the shared state.
A configuration error will occur.
* <ul>
* <p> <code>keyTab</code> =
< filename >
<code>doNotPrompt</code>=true ;
* <p> <code>keyTab</code> =
<filename>
<code>doNotPrompt</code>=true ;
* </ul>
* <p>This is an illegal combination since useKeyTab is not set to true and
* the keyTab is set. A configuration error will occur.
...
...
@@ -260,7 +277,7 @@ import sun.misc.HexDumpEncoder;
* with the principal and TGT. If the TGT is not available,
* do not prompt the user, instead fail the authentication.
* <ul>
* <p><code>principal</code>=
< name >
<code>useTicketCache</code> = true
* <p><code>principal</code>=
<name>
<code>useTicketCache</code> = true
* <code>doNotPrompt</code>=true;
*</ul>
* <p> Get the TGT from the default cache for the principal and populate the
...
...
@@ -269,9 +286,9 @@ import sun.misc.HexDumpEncoder;
* authentication will fail.
* <ul>
* <p> <code>useTicketCache</code> = true
* <code>ticketCache</code>=
< file name >
<code>useKeyTab</code> = true
* <code> keyTab</code>=
< keytab filename >
* <code>principal</code> =
< principal name >
* <code>ticketCache</code>=
<file name>
<code>useKeyTab</code> = true
* <code> keyTab</code>=
<keytab filename>
* <code>principal</code> =
<principal name>
* <code>doNotPrompt</code>=true;
*</ul>
* <p> Search the cache for the principal's TGT. If it is not available
...
...
@@ -281,7 +298,7 @@ import sun.misc.HexDumpEncoder;
* If the key is not available or valid then authentication will fail.
* <ul>
* <p><code>useTicketCache</code> = true
* <code>ticketCache</code>=
< file name >
* <code>ticketCache</code>=
<file name>
*</ul>
* <p> The TGT will be obtained from the cache specified.
* The Kerberos principal name used will be the principal name in
...
...
@@ -292,8 +309,8 @@ import sun.misc.HexDumpEncoder;
* The Subject will be populated with the TGT.
*<ul>
* <p> <code>useKeyTab</code> = true
* <code>keyTab</code>=
< keytab filename >
* <code>principal</code>=
< principal name >
* <code>keyTab</code>=
<keytab filename>
* <code>principal</code>=
<principal name>
* <code>storeKey</code>=true;
*</ul>
* <p> The key for the principal will be retrieved from the keytab.
...
...
@@ -303,7 +320,7 @@ import sun.misc.HexDumpEncoder;
* password entered.
* <ul>
* <p> <code>useKeyTab</code> = true
* <code>keyTab</code>=
< keytabname >
* <code>keyTab</code>=
<keytabname>
* <code>storeKey</code>=true
* <code>doNotPrompt</code>=true;
*</ul>
...
...
@@ -316,21 +333,23 @@ import sun.misc.HexDumpEncoder;
* Subject's private credentials set. Otherwise the authentication will
* fail.
*<ul>
* <p><code>useKeyTab</code> = true
* <code>keyTab</code>=< file name > <code>storeKey</code>=true
* <code>principal</code>= < principal name >
* <p>
* <code>useTicketCache</code>=true
* <code>ticketCache</code>=< file name >;
* <code>ticketCache</code>=<file name>;
* <code>useKeyTab</code> = true
* <code>keyTab</code>=<file name> <code>storeKey</code>=true
* <code>principal</code>= <principal name>
*</ul>
* <p>The principal's key will be retrieved from the keytab and added
* to the <code>Subject</code>'s private credentials. If the key
* is not available, the
* user will be prompted for the password; the key derived from the password
* will be added to the Subject's private credentials set. The
* client's TGT will be retrieved from the ticket cache and added to the
* <p>
* The client's TGT will be retrieved from the ticket cache and added to the
* <code>Subject</code>'s private credentials. If the TGT is not available
* in the ticket cache, it will be obtained using the authentication
* in the ticket cache, or the TGT's client name does not match the principal
* name, Java will use a secret key to obtain the TGT using the authentication
* exchange and added to the Subject's private credentials.
* This secret key will be first retrieved from the keytab. If the key
* is not available, the user will be prompted for the password. In either
* case, the key derived from the password will be added to the
* Subject's private credentials set.
* <ul>
* <p><code>isInitiator</code> = false
*</ul>
...
...
@@ -856,11 +875,13 @@ public class Krb5LoginModule implements LoginModule {
}
private
void
validateConfiguration
()
throws
LoginException
{
if
(
doNotPrompt
&&
!
useTicketCache
&&
!
useKeyTab
)
if
(
doNotPrompt
&&
!
useTicketCache
&&
!
useKeyTab
&&
!
tryFirstPass
&&
!
useFirstPass
)
throw
new
LoginException
(
"Configuration Error"
+
" - either doNotPrompt should be "
+
" false or useTicketCache/useKeyTab "
+
" false or at least one of useTicketCache, "
+
" useKeyTab, tryFirstPass and useFirstPass"
+
" should be true"
);
if
(
ticketCacheName
!=
null
&&
!
useTicketCache
)
throw
new
LoginException
...
...
@@ -872,11 +893,12 @@ public class Krb5LoginModule implements LoginModule {
throw
new
LoginException
(
"Configuration Error - useKeyTab should be set to true "
+
"to use the keytab"
+
keyTabName
);
if
(
storeKey
&&
doNotPrompt
&&
!
useKeyTab
)
if
(
storeKey
&&
doNotPrompt
&&
!
useKeyTab
&&
!
tryFirstPass
&&
!
useFirstPass
)
throw
new
LoginException
(
"Configuration Error - either doNotPrompt "
+
"
should be set to false or
"
+
"useKeyTab must be set to true for storeKey option"
);
(
"Configuration Error - either doNotPrompt
should be set to
"
+
"
false or at least one of tryFirstPass, useFirstPass
"
+
"
or
useKeyTab must be set to true for storeKey option"
);
if
(
renewTGT
&&
!
useTicketCache
)
throw
new
LoginException
(
"Configuration Error"
...
...
test/sun/security/krb5/auto/Context.java
浏览文件 @
1f73cdd5
...
...
@@ -109,13 +109,22 @@ public class Context {
out
.
s
=
new
Subject
();
Krb5LoginModule
krb5
=
new
Krb5LoginModule
();
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
map
.
put
(
"tryFirstPass"
,
"true"
);
Map
<
String
,
Object
>
shared
=
new
HashMap
<
String
,
Object
>();
if
(
pass
!=
null
)
{
map
.
put
(
"useFirstPass"
,
"true"
);
shared
.
put
(
"javax.security.auth.login.name"
,
user
);
shared
.
put
(
"javax.security.auth.login.password"
,
pass
);
}
else
{
map
.
put
(
"doNotPrompt"
,
"true"
);
map
.
put
(
"useTicketCache"
,
"true"
);
if
(
user
!=
null
)
{
map
.
put
(
"principal"
,
user
);
}
}
if
(
storeKey
)
{
map
.
put
(
"storeKey"
,
"true"
);
}
Map
<
String
,
Object
>
shared
=
new
HashMap
<
String
,
Object
>();
shared
.
put
(
"javax.security.auth.login.name"
,
user
);
shared
.
put
(
"javax.security.auth.login.password"
,
pass
);
krb5
.
initialize
(
out
.
s
,
null
,
shared
,
map
);
krb5
.
login
();
...
...
test/sun/security/krb5/auto/KDC.java
浏览文件 @
1f73cdd5
...
...
@@ -32,6 +32,7 @@ import java.util.*;
import
java.util.concurrent.*
;
import
sun.security.krb5.*
;
import
sun.security.krb5.internal.*
;
import
sun.security.krb5.internal.ccache.CredentialsCache
;
import
sun.security.krb5.internal.crypto.KeyUsage
;
import
sun.security.krb5.internal.ktab.KeyTab
;
import
sun.security.util.DerInputStream
;
...
...
@@ -765,7 +766,29 @@ public class KDC {
DerOutputStream
out
=
new
DerOutputStream
();
out
.
write
(
DerValue
.
createTag
(
DerValue
.
TAG_APPLICATION
,
true
,
(
byte
)
Krb5
.
KRB_AS_REP
),
asRep
.
asn1Encode
());
return
out
.
toByteArray
();
byte
[]
result
=
out
.
toByteArray
();
// Added feature:
// Write the current issuing TGT into a ccache file specified
// by the system property below.
String
ccache
=
System
.
getProperty
(
"test.kdc.save.ccache"
);
if
(
ccache
!=
null
)
{
asRep
.
encKDCRepPart
=
enc_part
;
sun
.
security
.
krb5
.
internal
.
ccache
.
Credentials
credentials
=
new
sun
.
security
.
krb5
.
internal
.
ccache
.
Credentials
(
asRep
);
asReq
.
reqBody
.
cname
.
setRealm
(
getRealm
());
CredentialsCache
cache
=
CredentialsCache
.
create
(
asReq
.
reqBody
.
cname
,
ccache
);
if
(
cache
==
null
)
{
throw
new
IOException
(
"Unable to create the cache file "
+
ccache
);
}
cache
.
update
(
credentials
);
cache
.
save
();
new
File
(
ccache
).
deleteOnExit
();
}
return
result
;
}
catch
(
KrbException
ke
)
{
ke
.
printStackTrace
(
System
.
out
);
KRBError
kerr
=
ke
.
getError
();
...
...
test/sun/security/krb5/auto/LoginModuleOptions.java
0 → 100644
浏览文件 @
1f73cdd5
/*
* Copyright 2008 Sun Microsystems, Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6765491
* @summary Krb5LoginModule a little too restrictive, and the doc is not clear.
*/
import
com.sun.security.auth.module.Krb5LoginModule
;
import
java.io.IOException
;
import
java.util.HashMap
;
import
java.util.Map
;
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
;
public
class
LoginModuleOptions
{
private
static
final
String
NAME
=
"javax.security.auth.login.name"
;
private
static
final
String
PWD
=
"javax.security.auth.login.password"
;
public
static
void
main
(
String
[]
args
)
throws
Exception
{
OneKDC
kdc
=
new
OneKDC
(
null
);
kdc
.
addPrincipal
(
"foo"
,
"bar"
.
toCharArray
());
kdc
.
writeKtab
(
OneKDC
.
KTAB
);
// rewrite to add foo
// All 4 works: keytab, shared state, callback, cache
login
(
null
,
"useKeyTab"
,
"true"
,
"principal"
,
"dummy"
);
login
(
null
,
"tryFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
OneKDC
.
PASS
);
System
.
setProperty
(
"test.kdc.save.ccache"
,
"krbcc"
);
login
(
new
MyCallback
(
OneKDC
.
USER
,
OneKDC
.
PASS
));
// save the cache
System
.
clearProperty
(
"test.kdc.save.ccache"
);
login
(
null
,
"useTicketCache"
,
"true"
,
"ticketCache"
,
"krbcc"
);
// Fallbacks
// 1. ccache -> keytab
login
(
null
,
"useTicketCache"
,
"true"
,
"ticketCache"
,
"krbcc_non_exists"
,
"useKeyTab"
,
"true"
,
"principal"
,
"dummy"
);
// 2. keytab -> shared
login
(
null
,
"useKeyTab"
,
"true"
,
"principal"
,
"dummy"
,
"keyTab"
,
"ktab_non_exist"
,
"tryFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
OneKDC
.
PASS
);
// 3. shared -> callback
// 3.1. useFirstPass, no callback
boolean
failed
=
false
;
try
{
login
(
new
MyCallback
(
OneKDC
.
USER
,
OneKDC
.
PASS
),
"useFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
"haha"
.
toCharArray
());
}
catch
(
Exception
e
)
{
failed
=
true
;
}
if
(!
failed
)
{
throw
new
Exception
(
"useFirstPass should not fallback to callback"
);
}
// 3.2. tryFirstPass, has callback
login
(
new
MyCallback
(
OneKDC
.
USER
,
OneKDC
.
PASS
),
"tryFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
"haha"
.
toCharArray
());
// Preferences of type
// 1. ccache preferred to keytab
login
(
new
MyCallback
(
"foo"
,
null
),
"useTicketCache"
,
"true"
,
"ticketCache"
,
"krbcc"
,
"useKeyTab"
,
"true"
);
// 2. keytab preferred to shared. This test case is not exactly correct,
// because principal=dummy would shadow the PWD setting in the shared
// state. So by only looking at the final authentication user name
// (which is how this program does), there's no way to tell if keyTab
// is picked first, or shared is tried first but fallback to keytab.
login
(
null
,
"useKeyTab"
,
"true"
,
"principal"
,
"dummy"
,
"tryFirstPass"
,
"true"
,
NAME
,
"foo"
,
PWD
,
"bar"
.
toCharArray
());
// 3. shared preferred to callback
login
(
new
MyCallback
(
"foo"
,
"bar"
.
toCharArray
()),
"tryFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
OneKDC
.
PASS
);
// Preferences of username
// 1. principal preferred to NAME (NAME can be wrong or missing)
login
(
null
,
"principal"
,
OneKDC
.
USER
,
"tryFirstPass"
,
"true"
,
NAME
,
"someone_else"
,
PWD
,
OneKDC
.
PASS
);
login
(
null
,
"principal"
,
OneKDC
.
USER
,
"tryFirstPass"
,
"true"
,
PWD
,
OneKDC
.
PASS
);
// 2. NAME preferred to callback
login
(
new
MyCallback
(
"someone_else"
,
OneKDC
.
PASS
),
"principal"
,
OneKDC
.
USER
);
// 3. With tryFirstPass, NAME preferred to callback
login
(
new
MyCallback
(
"someone_else"
,
null
),
"tryFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
OneKDC
.
PASS
);
// 3.1. you must provide a NAME (when there's no principal)
failed
=
false
;
try
{
login
(
new
MyCallback
(
OneKDC
.
USER
,
null
),
"tryFirstPass"
,
"true"
,
PWD
,
OneKDC
.
PASS
);
}
catch
(
Exception
e
)
{
failed
=
true
;
}
if
(!
failed
)
{
throw
new
Exception
(
"useFirstPass must provide a NAME"
);
}
// 3.2 Hybrid, you can use NAME as "", and provide it using callback.
// I don't think this is designed.
login
(
new
MyCallback
(
OneKDC
.
USER
,
null
),
"tryFirstPass"
,
"true"
,
NAME
,
""
,
PWD
,
OneKDC
.
PASS
);
// Test for the bug fix: doNotPrompt can be true if tryFirstPass=true
login
(
null
,
"doNotPrompt"
,
"true"
,
"storeKey"
,
"true"
,
"tryFirstPass"
,
"true"
,
NAME
,
OneKDC
.
USER
,
PWD
,
OneKDC
.
PASS
);
}
static
void
login
(
CallbackHandler
callback
,
Object
...
options
)
throws
Exception
{
Krb5LoginModule
krb5
=
new
Krb5LoginModule
();
Subject
subject
=
new
Subject
();
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
Map
<
String
,
Object
>
shared
=
new
HashMap
<
String
,
Object
>();
int
count
=
options
.
length
/
2
;
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
String
key
=
(
String
)
options
[
2
*
i
];
Object
value
=
options
[
2
*
i
+
1
];
if
(
key
.
startsWith
(
"javax"
))
{
shared
.
put
(
key
,
value
);
}
else
{
map
.
put
(
key
,
(
String
)
value
);
}
}
krb5
.
initialize
(
subject
,
callback
,
shared
,
map
);
krb5
.
login
();
krb5
.
commit
();
if
(!
subject
.
getPrincipals
().
iterator
().
next
()
.
getName
().
startsWith
(
OneKDC
.
USER
))
{
throw
new
Exception
(
"The authenticated is not "
+
OneKDC
.
USER
);
}
}
static
class
MyCallback
implements
CallbackHandler
{
private
String
name
;
private
char
[]
password
;
public
MyCallback
(
String
name
,
char
[]
password
)
{
this
.
name
=
name
;
this
.
password
=
password
;
}
public
void
handle
(
Callback
[]
callbacks
)
{
for
(
Callback
callback
:
callbacks
)
{
System
.
err
.
println
(
callback
);
if
(
callback
instanceof
NameCallback
)
{
System
.
err
.
println
(
"name is "
+
name
);
((
NameCallback
)
callback
).
setName
(
name
);
}
if
(
callback
instanceof
PasswordCallback
)
{
System
.
err
.
println
(
"pass is "
+
new
String
(
password
));
((
PasswordCallback
)
callback
).
setPassword
(
password
);
}
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录