【问题标题】:Connect to SAP HANA DB using jdbc and Kerberos Delegation使用 jdbc 和 Kerberos 委派连接到 SAP HANA 数据库
【发布时间】:2017-09-30 22:13:14
【问题描述】:

是否可以使用 jdbc 和 Kerberos 委派从我的 java 应用程序连接到 SAP HANA DB?

现在我可以创建与 SAP HANA 数据库的 jdbc 连接,而无需输入数据库登录名和密码,只使​​用 Windows 登录名。 为此,我在 SAP HANA 管理控制台 (user1@domain_name) 中为 db 用户设置 Kerberos 外部 ID,并在创建 jdbc 连接时使用属性“NativeAuthentification=true”。 然后我通过 user1 登录到 Windows 并运行我的应用程序,我可以连接到 SAP HANA DB 并选择数据。

但是我需要在客户端计算机上登录到 Windows,运行我的客户端 java 应用程序,连接到我的应用程序服务器,应用程序服务器必须连接到 SAP HANA DB 并具有已连接用户的权限并选择授予此用户的数据。

在客户端 java 应用程序中,我使用 waffle-jna 库获得了 kerberos 令牌,然后我使用它使用 Spring Security 连接到我的应用程序服务器(它有效),但我无法使用此令牌创建与 SAP HANA DB 的 jdbc 连接。我不能使用 Kerberos 委派。

有人知道通过 jdbc 在 SAP HANA DB 中的 Kerberos 委派吗?谢谢。

【问题讨论】:

  • 嗨,Alexander,您找到解决方案了吗?我们正在做确切的事情,但无法弄清楚如何进行。
  • 是的,我做到了。属性“Native Authentication=true”是错误的方式。我使用 gss api 将 HANA 配置为通过 jdbc 和 Kerberos 委派工作。 docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/…今天我将尝试简单描述一下我做了哪些设置以及我使用了哪些代码。
  • 谢谢,等待您的回复。
  • @Alexander 您是如何在不输入数据库登录名和密码(从客户端机器到 HANA)的情况下创建到 SAP HANA DB 的 jdbc 连接的?我专门寻找所需的设置和 JDBC 连接属性/字符串。您是否需要在客户端机器上设置任何 .conf 文件?很抱歉再次提出一个老问题,但我似乎找不到除您之外的任何成功案例。
  • 在我的例子中,JDBC 连接属性在服务器端 properties.setProperty("hibernate.connection.url", "jdbc:sap://10.0.0.121:31015"); properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HANAColumnStoreDialect");和其他财产。但是,也许我误解了你的问题,英语不是我的母语..

标签: java jdbc single-sign-on hana kerberos-delegation


【解决方案1】:

我使用 GSS API 解决了这个问题。现在我简要描述一下在我的环境中工作的设置和代码

1.环境

客户端 java 应用程序在 Windows 7 上运行(java SE 版本 8,swing),应用程序服务器在 Windows 2012 r2 上运行(java 8,tomcat 或 jetty,在 glassfish 上不起作用),sap hana db 在 linux 上运行。 将连接到hana db的Windows用户和运行应用程序服务器的Windows用户在一个windows域(活动目录)中。

2。配置windows域

在 windows 域控制器中创建 spn 和 .keytab 文件

3。配置hana

有很好的指南“HowTo_HANA_SSO_Kerberos_v1.7.1.pdf” 使用外部 ID user@windowsdomain(来自 windows 活动目录的帐户名)在 hana 中创建了 db 用户 有很好的 python 脚本用于为 kerberos 配置 hana 并检查配置。我们通过 sap hana 支持网站获得了这个脚本。

4.客户端配置

windows 注册表项 allowtgtsessionkey 必须设置为 true

在客户端是文件 登录.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.服务器配置

服务器上有文件

登录.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

【讨论】:

  • 非常感谢 Alex 的全面回答。在#7 给出的代码示例中,我将传入的令牌提交给 jdbc 调用,但我从 SAP HANA 获得了身份验证异常。我的令牌来自浏览器。我仍然会再次验证,因为令牌只是一个令牌,它应该与它来自哪里——来自浏览器或来自 java 代码无关。
  • 也许使用来自浏览器的token有它自己的特殊性。我只使用了从 java 收到的令牌。
  • 嗨,Alex,我试过上面的代码,GSSCredential clientCr = context.getDelegCred();工作中。但是,当我执行 Subject s = GSSUtil.createSubject(clientCr.getName(), clientCr); ,主题仅包含名称而不包含凭据。你知道为什么会这样吗?我在这里问过这个问题stackoverflow.com/questions/56320386/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多