提交 cdf11def 编写于 作者: A andrew

8044500: Add kinit options and krb5.conf flags that allow users to obtain...

8044500: Add kinit options and krb5.conf flags that allow users to obtain renewable tickets and specify ticket lifetimes
Reviewed-by: mbalao
上级 2441b8c1
...@@ -30,22 +30,20 @@ ...@@ -30,22 +30,20 @@
*/ */
package sun.security.krb5; package sun.security.krb5;
import java.io.File; import java.io.*;
import java.io.FileInputStream;
import java.util.Hashtable;
import java.util.Vector;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sun.net.dns.ResolverConfiguration; import sun.net.dns.ResolverConfiguration;
import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.crypto.EType;
import sun.security.krb5.internal.Krb5; import sun.security.krb5.internal.Krb5;
...@@ -349,6 +347,72 @@ public class Config { ...@@ -349,6 +347,72 @@ public class Config {
} }
} }
/**
* Translates a duration value into seconds.
*
* The format can be one of "h:m[:s]", "NdNhNmNs", and "N". See
* http://web.mit.edu/kerberos/krb5-devel/doc/basic/date_format.html#duration
* for definitions.
*
* @param s the string duration
* @return time in seconds
* @throw KrbException if format is illegal
*/
public static int duration(String s) throws KrbException {
if (s.isEmpty()) {
throw new KrbException("Duration cannot be empty");
}
// N
if (s.matches("\\d+")) {
return Integer.parseInt(s);
}
// h:m[:s]
Matcher m = Pattern.compile("(\\d+):(\\d+)(:(\\d+))?").matcher(s);
if (m.matches()) {
int hr = Integer.parseInt(m.group(1));
int min = Integer.parseInt(m.group(2));
if (min >= 60) {
throw new KrbException("Illegal duration format " + s);
}
int result = hr * 3600 + min * 60;
if (m.group(4) != null) {
int sec = Integer.parseInt(m.group(4));
if (sec >= 60) {
throw new KrbException("Illegal duration format " + s);
}
result += sec;
}
return result;
}
// NdNhNmNs
// 120m allowed. Maybe 1h120m is not good, but still allowed
m = Pattern.compile(
"((\\d+)d)?\\s*((\\d+)h)?\\s*((\\d+)m)?\\s*((\\d+)s)?",
Pattern.CASE_INSENSITIVE).matcher(s);
if (m.matches()) {
int result = 0;
if (m.group(2) != null) {
result += 86400 * Integer.parseInt(m.group(2));
}
if (m.group(4) != null) {
result += 3600 * Integer.parseInt(m.group(4));
}
if (m.group(6) != null) {
result += 60 * Integer.parseInt(m.group(6));
}
if (m.group(8) != null) {
result += Integer.parseInt(m.group(8));
}
return result;
}
throw new KrbException("Illegal duration format " + s);
}
/** /**
* Gets the int value for the specified keys. * Gets the int value for the specified keys.
* @param keys the keys * @param keys the keys
......
...@@ -531,4 +531,23 @@ public class Credentials { ...@@ -531,4 +531,23 @@ public class Credentials {
return buffer.toString(); return buffer.toString();
} }
public sun.security.krb5.internal.ccache.Credentials toCCacheCreds() {
return new sun.security.krb5.internal.ccache.Credentials(
getClient(), getServer(),
getSessionKey(),
date2kt(getAuthTime()),
date2kt(getStartTime()),
date2kt(getEndTime()),
date2kt(getRenewTill()),
false,
flags,
new HostAddresses(getClientAddresses()),
getAuthzData(),
getTicket(),
null);
}
private static KerberosTime date2kt(Date d) {
return d == null ? null : new KerberosTime(d);
}
} }
...@@ -35,6 +35,7 @@ import sun.security.krb5.internal.*; ...@@ -35,6 +35,7 @@ import sun.security.krb5.internal.*;
import sun.security.krb5.internal.crypto.Nonce; import sun.security.krb5.internal.crypto.Nonce;
import sun.security.krb5.internal.crypto.KeyUsage; import sun.security.krb5.internal.crypto.KeyUsage;
import java.io.IOException; import java.io.IOException;
import java.time.Instant;
import java.util.Arrays; import java.util.Arrays;
/** /**
...@@ -66,7 +67,6 @@ public class KrbAsReq { ...@@ -66,7 +67,6 @@ public class KrbAsReq {
if (options == null) { if (options == null) {
options = new KDCOptions(); options = new KDCOptions();
} }
// check if they are valid arguments. The optional fields should be // check if they are valid arguments. The optional fields should be
// consistent with settings in KDCOptions. Mar 17 2000 // consistent with settings in KDCOptions. Mar 17 2000
if (options.get(KDCOptions.FORWARDED) || if (options.get(KDCOptions.FORWARDED) ||
...@@ -84,12 +84,6 @@ public class KrbAsReq { ...@@ -84,12 +84,6 @@ public class KrbAsReq {
} else { } else {
if (from != null) from = null; if (from != null) from = null;
} }
if (options.get(KDCOptions.RENEWABLE)) {
// if (rtime == null)
// throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
} else {
if (rtime != null) rtime = null;
}
PAData[] paData = null; PAData[] paData = null;
if (pakey != null) { if (pakey != null) {
...@@ -120,8 +114,10 @@ public class KrbAsReq { ...@@ -120,8 +114,10 @@ public class KrbAsReq {
System.out.println(">>> KrbAsReq creating message"); System.out.println(">>> KrbAsReq creating message");
} }
Config cfg = Config.getInstance();
// check to use addresses in tickets // check to use addresses in tickets
if (addresses == null && Config.getInstance().useAddresses()) { if (addresses == null && cfg.useAddresses()) {
addresses = HostAddresses.getLocalAddresses(); addresses = HostAddresses.getLocalAddresses();
} }
...@@ -131,8 +127,27 @@ public class KrbAsReq { ...@@ -131,8 +127,27 @@ public class KrbAsReq {
} }
if (till == null) { if (till == null) {
String d = cfg.get("libdefaults", "ticket_lifetime");
if (d != null) {
till = new KerberosTime(Instant.now().plusSeconds(Config.duration(d)));
} else {
till = new KerberosTime(0); // Choose KDC maximum allowed till = new KerberosTime(0); // Choose KDC maximum allowed
} }
}
if (rtime == null) {
String d = cfg.get("libdefaults", "renew_lifetime");
if (d != null) {
rtime = new KerberosTime(Instant.now().plusSeconds(Config.duration(d)));
}
}
if (rtime != null) {
options.set(KDCOptions.RENEWABLE, true);
if (till.greaterThan(rtime)) {
rtime = till;
}
}
// enc-authorization-data and additional-tickets never in AS-REQ // enc-authorization-data and additional-tickets never in AS-REQ
KDCReqBody kdc_req_body = new KDCReqBody(options, KDCReqBody kdc_req_body = new KDCReqBody(options,
......
...@@ -224,6 +224,16 @@ public final class KrbAsReqBuilder { ...@@ -224,6 +224,16 @@ public final class KrbAsReqBuilder {
this.options = options; this.options = options;
} }
public void setTill(KerberosTime till) {
checkState(State.INIT, "Cannot specify till");
this.till = till;
}
public void setRTime(KerberosTime rtime) {
checkState(State.INIT, "Cannot specify rtime");
this.rtime = rtime;
}
/** /**
* Sets or clears target. If cleared, KrbAsReq might choose krbtgt * Sets or clears target. If cleared, KrbAsReq might choose krbtgt
* for cname realm * for cname realm
......
...@@ -100,21 +100,24 @@ abstract class KrbKdcRep { ...@@ -100,21 +100,24 @@ abstract class KrbKdcRep {
!rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) { !rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) {
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
} }
if ((req.reqBody.from == null) || req.reqBody.from.isZero())
if ((req.reqBody.from == null) || req.reqBody.from.isZero()) {
// verify this is allowed // verify this is allowed
if ((rep.encKDCRepPart.starttime != null) && if ((rep.encKDCRepPart.starttime != null) &&
!rep.encKDCRepPart.starttime.inClockSkew()) { !rep.encKDCRepPart.starttime.inClockSkew()) {
rep.encKDCRepPart.key.destroy(); rep.encKDCRepPart.key.destroy();
throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
} }
}
if ((req.reqBody.from != null) && !req.reqBody.from.isZero()) if ((req.reqBody.from != null) && !req.reqBody.from.isZero()) {
// verify this is allowed // verify this is allowed
if ((rep.encKDCRepPart.starttime != null) && if ((rep.encKDCRepPart.starttime != null) &&
!req.reqBody.from.equals(rep.encKDCRepPart.starttime)) { !req.reqBody.from.equals(rep.encKDCRepPart.starttime)) {
rep.encKDCRepPart.key.destroy(); rep.encKDCRepPart.key.destroy();
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
} }
}
if (!req.reqBody.till.isZero() && if (!req.reqBody.till.isZero() &&
rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) { rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) {
...@@ -164,8 +167,8 @@ abstract class KrbKdcRep { ...@@ -164,8 +167,8 @@ abstract class KrbKdcRep {
} }
} }
if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) {
if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) {
// verify this is required // verify this is required
if ((rep.encKDCRepPart.renewTill == null) || if ((rep.encKDCRepPart.renewTill == null) ||
rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime) rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime)
...@@ -174,17 +177,7 @@ abstract class KrbKdcRep { ...@@ -174,17 +177,7 @@ abstract class KrbKdcRep {
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
} }
if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE_OK) &&
rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE))
if (!req.reqBody.till.isZero())
// verify this is required
if ((rep.encKDCRepPart.renewTill == null) ||
rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.till)
) {
rep.encKDCRepPart.key.destroy();
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
} }
} }
}
} }
...@@ -250,6 +250,10 @@ public class HostAddresses implements Cloneable { ...@@ -250,6 +250,10 @@ public class HostAddresses implements Cloneable {
*/ */
public void writeAddrs(CCacheOutputStream cos) throws IOException { public void writeAddrs(CCacheOutputStream cos) throws IOException {
if (addresses == null || addresses.length == 0) {
cos.write32(0);
return;
}
cos.write32(addresses.length); cos.write32(addresses.length);
for (int i = 0; i < addresses.length; i++) { for (int i = 0; i < addresses.length; i++) {
cos.write16(addresses[i].addrType); cos.write16(addresses[i].addrType);
......
...@@ -38,6 +38,7 @@ import sun.security.util.DerOutputStream; ...@@ -38,6 +38,7 @@ import sun.security.util.DerOutputStream;
import sun.security.util.DerValue; import sun.security.util.DerValue;
import java.io.IOException; import java.io.IOException;
import java.time.Instant;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.TimeZone; import java.util.TimeZone;
...@@ -128,6 +129,14 @@ public class KerberosTime { ...@@ -128,6 +129,14 @@ public class KerberosTime {
this(time.getTime(), 0); this(time.getTime(), 0);
} }
/**
* Creates a KerberosTime object from an Instant object
*/
public KerberosTime(Instant instant) {
this(instant.getEpochSecond()*1000 + instant.getNano()/1000000L,
instant.getNano()/1000%1000);
}
/** /**
* Creates a KerberosTime object for now. It uses System.nanoTime() * Creates a KerberosTime object for now. It uses System.nanoTime()
* to get a more precise time than "new Date()". * to get a more precise time than "new Date()".
......
...@@ -36,7 +36,6 @@ import sun.security.krb5.internal.*; ...@@ -36,7 +36,6 @@ import sun.security.krb5.internal.*;
import sun.security.krb5.internal.ccache.*; import sun.security.krb5.internal.ccache.*;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import javax.security.auth.kerberos.KerberosPrincipal;
import sun.security.util.Password; import sun.security.util.Password;
import javax.security.auth.kerberos.KeyTab; import javax.security.auth.kerberos.KeyTab;
...@@ -53,22 +52,9 @@ public class Kinit { ...@@ -53,22 +52,9 @@ public class Kinit {
/** /**
* The main method is used to accept user command line input for ticket * The main method is used to accept user command line input for ticket
* request. * request. Read {@link KinitOptions#printHelp} for usages or call
* <p> * java sun.security.krb5.internal.tools.Kinit -help
* Usage: kinit [-A] [-f] [-p] [-c cachename] [[-k [-t keytab_file_name]] * to bring up help menu.
* [principal] [password]
* <ul>
* <li> -A do not include addresses
* <li> -f forwardable
* <li> -p proxiable
* <li> -c cache name (i.e., FILE://c:\temp\mykrb5cc)
* <li> -k use keytab
* <li> -t keytab file name
* <li> principal the principal name (i.e., duke@java.sun.com)
* <li> password the principal's Kerberos password
* </ul>
* <p>
* Use java sun.security.krb5.tools.Kinit -help to bring up help menu.
* <p> * <p>
* We currently support only file-based credentials cache to * We currently support only file-based credentials cache to
* store the tickets obtained from the KDC. * store the tickets obtained from the KDC.
...@@ -146,6 +132,49 @@ public class Kinit { ...@@ -146,6 +132,49 @@ public class Kinit {
} else { } else {
options = new KinitOptions(args); options = new KinitOptions(args);
} }
switch (options.action) {
case 1:
acquire();
break;
case 2:
renew();
break;
default:
throw new KrbException("kinit does not support action "
+ options.action);
}
}
private void renew()
throws IOException, RealmException, KrbException {
PrincipalName principal = options.getPrincipal();
String realm = principal.getRealmAsString();
CredentialsCache cache = CredentialsCache.getInstance(options.cachename);
if (cache == null) {
throw new IOException("Unable to find existing cache file " +
options.cachename);
}
sun.security.krb5.internal.ccache.Credentials credentials =
cache.getCreds(PrincipalName.tgsService(realm, realm));
credentials = credentials.setKrbCreds()
.renew()
.toCCacheCreds();
cache = CredentialsCache.create(principal, options.cachename);
if (cache == null) {
throw new IOException("Unable to create the cache file " +
options.cachename);
}
cache.update(credentials);
cache.save();
}
private void acquire()
throws IOException, RealmException, KrbException {
String princName = null; String princName = null;
PrincipalName principal = options.getPrincipal(); PrincipalName principal = options.getPrincipal();
if (principal != null) { if (principal != null) {
...@@ -216,6 +245,9 @@ public class Kinit { ...@@ -216,6 +245,9 @@ public class Kinit {
if (options.getAddressOption()) if (options.getAddressOption())
builder.setAddresses(HostAddresses.getLocalAddresses()); builder.setAddresses(HostAddresses.getLocalAddresses());
builder.setTill(options.lifetime);
builder.setRTime(options.renewable_lifetime);
builder.action(); builder.action();
sun.security.krb5.internal.ccache.Credentials credentials = sun.security.krb5.internal.ccache.Credentials credentials =
......
...@@ -33,12 +33,8 @@ package sun.security.krb5.internal.tools; ...@@ -33,12 +33,8 @@ package sun.security.krb5.internal.tools;
import sun.security.krb5.*; import sun.security.krb5.*;
import sun.security.krb5.internal.*; import sun.security.krb5.internal.*;
import sun.security.krb5.internal.ccache.*; import sun.security.krb5.internal.ccache.*;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.StringTokenizer; import java.time.Instant;
import java.util.Vector;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream; import java.io.FileInputStream;
/** /**
...@@ -49,14 +45,15 @@ import java.io.FileInputStream; ...@@ -49,14 +45,15 @@ import java.io.FileInputStream;
* @author Ram Marti * @author Ram Marti
*/ */
class KinitOptions { class KinitOptions {
public boolean validate = false;
// 1. acquire, 2. renew, 3. validate
public int action = 1;
// forwardable and proxiable flags have two states: // forwardable and proxiable flags have two states:
// -1 - flag set to be not forwardable or proxiable; // -1 - flag set to be not forwardable or proxiable;
// 1 - flag set to be forwardable or proxiable. // 1 - flag set to be forwardable or proxiable.
public short forwardable = -1; public short forwardable = 0;
public short proxiable = -1; public short proxiable = 0;
public boolean renew = false;
public KerberosTime lifetime; public KerberosTime lifetime;
public KerberosTime renewable_lifetime; public KerberosTime renewable_lifetime;
public String target_service; public String target_service;
...@@ -134,6 +131,12 @@ class KinitOptions { ...@@ -134,6 +131,12 @@ class KinitOptions {
} }
useKeytab = true; useKeytab = true;
} else if (args[i].equals("-R")) {
action = 2;
} else if (args[i].equals("-l")) {
lifetime = getTime(Config.duration(args[++i]));
} else if (args[i].equals("-r")) {
renewable_lifetime = getTime(Config.duration(args[++i]));
} else if (args[i].equalsIgnoreCase("-help")) { } else if (args[i].equalsIgnoreCase("-help")) {
printHelp(); printHelp();
System.exit(0); System.exit(0);
...@@ -223,23 +226,28 @@ class KinitOptions { ...@@ -223,23 +226,28 @@ class KinitOptions {
void printHelp() { void printHelp() {
System.out.println("Usage: kinit " + System.out.println("Usage:\n\n1. Initial ticket request:\n" +
"[-A] [-f] [-p] [-c cachename] " + " kinit [-A] [-f] [-p] [-c cachename] " +
"[[-k [-t keytab_file_name]] [principal] " + "[-l lifetime] [-r renewable_time]\n" +
" [[-k [-t keytab_file_name]] [principal] " +
"[password]"); "[password]");
System.out.println("\tavailable options to " + System.out.println("2. Renew a ticket:\n" +
" kinit -R [-c cachename] [principal]");
System.out.println("\nAvailable options to " +
"Kerberos 5 ticket request:"); "Kerberos 5 ticket request:");
System.out.println("\t -A do not include addresses"); System.out.println("\t-A do not include addresses");
System.out.println("\t -f forwardable"); System.out.println("\t-f forwardable");
System.out.println("\t -p proxiable"); System.out.println("\t-p proxiable");
System.out.println("\t -c cache name " + System.out.println("\t-c cache name " +
"(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)"); "(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)");
System.out.println("\t -k use keytab"); System.out.println("\t-l lifetime");
System.out.println("\t -t keytab file name"); System.out.println("\t-r renewable time " +
System.out.println("\t principal the principal name "+ "(total lifetime a ticket can be renewed)");
System.out.println("\t-k use keytab");
System.out.println("\t-t keytab file name");
System.out.println("\tprincipal the principal name "+
"(i.e., qweadf@ATHENA.MIT.EDU qweadf)"); "(i.e., qweadf@ATHENA.MIT.EDU qweadf)");
System.out.println("\t password " + System.out.println("\tpassword the principal's Kerberos password");
"the principal's Kerberos password");
} }
public boolean getAddressOption() { public boolean getAddressOption() {
...@@ -257,4 +265,8 @@ class KinitOptions { ...@@ -257,4 +265,8 @@ class KinitOptions {
public PrincipalName getPrincipal() { public PrincipalName getPrincipal() {
return principal; return principal;
} }
private KerberosTime getTime(int s) {
return new KerberosTime(Instant.now().plusSeconds(s));
}
} }
...@@ -40,6 +40,7 @@ import sun.net.spi.nameservice.NameServiceDescriptor; ...@@ -40,6 +40,7 @@ import sun.net.spi.nameservice.NameServiceDescriptor;
import sun.security.krb5.*; import sun.security.krb5.*;
import sun.security.krb5.internal.*; import sun.security.krb5.internal.*;
import sun.security.krb5.internal.ccache.CredentialsCache; import sun.security.krb5.internal.ccache.CredentialsCache;
import sun.security.krb5.internal.crypto.EType;
import sun.security.krb5.internal.crypto.KeyUsage; import sun.security.krb5.internal.crypto.KeyUsage;
import sun.security.krb5.internal.ktab.KeyTab; import sun.security.krb5.internal.ktab.KeyTab;
import sun.security.util.DerInputStream; import sun.security.util.DerInputStream;
...@@ -127,11 +128,11 @@ import java.util.regex.Pattern; ...@@ -127,11 +128,11 @@ import java.util.regex.Pattern;
*/ */
public class KDC { public class KDC {
// Under the hood.
public static final int DEFAULT_LIFETIME = 39600; public static final int DEFAULT_LIFETIME = 39600;
public static final int DEFAULT_RENEWTIME = 86400; public static final int DEFAULT_RENEWTIME = 86400;
// Under the hood.
// The random generator to generate random keys (including session keys) // The random generator to generate random keys (including session keys)
private static SecureRandom secureRandom = new SecureRandom(); private static SecureRandom secureRandom = new SecureRandom();
...@@ -242,7 +243,8 @@ public class KDC { ...@@ -242,7 +243,8 @@ public class KDC {
* A standalone KDC server. * A standalone KDC server.
*/ */
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
KDC kdc = create("RABBIT.HOLE", "kdc.rabbit.hole", 0, false); int port = args.length > 0 ? Integer.parseInt(args[0]) : 0;
KDC kdc = create("RABBIT.HOLE", "kdc.rabbit.hole", port, false);
kdc.addPrincipal("dummy", "bogus".toCharArray()); kdc.addPrincipal("dummy", "bogus".toCharArray());
kdc.addPrincipal("foo", "bar".toCharArray()); kdc.addPrincipal("foo", "bar".toCharArray());
kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE"); kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE");
...@@ -830,10 +832,16 @@ public class KDC { ...@@ -830,10 +832,16 @@ public class KDC {
// Check time, TODO // Check time, TODO
KerberosTime till = body.till; KerberosTime till = body.till;
KerberosTime rtime = body.rtime;
if (till == null) { if (till == null) {
throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO
} else if (till.isZero()) { } else if (till.isZero()) {
till = new KerberosTime(new Date().getTime() + 1000 * 3600 * 11); till = new KerberosTime(
new Date().getTime() + 1000 * DEFAULT_LIFETIME);
}
if (rtime == null && body.kdcOptions.get(KDCOptions.RENEWABLE)) {
rtime = new KerberosTime(
new Date().getTime() + 1000 * DEFAULT_RENEWTIME);
} }
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
...@@ -939,7 +947,7 @@ public class KDC { ...@@ -939,7 +947,7 @@ public class KDC {
tFlags, tFlags,
new KerberosTime(new Date()), new KerberosTime(new Date()),
body.from, body.from,
till, body.rtime, till, rtime,
service, service,
body.addresses != null // always set caddr body.addresses != null // always set caddr
? body.addresses ? body.addresses
...@@ -1008,6 +1016,14 @@ public class KDC { ...@@ -1008,6 +1016,14 @@ public class KDC {
eTypes = KDCReqBodyDotEType(body); eTypes = KDCReqBodyDotEType(body);
int eType = eTypes[0]; int eType = eTypes[0];
// Maybe server does not support aes256, but a kinit does
if (!EType.isSupported(eType)) {
if (eTypes.length < 2) {
throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
}
eType = eTypes[1];
}
if (body.kdcOptions.get(KDCOptions.CANONICALIZE) && if (body.kdcOptions.get(KDCOptions.CANONICALIZE) &&
body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) { body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
PrincipalName principal = alias2Principals.get( PrincipalName principal = alias2Principals.get(
......
...@@ -40,7 +40,7 @@ public class LifeTimeInSeconds { ...@@ -40,7 +40,7 @@ public class LifeTimeInSeconds {
int time = cred.getRemainingLifetime(); int time = cred.getRemainingLifetime();
int time2 = cred.getRemainingInitLifetime(null); int time2 = cred.getRemainingInitLifetime(null);
// The test KDC issues a TGT with a default lifetime of 11 hours // The test KDC issues a TGT with a default lifetime of 11 hours
int elevenhrs = 11*3600; int elevenhrs = KDC.DEFAULT_LIFETIME;
if (time > elevenhrs+60 || time < elevenhrs-60) { if (time > elevenhrs+60 || time < elevenhrs-60) {
throw new Exception("getRemainingLifetime returns wrong value."); throw new Exception("getRemainingLifetime returns wrong value.");
} }
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8044500
* @summary Add kinit options and krb5.conf flags that allow users to
* obtain renewable tickets and specify ticket lifetimes
* @library ../../../../java/security/testlibrary/
* @compile -XDignore.symbol.file Renewal.java
* @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Renewal
*/
import sun.security.jgss.GSSUtil;
import sun.security.krb5.Config;
import sun.security.krb5.internal.ccache.Credentials;
import sun.security.krb5.internal.ccache.FileCredentialsCache;
import javax.security.auth.kerberos.KerberosTicket;
import java.util.Date;
import java.util.Random;
import java.util.Set;
// The basic krb5 test skeleton you can copy from
public class Renewal {
static OneKDC kdc;
static String clazz = "sun.security.krb5.internal.tools.Kinit";
public static void main(String[] args) throws Exception {
kdc = new OneKDC(null);
kdc.writeJAASConf();
kdc.setOption(KDC.Option.PREAUTH_REQUIRED, false);
checkLogin(null, null, KDC.DEFAULT_LIFETIME, -1);
checkLogin("1h", null, 3600, -1);
checkLogin(null, "2d", KDC.DEFAULT_LIFETIME, 86400*2);
checkLogin("1h", "10h", 3600, 36000);
// When rtime is before till, use till as rtime
checkLogin("10h", "1h", 36000, 36000);
try {
Class.forName(clazz);
} catch (ClassNotFoundException cnfe) {
return;
}
checkKinit(null, null, null, null, KDC.DEFAULT_LIFETIME, -1);
checkKinit("1h", "10h", null, null, 3600, 36000);
checkKinit(null, null, "30m", "5h", 1800, 18000);
checkKinit("1h", "10h", "30m", "5h", 1800, 18000);
checkKinitRenew();
}
static int count = 0;
static void checkKinit(
String s1, // ticket_lifetime in krb5.conf, null if none
String s2, // renew_lifetime in krb5.conf, null if none
String c1, // -l on kinit, null if none
String c2, // -r on kinit, null if none
int t1, int t2 // expected lifetimes, -1 of unexpected
) throws Exception {
KDC.saveConfig(OneKDC.KRB5_CONF, kdc,
s1 != null ? ("ticket_lifetime = " + s1) : "",
s2 != null ? ("renew_lifetime = " + s2) : "");
Proc p = Proc.create(clazz);
if (c1 != null) {
p.args("-l", c1);
}
if (c2 != null) {
p.args("-r", c2);
}
count++;
p.args(OneKDC.USER, new String(OneKDC.PASS))
.inheritIO()
.prop("sun.net.spi.nameservice.provider.1", "ns,mock")
.prop("java.security.krb5.conf", OneKDC.KRB5_CONF)
.env("KRB5CCNAME", "ccache" + count)
.start();
if (p.waitFor() != 0) {
throw new Exception();
}
FileCredentialsCache fcc =
FileCredentialsCache.acquireInstance(null, "ccache" + count);
Credentials cred = fcc.getDefaultCreds();
checkRough(cred.getEndTime().toDate(), t1);
if (cred.getRenewTill() == null) {
checkRough(null, t2);
} else {
checkRough(cred.getRenewTill().toDate(), t2);
}
}
static void checkKinitRenew() throws Exception {
Proc p = Proc.create(clazz)
.args("-R")
.inheritIO()
.prop("sun.net.spi.nameservice.provider.1", "ns,mock")
.prop("java.security.krb5.conf", OneKDC.KRB5_CONF)
.env("KRB5CCNAME", "ccache" + count)
.start();
if (p.waitFor() != 0) {
throw new Exception();
}
}
static void checkLogin(
String s1, // ticket_lifetime in krb5.conf, null if none
String s2, // renew_lifetime in krb5.conf, null if none
int t1, int t2 // expected lifetimes, -1 of unexpected
) throws Exception {
KDC.saveConfig(OneKDC.KRB5_CONF, kdc,
s1 != null ? ("ticket_lifetime = " + s1) : "",
s2 != null ? ("renew_lifetime = " + s2) : "");
Config.refresh();
Context c;
c = Context.fromJAAS("client");
Set<KerberosTicket> tickets =
c.s().getPrivateCredentials(KerberosTicket.class);
if (tickets.size() != 1) {
throw new Exception();
}
KerberosTicket ticket = tickets.iterator().next();
checkRough(ticket.getEndTime(), t1);
checkRough(ticket.getRenewTill(), t2);
}
static void checkRough(Date t, int duration) throws Exception {
Date now = new Date();
if (t == null && duration == -1) {
return;
}
long change = (t.getTime() - System.currentTimeMillis()) / 1000;
if (change > duration + 20 || change < duration - 20) {
throw new Exception(t + " is not " + duration);
}
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8044500
* @summary Add kinit options and krb5.conf flags that allow users to
* obtain renewable tickets and specify ticket lifetimes
* @compile -XDignore.symbol.file Duration.java
* @run main Duration
*/
import sun.security.krb5.Config;
import sun.security.krb5.KrbException;
public class Duration {
public static void main(String[] args) throws Exception {
check("123", 123);
check("1:1", 3660);
check("1:1:1", 3661);
check("1d", 86400);
check("1h", 3600);
check("1h1m", 3660);
check("1h 1m", 3660);
check("1d 1h 1m 1s", 90061);
check("1d1h1m1s", 90061);
check("", -1);
check("abc", -1);
check("1ms", -1);
check("1d1d", -1);
check("1h1d", -1);
check("x1h", -1);
check("1h x 1m", -1);
check(":", -1);
check("1:60", -1);
check("1:1:1:1", -1);
check("1:1:1:", -1);
}
static void check(String s, int ex) throws Exception {
System.out.print("\u001b[1;37;41m" +s + " " + ex);
System.out.print("\u001b[m\n");
try {
int result = Config.duration(s);
if (result != ex) throw new Exception("for " + s + " is " + result);
} catch (KrbException ke) {
ke.printStackTrace();
if (ex != -1) throw new Exception();
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册