mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-09 09:58:43 +00:00
8044500: Add kinit options and krb5.conf flags that allow users to obtain renewable tickets and specify ticket lifetimes
Reviewed-by: valeriep
This commit is contained in:
parent
77e5c6eadf
commit
26099e744a
@ -30,19 +30,19 @@
|
||||
*/
|
||||
package sun.security.krb5;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilePermission;
|
||||
import java.io.*;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Path;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import sun.net.dns.ResolverConfiguration;
|
||||
import sun.security.krb5.internal.crypto.EType;
|
||||
@ -314,6 +314,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.
|
||||
* @param keys the keys
|
||||
|
||||
@ -527,4 +527,23 @@ public class Credentials {
|
||||
return sb.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.*;
|
||||
import sun.security.krb5.internal.crypto.Nonce;
|
||||
import sun.security.krb5.internal.crypto.KeyUsage;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* This class encapsulates the KRB-AS-REQ message that the client
|
||||
@ -64,7 +65,6 @@ public class KrbAsReq {
|
||||
if (options == null) {
|
||||
options = new KDCOptions();
|
||||
}
|
||||
|
||||
// check if they are valid arguments. The optional fields should be
|
||||
// consistent with settings in KDCOptions. Mar 17 2000
|
||||
if (options.get(KDCOptions.FORWARDED) ||
|
||||
@ -82,12 +82,6 @@ public class KrbAsReq {
|
||||
} else {
|
||||
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;
|
||||
if (pakey != null) {
|
||||
@ -109,8 +103,10 @@ public class KrbAsReq {
|
||||
System.out.println(">>> KrbAsReq creating message");
|
||||
}
|
||||
|
||||
Config cfg = Config.getInstance();
|
||||
|
||||
// check to use addresses in tickets
|
||||
if (addresses == null && Config.getInstance().useAddresses()) {
|
||||
if (addresses == null && cfg.useAddresses()) {
|
||||
addresses = HostAddresses.getLocalAddresses();
|
||||
}
|
||||
|
||||
@ -120,7 +116,26 @@ public class KrbAsReq {
|
||||
}
|
||||
|
||||
if (till == null) {
|
||||
till = new KerberosTime(0); // Choose KDC maximum allowed
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -224,6 +224,16 @@ public final class KrbAsReqBuilder {
|
||||
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
|
||||
* for cname realm
|
||||
|
||||
@ -80,49 +80,41 @@ abstract class KrbKdcRep {
|
||||
rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) {
|
||||
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
|
||||
if ((rep.encKDCRepPart.starttime != null) &&
|
||||
!rep.encKDCRepPart.starttime.inClockSkew()) {
|
||||
!rep.encKDCRepPart.starttime.inClockSkew()) {
|
||||
rep.encKDCRepPart.key.destroy();
|
||||
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
|
||||
if ((rep.encKDCRepPart.starttime != null) &&
|
||||
!req.reqBody.from.equals(rep.encKDCRepPart.starttime)) {
|
||||
!req.reqBody.from.equals(rep.encKDCRepPart.starttime)) {
|
||||
rep.encKDCRepPart.key.destroy();
|
||||
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
if (!req.reqBody.till.isZero() &&
|
||||
rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) {
|
||||
rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) {
|
||||
rep.encKDCRepPart.key.destroy();
|
||||
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
|
||||
}
|
||||
|
||||
if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE))
|
||||
if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero())
|
||||
// verify this is required
|
||||
if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) {
|
||||
if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) {
|
||||
// verify this is required
|
||||
if ((rep.encKDCRepPart.renewTill == null) ||
|
||||
rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime)
|
||||
) {
|
||||
rep.encKDCRepPart.key.destroy();
|
||||
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.renewTill.greaterThan(req.reqBody.rtime)
|
||||
) {
|
||||
rep.encKDCRepPart.key.destroy();
|
||||
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@ import sun.security.krb5.internal.*;
|
||||
import sun.security.krb5.internal.crypto.*;
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class encapsulates a Kerberos TGS-REQ that is sent from the
|
||||
|
||||
@ -250,6 +250,10 @@ public class HostAddresses implements Cloneable {
|
||||
*/
|
||||
|
||||
public void writeAddrs(CCacheOutputStream cos) throws IOException {
|
||||
if (addresses == null || addresses.length == 0) {
|
||||
cos.write32(0);
|
||||
return;
|
||||
}
|
||||
cos.write32(addresses.length);
|
||||
for (int i = 0; i < addresses.length; i++) {
|
||||
cos.write16(addresses[i].addrType);
|
||||
|
||||
@ -38,6 +38,7 @@ import sun.security.util.DerOutputStream;
|
||||
import sun.security.util.DerValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
@ -128,6 +129,14 @@ public class KerberosTime {
|
||||
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()
|
||||
* to get a more precise time than "new Date()".
|
||||
|
||||
@ -36,7 +36,6 @@ import sun.security.krb5.internal.*;
|
||||
import sun.security.krb5.internal.ccache.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import sun.security.util.Password;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
|
||||
@ -53,22 +52,9 @@ public class Kinit {
|
||||
|
||||
/**
|
||||
* The main method is used to accept user command line input for ticket
|
||||
* request.
|
||||
* <p>
|
||||
* Usage: kinit [-A] [-f] [-p] [-c cachename] [[-k [-t keytab_file_name]]
|
||||
* [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.
|
||||
* request. Read {@link KinitOptions#printHelp} for usages or call
|
||||
* java sun.security.krb5.internal.tools.Kinit -help
|
||||
* to bring up help menu.
|
||||
* <p>
|
||||
* We currently support only file-based credentials cache to
|
||||
* store the tickets obtained from the KDC.
|
||||
@ -146,6 +132,49 @@ public class Kinit {
|
||||
} else {
|
||||
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;
|
||||
PrincipalName principal = options.getPrincipal();
|
||||
if (principal != null) {
|
||||
@ -216,6 +245,9 @@ public class Kinit {
|
||||
if (options.getAddressOption())
|
||||
builder.setAddresses(HostAddresses.getLocalAddresses());
|
||||
|
||||
builder.setTill(options.lifetime);
|
||||
builder.setRTime(options.renewable_lifetime);
|
||||
|
||||
builder.action();
|
||||
|
||||
sun.security.krb5.internal.ccache.Credentials credentials =
|
||||
|
||||
@ -33,12 +33,8 @@ package sun.security.krb5.internal.tools;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.internal.*;
|
||||
import sun.security.krb5.internal.ccache.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.time.Instant;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
@ -49,14 +45,15 @@ import java.io.FileInputStream;
|
||||
* @author Ram Marti
|
||||
*/
|
||||
class KinitOptions {
|
||||
public boolean validate = false;
|
||||
|
||||
// 1. acquire, 2. renew, 3. validate
|
||||
public int action = 1;
|
||||
|
||||
// forwardable and proxiable flags have two states:
|
||||
// -1 - flag set to be not forwardable or proxiable;
|
||||
// 1 - flag set to be forwardable or proxiable.
|
||||
public short forwardable = -1;
|
||||
public short proxiable = -1;
|
||||
public boolean renew = false;
|
||||
public short forwardable = 0;
|
||||
public short proxiable = 0;
|
||||
public KerberosTime lifetime;
|
||||
public KerberosTime renewable_lifetime;
|
||||
public String target_service;
|
||||
@ -134,6 +131,12 @@ class KinitOptions {
|
||||
}
|
||||
|
||||
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")) {
|
||||
printHelp();
|
||||
System.exit(0);
|
||||
@ -223,23 +226,28 @@ class KinitOptions {
|
||||
|
||||
|
||||
void printHelp() {
|
||||
System.out.println("Usage: kinit " +
|
||||
"[-A] [-f] [-p] [-c cachename] " +
|
||||
"[[-k [-t keytab_file_name]] [principal] " +
|
||||
System.out.println("Usage:\n\n1. Initial ticket request:\n" +
|
||||
" kinit [-A] [-f] [-p] [-c cachename] " +
|
||||
"[-l lifetime] [-r renewable_time]\n" +
|
||||
" [[-k [-t keytab_file_name]] [principal] " +
|
||||
"[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:");
|
||||
System.out.println("\t -A do not include addresses");
|
||||
System.out.println("\t -f forwardable");
|
||||
System.out.println("\t -p proxiable");
|
||||
System.out.println("\t -c cache name " +
|
||||
"(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)");
|
||||
System.out.println("\t -k use keytab");
|
||||
System.out.println("\t -t keytab file name");
|
||||
System.out.println("\t principal the principal name "+
|
||||
"(i.e., qweadf@ATHENA.MIT.EDU qweadf)");
|
||||
System.out.println("\t password " +
|
||||
"the principal's Kerberos password");
|
||||
System.out.println("\t-A do not include addresses");
|
||||
System.out.println("\t-f forwardable");
|
||||
System.out.println("\t-p proxiable");
|
||||
System.out.println("\t-c cache name " +
|
||||
"(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)");
|
||||
System.out.println("\t-l lifetime");
|
||||
System.out.println("\t-r renewable time " +
|
||||
"(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)");
|
||||
System.out.println("\tpassword the principal's Kerberos password");
|
||||
}
|
||||
|
||||
public boolean getAddressOption() {
|
||||
@ -257,4 +265,8 @@ class KinitOptions {
|
||||
public PrincipalName getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
private KerberosTime getTime(int s) {
|
||||
return new KerberosTime(Instant.now().plusSeconds(s));
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ import sun.net.spi.nameservice.NameServiceDescriptor;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.internal.*;
|
||||
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.ktab.KeyTab;
|
||||
import sun.security.util.DerInputStream;
|
||||
@ -120,6 +121,9 @@ import sun.security.util.DerValue;
|
||||
*/
|
||||
public class KDC {
|
||||
|
||||
public static final int DEFAULT_LIFETIME = 39600;
|
||||
public static final int DEFAULT_RENEWTIME = 86400;
|
||||
|
||||
// Under the hood.
|
||||
|
||||
// The random generator to generate random keys (including session keys)
|
||||
@ -204,7 +208,8 @@ public class KDC {
|
||||
* A standalone KDC server.
|
||||
*/
|
||||
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("foo", "bar".toCharArray());
|
||||
kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE");
|
||||
@ -871,6 +876,14 @@ public class KDC {
|
||||
eTypes = KDCReqBodyDotEType(body);
|
||||
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];
|
||||
}
|
||||
|
||||
EncryptionKey ckey = keyForUser(body.cname, eType, false);
|
||||
EncryptionKey skey = keyForUser(service, eType, true);
|
||||
|
||||
@ -899,10 +912,16 @@ public class KDC {
|
||||
EncryptionKey key = generateRandomKey(eType);
|
||||
// Check time, TODO
|
||||
KerberosTime till = body.till;
|
||||
KerberosTime rtime = body.rtime;
|
||||
if (till == null) {
|
||||
throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO
|
||||
} 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);
|
||||
}
|
||||
//body.from
|
||||
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
|
||||
@ -1053,7 +1072,7 @@ public class KDC {
|
||||
new TransitedEncoding(1, new byte[0]),
|
||||
new KerberosTime(new Date()),
|
||||
body.from,
|
||||
till, body.rtime,
|
||||
till, rtime,
|
||||
body.addresses,
|
||||
null);
|
||||
Ticket t = new Ticket(
|
||||
@ -1071,7 +1090,7 @@ public class KDC {
|
||||
tFlags,
|
||||
new KerberosTime(new Date()),
|
||||
body.from,
|
||||
till, body.rtime,
|
||||
till, rtime,
|
||||
service,
|
||||
body.addresses
|
||||
);
|
||||
|
||||
@ -40,7 +40,7 @@ public class LifeTimeInSeconds {
|
||||
int time = cred.getRemainingLifetime();
|
||||
int time2 = cred.getRemainingInitLifetime(null);
|
||||
// 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) {
|
||||
throw new Exception("getRemainingLifetime returns wrong value.");
|
||||
}
|
||||
|
||||
164
jdk/test/sun/security/krb5/auto/Renewal.java
Normal file
164
jdk/test/sun/security/krb5/auto/Renewal.java
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
jdk/test/sun/security/krb5/config/Duration.java
Normal file
71
jdk/test/sun/security/krb5/config/Duration.java
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user