mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
api: signature v3 to accept more formats (#2893)
It does it by reusing the DateUtil helpers. DateUtil uses java.time.* as that one knows how to deal with timezones correctly. The format expected by signatureVersion=3&expires=.... is quite limited. It should accept the following formats that are containing a timezone and/or milliseconds. 2018-10-01T08:12:14Z 2018-10-01T08:12:14+01:00 2018-10-01T08:12:14+0100 2018-10-01T08:12:14.000Z 2018-10-01T08:12:14.000+01:00 2018-10-01T08:12:14.000+0100 afaik only 2018-10-01T08:12:14+0100 is accepted by the current codebase. This PR echoes other pull requests I made earlier this year. #2392 and #2867 Signed-off-by: Yoan Blanc <yoan.blanc@exoscale.ch>
This commit is contained in:
parent
7479e2877f
commit
17c164d59a
@ -42,6 +42,7 @@ import com.cloud.user.User;
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.user.UserVO;
|
||||
import com.cloud.utils.ConstantTimeComparator;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.HttpUtils;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.Pair;
|
||||
@ -166,9 +167,7 @@ import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@ -228,7 +227,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
private ApiAsyncJobDispatcher asyncDispatcher;
|
||||
|
||||
private static int s_workerCount = 0;
|
||||
private static final DateFormat DateFormatToUse = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
private static Map<String, List<Class<?>>> s_apiNameCmdClassMap = new HashMap<String, List<Class<?>>>();
|
||||
|
||||
private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory(
|
||||
@ -883,14 +881,14 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
s_logger.debug("Missing Expires parameter -- ignoring request. Signature: " + signature + ", apiKey: " + apiKey);
|
||||
return false;
|
||||
}
|
||||
synchronized (DateFormatToUse) {
|
||||
|
||||
try {
|
||||
expiresTS = DateFormatToUse.parse(expires);
|
||||
expiresTS = DateUtil.parseTZDateString(expires);
|
||||
} catch (final ParseException pe) {
|
||||
s_logger.debug("Incorrect date format for Expires parameter", pe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final Date now = new Date(System.currentTimeMillis());
|
||||
if (expiresTS.before(now)) {
|
||||
s_logger.debug("Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey);
|
||||
|
||||
@ -26,6 +26,10 @@ import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class DateUtil {
|
||||
@ -33,20 +37,34 @@ public class DateUtil {
|
||||
public static final String YYYYMMDD_FORMAT = "yyyyMMddHHmmss";
|
||||
private static final DateFormat s_outputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
|
||||
private static final DateTimeFormatter[] parseFormats = new DateTimeFormatter[]{
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME,
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
DateTimeFormatter.ISO_INSTANT,
|
||||
// with milliseconds
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSX"),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ"),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"),
|
||||
// legacy and non-sensical format
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'Z")
|
||||
};
|
||||
|
||||
public static Date currentGMTTime() {
|
||||
// Date object always stores miliseconds offset based on GMT internally
|
||||
return new Date();
|
||||
}
|
||||
|
||||
// yyyy-MM-ddTHH:mm:ssZZZZ or yyyy-MM-ddTHH:mm:ssZxxxx
|
||||
public static Date parseTZDateString(String str) throws ParseException {
|
||||
for (DateTimeFormatter formatter : parseFormats) {
|
||||
try {
|
||||
return s_outputFormat.parse(str);
|
||||
} catch (ParseException e) {
|
||||
final DateFormat dfParse = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'Z");
|
||||
return dfParse.parse(str);
|
||||
OffsetDateTime dt = OffsetDateTime.parse(str, formatter);
|
||||
return Date.from(dt.toInstant());
|
||||
} catch (DateTimeParseException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
throw new ParseException("Unparseable date: \"" + str + "\"", 0);
|
||||
}
|
||||
|
||||
public static Date parseDateString(TimeZone tz, String dateString) {
|
||||
return parseDateString(tz, dateString, "yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@ -25,6 +25,10 @@ import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
import com.cloud.utils.DateUtil.IntervalType;
|
||||
|
||||
import org.junit.Test;
|
||||
@ -32,7 +36,6 @@ import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class DateUtilTest {
|
||||
|
||||
// command line test tool
|
||||
public static void main(String[] args) {
|
||||
TimeZone localTimezone = Calendar.getInstance().getTimeZone();
|
||||
@ -56,7 +59,7 @@ public class DateUtilTest {
|
||||
String str = dfDate.format(time);
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(time.toString(), dtParsed.toString());
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -66,6 +69,59 @@ public class DateUtilTest {
|
||||
String str = dfDate.format(time);
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(time.toString(), dtParsed.toString());
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zonedTimeFormatIsoOffsetDateTime() throws ParseException {
|
||||
Date time = new Date();
|
||||
String str = OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zonedTimeFormatIsoInstant() throws ParseException {
|
||||
Date time = new Date();
|
||||
String str = OffsetDateTime.now().format(DateTimeFormatter.ISO_INSTANT);
|
||||
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zonedTimeFormatIsoOffsetDateTimeMs() throws ParseException {
|
||||
Date time = new Date();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSX");
|
||||
String str = OffsetDateTime.now().format(formatter);
|
||||
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zonedTimeFormatIsoInstantMs() throws ParseException {
|
||||
Date time = new Date();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");
|
||||
String str = OffsetDateTime.now(ZoneOffset.UTC).format(formatter);
|
||||
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zonedTimeFormatIsoNoColonZMs() throws ParseException {
|
||||
Date time = new Date();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ");
|
||||
String str = OffsetDateTime.now().format(formatter);
|
||||
|
||||
Date dtParsed = DateUtil.parseTZDateString(str);
|
||||
|
||||
assertEquals(str, time.toString(), dtParsed.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user