2008-12-16 11 views
11

Est-ce que quelqu'un sait comment obtenir un ticket de service du Centre de distribution de clés (KDC) en utilisant Java GSS-API? J'ai une application client lourd qui s'authentifie d'abord via JAAS en utilisant Krb5LoginModule pour aller chercher le TGT dans le cache de ticket (background: Windows utilise par exemple une implémentation kerberos et stocke le ticket de ticket dans une zone de mémoire sécurisée). À partir de LoginManager, j'obtiens l'objet Subject qui contient le TGT. Maintenant, j'espérais que lorsque je créerais un objet GSSCredential spécifique pour mon service, le ticket de service serait également mis dans les informations d'identification privées du sujet (j'ai lu quelque part sur le web). J'ai donc essayé ce qui suit:Comment obtenir un ticket de service kerberos via GSS-API?

// Exception handling ommitted 
LoginContext lc = new LoginContext("HelloEjbClient", new DialogCallbackHandler()); 
lc.login() 
Subject.doAs(lc.getSubject(), new PrivilegedAction() { 

    public Object run() { 
     GSSManager manager = GSSManager.getInstance(); 
     GSSName clientName = manager.createName("clientUser", GSSName.NT_USER_NAME); 
     GSSCredential clientCreds = manager.createCredential(clientName, 8 * 3600, createKerberosOid(), GSSCredential.INITIATE_ONLY); 

     GSSName serverName = manager.createName("[email protected]", GSSName.NT_HOSTBASED_SERVICE); 
     manager.createCredential(serverName, GSSCredential.INDEFINITE_LIFETIME, createKerberosOid(), GSSCredential.INITIATE_ONLY); 
     return null; 
    } 

    private Oid createKerberosOid() { 
     return new Oid("1.2.840.113554.1.2.2"); 
    } 

}); 

Malheureusement je reçois une GSSException: Aucune information d'identification valides fournies (niveau du mécanisme: Impossible de trouver Kerberos TGT).

Répondre

14

Ma compréhension de l'obtention du ticket de service était erronée. Je n'ai pas besoin d'obtenir les informations d'identification du service - ce n'est pas possible sur le client, car le client n'a pas vraiment de TGT pour le serveur et n'a donc pas les droits pour obtenir les informations d'identification du service. Ce qui manque ici, c'est de créer un nouveau GSSContext et de l'initialiser. La valeur de retour de cette méthode contient le ticket de service, si j'ai bien compris. Voici un exemple de code de travail. Il doit être exécuté dans un PrivilegedAction au nom d'un sujet connecté:

GSSManager manager = GSSManager.getInstance(); 
    GSSName clientName = manager.createName("clientUser", GSSName.NT_USER_NAME); 
    GSSCredential clientCred = manager.createCredential(clientName, 
                 8 * 3600, 
                 createKerberosOid(), 
                 GSSCredential.INITIATE_ONLY); 

    GSSName serverName = manager.createName("[email protected]", GSSName.NT_HOSTBASED_SERVICE); 

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

    byte[] outToken = context.initSecContext(new byte[0], 0, 0); 
    System.out.println(new BASE64Encoder().encode(outToken)); 
    context.dispose(); 

Le outToken contient contient alors le service vente de billets. Cependant, ce n'est pas la manière dont l'API GSS devait être utilisée. Son but était de cacher ces détails au code, il est donc préférable d'établir un contexte GSS en utilisant l'API GSS des deux côtés. Sinon, vous devriez vraiment savoir ce que vous faites en raison des failles de sécurité potentielles. Pour plus d'informations, lisez le Sun SSO tutorial with kerberos plus attentivement que moi.

EDIT: J'ai juste oublié que j'utilise Windows XP avec SP2. Il y a une nouvelle "fonctionnalité" dans cette version de Windows qui interdit l'utilisation du TGT dans la RAM Windows. Vous devez modifier le registre pour permettre cela. Pour plus d'informations jetez un oeil à la rubrique JGSS Troubleshooting page dans le cas où vous rencontrez un "KrbException: KDC n'a pas de support pour le type de cryptage (14)" comme je l'ai fait.

+0

@Michael: Merci pour votre contribution. Comme vous pouvez le voir, j'ai écrit cela il y a un certain temps, donc je ne me souviens pas des détails exacts, mais je suis à peu près sûr que c'était juste un exemple. Que pensez-vous peut être fait pour améliorer cette réponse? –

+0

vérifiez votre lien vers le tutoriel Sun SSO avec Kerberos et jetez un oeil à la figure 6. Il ya la boucle que j'ai écrit à propos de. –

+0

Je pense que je n'ai pas inclus la boucle car je ne pouvais pas comprendre ce que les méthodes readToken() et sendToken (...) sont supposées faire. –

7

J'ai eu beaucoup de problèmes pour utiliser ce code, mais j'ai au moins une solution. Je le poste ici, peut-être qu'il aidera certains d'entre vous ...

/** 
* 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>[email protected]</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()); 
     lc.login(); 

     // 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("MYFIRM.COM", "kerbserver", "HTTP/webserver.myfirm.com"); 
     System.out.println(ticket); 
    } 
} 
Questions connexes