// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/blink/public/common/origin_trials/trial_token_validator.h" #include <memory> #include <string> #include <string_view> #include <vector> #include "base/containers/flat_set.h" #include "base/functional/bind.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ref.h" #include "base/strings/string_util.h" #include "base/test/simple_test_clock.h" #include "base/time/time.h" #include "net/http/http_response_headers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/origin_trials/origin_trial_policy.h" #include "third_party/blink/public/common/origin_trials/trial_token.h" #include "third_party/blink/public/common/origin_trials/trial_token_result.h" #include "url/gurl.h" namespace blink::trial_token_validator_unittest { // These are sample public keys for testing the API. // For the first public key, the corresponding private key (use this // to generate new samples for this test file) is: // // 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13, // 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba, // 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75, // 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, // 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, // 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 // For the second public key, the corresponding private key is: // 0x21, 0xee, 0xfa, 0x81, 0x6a, 0xff, 0xdf, 0xb8, 0xc1, 0xdd, 0x75, // 0x05, 0x04, 0x29, 0x68, 0x67, 0x60, 0x85, 0x91, 0xd0, 0x50, 0x16, // 0x0a, 0xcf, 0xa2, 0x37, 0xa3, 0x2e, 0x11, 0x7a, 0x17, 0x96, 0x50, // 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, 0x47, // 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, 0x3e, // 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca const OriginTrialPublicKey kTestPublicKey1 = …; const OriginTrialPublicKey kTestPublicKey2 = …; // This is a good trial token, signed with the above test private key. // TODO(iclelland): This token expires in 2033. Update it or find a way // to autogenerate it before then. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com Frobulate --expire-timestamp=2000000000 const char kSampleToken[] = …; const uint8_t kSampleTokenSignature[] = …; // The expiry time of the sample token (2033-05-18 03:33:20 UTC). const base::Time kSampleTokenExpiryTime = …; // This is a trial token signed with the corresponding private key // for kTestPublicKeys2 // TODO(iclelland): This token expires in 2033. Update it or find a way // to autogenerate it before then. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com Frobulate --expire-timestamp=2000000000 // --key-file=eftest2.key const char kSampleToken2[] = …; // The token should be valid for this origin and for this feature. const char kAppropriateOrigin[] = …; const char kAppropriateFeatureName[] = …; const char kAppropriateThirdPartyFeatureName[] = …; const char kAppropriateDeprecationFeatureName[] = …; const char kAppropriateGracePeriodFeatureName[] = …; const char kInappropriateFeatureName[] = …; const char kInappropriateOrigin[] = …; const char kInsecureOrigin[] = …; const char kUnrelatedOrigin[] = …; // Well-formed trial token with an invalid signature. // This token is a corruption of the above valid token. const char kInvalidSignatureToken[] = …; // Well-formed, but expired, trial token. (Expired in 2001) // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com Frobulate --expire-timestamp=1000000000 const char kExpiredToken[] = …; const uint8_t kExpiredTokenSignature[] = …; const char kUnparsableToken[] = …; // Well-formed token, for an insecure origin. // Generate this token with the command (in tools/origin_trials): // generate_token.py http://valid.example.com Frobulate // --expire-timestamp=2000000000 const char kInsecureOriginToken[] = …; // Well-formed token, for match against third party origins. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com FrobulateThirdParty // --is-third-party --expire-timestamp=2000000000 const char kThirdPartyToken[] = …; // Well-formed token, for match against third party origins and its usage // set to user subset exclusion. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com FrobulateThirdParty // --version 3 --is-third-party --usage-restriction subset // --expire-timestamp=2000000000 const char kThirdPartyUsageSubsetToken[] = …; // Well-formed token, for first party, with usage set to user subset exclusion. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com FrobulateThirdParty // --version 3 --usage-restriction subset --expire-timestamp=2000000000 const char kUsageSubsetToken[] = …; // Well-formed token for a feature with an expiry grace period. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com FrobulateExpiryGracePeriod // --expire-timestamp=2000000000 const char kExpiryGracePeriodToken[] = …; // Well-formed token for match against third party origins and a feature with an // expiry grace period. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com FrobulateExpiryGracePeriodThirdParty // --is-third-party --expire-timestamp=2000000000 const char kExpiryGracePeriodThirdPartyToken[] = …; // Well-formed token, with an unknown feature name. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com Grokalyze // --expire-timestamp=2000000000 const char kUnknownFeatureToken[] = …; // Well-formed token for match against third party origins, with an unknown // feature name. Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com Grokalyze // --is-third-party --expire-timestamp=2000000000 const char kUnknownFeatureThirdPartyToken[] = …; // Well-formed token, for match against third party origins for a trial that // doesn't allow third-party origins. // Generate this token with the command (in tools/origin_trials): // generate_token.py valid.example.com Frobulate // --is-third-party --expire-timestamp=2000000000 const char kThirdPartyTokenForNonThirdPartyTrial[] = …; // Well-formed token, for match against insecure origins for a deprecation // trial. // Generate this token with the command (in tools/origin_trials): // generate_token.py http://valid.example.com FrobulateDeprecation // --expire-timestamp=2000000000 const char kDeprecationInsecureToken[] = …; // Well-formed token, for match against insecure third-party origins. // Generate this token with the command (in tools/origin_trials): // generate_token.py http://valid.example.com FrobulateThirdParty // --is-third-party --expire-timestamp=2000000000 const char kThirdPartyInsecureToken[] = …; // Well-formed token, for match against subdomain origins. // Generate this token with the command (in tools/origin_trials): // generate_token.py example.com Frobulate // --is-subdomain --expire-timestamp=2000000000 const char kSubdomainToken[] = …; // Well-formed token, for match against third-party subdomain origins. // Generate this token with the command (in tools/origin_trials): // generate_token.py example.com FrobulateThirdParty // --is-subdomain --is-third-party --expire-timestamp=2000000000 const char kThirdPartySubdomainToken[] = …; // Token for insecure third-party subdomain matching. // Generate this token with the command (in tools/origin_trials): // generate_token.py http://example.com FrobulateThirdParty // --is-subdomain --is-third-party --expire-timestamp=2000000000 const char kThirdPartyInsecureSubdomainToken[] = …; // This timestamp is set to a time after the expiry timestamp of kExpiredToken, // but before the expiry timestamp of kValidToken. double kNowTimestamp = …; class TestOriginTrialPolicy : public OriginTrialPolicy { … }; class TrialTokenValidatorTest : public testing::Test { … }; // Define two classes that wrap the ValidateToken and ValidateTokenAndTrial // methods respectively under a common name, so we can repeat the tests for each // function where it makes sense class ValidateTokenWrapper { … }; class ValidateTokenAndTrialWrapper : public ValidateTokenWrapper { … }; class ValidateTokenAndTrialWithOriginInfoWrapper : public ValidateTokenWrapper { … }; // Factory classes that allows us to instantiate a parameterized test class ValidateTokenWrapperFactory { … }; class ValidateTokenAndTrialWrapperFactory : public ValidateTokenWrapperFactory { … }; class ValidateTokenAndTrialWithOriginInfoWrapperFactory : public ValidateTokenWrapperFactory { … }; // Test suite for tests where TrialTokenValidator::ValidateToken and // TrialTokenValidator::ValidateTokenAndTrial should yield the same result class TrialTokenValidatorEquivalenceTest : public TrialTokenValidatorTest, public testing::WithParamInterface<ValidateTokenWrapperFactory> { … }; // Tests of the basic ValidateToken functionality where ValidateTokenAndTrial // should yield the same result // Using TrialTokenValidatorTest as prefix to allow for unified gtest_filter INSTANTIATE_TEST_SUITE_P(…); TEST_P(TrialTokenValidatorEquivalenceTest, ValidateValidToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartyToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartyTokenFromExternalScript) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartyTokenFromMultipleExternalScripts) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartyTokenFromInappropriateScriptOrigin) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartyTokenFromMultipleInappropriateScriptOrigins) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartyTokenNotFromExternalScript) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateInappropriateOrigin) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateInvalidSignature) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateUnparsableToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateExpiredToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateValidTokenWithIncorrectKey) { … } TEST_P(TrialTokenValidatorEquivalenceTest, PublicKeyNotAvailable) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidatorRespectsDisabledFeatures) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidatorRespectsDisabledFeaturesForUserWithFirstPartyToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidatorRespectsDisabledFeaturesForUserWithThirdPartyToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidatorRespectsDisabledTokens) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateValidExpiryGraceToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateExpiredExpiryGraceToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateValidExpiryGraceThirdPartyToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateExpiredExpiryGraceThirdPartyToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateSubdomainToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateSubdomainTokenUnrelatedOrigin) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartySubdomainToken) { … } TEST_P(TrialTokenValidatorEquivalenceTest, ValidateThirdPartySubdomainTokenInsecureOrigin) { … } // Tests of RequestEnablesFeature methods TEST_F(TrialTokenValidatorTest, ValidateRequestInsecure) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestForDeprecationInsecure) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestValidToken) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestForDeprecationValidToken) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestNoTokens) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestForDeprecationNoTokens) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestMultipleHeaders) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestMultipleHeaderValues) { … } TEST_F(TrialTokenValidatorTest, ValidateRequestUnknownFeatureToken) { … } // Tests where ValidateToken and ValidateTokenAndTrial are expected // to yield different results. // These tests should test both |ValidateToken|, |ValidateTokenAndTrial|, // and |ValidateTokenAndTrialWithOriginInfo| to ensure all entry points // give the expected results TEST_F(TrialTokenValidatorTest, ValidateUnknownFeatureToken) { … } TEST_F(TrialTokenValidatorTest, ValidateUnknownFeatureThirdPartyToken) { … } TEST_F(TrialTokenValidatorTest, ValidateInsecureToken) { … } TEST_F(TrialTokenValidatorTest, ValidateThirdPartyTokenForNonThirdPartyFeature) { … } TEST_F(TrialTokenValidatorTest, ValidateInsecureThirdPartyToken) { … } TEST_F(TrialTokenValidatorTest, ValidateInsecureThirdPartyTokenInsecureOrigin) { … } TEST_F(TrialTokenValidatorTest, ValidateInsecureThirdPartyTokenMultipleOrigins) { … } TEST_F(TrialTokenValidatorTest, ValidateThirdPartyTokenInsecureOrigin) { … } // Tests that only check the behaviour of // |ValidateTokenAndTrialWithOriginInfo| - these are the ones // that rely on changes in passing in specific OriginInfo TEST_F(TrialTokenValidatorTest, ValidateInsecureOriginInfo) { … } TEST_F(TrialTokenValidatorTest, ValidateInsecureOriginThirdPartyOriginInfo) { … } TEST_F(TrialTokenValidatorTest, ValidateInsecureThirdPartyOriginThirdPartyOriginInfo) { … } TEST_F(TrialTokenValidatorTest, ValidateMultipleInsecureThirdPartyOriginThirdPartyOriginInfo) { … } // // Tests of |RevalidateTokenAndTrial| // TEST_F(TrialTokenValidatorTest, RevalidateTokenInformation) { … } TEST_F(TrialTokenValidatorTest, RevalidateExpiredToken) { … } TEST_F(TrialTokenValidatorTest, RevalidateDisabledTrial) { … } TEST_F(TrialTokenValidatorTest, RevalidateDisabledToken) { … } TEST_F(TrialTokenValidatorTest, RevalidateDisabledTrialForUser) { … } TEST_F(TrialTokenValidatorTest, XRWTrialAllowedForAll3POrigins) { … } } // namespace blink::trial_token_validator_unittest