2

之前在这个论坛上问过一个类似的问题,但接受的答案对我没有帮助。我的服务器有一个 Kerberos 密钥表文件,我想用它来验证客户端发送的服务票证。

根据 Sun 的文档和分散在其他地方的示例代码,这是我目前拥有的:

  1. 客户端向 KDC 请求 MYSPN 的服务票证
  2. 客户端将文件发送到服务服务器以请求访问服务。
  3. 服务器在使用已拥有的 MYSPN 的 keytab 验证服务票证后授予访问权限。

我无法让#3 工作。我得到的具体错误是:

GSSException: No valid credentials provided (Mechanism level: Attempt to obtain new ACCEPT credentials failed!)
    at sun.security.jgss.krb5.Krb5AcceptCredential.getInstance(Krb5AcceptCredential.java:100)
    at sun.security.jgss.krb5.Krb5MechFactory.getCredentialElement(Krb5MechFactory.java:128)
    at sun.security.jgss.krb5.Krb5MechFactory.getMechanismContext(Krb5MechFactory.java:200)
    at sun.security.jgss.GSSManagerImpl.getMechanismContext(GSSManagerImpl.java:231)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:319)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
    at cms.gssapi.Server$1.run(Server.java:188)
    at cms.gssapi.Server$1.run(Server.java:1)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:357)
    at cms.gssapi.Server.acceptSecurityContext(Server.java:182)
    at cms.gssapi.Server.main(Server.java:59)
Caused by: javax.security.auth.login.LoginException: Unable to obtain Princpal Name for authentication 
    at com.sun.security.auth.module.Krb5LoginModule.promptForName(Krb5LoginModule.java:750)
    at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:646)
    at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:559)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:784)
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:203)
    at javax.security.auth.login.LoginContext$5.run(LoginContext.java:721)
    at javax.security.auth.login.LoginContext$5.run(LoginContext.java:719)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.LoginContext.invokeCreatorPriv(LoginContext.java:718)
    at javax.security.auth.login.LoginContext.login(LoginContext.java:590)
    at sun.security.jgss.GSSUtil.login(GSSUtil.java:264)
    at sun.security.jgss.krb5.Krb5Util.getKeys(Krb5Util.java:202)
    at sun.security.jgss.krb5.Krb5AcceptCredential$1.run(Krb5AcceptCredential.java:95)
    at sun.security.jgss.krb5.Krb5AcceptCredential$1.run(Krb5AcceptCredential.java:93)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.security.jgss.krb5.Krb5AcceptCredential.getInstance(Krb5AcceptCredential.java:92)
    ... 11 more

这是尝试使用 keytab 验证客户端服务票证的服务器代码片段:

 public static void main( String[] args) {
      Properties props = new Properties();
      props.load( new FileInputStream( "server.properties"));
      System.setProperty( "sun.security.krb5.debug", "true");
      System.setProperty( "java.security.krb5.realm", props.getProperty( "realm"));
      System.setProperty( "java.security.krb5.kdc", props.getProperty( "kdc"));
      System.setProperty( "java.security.auth.login.config", "./jaas.conf");
      System.setProperty( "javax.security.auth.useSubjectCredsOnly", "false");
      krb5Oid = new Oid( "1.2.840.113554.1.2.2");
      Server server = new Server();
      server.login();
      byte serviceTicket[] = readClientTicketFromFile();
      String clientName = server.acceptSecurityContext(serviceTicket);
  }

  private static byte[] readClientTicketFromFile() throws IOException {
    BufferedReader in = new BufferedReader( new FileReader( "serviceticket.token"));
    String str;
    StringBuffer buffer = new StringBuffer();
    while ((str = in.readLine()) != null) {
       buffer.append( str + "\n");
    }
    in.close();
    BASE64Decoder decoder = new BASE64Decoder();
    return decoder.decodeBuffer( buffer.toString());
  }

  private static Oid krb5Oid;

  private Subject login() throws LoginException {
    LoginContext loginCtx = null;
    loginCtx = new LoginContext( "Server", new LoginCallbackHandler(null,null));   
    System.out.println("Attempting to do Login...");
    loginCtx.login();
    Subject ret_sub = loginCtx.getSubject();
     return ret_sub;
  }


  private String acceptSecurityContext( final byte[] serviceTicket) 
      throws GSSException {
    krb5Oid = new Oid( "1.2.840.113554.1.2.2");
    return Subject.doAs( subject, new PrivilegedAction<String>() {
      public String run() {
        try {
          GSSManager manager = GSSManager.getInstance();
          GSSContext context = manager.createContext( (GSSCredential) null);
          context.acceptSecContext( serviceTicket, 0, serviceTicket.length);
          return context.getSrcName().toString();
        }
        catch ( Exception e) {
          e.printStackTrace();
          return null;
        }
      }
    });
  }

这是我的 server.properties

realm=MYREALM
kdc=192.168.1.1

和 jaas.conf 文件

Client {
  com.sun.security.auth.module.Krb5LoginModule required
  useTicketCache=false
  useKeyTab=false
  storeKey=false
  isInitiator=true
  debug=true
  ;
};

Server {
     com.sun.security.auth.module.Krb5LoginModule required 
     useKeyTab=true 
     storeKey=true 
     doNotPrompt=true
     isInitiator=false
     keyTab="/etc/krb5.keytab"
     principal="MYSPN/host.domain.com@MYREALM"
     debug=true
     ;
};

我确定服务票证是有效的,因为如果我为服务帐户提供密码,服务器可以进行身份​​验证,但我想使用 keytab 文件而不是密码。

4

0 回答 0