簡體   English   中英

使用Java的Kerberos

[英]Kerberos with Java

我嘗試從Java登錄kerberos kdc。 但Java正在拋出異常。 似乎登錄成功但有些東西停止登錄。 我不知道為什么? 有人有解決這個問題的方法嗎? 這是我的java系統輸出:

Debug is  true storeKey false useTicketCache true useKeyTab false doNotPrompt false ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is true principal is null tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Refreshing Kerberos configuration
Acquire TGT from Cache
Principal is null
null credentials from Ticket Cache
                [Krb5LoginModule] user entered username: kadirb

principal is kadirb@EXAMPLE.COM
Commit Succeeded

Exception in thread "main" java.lang.Error: GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7) - LOOKING_UP_SERVER)
        at KerberosTicketRetriever$TicketCreatorAction.run(KerberosTicketRetriever.java:76)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAsPrivileged(Subject.java:473)
        at KerberosTicketRetriever.retrieveTicket(KerberosTicketRetriever.java:179)
        at KerberosTicketRetriever.main(KerberosTicketRetriever.java:188)
Caused by: GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7) - LOOKING_UP_SERVER)
        at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:710)
        at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
        at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
        at KerberosTicketRetriever$TicketCreatorAction.createTicket(KerberosTicketRetriever.java:105)
        at KerberosTicketRetriever$TicketCreatorAction.run(KerberosTicketRetriever.java:72)
        ... 4 more
Caused by: KrbException: Server not found in Kerberos database (7) - LOOKING_UP_SERVER
        at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:73)
        at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:192)
        at sun.security.krb5.KrbTgsReq.sendAndGetCreds(KrbTgsReq.java:203)
        at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:311)
        at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:115)
        at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:442)
        at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:641)
        ... 8 more
Caused by: KrbException: Identifier doesn't match expected value (906)
        at sun.security.krb5.internal.KDCRep.init(KDCRep.java:143)
        at sun.security.krb5.internal.TGSRep.init(TGSRep.java:66)
        at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:61)
        at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:55)
        ... 14 more
Disconnected from the target VM, address: '127.0.0.1:51126', transport: 'socket'

Process finished with exit code 1

我的java代碼:

import com.sun.security.auth.callback.DialogCallbackHandler;
import org.ietf.jgss.*;
import sun.misc.BASE64Encoder;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.*;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Set;

/**
 * Tool to retrieve a kerberos ticket. This one will not be stored in the windows ticket cache.
 */
public final class KerberosTicketRetriever
{
private final static Oid KERB_V5_OID;
private final static Oid KRB5_PRINCIPAL_NAME_OID;

static {
    try
    {
        KERB_V5_OID = new Oid("1.2.840.113554.1.2.2");
        KRB5_PRINCIPAL_NAME_OID = new Oid("1.2.840.113554.1.2.2.1");

    } catch (final GSSException ex)
    {
        throw new Error(ex);
    }
}

/**
 * Not to be instanciated
 */
private KerberosTicketRetriever() {};

/**
 *
 */
private static class TicketCreatorAction implements PrivilegedAction
{
    final String userPrincipal;
    final String applicationPrincipal;

    private StringBuffer outputBuffer;

    /**
     *
     * @param userPrincipal  p.ex. <tt>MuelleHA@MYFIRM.COM</tt>
     * @param applicationPrincipal  p.ex. <tt>HTTP/webserver.myfirm.com</tt>
     */
    private TicketCreatorAction(final String userPrincipal, final String applicationPrincipal)
    {
        this.userPrincipal = userPrincipal;
        this.applicationPrincipal = applicationPrincipal;
    }

    private void setOutputBuffer(final StringBuffer newOutputBuffer)
    {
        outputBuffer = newOutputBuffer;
    }

    /**
     * Only calls {@link #createTicket()}
     * @return <tt>null</tt>
     */
    public Object run()
    {
        try
        {
            createTicket();
        }
        catch (final GSSException  ex)
        {
            throw new Error(ex);
        }

        return null;
    }

