使用 Kerberos 连接到 SMB 共享时出现 KrbException“消息流已修改 (41)”
Posted
技术标签:
【中文标题】使用 Kerberos 连接到 SMB 共享时出现 KrbException“消息流已修改 (41)”【英文标题】:KrbException "Message Stream Modified (41)" when connecting to SMB share using Kerberos 【发布时间】:2014-01-26 22:12:33 【问题描述】:我在使用 JCifs 执行文件管理时遇到了一些 Kerberos 身份验证问题(Kerberos 扩展版本 1.3.17)
这是我当前的 krb5.conf 配置:
[libdefaults]
default_realm = <REALM_NAME_UPPERCASE>
udp_preference_limit = 1
[realms]
<REALM_NAME_UPPERCASE> =
kdc = <DOMAIN_NAME_UPPERCASE>:88
admin_server = <DOMAIN_NAME_UPPERCASE>
default_domain = <DOMAIN_NAME_UPPERCASE>
[domain_realm]
.<domain_name> = <REALM_NAME_UPPERCASE>
<domain_name> = <REALM_NAME_UPPERCASE>
[appdefaults]
kinit =
renewable = true
forwardable = true
这是对用户进行身份验证的代码,然后尝试在网络中的文件服务器上查找文件:
public static void main (String[] args) throws Exception
Subject subject = new Subject();
System.setProperty("java.security.krb5.conf", "C:/krb5.conf");
System.setProperty("sun.security.krb5.debug", "true");
Map<String, Object> state = new HashMap<String, Object>();
state.put("javax.security.auth.login.name", "USERNAME");
state.put("javax.security.auth.login.password", "PASSWORD".toCharArray());
Map<String, Object> options = new HashMap<String, Object>();
options.put("debug", "true");
options.put("useFirstPass", "true");
Krb5LoginModule login = new Krb5LoginModule();
login.initialize(subject, null, state, options);
if (login.login())
login.commit();
String path = "file://HOST/242269/"; // existing file server folder
Kerb5Authenticator kerberosAuthenticator = new Kerb5Authenticator(subject);
SmbFile smbFile = new SmbFile(path, kerberosAuthenticator);
SmbFile[] files = smbFile.listFiles();
for (SmbFile file : files)
System.out.println(file);
现在,当我运行此代码时,它说它可以使用这些凭据对用户进行身份验证(当我更改凭据时,身份验证失败)并为该用户创建一个票证。 当我稍后尝试通过 CIFS 检索文件目录的内容时,它给了我以下错误:
GSSException: No valid credentials provided (Mechanism level: Message stream modified (41))
at sun.security.jgss.krb5.Krb5Context.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at jcifs.smb.SpnegoContext.initSecContext(SpnegoContext.java:80)
at jcifs.smb.Kerb5Authenticator.setup(Kerb5Authenticator.java:196)
at jcifs.smb.Kerb5Authenticator.access$000(Kerb5Authenticator.java:30)
at jcifs.smb.Kerb5Authenticator$1.run(Kerb5Authenticator.java:168)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at jcifs.smb.Kerb5Authenticator.sessionSetup(Kerb5Authenticator.java:166)
at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:320)
at jcifs.smb.SmbSession.send(SmbSession.java:239)
at jcifs.smb.SmbTree.treeConnect(SmbTree.java:176)
at jcifs.smb.SmbFile.doConnect(SmbFile.java:925)
at jcifs.smb.SmbFile.connect(SmbFile.java:974)
at jcifs.smb.SmbFile.connect0(SmbFile.java:890)
at jcifs.smb.SmbFile.resolveDfs(SmbFile.java:669)
at jcifs.smb.SmbFile.send(SmbFile.java:783)
at jcifs.smb.SmbFile.doFindFirstNext(SmbFile.java:2009)
at jcifs.smb.SmbFile.doEnum(SmbFile.java:1758)
at jcifs.smb.SmbFile.listFiles(SmbFile.java:1735)
at jcifs.smb.SmbFile.listFiles(SmbFile.java:1668)
你可以找到完整的错误日志here(一些细节被混淆了)
有人可以让我朝着正确的方向前进吗?
【问题讨论】:
另一个(有用的?)评论:这个用户帐户不能访问文件服务器的根目录,只能访问那个特定的子文件夹。我不知道这是否相关。 尝试将 krb5.conf 和 login.conf 文件放入 tomcat 的 lib 文件夹中,然后重试。 【参考方案1】:大写领域对于避免“Exception: krb_error 41 Message stream modified (41)
”非常重要。
见http://sourceforge.net/p/spnego/discussion/1003769/thread/99b3ff67/
【讨论】:
您能否更具体地回答您的问题并说明(最好使用代码)您的建议对提问者有何帮助?请多解释一下。我(作为读者)发现很难理解您的答案如何成为解决方案。在我看来,发布链接更适合作为评论。 问题在于 Kerberos 通过根据密码和参数计算校验和来检查答案的完整性。如果收到的答案是肯定的,但输入参数不匹配,则会给出此“流已修改”错误。最可能的原因是服务器使用实数作为大写流,而客户端使用小写。 在某些环境中,这个一般错误肯定是由这个引起的。不过,我不知道为什么。【参考方案2】:讨厌 necrobump,但在 Docker 容器中启动 Spark 和 Zeppelin 时遇到了同样的问题,而主服务器是启用 Kerberos 的远程 YARN 集群。但是,在这种情况下,大写/小写领域名称不是问题。
几个小时后,我找到了this thread,它建议从krb5.conf
文件中删除以下行:
renew_lifetime = 7d
这就解决了这个问题。希望这对某人有所帮助。
【讨论】:
删除该行后也为我工作。【参考方案3】:删除配置中的renew_lifetime = 7d
行的替代(和更好)答案是允许委托人进行续订。在 CentOS 7 中,示例命令如下:
kadmin -p admin/admin@EXAMPLE.COM
我假设admin/admin@EXAMPLE.COM
是管理员主体,那么:
modprinc -maxrenewlife 90day +allow_renewable your_service@EXAMPLE.COM
我假设导致问题的服务的主体是your_service@EXAMPLE.COM
;而90day
renew life 是任意的。
这解决了问题从krb5.conf
文件中删除renew_lifetime=7d
!
【讨论】:
以上是关于使用 Kerberos 连接到 SMB 共享时出现 KrbException“消息流已修改 (41)”的主要内容,如果未能解决你的问题,请参考以下文章
使用 PyMongo 和 x509 SSL 证书连接到 MongoDB 数据库时出现 ServerSelectionTimeoutError
JCIFS jcifs.smb.SmbException:连接到系统的设备无法正常工作