我可以使用 okinit 实用程序避免输入密码吗?

问题描述 投票:0回答:2

在我的配置中,我有:

  • 域控制器(Windows Server 2008 R2)
  • Oracle 数据库服务器(Windows Server 2016 标准版)
  • 客户端(Windows 10 专业版)

example.ru - 是域名。

mydb - 是数据库的 sid。

我使用 Kerberos 身份验证。

在数据库服务器上我创建了用户:

CREATE USER myuser IDENTIFIED EXTERNALLY as '[email protected]';
GRANT CREATE SESSION TO myuser;

在客户端,我以域用户 myuser 身份登录。

为我的用户获取门票:

okinit myuser

然后,okinit 询问密码,我输入它

然后我登录数据库:

sqlplus /@mydb

连接成功。

但是8小时后,如果我想再次登录数据库,我必须再次执行“okinit myuser”并输入密码。

我可以避免输入密码吗?它安全吗? 也许我必须在 krb5.conf 中配置 ticket_lifetimerenew_lifetime (并且无需密码续订票据)?

windows oracle kerberos
2个回答
2
投票

恐怕你对此无能为力。 Oracle 的 Kerberos 实现非常古老,直到现在还没有达到今天的标准。

Windows/AD生态系统是LDAP+Kerberos两种技术的结合。 AD有自己的Kerberos服务器,Windows登录服务是Kerberos客户端。问题来了。现在Window不会让你看到你自己的Kerberos TGT(票证授予票证)。如果执行

klist tgt
,您将看到全零。

为了使用 Kerberos SSO,您的软件必须与称为 SSPI 的 Microsoft 专有 API 集成。为了将 Oracle 胖客户端库与 SSPI 集成,您必须将其放入我们的 sqlnet.ora

SQLNET.KERBEROS5_CC_NAME=MSLSA:

SQLNET.KERBEROS5_CC_NAME=OSMSFT:

这指示 Oracle 的客户端库从 Windows 本机缓存而不是从文件中撤回 Kerberos 票证。 我不确定这是否适合你。它没有很好的记录。使用此选项进行谷歌搜索。一般来说,将 Oracle 与 Kerberos 集成是一个兔子洞。

如果是 Java/JDBC,问题就更大了。 Java JDK 花了 7 年多的时间才添加对 SSPI 的支持。然后将支持添加到 JDBC 驱动程序中。 请参见下面的示例。 但 Oracle SQL Developer 中的支持仍悬而未决。增强请求是几年前创建的,但仍然没有进展。

/*
  Copyright (c) 2021, 2022, Oracle and/or its affiliates.

  This software is dual-licensed to you under the Universal Permissive License
  (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License
  2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
  either license.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

     https://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*
   DESCRIPTION
    This sample shows how to use SSO uging Kerberos in Windows.
    Since WIN2019 allowtgtsessionkey registry key is not available 
    and the only option how to acces Kerberos TGT is via Java's SSPI bridge.
    
   PREREQUISITIES
    - Confirure Kerberos authentication for Oracle database as describe here:
      https://blog.pythian.com/part-4-implementing-oracle-database-single-sign-on-using-kerberos-active-directory-and-oracle-cmu/
      
   - Create DB user identified extenally as:
     CREATE USER <AD LOGIN> IDENTIFIED EXTERNALLY AS '<AD LOGIN>@<AD REALM>';
     GRANT CONNECT TO <AD LOGIN>;
     
   - Check your Windows has generater Kerb tickets during logon
     klist tgt
     klist
     
   - Connect to database using this program. 
     Java's SSPI bridge should be used to renerate required Kerberos ticket for SSO.
   
*/
     
package kerb;

import java.sql.ResultSet;
import java.sql.Statement;

import java.util.Properties;

import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;

import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleConnectionBuilder;
import oracle.jdbc.pool.OracleDataSource;
import oracle.net.ano.AnoServices;

// The whole code was inspired by
// https://blogs.nologin.es/rickyepoderi/index.php?/archives/105-Oracle-Driver-and-Kerberos.html