    /**
     *
     * @throws GSSException
     */
    private void createTicket () throws GSSException
    {
        final GSSManager manager = GSSManager.getInstance();
        final GSSName clientName = manager.createName(userPrincipal, KRB5_PRINCIPAL_NAME_OID);
        final GSSCredential clientCred = manager.createCredential(clientName,
                8 * 3600,
                KERB_V5_OID,
                GSSCredential.INITIATE_ONLY);

        final GSSName serverName = manager.createName(applicationPrincipal, KRB5_PRINCIPAL_NAME_OID);

        final GSSContext context = manager.createContext(serverName,
                KERB_V5_OID,
                clientCred,
                GSSContext.DEFAULT_LIFETIME);
        context.requestMutualAuth(true);
        context.requestConf(false);
        context.requestInteg(true);

        final byte[] outToken = context.initSecContext(new byte[0], 0, 0);

        if (outputBuffer !=null)
        {
            outputBuffer.append(String.format("Src Name: %s\n", context.getSrcName()));
            outputBuffer.append(String.format("Target  : %s\n", context.getTargName()));
            outputBuffer.append(new BASE64Encoder().encode(outToken));
            outputBuffer.append("\n");
        }

        context.dispose();
    }
}

/**
 *
 * @param realm p.ex. <tt>MYFIRM.COM</tt>
 * @param kdc p.ex. <tt>kerbserver.myfirm.com</tt>
 * @param applicationPrincipal   cf. {@link #TicketCreatorAction(String, String)}
 * @throws GSSException
 * @throws LoginException
 */
static public String retrieveTicket(
        final String realm,
        final String kdc,
        final String applicationPrincipal)
        throws GSSException, LoginException
{

    // create the jass-config-file
    final File jaasConfFile;
    try
    {
        jaasConfFile = File.createTempFile("jaas.conf", null);
        final PrintStream bos = new PrintStream(new FileOutputStream(jaasConfFile));
        bos.print(String.format(
                "Krb5LoginContext { com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useTicketCache=true debug=true ; };"
        ));
        bos.close();
        jaasConfFile.deleteOnExit();
    }
    catch (final IOException ex)
    {
        throw new IOError(ex);
    }

    // set the properties
    System.setProperty("java.security.krb5.realm", realm);
    System.setProperty("java.security.krb5.kdc", kdc);
    System.setProperty("java.security.auth.login.config",jaasConfFile.getAbsolutePath());

    // get the Subject(), i.e. the current user under Windows
    final Subject subject = new Subject();
    final LoginContext lc = new LoginContext("Krb5LoginContext", subject, new DialogCallbackHandler());
    try {
        lc.login();
    } catch (LoginException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        //e = Client not found in Kerberos database (6) - CLIENT_NOT_FOUND
        System.exit(0);
    }

    // extract our principal
    final Set<Principal> principalSet = subject.getPrincipals();
    if (principalSet.size() != 1)
        throw new AssertionError("No or several principals: " + principalSet);
    final Principal userPrincipal = principalSet.iterator().next();

    // now try to execute the SampleAction as the authenticated Subject
    // action.run() without doAsPrivileged leads to
    //   No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)
    final TicketCreatorAction action = new TicketCreatorAction(userPrincipal.getName(), applicationPrincipal);
    final StringBuffer outputBuffer = new StringBuffer();
    action.setOutputBuffer(outputBuffer);
    Subject.doAsPrivileged(lc.getSubject(), action, null);

    return outputBuffer.toString();
}

public static void main (final String args[]) throws Throwable
 {
    final String ticket = retrieveTicket("EXAMPLE.COM", "EXAMPLE.COM", "HTTP/webserver.myfirm.com");
    System.out.println(ticket);
 }
}

我沒有測試你的代碼,但是閱讀stacktrace我認為問題出在KDC域。 正如文件所說

默認領域和該領域的KDC在Kerberos krb5.conf中指示

通常krb5.conf中的KDC域是kdc fedora默認安裝示例:

[realms]
EXAMPLE.COM = {
kdc = kerberos.example.com
admin_server = kerberos.example.com
}

我似乎很明顯你應該用域名改變你的kdc域,而不是域名:

final String ticket = retrieveTicket("EXAMPLE.COM", "localhost", "HTTP/webserver.myfirm.com");

您在本地計算機上使用Kerberos,您可能希望向krb5.conf添加選項dns_lookup_kdc = false

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM