Index: content/common/origin_trials/trial_token_unittest.cc |
diff --git a/content/common/origin_trials/trial_token_unittest.cc b/content/common/origin_trials/trial_token_unittest.cc |
index dd8350860fc34a3e994efaab11c9a8dff7998072..e5b9e67fed3a4e1e82ac8fe2bf3b71c467f5fa62 100644 |
--- a/content/common/origin_trials/trial_token_unittest.cc |
+++ b/content/common/origin_trials/trial_token_unittest.cc |
@@ -48,14 +48,14 @@ const uint8_t kTestPublicKey2[] = { |
}; |
// This is a good trial token, signed with the above test private key. |
+// Generate this token with the command (in tools/origin_trials): |
+// generate_token.py valid.example.com Frobulate --expire-timestamp=1458766277 |
const char* kSampleToken = |
- "1|UsEO0cNxoUtBnHDJdGPWTlXuLENjXcEIPL7Bs7sbvicPCcvAtyqhQuTJ9h/u1R3VZpWigtI+" |
- "SdUwk7Dyk/qbDw==|https://valid.example.com|Frobulate|1458766277"; |
-const uint8_t kExpectedVersion = 1; |
-const char* kExpectedSignature = |
- "UsEO0cNxoUtBnHDJdGPWTlXuLENjXcEIPL7Bs7sbvicPCcvAtyqhQuTJ9h/u1R3VZpWigtI+S" |
- "dUwk7Dyk/qbDw=="; |
-const char* kExpectedData = "https://valid.example.com|Frobulate|1458766277"; |
+ "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj" |
+ "7FO5L22sNvkZZnacLvmfNwsAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" |
+ "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" |
+ "IjogMTQ1ODc2NjI3N30="; |
+ |
const char* kExpectedFeatureName = "Frobulate"; |
const char* kExpectedOrigin = "https://valid.example.com"; |
const uint64_t kExpectedExpiry = 1458766277; |
@@ -74,39 +74,64 @@ double kInvalidTimestamp = 1458766278.0; |
// Well-formed trial token with an invalid signature. |
const char* kInvalidSignatureToken = |
- "1|CO8hDne98QeFeOJ0DbRZCBN3uE0nyaPgaLlkYhSWnbRoDfEAg+TXELaYfQPfEvKYFauBg/" |
- "hnxmba765hz0mXMc==|https://valid.example.com|Frobulate|1458766277"; |
+ "AYeNXSDktgG9p4ns5B1WKsLq2TytMxfR4whfbi+oyT0rXyzh+qXYfxbDMGmyjU2Z" |
+ "lEJ16vQObMXJoOaYUqd8xwkAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" |
+ "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" |
+ "IjogMTQ1ODc2NjI3N30="; |
+ |
+// Trial token truncated in the middle of the length field; too short to |
+// possibly be valid. |
+const char kTruncatedToken[] = |
+ "Ap+Q/Qm0ELadZql+dlEGSwnAVsFZKgCEtUZg8idQC3uekkIeSZIY1tftoYdrwhqj" |
+ "7FO5L22sNvkZZnacLvmfNwsA"; |
+ |
+// Trial token with an incorrectly-declared length, but with a valid signature. |
+const char kIncorrectLengthToken[] = |
+ "Ao06eNl/CZuM88qurWKX4RfoVEpHcVHWxdOTrEXZkaC1GUHyb/8L4sthADiVWdc9" |
+ "kXFyF1BW5bbraqp6MBVr3wEAAABaeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" |
+ "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" |
+ "IjogMTQ1ODc2NjI3N30="; |
+ |
+// Trial token with a misidentified version (42). |
+const char kIncorrectVersionToken[] = |
+ "KlH8wVLT5o59uDvlJESorMDjzgWnvG1hmIn/GiT9Ng3f45ratVeiXCNTeaJheOaG" |
+ "A6kX4ir4Amv8aHVC+OJHZQkAAABZeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l" |
+ "eGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5" |
+ "IjogMTQ1ODc2NjI3N30="; |
+ |
+const char kSampleTokenJSON[] = |
+ "{\"origin\": \"https://valid.example.com:443\", \"feature\": " |
+ "\"Frobulate\", \"expiry\": 1458766277}"; |
// Various ill-formed trial tokens. These should all fail to parse. |
const char* kInvalidTokens[] = { |
- // Invalid - only one part |
+ // Invalid - Not JSON at all |
"abcde", |
- // Not enough parts |
- "https://valid.example.com|FeatureName|1458766277", |
- "Signature|https://valid.example.com|FeatureName|1458766277", |
- // Non-numeric version |
- "a|Signature|https://valid.example.com|FeatureName|1458766277", |
- "1x|Signature|https://valid.example.com|FeatureName|1458766277", |
- // Unsupported version (< min, > max, negative, overflow) |
- "0|Signature|https://valid.example.com|FeatureName|1458766277", |
- "2|Signature|https://valid.example.com|FeatureName|1458766277", |
- "-1|Signature|https://valid.example.com|FeatureName|1458766277", |
- "99999|Signature|https://valid.example.com|FeatureName|1458766277", |
- // Delimiter in feature name |
- "1|Signature|https://valid.example.com|Feature|Name|1458766277", |
- // Extra string field |
- "1|Signature|https://valid.example.com|FeatureName|1458766277|ExtraField", |
- // Extra numeric field |
- "1|Signature|https://valid.example.com|FeatureName|1458766277|1458766277", |
- // Non-numeric expiry timestamp |
- "1|Signature|https://valid.example.com|FeatureName|abcdefghij", |
- "1|Signature|https://valid.example.com|FeatureName|1458766277x", |
+ // Invalid JSON |
+ "{", |
+ // Not an object |
+ "\"abcde\"", |
+ "123.4", |
+ "[0, 1, 2]", |
+ // Missing keys |
+ "{}", |
+ "{\"something\": 1}", |
+ "{\"origin\": \"https://a.a\"}", |
+ "{\"origin\": \"https://a.a\", \"feature\": \"a\"}" |
+ "{\"origin\": \"https://a.a\", \"expiry\": 1458766277}", |
+ "{\"feature\": \"FeatureName\", \"expiry\": 1458766277}", |
+ // Incorrect types |
+ "{\"origin\": 1, \"feature\": \"a\", \"expiry\": 1458766277}", |
+ "{\"origin\": \"https://a.a\", \"feature\": 1, \"expiry\": 1458766277}", |
+ "{\"origin\": \"https://a.a\", \"feature\": \"a\", \"expiry\": \"1\"}", |
// Negative expiry timestamp |
- "1|Signature|https://valid.example.com|FeatureName|-1458766277", |
+ "{\"origin\": \"https://a.a\", \"feature\": \"a\", \"expiry\": -1}", |
// Origin not a proper origin URL |
- "1|Signature|abcdef|FeatureName|1458766277", |
- "1|Signature|data:text/plain,abcdef|FeatureName|1458766277", |
- "1|Signature|javascript:alert(1)|FeatureName|1458766277"}; |
+ "{\"origin\": \"abcdef\", \"feature\": \"a\", \"expiry\": 1458766277}", |
+ "{\"origin\": \"data:text/plain,abcdef\", \"feature\": \"a\", \"expiry\": " |
+ "1458766277}", |
+ "{\"origin\": \"javascript:alert(1)\", \"feature\": \"a\", \"expiry\": " |
+ "1458766277}"}; |
const size_t kNumInvalidTokens = arraysize(kInvalidTokens); |
} // namespace |
@@ -117,6 +142,9 @@ class TrialTokenTest : public testing::Test { |
: expected_origin_(GURL(kExpectedOrigin)), |
invalid_origin_(GURL(kInvalidOrigin)), |
insecure_origin_(GURL(kInsecureOrigin)), |
+ expected_expiry_(base::Time::FromDoubleT(kExpectedExpiry)), |
+ valid_timestamp_(base::Time::FromDoubleT(kValidTimestamp)), |
+ invalid_timestamp_(base::Time::FromDoubleT(kInvalidTimestamp)), |
correct_public_key_( |
base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey), |
arraysize(kTestPublicKey))), |
@@ -125,6 +153,14 @@ class TrialTokenTest : public testing::Test { |
arraysize(kTestPublicKey2))) {} |
protected: |
+ scoped_ptr<std::string> Extract(const std::string& token_text, |
+ base::StringPiece public_key) { |
+ return TrialToken::Extract(token_text, public_key); |
+ } |
+ scoped_ptr<TrialToken> Parse(const std::string& token_payload) { |
+ return TrialToken::Parse(token_payload); |
+ } |
+ |
bool ValidateOrigin(TrialToken* token, const url::Origin origin) { |
return token->ValidateOrigin(origin); |
} |
@@ -137,11 +173,6 @@ class TrialTokenTest : public testing::Test { |
return token->ValidateDate(now); |
} |
- bool ValidateSignature(TrialToken* token, |
- const base::StringPiece& public_key) { |
- return token->ValidateSignature(public_key); |
- } |
- |
base::StringPiece correct_public_key() { return correct_public_key_; } |
base::StringPiece incorrect_public_key() { return incorrect_public_key_; } |
@@ -149,37 +180,88 @@ class TrialTokenTest : public testing::Test { |
const url::Origin invalid_origin_; |
const url::Origin insecure_origin_; |
+ const base::Time expected_expiry_; |
+ const base::Time valid_timestamp_; |
+ const base::Time invalid_timestamp_; |
+ |
private: |
base::StringPiece correct_public_key_; |
base::StringPiece incorrect_public_key_; |
}; |
+// Test the extraction of the signed payload from token strings. This includes |
+// checking the included version identifier, payload length, and cryptographic |
+// signature. |
+ |
+/* Test verification of signature and extraction of token JSON from signed token |
Marijn Kruisselbrink
2016/04/08 21:19:30
// is much more common to use for comments. And th
iclelland
2016/04/11 16:59:37
Done.
|
+ */ |
+TEST_F(TrialTokenTest, ValidateValidSignature) { |
+ scoped_ptr<std::string> token_payload = |
+ Extract(kSampleToken, correct_public_key()); |
+ ASSERT_TRUE(token_payload); |
+ EXPECT_STREQ(kSampleTokenJSON, token_payload.get()->c_str()); |
+} |
+ |
+TEST_F(TrialTokenTest, ValidateInvalidSignature) { |
+ scoped_ptr<std::string> token_payload = |
+ Extract(kInvalidSignatureToken, correct_public_key()); |
+ ASSERT_FALSE(token_payload); |
+} |
+ |
+TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectKey) { |
+ scoped_ptr<std::string> token_payload = |
+ Extract(kSampleToken, incorrect_public_key()); |
+ ASSERT_FALSE(token_payload); |
+} |
+ |
+TEST_F(TrialTokenTest, ValidateEmptyToken) { |
+ scoped_ptr<std::string> token_payload = Extract("", correct_public_key()); |
+ ASSERT_FALSE(token_payload); |
+} |
+ |
+TEST_F(TrialTokenTest, ValidateShortToken) { |
+ scoped_ptr<std::string> token_payload = |
+ Extract(kTruncatedToken, correct_public_key()); |
+ ASSERT_FALSE(token_payload); |
+} |
+ |
+TEST_F(TrialTokenTest, ValidateUnsupportedVersion) { |
+ scoped_ptr<std::string> token_payload = |
+ Extract(kIncorrectVersionToken, correct_public_key()); |
+ ASSERT_FALSE(token_payload); |
+} |
+ |
+TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectLength) { |
+ scoped_ptr<std::string> token = |
+ Extract(kIncorrectLengthToken, correct_public_key()); |
+ ASSERT_FALSE(token); |
+} |
+ |
+/* Test parsing of fields from JSON token */ |
+ |
TEST_F(TrialTokenTest, ParseEmptyString) { |
- scoped_ptr<TrialToken> empty_token = TrialToken::Parse(""); |
+ scoped_ptr<TrialToken> empty_token = Parse(""); |
EXPECT_FALSE(empty_token); |
} |
TEST_F(TrialTokenTest, ParseInvalidStrings) { |
for (size_t i = 0; i < kNumInvalidTokens; ++i) { |
- scoped_ptr<TrialToken> empty_token = TrialToken::Parse(kInvalidTokens[i]); |
+ scoped_ptr<TrialToken> empty_token = Parse(kInvalidTokens[i]); |
Marijn Kruisselbrink
2016/04/08 21:19:30
nit: not really part of this CL, but it would be n
iclelland
2016/04/11 16:59:37
Thanks for that pointer -- done.
|
EXPECT_FALSE(empty_token) << "Invalid trial token should not parse: " |
<< kInvalidTokens[i]; |
} |
} |
TEST_F(TrialTokenTest, ParseValidToken) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
+ scoped_ptr<TrialToken> token = Parse(kSampleTokenJSON); |
ASSERT_TRUE(token); |
- EXPECT_EQ(kExpectedVersion, token->version()); |
EXPECT_EQ(kExpectedFeatureName, token->feature_name()); |
- EXPECT_EQ(kExpectedSignature, token->signature()); |
- EXPECT_EQ(kExpectedData, token->data()); |
EXPECT_EQ(expected_origin_, token->origin()); |
- EXPECT_EQ(base::Time::FromDoubleT(kExpectedExpiry), token->expiry_time()); |
+ EXPECT_EQ(expected_expiry_, token->expiry_time()); |
} |
TEST_F(TrialTokenTest, ValidateValidToken) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
+ scoped_ptr<TrialToken> token = Parse(kSampleTokenJSON); |
ASSERT_TRUE(token); |
EXPECT_TRUE(ValidateOrigin(token.get(), expected_origin_)); |
EXPECT_FALSE(ValidateOrigin(token.get(), invalid_origin_)); |
@@ -190,54 +272,30 @@ TEST_F(TrialTokenTest, ValidateValidToken) { |
token.get(), base::ToUpperASCII(kExpectedFeatureName).c_str())); |
EXPECT_FALSE(ValidateFeatureName( |
token.get(), base::ToLowerASCII(kExpectedFeatureName).c_str())); |
- EXPECT_TRUE( |
- ValidateDate(token.get(), base::Time::FromDoubleT(kValidTimestamp))); |
- EXPECT_FALSE( |
- ValidateDate(token.get(), base::Time::FromDoubleT(kInvalidTimestamp))); |
+ EXPECT_TRUE(ValidateDate(token.get(), valid_timestamp_)); |
+ EXPECT_FALSE(ValidateDate(token.get(), invalid_timestamp_)); |
} |
-TEST_F(TrialTokenTest, TokenIsAppropriateForOriginAndFeature) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
+TEST_F(TrialTokenTest, TokenIsValidForFeature) { |
+ scoped_ptr<TrialToken> token = Parse(kSampleTokenJSON); |
ASSERT_TRUE(token); |
- EXPECT_TRUE(token->IsAppropriate(expected_origin_, kExpectedFeatureName)); |
- EXPECT_FALSE(token->IsAppropriate(expected_origin_, |
- base::ToUpperASCII(kExpectedFeatureName))); |
- EXPECT_FALSE(token->IsAppropriate(expected_origin_, |
- base::ToLowerASCII(kExpectedFeatureName))); |
- EXPECT_FALSE(token->IsAppropriate(invalid_origin_, kExpectedFeatureName)); |
- EXPECT_FALSE(token->IsAppropriate(insecure_origin_, kExpectedFeatureName)); |
- EXPECT_FALSE(token->IsAppropriate(expected_origin_, kInvalidFeatureName)); |
+ EXPECT_TRUE(token->IsValidForFeature(expected_origin_, kExpectedFeatureName, |
+ valid_timestamp_)); |
+ EXPECT_FALSE(token->IsValidForFeature( |
+ expected_origin_, base::ToUpperASCII(kExpectedFeatureName), |
+ valid_timestamp_)); |
+ EXPECT_FALSE(token->IsValidForFeature( |
+ expected_origin_, base::ToLowerASCII(kExpectedFeatureName), |
+ valid_timestamp_)); |
+ EXPECT_FALSE(token->IsValidForFeature(invalid_origin_, kExpectedFeatureName, |
+ valid_timestamp_)); |
+ EXPECT_FALSE(token->IsValidForFeature(insecure_origin_, kExpectedFeatureName, |
+ valid_timestamp_)); |
+ EXPECT_FALSE(token->IsValidForFeature(expected_origin_, kInvalidFeatureName, |
+ valid_timestamp_)); |
+ EXPECT_FALSE(token->IsValidForFeature(expected_origin_, kExpectedFeatureName, |
+ invalid_timestamp_)); |
} |
-TEST_F(TrialTokenTest, ValidateValidSignature) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
- ASSERT_TRUE(token); |
- EXPECT_TRUE(ValidateSignature(token.get(), correct_public_key())); |
-} |
- |
-TEST_F(TrialTokenTest, ValidateInvalidSignature) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kInvalidSignatureToken); |
- ASSERT_TRUE(token); |
- EXPECT_FALSE(ValidateSignature(token.get(), correct_public_key())); |
-} |
- |
-TEST_F(TrialTokenTest, ValidateTokenWithCorrectKey) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
- ASSERT_TRUE(token); |
- EXPECT_TRUE(token->IsValid(base::Time::FromDoubleT(kValidTimestamp), |
- correct_public_key())); |
-} |
- |
-TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectKey) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
- ASSERT_TRUE(token); |
- EXPECT_FALSE(token->IsValid(base::Time::FromDoubleT(kValidTimestamp), |
- incorrect_public_key())); |
-} |
- |
-TEST_F(TrialTokenTest, ValidateWhenNotExpired) { |
- scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken); |
- ASSERT_TRUE(token); |
-} |
} // namespace content |