尝试通过 JDBC 和与 Kerberos 集成的身份验证从运行在 Linux (RHEL) 上的 Tomcat 应用程序到运行 SQL Server 的 Windows 主机建立数据库连接。不断地碰到:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Integrated authentication failed. ClientConnectionId:48e48e7d-9590-4d72-bde7-085fa6df61d8
at
at <Ommitted>
... 8 more
Caused by: GSSException: Defective token detected (Mechanism level: AP_REP token id does not match!)
at sun.security.jgss.krb5.AcceptSecContextToken.<init>(AcceptSecContextToken.java:80)
我的 Windows 和 Evolven Server 都位于同一域 (EVOLVEN.CORP)。我已经配置了两个用户:
环境看起来像这样,我已经使用以下命令使用volvendbuser用户名和我的MSSQL主机配置了服务原则:
setspn -A MSSQLSvc/mssql-g1cftve.evolven.corp:1433 evolvendbuser
确认我已为我的用户和 MSSQL 主机准备好 SPN。
Registered ServicePrincipalNames for CN=evolvendbuser,CN=Users,DC=evolven,DC=corp:
MSSQLSvc/mssql-g1cftve.evolven.corp
MSSQLSvc/mssql-g1cftve.evolven.corp:1433
接下来,我为我的客户端用户 evolvendbclientuser 生成了一个 keytab 文件:
ktpass -princ [email protected] -mapuser EVOLVEN\evolvendbclientuser -crypto ALL -ptype KRB5_NT_PRINCIPAL -pass <password> -out evolvendbclientuser.keytab -SetPass
然后,我获取此密钥文件并将其添加到我的 RHEL 服务器主机,以便与我的 JDBC 和 Jaas 配置一起使用。
Keytab 看起来不错:
[root@evolvenserver opt]# klist -k /etc/evolvendbclientuser.keytab
Keytab name: FILE:/etc/evolvendbclientuser.keytab
KVNO Principal
---- --------------------------------------------------------------------------
5 [email protected]
5 [email protected]
5 [email protected]
5 [email protected]
5 [email protected]
我测试过我可以通过以下方式获得门票:
kinit -kt /etc/evolvendbclientuser.keytab [email protected]
还做了:
[root@evolvenserver opt]# kvno MSSQLSvc/mssql-g1cftve.evolven.corp:1433
MSSQLSvc/mssql-g1cftve.evolven.corp:[email protected]: kvno = 20
我的 JDBC 适配器的 JaaS 配置:
com.sun.security.jgss.krb5.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/etc/evolvendbclientuser.keytab"
storeKey=true
principal="[email protected]"
doNotPrompt=true
debug=true;
};
我的 krb5.conf 文件非常基本:
[libdefaults]
rnds = false
default_realm = EVOLVEN.CORP
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 30d
renew_lifetime = 30d
forwardable = true
udp_preference_limit = 0
default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 rc4-hmac
default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 rc4-hmac
permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 rc4-hmac
[realms]
EVOLVEN.CORP = {
kdc = EC2AMAZ-AEHRC46.evolven.corp
admin_server = EC2AMAZ-AEHRC46.evolven.corp
}
[domain_realm]
.evolven.corp = EVOLVEN.CORP
evolven.corp = EVOLVEN.CORP
当我尝试通过 JDBC 使用集成身份验证连接到 MSSQL 实例时:
java -Djavax.security.auth.useSubjectCredsOnly=false \
-Djava.security.auth.login.config=/opt/tomcat/bin/jaas.conf \
-Djava.security.krb5.conf=/etc/krb5.conf \
-Dsun.security.krb5.debug=true \
-Dsun.security.spnego.debug=true \
-jar ms-sqlserver-jdbc-1.0.jar \
"jdbc:sqlserver://MSSQL-G1CFTVE.evolven.corp:1433;DatabaseName=master;authenticationScheme=JavaKerberos;integratedSecurity=true;trustServerCertificate=true"
我总是得到:
<A bunch of hexdecimal gunk/binary stream>
Entered Krb5Context.initSecContext with state=STATE_IN_PROCESS
15:00:29.503 [main] INFO Main - Time elapsed: 28941
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Integrated authentication failed. ClientConnectionId:a6a73dc6-2b15-46d8-b014-183f8c99c8e2
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:3208)
at com.microsoft.sqlserver.jdbc.KerbAuthentication.intAuthHandShake(KerbAuthentication.java:178)
at com.microsoft.sqlserver.jdbc.KerbAuthentication.generateClientContext(KerbAuthentication.java:209)
Caused by: GSSException: Defective token detected (Mechanism level: AP_REP token id does not match!)
at sun.security.jgss.krb5.AcceptSecContextToken.<init>(AcceptSecContextToken.java:80)
at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:755)
at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
at com.microsoft.sqlserver.jdbc.KerbAuthentication.intAuthHandShake(KerbAuthentication.java:158)
... 26 more
我还能如何调试?完全卡住了。
我希望这可以帮助任何陷入困境的人,但显然我的配置有问题。我从头开始,首先在 Active Directory 中创建两个新用户:
设置 evolvedndbuser 来运行我的 SQL Server 服务。然后,在 SQL Server 数据库中为域 [email protected] 用户创建基于 SQL“Windows 身份验证”的登录。
然后我在Windows AD域主机上为我的evolvedndbuser创建了SPN:
setspn -A MSSQLSvc/mssql-g1cftve.evolven.corp:1433 evolvendbuser
setspn -A MSSQLSvc/mssql-g1cftve.evolven.corp evolvendbuser
确认它们就位:
PS C:\Users\Administrator> setspn -L evolvendbuser
Registered ServicePrincipalNames for CN=evolvendbuser,CN=Users,DC=evolven,DC=corp:
MSSQLSvc/mssql-g1cftve.evolven.corp:1433
MSSQLSvc/mssql-g1cftve.evolven.corp
然后我在活动目录服务器上为evolvendbclientuser创建了一个keytab文件。请注意,我将加密参数设置为 ALL,您可以根据需要设置特定的加密算法(AES-128、AES-256)。只需确保您的 kdc 服务器支持该加密类型并且 krb5.conf 文件允许使用该加密类型):
ktpass -princ [email protected] -mapuser EVOLVEN\evolvendbclientuser -crypto ALL -ptype KRB5_NT_PRINCIPAL -pass <password> -out evolvendbclientuser.keytab -SetPass
接下来,我将 keytab 文件上传到 RHEL 服务器的
/etc
目录中。然后更新我的 Jaas 文件以引用新的密钥表文件和主体到我的[电子邮件受保护]。
com.sun.security.jgss.krb5.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/etc/evolvendbclientuser.keytab"
storeKey=true
principal="[email protected]"
doNotPrompt=true
debug=true;
};
供参考我的 krb5.conf 文件:
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
rnds = false
default_realm = EVOLVEN.CORP
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 30d
renew_lifetime = 30d
forwardable = true
udp_preference_limit = 0
default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 rc4-hmac
default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 rc4-hmac
permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 rc4-hmac
[realms]
EVOLVEN.CORP = {
kdc = EC2AMAZ-AEHRC46.evolven.corp
admin_server = EC2AMAZ-AEHRC46.evolven.corp
}
最后,我厌倦了启动 Tomcat 应用程序并等待它失败,因此我编写了一个小 Java 应用程序,您可以将其与 JDBC 适配器一起编译以测试连接:
您需要将其放入与 mssql-jdbc jar 相同的目录中。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCConnectionWrapper {
public static void main(String[] args) {
// Check if a connection string is provided as an argument
if (args.length < 1) {
System.out.println("Please provide the JDBC connection string as an argument.");
System.exit(1);
}
// Capture the JDBC connection string from the command-line argument
String jdbcUrl = args[0];
System.out.println("Connecting to: " + jdbcUrl);
try (Connection connection = DriverManager.getConnection(jdbcUrl)) {
System.out.println("Connected to the database!");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
然后您可以编译并测试 JDBC 连接性。请注意告诉 JDBC 适配器使用 krb5.conf 文件的附加参数以及供 JDBC 适配器使用的 JaaS 配置。还增加了日志记录。
java -Djavax.security.auth.useSubjectCredsOnly=false \
-Djava.security.auth.login.config=/opt/tomcat/bin/jaas.conf \
-Djava.security.krb5.conf=/etc/krb5.conf \
-Dsun.security.krb5.debug=true \
-Dsun.security.spnego.debug=true \
-cp .:mssql-jdbc-7.2.2.jre8.jar JDBCConnectionWrapper \
"jdbc:sqlserver://MSSQL-G1CFTVE.evolven.corp:1433;DatabaseName=master;authenticationScheme=JavaKerberos;integratedSecurity=true;trustServerCertificate=true"
现在不再出现可怕的“集成身份验证失败”和检测到有缺陷的令牌(机制级别:AP_REP 令牌 ID 不匹配!)错误。我得到:
Entered Krb5Context.initSecContext with state=STATE_IN_PROCESS
>>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
Krb5Context setting peerSeqNumber to: 813842378
Connected to the database!
非常感谢大家!如果您正在为此苦苦挣扎,我希望这会有所帮助!