jdk/test/sun/security/krb5/auto/KDC.java
changeset 4336 4c792c19266e
parent 4168 1a8d21bb898c
child 4531 3a9206343ab2
equal deleted inserted replaced
4335:365eb4449319 4336:4c792c19266e
    61  * settings (except for the <code>writeKtab()</code> method). However, to make
    61  * settings (except for the <code>writeKtab()</code> method). However, to make
    62  * sure nothing ever goes wrong, if you want to make any changes to these
    62  * sure nothing ever goes wrong, if you want to make any changes to these
    63  * settings after calling a KDC method, call <code>Config.refresh()</code> to
    63  * settings after calling a KDC method, call <code>Config.refresh()</code> to
    64  * make sure your changes are reflected in the <code>Config</code> object.
    64  * make sure your changes are reflected in the <code>Config</code> object.
    65  * </ol>
    65  * </ol>
       
    66  * System properties recognized:
       
    67  * <ul>
       
    68  * <li>test.kdc.save.ccache
       
    69  * </ul>
       
    70  * Support policies:
       
    71  * <ul>
       
    72  * <li>ok-as-delegate
       
    73  * </ul>
    66  * Issues and TODOs:
    74  * Issues and TODOs:
    67  * <ol>
    75  * <ol>
    68  * <li> Generates krb5.conf to be used on another machine, currently the kdc is
    76  * <li> Generates krb5.conf to be used on another machine, currently the kdc is
    69  * always localhost
    77  * always localhost
    70  * <li> More options to KDC, say, error output, say, response nonce !=
    78  * <li> More options to KDC, say, error output, say, response nonce !=
   149 
   157 
   150     /**
   158     /**
   151      * A standalone KDC server.
   159      * A standalone KDC server.
   152      */
   160      */
   153     public static void main(String[] args) throws Exception {
   161     public static void main(String[] args) throws Exception {
   154         KDC kdc = create("RABBIT.HOLE", "kdc.rabbit,hole", 0, false);
   162         KDC kdc = create("RABBIT.HOLE", "kdc.rabbit.hole", 0, false);
   155         kdc.addPrincipal("dummy", "bogus".toCharArray());
   163         kdc.addPrincipal("dummy", "bogus".toCharArray());
   156         kdc.addPrincipal("foo", "bar".toCharArray());
   164         kdc.addPrincipal("foo", "bar".toCharArray());
   157         kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE");
   165         kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE");
   158         kdc.addPrincipalRandKey("server/host.rabbit.hole");
   166         kdc.addPrincipalRandKey("server/host.rabbit.hole");
   159         kdc.addPrincipalRandKey("backend/host.rabbit.hole");
   167         kdc.addPrincipalRandKey("backend/host.rabbit.hole");
   424      * @param p principal
   432      * @param p principal
   425      * @return the password
   433      * @return the password
   426      * @throws sun.security.krb5.KrbException when the principal is not inside
   434      * @throws sun.security.krb5.KrbException when the principal is not inside
   427      *         the database.
   435      *         the database.
   428      */
   436      */
   429     private char[] getPassword(PrincipalName p) throws KrbException {
   437     private char[] getPassword(PrincipalName p, boolean server)
       
   438             throws KrbException {
   430         String pn = p.toString();
   439         String pn = p.toString();
   431         if (p.getRealmString() == null) {
   440         if (p.getRealmString() == null) {
   432             pn = pn + "@" + getRealm();
   441             pn = pn + "@" + getRealm();
   433         }
   442         }
   434         char[] pass = passwords.get(pn);
   443         char[] pass = passwords.get(pn);
   435         if (pass == null) {
   444         if (pass == null) {
   436             throw new KrbException(Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
   445             throw new KrbException(server?
       
   446                 Krb5.KDC_ERR_S_PRINCIPAL_UNKNOWN:
       
   447                 Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
   437         }
   448         }
   438         return pass;
   449         return pass;
   439     }
   450     }
   440 
   451 
   441     /**
   452     /**
   455 
   466 
   456     /**
   467     /**
   457      * Returns the key for a given principal of the given encryption type
   468      * Returns the key for a given principal of the given encryption type
   458      * @param p the principal
   469      * @param p the principal
   459      * @param etype the encryption type
   470      * @param etype the encryption type
       
   471      * @param server looking for a server principal?
   460      * @return the key
   472      * @return the key
   461      * @throws sun.security.krb5.KrbException for unknown/unsupported etype
   473      * @throws sun.security.krb5.KrbException for unknown/unsupported etype
   462      */
   474      */
   463     private EncryptionKey keyForUser(PrincipalName p, int etype) throws KrbException {
   475     private EncryptionKey keyForUser(PrincipalName p, int etype, boolean server)
       
   476             throws KrbException {
   464         try {
   477         try {
   465             // Do not call EncryptionKey.acquireSecretKeys(), otherwise
   478             // Do not call EncryptionKey.acquireSecretKeys(), otherwise
   466             // the krb5.conf config file would be loaded.
   479             // the krb5.conf config file would be loaded.
   467             Method stringToKey = EncryptionKey.class.getDeclaredMethod("stringToKey", char[].class, String.class, byte[].class, Integer.TYPE);
   480             Method stringToKey = EncryptionKey.class.getDeclaredMethod("stringToKey", char[].class, String.class, byte[].class, Integer.TYPE);
   468             stringToKey.setAccessible(true);
   481             stringToKey.setAccessible(true);
   469             Integer kvno = null;
   482             Integer kvno = null;
   470             // For service whose password ending with a number, use it as kvno
   483             // For service whose password ending with a number, use it as kvno
   471             if (p.toString().indexOf('/') >= 0) {
   484             if (p.toString().indexOf('/') >= 0) {
   472                 char[] pass = getPassword(p);
   485                 char[] pass = getPassword(p, server);
   473                 if (Character.isDigit(pass[pass.length-1])) {
   486                 if (Character.isDigit(pass[pass.length-1])) {
   474                     kvno = pass[pass.length-1] - '0';
   487                     kvno = pass[pass.length-1] - '0';
   475                 }
   488                 }
   476             }
   489             }
   477             return new EncryptionKey((byte[]) stringToKey.invoke(
   490             return new EncryptionKey((byte[]) stringToKey.invoke(
   478                     null, getPassword(p), getSalt(p), null, etype),
   491                     null, getPassword(p, server), getSalt(p), null, etype),
   479                     etype, kvno);
   492                     etype, kvno);
   480         } catch (InvocationTargetException ex) {
   493         } catch (InvocationTargetException ex) {
   481             KrbException ke = (KrbException)ex.getCause();
   494             KrbException ke = (KrbException)ex.getCause();
   482             throw ke;
   495             throw ke;
       
   496         } catch (KrbException ke) {
       
   497             throw ke;
   483         } catch (Exception e) {
   498         } catch (Exception e) {
   484             throw new RuntimeException(e);  // should not happen
   499             throw new RuntimeException(e);  // should not happen
   485         }
   500         }
   486     }
   501     }
       
   502 
       
   503     private Map<String,String> policies = new HashMap<String,String>();
       
   504 
       
   505     public void setPolicy(String rule, String value) {
       
   506         if (value == null) {
       
   507             policies.remove(rule);
       
   508         } else {
       
   509             policies.put(rule, value);
       
   510         }
       
   511     }
       
   512     /**
       
   513      * If the provided client/server pair matches a rule
       
   514      *
       
   515      * A system property named test.kdc.policy.RULE will be consulted.
       
   516      * If it's unset, returns false. If its value is "", any pair is
       
   517      * matched. Otherwise, it should contains the server name matched.
       
   518      *
       
   519      * TODO: client name is not used currently.
       
   520      *
       
   521      * @param c client name
       
   522      * @param s server name
       
   523      * @param rule rule name
       
   524      * @return if a match is found
       
   525      */
       
   526     private boolean configMatch(String c, String s, String rule) {
       
   527         String policy = policies.get(rule);
       
   528         boolean result = false;
       
   529         if (policy == null) {
       
   530             result = false;
       
   531         } else if (policy.length() == 0) {
       
   532             result = true;
       
   533         } else {
       
   534             String[] names = policy.split("\\s+");
       
   535             for (String name: names) {
       
   536                 if (name.equals(s)) {
       
   537                     result = true;
       
   538                     break;
       
   539                 }
       
   540             }
       
   541         }
       
   542         if (result) {
       
   543             System.out.printf(">>>> Policy match result (%s vs %s on %s) %b\n",
       
   544                     c, s, rule, result);
       
   545         }
       
   546         return result;
       
   547     }
       
   548 
   487 
   549 
   488     /**
   550     /**
   489      * Processes an incoming request and generates a response.
   551      * Processes an incoming request and generates a response.
   490      * @param in the request
   552      * @param in the request
   491      * @return the response
   553      * @return the response
   528                         APReq apReq = new APReq(pa.getValue());
   590                         APReq apReq = new APReq(pa.getValue());
   529                         EncryptedData ed = apReq.authenticator;
   591                         EncryptedData ed = apReq.authenticator;
   530                         tkt = apReq.ticket;
   592                         tkt = apReq.ticket;
   531                         etype = tkt.encPart.getEType();
   593                         etype = tkt.encPart.getEType();
   532                         tkt.sname.setRealm(tkt.realm);
   594                         tkt.sname.setRealm(tkt.realm);
   533                         EncryptionKey kkey = keyForUser(tkt.sname, etype);
   595                         EncryptionKey kkey = keyForUser(tkt.sname, etype, true);
   534                         byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
   596                         byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
   535                         DerInputStream derIn = new DerInputStream(bb);
   597                         DerInputStream derIn = new DerInputStream(bb);
   536                         DerValue der = derIn.getDerValue();
   598                         DerValue der = derIn.getDerValue();
   537                         etp = new EncTicketPart(der.toByteArray());
   599                         etp = new EncTicketPart(der.toByteArray());
   538                     }
   600                     }
   539                 }
   601                 }
   540                 if (tkt == null) {
   602                 if (tkt == null) {
   541                     throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
   603                     throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
   542                 }
   604                 }
   543             }
   605             }
   544             EncryptionKey skey = keyForUser(body.sname, etype);
   606             EncryptionKey skey = keyForUser(body.sname, etype, true);
   545             if (skey == null) {
   607             if (skey == null) {
   546                 throw new KrbException(Krb5.KDC_ERR_SUMTYPE_NOSUPP); // TODO
   608                 throw new KrbException(Krb5.KDC_ERR_SUMTYPE_NOSUPP); // TODO
   547             }
   609             }
   548 
   610 
   549             // Session key for original ticket, TGT
   611             // Session key for original ticket, TGT
   578             if (body.kdcOptions.get(KDCOptions.POSTDATED)) {
   640             if (body.kdcOptions.get(KDCOptions.POSTDATED)) {
   579                 bFlags[Krb5.TKT_OPTS_POSTDATED] = true;
   641                 bFlags[Krb5.TKT_OPTS_POSTDATED] = true;
   580             }
   642             }
   581             if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) {
   643             if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) {
   582                 bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true;
   644                 bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true;
       
   645             }
       
   646 
       
   647             if (configMatch("", body.sname.getNameString(), "ok-as-delegate")) {
       
   648                 bFlags[Krb5.TKT_OPTS_DELEGATE] = true;
   583             }
   649             }
   584             bFlags[Krb5.TKT_OPTS_INITIAL] = true;
   650             bFlags[Krb5.TKT_OPTS_INITIAL] = true;
   585 
   651 
   586             TicketFlags tFlags = new TicketFlags(bFlags);
   652             TicketFlags tFlags = new TicketFlags(bFlags);
   587             EncTicketPart enc = new EncTicketPart(
   653             EncTicketPart enc = new EncTicketPart(
   669             Field f = KDCReqBody.class.getDeclaredField("eType");
   735             Field f = KDCReqBody.class.getDeclaredField("eType");
   670             f.setAccessible(true);
   736             f.setAccessible(true);
   671             eTypes = (int[])f.get(body);
   737             eTypes = (int[])f.get(body);
   672             int eType = eTypes[0];
   738             int eType = eTypes[0];
   673 
   739 
   674             EncryptionKey ckey = keyForUser(body.cname, eType);
   740             EncryptionKey ckey = keyForUser(body.cname, eType, false);
   675             EncryptionKey skey = keyForUser(body.sname, eType);
   741             EncryptionKey skey = keyForUser(body.sname, eType, true);
   676             if (ckey == null) {
   742             if (ckey == null) {
   677                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
   743                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
   678             }
   744             }
   679             if (skey == null) {
   745             if (skey == null) {
   680                 throw new KrbException(Krb5.KDC_ERR_SUMTYPE_NOSUPP); // TODO
   746                 throw new KrbException(Krb5.KDC_ERR_SUMTYPE_NOSUPP); // TODO