public class GSSAuthSSPIConnectSample {
    // This should return your AD LOGIN
    String username = System.getProperty("user.name");
    // This should return your AD KERBEROS REALM
    String domain = System.getenv("USERDNSDOMAIN");
    String url = "jdbc:oracle:thin:@//dbhost1:1521/DBSERVICE";

    public GSSAuthSSPIConnectSample() {
    }

    public void doit() throws Exception
    {
        // Use env variable SSPI_BRIDGE_TRACE=1 in order to trace Javas sspi_bridge.dll plugin
        // export SSPI_BRIDGE_TRACE=1
        
        // Various useful tracing options
        //System.setProperty("java.util.logging.config.file", "D:/devel/UCP/target/classes/OracleLog.properties");      
        //System.setProperty("oracle.jdbc.Trace", "true");      

        //System.setProperty("sun.security.krb5.debug", "true");
        //System.setProperty("sun.security.spnego.debug", "true");
        //System.setProperty("sun.security.jgss.debug", "true");
        //System.setProperty("java.security.debug", "true");
        //System.setProperty("sun.security.nativegss.debug", "true");

        System.setProperty("sun.security.jgss.native", "true");
        System.setProperty("sun.security.jgss.lib", "sspi_bridge.dll");

        Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
        GSSManager manager = GSSManager.getInstance();

        GSSName srcName = manager.createName(username + "@" + domain, GSSName.NT_USER_NAME);
        GSSCredential cred = manager.createCredential(srcName
                , GSSCredential.DEFAULT_LIFETIME
                , krb5Oid, GSSCredential.INITIATE_ONLY);

        Properties prop = new Properties();
        prop.setProperty(AnoServices.AUTHENTICATION_PROPERTY_SERVICES, "(" + AnoServices.AUTHENTICATION_KERBEROS5 + ")");
        prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERVICES,"( " + AnoServices.AUTHENTICATION_KERBEROS5 + " )");
        prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5_MUTUAL, "true");

        OracleDataSource ods = new OracleDataSource();
        ods.setURL(url);
        ods.setConnectionProperties(prop);
        OracleConnectionBuilder builder = ods.createConnectionBuilder();
        OracleConnection conn = builder.gssCredential(cred).build();
        
        String auth = ((OracleConnection)conn).getAuthenticationAdaptorName();
        System.out.println("Authentication adaptor:"+auth);

        String sql = "select user from dual";
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next())
            System.out.println("whoami: " + rs.getString(1));

        conn.close();
    }

    public static void main(String[] args) {
        GSSAuthSSPIConnectSample test = new GSSAuthSSPIConnectSample();
        try {
            test.doit();
            System.out.println("Done");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

0
投票

但是8小时后,如果我想再次登录数据库,我必须再次执行“okinit myuser”并输入密码。

我可以避免输入密码吗?会安全吗?也许我必须在 krb5.conf 中配置ticket_lifetime和renew_lifetime(并且无需密码更新ticket)?

理论上是的,根据您的领域的配置方式,将 renew_lifetime 设置为

14d
(典型的最大值) – 或执行
okinit -r 14d
– 可以让您一次又一次地使用
okinit -R
将生命周期延长至 8 小时,最多到两周。

请注意,您必须在过期之前不断续订门票。

理想情况下,Oracle 应该使用 Windows LSA 票证缓存,MIT Kerberos 可以通过

MSLSA:
缓存类型使用它(如 ibre5041 的答案)......但我认为现在它无法正常工作。 “MSLSA:”的工作方式不是让 LSA/SSPI 处理所有事情,而是从 LSA 缓存中提取原始 TGT,并让 MIT Kerberos 完成剩下的工作,并且默认情况下不仅禁用提取 TGT 的功能 但也与 Credential Guard 完全不兼容。所以,单独继续
okinit
将是不太糟糕的选择。

© www.soinside.com 2019 - 2024. All rights reserved.