使用 jdbc 和 Kerberos 委派连接到 SAP HANA 数据库
Connect to SAP HANA DB using jdbc and Kerberos Delegation
是否可以使用 jdbc 和 Kerberos 委派从我的 java 应用程序连接到 SAP HANA 数据库?
现在我可以创建 jdbc 到 SAP HANA 数据库的连接而无需输入数据库登录名和密码,仅使用 windows 登录名。
为此,我在 SAP HANA 管理控制台 (user1@domain_name) 中为数据库用户设置了 Kerberos 外部 ID,并在创建 jdbc 连接时使用 属性 "NativeAuthentification=true"。
然后我通过 user1 和 运行 我的应用程序登录 Windows,我可以连接到 SAP HANA 数据库和 select 数据。
但我需要在客户端计算机上登录 Windows,运行 我的客户端 java 应用程序,连接到我的应用程序服务器,应用程序服务器必须使用以下权限连接到 SAP HANA DB连接的用户和 select 数据,授予该用户。
在客户端 java 应用程序中,我使用 waffle-jna 库获得了 kerberos 令牌,然后我使用它使用 Spring 安全性(有效)连接到我的应用程序服务器,但我无法创建jdbc 使用此令牌连接到 SAP HANA 数据库。我无法使用 Kerberos 委派。
有人通过 jdbc 了解 SAP HANA 数据库中的 Kerberos 委派吗?谢谢
我使用 GSS API 解决了这个问题。现在我简要描述在我的环境中工作的设置和代码
1.环境
客户端 java 应用程序 运行 在 Windows 7(java SE 版本 8,swing),应用程序服务器 运行 在 Windows 2012 r2(java 8,tomcat 或码头,在 glassfish 上不起作用),sap hana db 运行 在 linux 上。
Windows 用户,它将连接到 hana 数据库,Windows 用户,运行 应用程序服务器,在一个 windows 域(活动目录)中。
2。配置windows域
在 windows 域控制器中创建了 spn 和 .keytab 文件
3。配置hana
有好攻略"HowTo_HANA_SSO_Kerberos_v1.7.1.pdf"
使用外部 ID user@windowsdomain 在 hana 中创建了数据库用户(来自 windows 活动目录的帐户名)
有很好的 python 脚本可以为 kerberos 配置 hana 并检查配置。我们通过 sap hana 支持站点获得了这个脚本。
4.客户端配置
windows 注册表项 allowtgtsessionkey 必须设置为 true
客户端上有文件
login.conf
com.sun.security.jgss.login {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
doNotPrompt=true
debug=true;
};
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
principal="saphanauser"
debug=true;
};
和krb5.conf
[libdefaults]
default_realm = DOMAINNAME.NEW
forwardable = true
clockskew = 3000
default_tkt_enctypes = aes256-cts aes128-cts rc4-hmac
default_tgs_enctypes = aes256-cts aes128-cts rc4-hmac
permitted_enctypes = aes256-cts aes128-cts rc4-hmac
[realms]
DOMAINNAME.NEW = {
kdc = KDCSERVERNAME
default_domain = DOMAINNAME.NEW
}
[domain_realm]
.domainname.new = DOMAINNAME.NEW
domainname.new = DOMAINNAME.NEW
5.服务器配置
服务器上有文件
login.conf
com.sun.security.jgss.login {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
doNotPrompt=true
debug=true;
};
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
debug=true;
};
com.sun.security.jgss.accept {
com.sun.security.auth.module.Krb5LoginModule required
storeKey=true
keyTab="C:/krb/keytab/krb5_hdb.keytab"
useKeyTab=true
realm="DOMAINNAME.NEW"
principal="HDB/LINUX.DOMAINNAME.NEW"
isInitiator=false
debug=true;
};
和krb5.conf
[libdefaults]
default_realm = DOMAINNAME.NEW
forwardable = true
default_tkt_enctypes = aes256-cts aes128-cts rc4-hmac
default_tgs_enctypes = aes256-cts aes128-cts rc4-hmac
permitted_enctypes = aes256-cts aes128-cts rc4-hmac
[realms]
DOMAINNAME.NEW = {
kdc = KDCSERVERNAME
default_domain = DOMAINNAME.NEW
}
[domain_realm]
.domainname.new = DOMAINNAME.NEW
domainname.new = DOMAINNAME.NEW
6.客户端代码
获取令牌以将其发送到应用程序服务器
public static byte[] getTokenGss() throws GSSException {
String spnName = "spn_name";
String oidValue= "1.2.840.113554.1.2.2"; // KERBEROS_MECH_OID
String userLogin = System.getProperty("user.name");
Oid mechOid = new Oid(oidValue);
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
Path directoryConf = "C:\client\krb";
String pathToGssConfigFile = directoryConf.resolve("login.conf").toString();
System.setProperty("java.security.auth.login.config", pathToGssConfigFile);
String pathToKrb5ConfigFile = directoryConf.resolve("krb5.conf").toString();
System.setProperty("java.security.krb5.conf", pathToKrb5ConfigFile);
System.setProperty("sun.security.krb5.debug", "true");
GSSManager manager = GSSManager.getInstance();
GSSName gssUserName = manager.createName(userLogin, GSSName.NT_USER_NAME, mechOid);
logger.debug("before createCredential");
GSSCredential clientGssCreds =
manager.createCredential(gssUserName.canonicalize(mechOid), GSSCredential.INDEFINITE_LIFETIME, mechOid,
GSSCredential.INITIATE_ONLY);
byte[] token = new byte[0];
// create target server SPN
GSSName gssServerName = manager.createName(spnName, GSSName.NT_USER_NAME);
logger.debug("before createContext");
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(mechOid), mechOid, clientGssCreds,
GSSContext.DEFAULT_LIFETIME);
// optional enable GSS credential delegation
clientContext.requestCredDeleg(true);
token = clientContext.initSecContext(token, 0, token.length);
return token;
}
7.服务器代码
使用来自客户端的令牌创建休眠 EntityManagerFactory
private EntityManagerFactory createEntNamagerFactoryViaKerberos(byte[] inToken)
throws Exception {
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
System.setProperty("java.security.auth.login.config", "C:\krb\gsslogin\login.conf");
System.setProperty("java.security.krb5.conf", "C:\krb\krb5.conf");
Oid mechOid = new Oid("1.2.840.113554.1.2.2");
GSSManager manager = GSSManager.getInstance();
//first obtain it's own credentials...
GSSCredential myCred =
manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME, mechOid, GSSCredential.ACCEPT_ONLY);
//...and create a context for this credentials...
GSSContext context = manager.createContext(myCred);
//...then use that context to authenticate the calling peer by reading his token
byte[] tokenForPeer = context.acceptSecContext(inToken, 0, inToken.length);
if (!context.isEstablished()) {
throw new Exception("Context not established!");
}
//...then obtain information from the context
logger.debug("Clientcipal is " + context.getSrcName());
logger.debug("Servercipal is " + context.getTargName());
if (context.getCredDelegState()) {
logger.debug("Then is delegatable.");
} else {
logger.debug("Then is NOT delegatable");
}
GSSCredential clientCr = context.getDelegCred();
Subject s = GSSUtil.createSubject(clientCr.getName(), clientCr);
KerberosActionCreateEmf kerberosAction = new KerberosActionCreateEmf();
kerberosAction.unicalEntFactoryName = "kerb" + System.currentTimeMillis();
Subject.doAs(s, kerberosAction);
EntityManagerFactory emf = kerberosAction.emf;
return emf;
}
class KerberosActionCreateEmf implements PrivilegedExceptionAction {
public EntityManagerFactory emf;
public String modelName;
public String unicalEntFactoryName;
@Override
public Object run() throws Exception {
Properties properties = new Properties();
properties.setProperty("javax.persistence.jdbc.driver", "com.sap.db.jdbc.Driver");
properties.setProperty("hibernate.connection.url", "jdbc:sap://10.0.0.121:31015");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HANAColumnStoreDialect");
// do not use login and pass, use kerberos delegation (token)
//properties.setProperty("hibernate.connection.username", login);
//properties.setProperty("hibernate.connection.password", pass);
properties.setProperty("hibernate.default_schema", "default_schema");
properties.setProperty("hibernate.show_sql", model_manager_hibernate_show_sql);
properties.setProperty("hibernate.ejb.entitymanager_factory_name", unicalEntFactoryName);
properties.setProperty("hibernate.cache.use_query_cache", "false");
properties.setProperty("hibernate.query.plan_cache_max_soft_references", "1");
properties.setProperty("hibernate.query.plan_cache_max_strong_references", "1");
properties.setProperty("hibernate.hikari.minimumIdle", "3");
properties.setProperty("hibernate.hikari.maximumPoolSize", "20");
properties.setProperty("hibernate.hikari.idleTimeout", "600000");
properties.setProperty("hibernate.hikari.AutoCommit", "false");
properties.setProperty("hibernate.hikari.poolName", unicalEntFactoryName);
properties.setProperty("hibernate.hikari.connectionTimeout", "1800000");
EntityManagerFactory newEntityManagerFactory =
Persistence.createEntityManagerFactory("persistenceUnitName", properties);
emf = newEntityManagerFactory;
return null;
}
}
8.有用的链接
http://thejavamonkey.blogspot.com/2008/04/clientserver-hello-world-in-kerberos.html
https://dmdaa.wordpress.com/category/java/jgss/
https://dmdaa.wordpress.com/2010/03/13/kerberos-setup-and-jaas-configuration-for-running-sun-jgss-tutorial-against-ad/
http://cr.openjdk.java.net/~weijun/special/krb5winguide-2/raw_files/new/kwin
是否可以使用 jdbc 和 Kerberos 委派从我的 java 应用程序连接到 SAP HANA 数据库?
现在我可以创建 jdbc 到 SAP HANA 数据库的连接而无需输入数据库登录名和密码,仅使用 windows 登录名。 为此,我在 SAP HANA 管理控制台 (user1@domain_name) 中为数据库用户设置了 Kerberos 外部 ID,并在创建 jdbc 连接时使用 属性 "NativeAuthentification=true"。 然后我通过 user1 和 运行 我的应用程序登录 Windows,我可以连接到 SAP HANA 数据库和 select 数据。
但我需要在客户端计算机上登录 Windows,运行 我的客户端 java 应用程序,连接到我的应用程序服务器,应用程序服务器必须使用以下权限连接到 SAP HANA DB连接的用户和 select 数据,授予该用户。
在客户端 java 应用程序中,我使用 waffle-jna 库获得了 kerberos 令牌,然后我使用它使用 Spring 安全性(有效)连接到我的应用程序服务器,但我无法创建jdbc 使用此令牌连接到 SAP HANA 数据库。我无法使用 Kerberos 委派。
有人通过 jdbc 了解 SAP HANA 数据库中的 Kerberos 委派吗?谢谢
我使用 GSS API 解决了这个问题。现在我简要描述在我的环境中工作的设置和代码
1.环境
客户端 java 应用程序 运行 在 Windows 7(java SE 版本 8,swing),应用程序服务器 运行 在 Windows 2012 r2(java 8,tomcat 或码头,在 glassfish 上不起作用),sap hana db 运行 在 linux 上。 Windows 用户,它将连接到 hana 数据库,Windows 用户,运行 应用程序服务器,在一个 windows 域(活动目录)中。
2。配置windows域
在 windows 域控制器中创建了 spn 和 .keytab 文件
3。配置hana
有好攻略"HowTo_HANA_SSO_Kerberos_v1.7.1.pdf" 使用外部 ID user@windowsdomain 在 hana 中创建了数据库用户(来自 windows 活动目录的帐户名) 有很好的 python 脚本可以为 kerberos 配置 hana 并检查配置。我们通过 sap hana 支持站点获得了这个脚本。
4.客户端配置
windows 注册表项 allowtgtsessionkey 必须设置为 true
客户端上有文件 login.conf
com.sun.security.jgss.login {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
doNotPrompt=true
debug=true;
};
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
principal="saphanauser"
debug=true;
};
和krb5.conf
[libdefaults]
default_realm = DOMAINNAME.NEW
forwardable = true
clockskew = 3000
default_tkt_enctypes = aes256-cts aes128-cts rc4-hmac
default_tgs_enctypes = aes256-cts aes128-cts rc4-hmac
permitted_enctypes = aes256-cts aes128-cts rc4-hmac
[realms]
DOMAINNAME.NEW = {
kdc = KDCSERVERNAME
default_domain = DOMAINNAME.NEW
}
[domain_realm]
.domainname.new = DOMAINNAME.NEW
domainname.new = DOMAINNAME.NEW
5.服务器配置
服务器上有文件
login.conf
com.sun.security.jgss.login {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
doNotPrompt=true
debug=true;
};
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
debug=true;
};
com.sun.security.jgss.accept {
com.sun.security.auth.module.Krb5LoginModule required
storeKey=true
keyTab="C:/krb/keytab/krb5_hdb.keytab"
useKeyTab=true
realm="DOMAINNAME.NEW"
principal="HDB/LINUX.DOMAINNAME.NEW"
isInitiator=false
debug=true;
};
和krb5.conf
[libdefaults]
default_realm = DOMAINNAME.NEW
forwardable = true
default_tkt_enctypes = aes256-cts aes128-cts rc4-hmac
default_tgs_enctypes = aes256-cts aes128-cts rc4-hmac
permitted_enctypes = aes256-cts aes128-cts rc4-hmac
[realms]
DOMAINNAME.NEW = {
kdc = KDCSERVERNAME
default_domain = DOMAINNAME.NEW
}
[domain_realm]
.domainname.new = DOMAINNAME.NEW
domainname.new = DOMAINNAME.NEW
6.客户端代码
获取令牌以将其发送到应用程序服务器
public static byte[] getTokenGss() throws GSSException {
String spnName = "spn_name";
String oidValue= "1.2.840.113554.1.2.2"; // KERBEROS_MECH_OID
String userLogin = System.getProperty("user.name");
Oid mechOid = new Oid(oidValue);
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
Path directoryConf = "C:\client\krb";
String pathToGssConfigFile = directoryConf.resolve("login.conf").toString();
System.setProperty("java.security.auth.login.config", pathToGssConfigFile);
String pathToKrb5ConfigFile = directoryConf.resolve("krb5.conf").toString();
System.setProperty("java.security.krb5.conf", pathToKrb5ConfigFile);
System.setProperty("sun.security.krb5.debug", "true");
GSSManager manager = GSSManager.getInstance();
GSSName gssUserName = manager.createName(userLogin, GSSName.NT_USER_NAME, mechOid);
logger.debug("before createCredential");
GSSCredential clientGssCreds =
manager.createCredential(gssUserName.canonicalize(mechOid), GSSCredential.INDEFINITE_LIFETIME, mechOid,
GSSCredential.INITIATE_ONLY);
byte[] token = new byte[0];
// create target server SPN
GSSName gssServerName = manager.createName(spnName, GSSName.NT_USER_NAME);
logger.debug("before createContext");
GSSContext clientContext = manager.createContext(gssServerName.canonicalize(mechOid), mechOid, clientGssCreds,
GSSContext.DEFAULT_LIFETIME);
// optional enable GSS credential delegation
clientContext.requestCredDeleg(true);
token = clientContext.initSecContext(token, 0, token.length);
return token;
}
7.服务器代码
使用来自客户端的令牌创建休眠 EntityManagerFactory
private EntityManagerFactory createEntNamagerFactoryViaKerberos(byte[] inToken)
throws Exception {
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
System.setProperty("java.security.auth.login.config", "C:\krb\gsslogin\login.conf");
System.setProperty("java.security.krb5.conf", "C:\krb\krb5.conf");
Oid mechOid = new Oid("1.2.840.113554.1.2.2");
GSSManager manager = GSSManager.getInstance();
//first obtain it's own credentials...
GSSCredential myCred =
manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME, mechOid, GSSCredential.ACCEPT_ONLY);
//...and create a context for this credentials...
GSSContext context = manager.createContext(myCred);
//...then use that context to authenticate the calling peer by reading his token
byte[] tokenForPeer = context.acceptSecContext(inToken, 0, inToken.length);
if (!context.isEstablished()) {
throw new Exception("Context not established!");
}
//...then obtain information from the context
logger.debug("Clientcipal is " + context.getSrcName());
logger.debug("Servercipal is " + context.getTargName());
if (context.getCredDelegState()) {
logger.debug("Then is delegatable.");
} else {
logger.debug("Then is NOT delegatable");
}
GSSCredential clientCr = context.getDelegCred();
Subject s = GSSUtil.createSubject(clientCr.getName(), clientCr);
KerberosActionCreateEmf kerberosAction = new KerberosActionCreateEmf();
kerberosAction.unicalEntFactoryName = "kerb" + System.currentTimeMillis();
Subject.doAs(s, kerberosAction);
EntityManagerFactory emf = kerberosAction.emf;
return emf;
}
class KerberosActionCreateEmf implements PrivilegedExceptionAction {
public EntityManagerFactory emf;
public String modelName;
public String unicalEntFactoryName;
@Override
public Object run() throws Exception {
Properties properties = new Properties();
properties.setProperty("javax.persistence.jdbc.driver", "com.sap.db.jdbc.Driver");
properties.setProperty("hibernate.connection.url", "jdbc:sap://10.0.0.121:31015");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HANAColumnStoreDialect");
// do not use login and pass, use kerberos delegation (token)
//properties.setProperty("hibernate.connection.username", login);
//properties.setProperty("hibernate.connection.password", pass);
properties.setProperty("hibernate.default_schema", "default_schema");
properties.setProperty("hibernate.show_sql", model_manager_hibernate_show_sql);
properties.setProperty("hibernate.ejb.entitymanager_factory_name", unicalEntFactoryName);
properties.setProperty("hibernate.cache.use_query_cache", "false");
properties.setProperty("hibernate.query.plan_cache_max_soft_references", "1");
properties.setProperty("hibernate.query.plan_cache_max_strong_references", "1");
properties.setProperty("hibernate.hikari.minimumIdle", "3");
properties.setProperty("hibernate.hikari.maximumPoolSize", "20");
properties.setProperty("hibernate.hikari.idleTimeout", "600000");
properties.setProperty("hibernate.hikari.AutoCommit", "false");
properties.setProperty("hibernate.hikari.poolName", unicalEntFactoryName);
properties.setProperty("hibernate.hikari.connectionTimeout", "1800000");
EntityManagerFactory newEntityManagerFactory =
Persistence.createEntityManagerFactory("persistenceUnitName", properties);
emf = newEntityManagerFactory;
return null;
}
}
8.有用的链接
http://thejavamonkey.blogspot.com/2008/04/clientserver-hello-world-in-kerberos.html https://dmdaa.wordpress.com/category/java/jgss/ https://dmdaa.wordpress.com/2010/03/13/kerberos-setup-and-jaas-configuration-for-running-sun-jgss-tutorial-against-ad/ http://cr.openjdk.java.net/~weijun/special/krb5winguide-2/raw_files/new/kwin