jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
changeset 16905 0419f45c7761
parent 14327 c0d86f6f8be8
child 25186 63e1a2ec30f5
equal deleted inserted replaced
16904:5eb5ed2346aa 16905:0419f45c7761
    28  *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
    28  *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
    29  */
    29  */
    30 
    30 
    31 package sun.security.krb5.internal;
    31 package sun.security.krb5.internal;
    32 
    32 
    33 import java.util.TimeZone;
    33 import sun.security.krb5.Asn1Exception;
    34 import sun.security.util.*;
       
    35 import sun.security.krb5.Config;
    34 import sun.security.krb5.Config;
    36 import sun.security.krb5.KrbException;
    35 import sun.security.krb5.KrbException;
    37 import sun.security.krb5.Asn1Exception;
    36 import sun.security.util.DerInputStream;
       
    37 import sun.security.util.DerOutputStream;
       
    38 import sun.security.util.DerValue;
       
    39 
       
    40 import java.io.IOException;
       
    41 import java.util.Calendar;
    38 import java.util.Date;
    42 import java.util.Date;
    39 import java.util.GregorianCalendar;
    43 import java.util.TimeZone;
    40 import java.util.Calendar;
       
    41 import java.io.IOException;
       
    42 
    44 
    43 /**
    45 /**
    44  * Implements the ASN.1 KerberosTime type.
    46  * Implements the ASN.1 KerberosTime type. This is an immutable class.
    45  *
    47  *
    46  * <xmp>
    48  * <xmp>
    47  * KerberosTime    ::= GeneralizedTime -- with no fractional seconds
    49  * KerberosTime    ::= GeneralizedTime -- with no fractional seconds
    48  * </xmp>
    50  * </xmp>
    49  *
    51  *
    60  *
    62  *
    61  * The implementation also includes the microseconds info so that the
    63  * The implementation also includes the microseconds info so that the
    62  * same class can be used as a precise timestamp in Authenticator etc.
    64  * same class can be used as a precise timestamp in Authenticator etc.
    63  */
    65  */
    64 
    66 
    65 public class KerberosTime implements Cloneable {
    67 public class KerberosTime {
    66 
    68 
    67     private long kerberosTime; // milliseconds since epoch, a Date.getTime() value
    69     private final long kerberosTime; // milliseconds since epoch, Date.getTime()
    68     private int  microSeconds; // the last three digits of the microsecond value
    70     private final int  microSeconds; // last 3 digits of the real microsecond
    69 
    71 
    70     // The time when this class is loaded. Used in setNow()
    72     // The time when this class is loaded. Used in setNow()
    71     private static long initMilli = System.currentTimeMillis();
    73     private static long initMilli = System.currentTimeMillis();
    72     private static long initMicro = System.nanoTime() / 1000;
    74     private static long initMicro = System.nanoTime() / 1000;
    73 
    75 
    74     private static long syncTime;
       
    75     private static boolean DEBUG = Krb5.DEBUG;
    76     private static boolean DEBUG = Krb5.DEBUG;
    76 
    77 
    77     public static final boolean NOW = true;
    78     // Do not make this public. It's a little confusing that micro
    78     public static final boolean UNADJUSTED_NOW = false;
    79     // is only the last 3 digits of microsecond.
    79 
       
    80     public KerberosTime(long time) {
       
    81         kerberosTime = time;
       
    82     }
       
    83 
       
    84     private KerberosTime(long time, int micro) {
    80     private KerberosTime(long time, int micro) {
    85         kerberosTime = time;
    81         kerberosTime = time;
    86         microSeconds = micro;
    82         microSeconds = micro;
    87     }
    83     }
    88 
    84 
    89     public Object clone() {
    85     /**
    90         return new KerberosTime(kerberosTime, microSeconds);
    86      * Creates a KerberosTime object from milliseconds since epoch.
       
    87      */
       
    88     public KerberosTime(long time) {
       
    89         this(time, 0);
    91     }
    90     }
    92 
    91 
    93     // This constructor is used in the native code
    92     // This constructor is used in the native code
    94     // src/windows/native/sun/security/krb5/NativeCreds.c
    93     // src/windows/native/sun/security/krb5/NativeCreds.c
    95     public KerberosTime(String time) throws Asn1Exception {
    94     public KerberosTime(String time) throws Asn1Exception {
    96         kerberosTime = toKerberosTime(time);
    95         this(toKerberosTime(time), 0);
    97     }
       
    98 
       
    99     /**
       
   100      * Constructs a KerberosTime object.
       
   101      * @param encoding a DER-encoded data.
       
   102      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
       
   103      * @exception IOException if an I/O error occurs while reading encoded data.
       
   104      */
       
   105     public KerberosTime(DerValue encoding) throws Asn1Exception, IOException {
       
   106         GregorianCalendar calendar = new GregorianCalendar();
       
   107         Date temp = encoding.getGeneralizedTime();
       
   108         kerberosTime = temp.getTime();
       
   109     }
    96     }
   110 
    97 
   111     private static long toKerberosTime(String time) throws Asn1Exception {
    98     private static long toKerberosTime(String time) throws Asn1Exception {
   112         // this method only used by KerberosTime class.
       
   113 
       
   114         // ASN.1 GeneralizedTime format:
    99         // ASN.1 GeneralizedTime format:
   115 
   100 
   116         // "19700101000000Z"
   101         // "19700101000000Z"
   117         //  |   | | | | | |
   102         //  |   | | | | | |
   118         //  0   4 6 8 | | |
   103         //  0   4 6 8 | | |
   131                      Integer.parseInt(time.substring(4, 6)) - 1,
   116                      Integer.parseInt(time.substring(4, 6)) - 1,
   132                      Integer.parseInt(time.substring(6, 8)),
   117                      Integer.parseInt(time.substring(6, 8)),
   133                      Integer.parseInt(time.substring(8, 10)),
   118                      Integer.parseInt(time.substring(8, 10)),
   134                      Integer.parseInt(time.substring(10, 12)),
   119                      Integer.parseInt(time.substring(10, 12)),
   135                      Integer.parseInt(time.substring(12, 14)));
   120                      Integer.parseInt(time.substring(12, 14)));
   136 
   121         return calendar.getTimeInMillis();
   137         //The Date constructor assumes the setting are local relative
   122     }
   138         //and converts the time to UTC before storing it.  Since we
   123 
   139         //want the internal representation to correspond to local
   124     /**
   140         //and not UTC time we subtract the UTC time offset.
   125      * Creates a KerberosTime object from a Date object.
   141         return (calendar.getTime().getTime());
   126      */
   142 
       
   143     }
       
   144 
       
   145     // should be moved to sun.security.krb5.util class
       
   146     public static String zeroPad(String s, int length) {
       
   147         StringBuffer temp = new StringBuffer(s);
       
   148         while (temp.length() < length)
       
   149             temp.insert(0, '0');
       
   150         return temp.toString();
       
   151     }
       
   152 
       
   153     public KerberosTime(Date time) {
   127     public KerberosTime(Date time) {
   154         kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
   128         this(time.getTime(), 0);
   155     }
   129     }
   156 
   130 
   157     public KerberosTime(boolean initToNow) {
   131     /**
   158         if (initToNow) {
   132      * Creates a KerberosTime object for now. It uses System.nanoTime()
   159             setNow();
   133      * to get a more precise time than "new Date()".
   160         }
   134      */
   161     }
   135     public static KerberosTime now() {
   162 
       
   163     /**
       
   164      * Returns a string representation of KerberosTime object.
       
   165      * @return a string representation of this object.
       
   166      */
       
   167     public String toGeneralizedTimeString() {
       
   168         Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
       
   169         calendar.clear();
       
   170 
       
   171         calendar.setTimeInMillis(kerberosTime);
       
   172         return zeroPad(Integer.toString(calendar.get(Calendar.YEAR)), 4) +
       
   173             zeroPad(Integer.toString(calendar.get(Calendar.MONTH) + 1), 2) +
       
   174             zeroPad(Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), 2) +
       
   175             zeroPad(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)), 2) +
       
   176             zeroPad(Integer.toString(calendar.get(Calendar.MINUTE)), 2) +
       
   177             zeroPad(Integer.toString(calendar.get(Calendar.SECOND)), 2) + 'Z';
       
   178 
       
   179     }
       
   180 
       
   181     /**
       
   182      * Encodes this object to a byte array.
       
   183      * @return a byte array of encoded data.
       
   184      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
       
   185      * @exception IOException if an I/O error occurs while reading encoded data.
       
   186      */
       
   187     public byte[] asn1Encode() throws Asn1Exception, IOException {
       
   188         DerOutputStream out = new DerOutputStream();
       
   189         out.putGeneralizedTime(this.toDate());
       
   190         return out.toByteArray();
       
   191     }
       
   192 
       
   193     public long getTime() {
       
   194         return kerberosTime;
       
   195     }
       
   196 
       
   197 
       
   198     public void setTime(Date time) {
       
   199         kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
       
   200         microSeconds = 0;
       
   201     }
       
   202 
       
   203     public void setTime(long time) {
       
   204         kerberosTime = time;
       
   205         microSeconds = 0;
       
   206     }
       
   207 
       
   208     public Date toDate() {
       
   209         Date temp = new Date(kerberosTime);
       
   210         temp.setTime(temp.getTime());
       
   211         return temp;
       
   212     }
       
   213 
       
   214     public void setNow() {
       
   215         long newMilli = System.currentTimeMillis();
   136         long newMilli = System.currentTimeMillis();
   216         long newMicro = System.nanoTime() / 1000;
   137         long newMicro = System.nanoTime() / 1000;
   217         long microElapsed = newMicro - initMicro;
   138         long microElapsed = newMicro - initMicro;
   218         long calcMilli = initMilli + microElapsed/1000;
   139         long calcMilli = initMilli + microElapsed/1000;
   219         if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {
   140         if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {
   220             if (DEBUG) {
   141             if (DEBUG) {
   221                 System.out.println("System time adjusted");
   142                 System.out.println("System time adjusted");
   222             }
   143             }
   223             initMilli = newMilli;
   144             initMilli = newMilli;
   224             initMicro = newMicro;
   145             initMicro = newMicro;
   225             setTime(newMilli);
   146             return new KerberosTime(newMilli, 0);
   226             microSeconds = 0;
       
   227         } else {
   147         } else {
   228             setTime(calcMilli);
   148             return new KerberosTime(calcMilli, (int)(microElapsed % 1000));
   229             microSeconds = (int)(microElapsed % 1000);
   149         }
   230         }
   150     }
       
   151 
       
   152     /**
       
   153      * Returns a string representation of KerberosTime object.
       
   154      * @return a string representation of this object.
       
   155      */
       
   156     public String toGeneralizedTimeString() {
       
   157         Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
       
   158         calendar.clear();
       
   159 
       
   160         calendar.setTimeInMillis(kerberosTime);
       
   161         return String.format("%04d%02d%02d%02d%02d%02dZ",
       
   162                 calendar.get(Calendar.YEAR),
       
   163                 calendar.get(Calendar.MONTH) + 1,
       
   164                 calendar.get(Calendar.DAY_OF_MONTH),
       
   165                 calendar.get(Calendar.HOUR_OF_DAY),
       
   166                 calendar.get(Calendar.MINUTE),
       
   167                 calendar.get(Calendar.SECOND));
       
   168     }
       
   169 
       
   170     /**
       
   171      * Encodes this object to a byte array.
       
   172      * @return a byte array of encoded data.
       
   173      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
       
   174      * @exception IOException if an I/O error occurs while reading encoded data.
       
   175      */
       
   176     public byte[] asn1Encode() throws Asn1Exception, IOException {
       
   177         DerOutputStream out = new DerOutputStream();
       
   178         out.putGeneralizedTime(this.toDate());
       
   179         return out.toByteArray();
       
   180     }
       
   181 
       
   182     public long getTime() {
       
   183         return kerberosTime;
       
   184     }
       
   185 
       
   186     public Date toDate() {
       
   187         return new Date(kerberosTime);
   231     }
   188     }
   232 
   189 
   233     public int getMicroSeconds() {
   190     public int getMicroSeconds() {
   234         Long temp_long = new Long((kerberosTime % 1000L) * 1000L);
   191         Long temp_long = new Long((kerberosTime % 1000L) * 1000L);
   235         return temp_long.intValue() + microSeconds;
   192         return temp_long.intValue() + microSeconds;
   236     }
   193     }
   237 
   194 
   238     public void setMicroSeconds(int usec) {
   195     /**
   239         microSeconds = usec % 1000;
   196      * Returns a new KerberosTime object with the original seconds
   240         Integer temp_int = new Integer(usec);
   197      * and the given microseconds.
   241         long temp_long = temp_int.longValue() / 1000L;
   198      */
   242         kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
   199     public KerberosTime withMicroSeconds(int usec) {
   243     }
   200         return new KerberosTime(
   244 
   201                 kerberosTime - kerberosTime%1000L + usec/1000L,
   245     public void setMicroSeconds(Integer usec) {
   202                 usec%1000);
   246         if (usec != null) {
   203     }
   247             microSeconds = usec.intValue() % 1000;
   204 
   248             long temp_long = usec.longValue() / 1000L;
   205     private boolean inClockSkew(int clockSkew) {
   249             kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
   206         return java.lang.Math.abs(kerberosTime - System.currentTimeMillis())
   250         }
   207                 <= clockSkew * 1000L;
   251     }
       
   252 
       
   253     public boolean inClockSkew(int clockSkew) {
       
   254         KerberosTime now = new KerberosTime(KerberosTime.NOW);
       
   255 
       
   256         if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
       
   257             clockSkew * 1000L)
       
   258             return false;
       
   259         return true;
       
   260     }
   208     }
   261 
   209 
   262     public boolean inClockSkew() {
   210     public boolean inClockSkew() {
   263         return inClockSkew(getDefaultSkew());
   211         return inClockSkew(getDefaultSkew());
   264     }
       
   265 
       
   266     public boolean inClockSkew(int clockSkew, KerberosTime now) {
       
   267         if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
       
   268             clockSkew * 1000L)
       
   269             return false;
       
   270         return true;
       
   271     }
       
   272 
       
   273     public boolean inClockSkew(KerberosTime time) {
       
   274         return inClockSkew(getDefaultSkew(), time);
       
   275     }
   212     }
   276 
   213 
   277     public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) {
   214     public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) {
   278         if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L)
   215         if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L)
   279             return true;
   216             return true;
   313     }
   250     }
   314 
   251 
   315     public int getSeconds() {
   252     public int getSeconds() {
   316         Long temp_long = new Long(kerberosTime / 1000L);
   253         Long temp_long = new Long(kerberosTime / 1000L);
   317         return temp_long.intValue();
   254         return temp_long.intValue();
   318     }
       
   319 
       
   320     public void setSeconds(int sec) {
       
   321         Integer temp_int = new Integer(sec);
       
   322         kerberosTime = temp_int.longValue() * 1000L;
       
   323     }
   255     }
   324 
   256 
   325     /**
   257     /**
   326      * Parse (unmarshal) a kerberostime from a DER input stream.  This form
   258      * Parse (unmarshal) a kerberostime from a DER input stream.  This form
   327      * parsing might be used when expanding a value which is part of
   259      * parsing might be used when expanding a value which is part of
   328      * a constructed sequence and uses explicitly tagged type.
   260      * a constructed sequence and uses explicitly tagged type.
   329      *
   261      *
   330      * @exception Asn1Exception on error.
   262      * @exception Asn1Exception on error.
   331      * @param data the Der input stream value, which contains one or more marshaled value.
   263      * @param data the Der input stream value, which contains
       
   264      *             one or more marshaled value.
   332      * @param explicitTag tag number.
   265      * @param explicitTag tag number.
   333      * @param optional indicates if this data field is optional
   266      * @param optional indicates if this data field is optional
   334      * @return an instance of KerberosTime.
   267      * @return an instance of KerberosTime.
   335      *
   268      *
   336      */
   269      */
   337     public static KerberosTime parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException {
   270     public static KerberosTime parse(
       
   271             DerInputStream data, byte explicitTag, boolean optional)
       
   272             throws Asn1Exception, IOException {
   338         if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag))
   273         if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag))
   339             return null;
   274             return null;
   340         DerValue der = data.getDerValue();
   275         DerValue der = data.getDerValue();
   341         if (explicitTag != (der.getTag() & (byte)0x1F))  {
   276         if (explicitTag != (der.getTag() & (byte)0x1F))  {
   342             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
   277             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
   343         }
   278         }
   344         else {
   279         else {
   345             DerValue subDer = der.getData().getDerValue();
   280             DerValue subDer = der.getData().getDerValue();
   346             return new KerberosTime(subDer);
   281             Date temp = subDer.getGeneralizedTime();
       
   282             return new KerberosTime(temp.getTime(), 0);
   347         }
   283         }
   348     }
   284     }
   349 
   285 
   350     public static int getDefaultSkew() {
   286     public static int getDefaultSkew() {
   351         int tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW;
   287         int tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW;