| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <vector> | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/memory/scoped_ptr.h" | |
| 9 #include "base/message_loop.h" | |
| 10 #include "base/string_util.h" | |
| 11 #include "chrome/browser/policy/cloud_policy_constants.h" | |
| 12 #include "chrome/browser/policy/cloud_policy_validator.h" | |
| 13 #include "chrome/browser/policy/policy_builder.h" | |
| 14 #include "content/public/test/test_browser_thread.h" | |
| 15 #include "crypto/rsa_private_key.h" | |
| 16 #include "testing/gmock/include/gmock/gmock.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 namespace em = enterprise_management; | |
| 20 | |
| 21 using testing::Invoke; | |
| 22 using testing::Mock; | |
| 23 | |
| 24 namespace policy { | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 ACTION_P(CheckStatus, expected_status) { | |
| 29 EXPECT_EQ(expected_status, arg0->status()); | |
| 30 }; | |
| 31 | |
| 32 class CloudPolicyValidatorTest : public testing::Test { | |
| 33 public: | |
| 34 CloudPolicyValidatorTest() | |
| 35 : loop_(MessageLoop::TYPE_UI), | |
| 36 timestamp_(base::Time::UnixEpoch() + | |
| 37 base::TimeDelta::FromMilliseconds( | |
| 38 PolicyBuilder::kFakeTimestamp)), | |
| 39 ignore_missing_timestamp_(false), | |
| 40 allow_key_rotation_(true), | |
| 41 file_thread_(content::BrowserThread::FILE, &loop_) { | |
| 42 policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey()); | |
| 43 } | |
| 44 | |
| 45 void Validate(testing::Action<void(UserCloudPolicyValidator*)> check_action) { | |
| 46 // Create a validator. | |
| 47 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(); | |
| 48 | |
| 49 // Run validation and check the result. | |
| 50 EXPECT_CALL(*this, ValidationCompletion(validator.get())).WillOnce( | |
| 51 check_action); | |
| 52 validator.release()->StartValidation( | |
| 53 base::Bind(&CloudPolicyValidatorTest::ValidationCompletion, | |
| 54 base::Unretained(this))); | |
| 55 loop_.RunUntilIdle(); | |
| 56 Mock::VerifyAndClearExpectations(this); | |
| 57 } | |
| 58 | |
| 59 scoped_ptr<UserCloudPolicyValidator> CreateValidator() { | |
| 60 std::vector<uint8> public_key; | |
| 61 EXPECT_TRUE( | |
| 62 PolicyBuilder::CreateTestSigningKey()->ExportPublicKey(&public_key)); | |
| 63 policy_.Build(); | |
| 64 | |
| 65 UserCloudPolicyValidator* validator = | |
| 66 UserCloudPolicyValidator::Create(policy_.GetCopy()); | |
| 67 validator->ValidateTimestamp(timestamp_, timestamp_, | |
| 68 ignore_missing_timestamp_); | |
| 69 validator->ValidateUsername(PolicyBuilder::kFakeUsername); | |
| 70 validator->ValidateDomain(PolicyBuilder::kFakeDomain); | |
| 71 validator->ValidateDMToken(PolicyBuilder::kFakeToken); | |
| 72 validator->ValidatePolicyType(dm_protocol::kChromeUserPolicyType); | |
| 73 validator->ValidatePayload(); | |
| 74 validator->ValidateSignature(public_key, allow_key_rotation_); | |
| 75 if (allow_key_rotation_) | |
| 76 validator->ValidateInitialKey(); | |
| 77 return make_scoped_ptr(validator); | |
| 78 } | |
| 79 | |
| 80 | |
| 81 void CheckSuccessfulValidation(UserCloudPolicyValidator* validator) { | |
| 82 EXPECT_TRUE(validator->success()); | |
| 83 EXPECT_EQ(policy_.policy().SerializeAsString(), | |
| 84 validator->policy()->SerializeAsString()); | |
| 85 EXPECT_EQ(policy_.policy_data().SerializeAsString(), | |
| 86 validator->policy_data()->SerializeAsString()); | |
| 87 EXPECT_EQ(policy_.payload().SerializeAsString(), | |
| 88 validator->payload()->SerializeAsString()); | |
| 89 } | |
| 90 | |
| 91 MessageLoop loop_; | |
| 92 base::Time timestamp_; | |
| 93 bool ignore_missing_timestamp_; | |
| 94 std::string signing_key_; | |
| 95 bool allow_key_rotation_; | |
| 96 | |
| 97 UserPolicyBuilder policy_; | |
| 98 | |
| 99 private: | |
| 100 MOCK_METHOD1(ValidationCompletion, void(UserCloudPolicyValidator* validator)); | |
| 101 | |
| 102 content::TestBrowserThread file_thread_; | |
| 103 | |
| 104 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorTest); | |
| 105 }; | |
| 106 | |
| 107 TEST_F(CloudPolicyValidatorTest, SuccessfulValidation) { | |
| 108 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); | |
| 109 } | |
| 110 | |
| 111 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidation) { | |
| 112 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(); | |
| 113 // Run validation immediately (no background tasks). | |
| 114 validator->RunValidation(); | |
| 115 CheckSuccessfulValidation(validator.get()); | |
| 116 } | |
| 117 | |
| 118 TEST_F(CloudPolicyValidatorTest, UsernameCanonicalization) { | |
| 119 policy_.policy_data().set_username( | |
| 120 StringToUpperASCII(std::string(PolicyBuilder::kFakeUsername))); | |
| 121 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); | |
| 122 } | |
| 123 | |
| 124 TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyType) { | |
| 125 policy_.policy_data().clear_policy_type(); | |
| 126 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); | |
| 127 } | |
| 128 | |
| 129 TEST_F(CloudPolicyValidatorTest, ErrorWrongPolicyType) { | |
| 130 policy_.policy_data().set_policy_type("invalid"); | |
| 131 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); | |
| 132 } | |
| 133 | |
| 134 TEST_F(CloudPolicyValidatorTest, ErrorNoTimestamp) { | |
| 135 policy_.policy_data().clear_timestamp(); | |
| 136 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); | |
| 137 } | |
| 138 | |
| 139 TEST_F(CloudPolicyValidatorTest, IgnoreMissingTimestamp) { | |
| 140 ignore_missing_timestamp_ = true; | |
| 141 policy_.policy_data().clear_timestamp(); | |
| 142 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); | |
| 143 } | |
| 144 | |
| 145 TEST_F(CloudPolicyValidatorTest, ErrorOldTimestamp) { | |
| 146 base::Time timestamp(timestamp_ - base::TimeDelta::FromMinutes(5)); | |
| 147 policy_.policy_data().set_timestamp( | |
| 148 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); | |
| 149 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); | |
| 150 } | |
| 151 | |
| 152 TEST_F(CloudPolicyValidatorTest, ErrorTimestampFromTheFuture) { | |
| 153 base::Time timestamp(timestamp_ + base::TimeDelta::FromMinutes(5)); | |
| 154 policy_.policy_data().set_timestamp( | |
| 155 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); | |
| 156 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); | |
| 157 } | |
| 158 | |
| 159 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestToken) { | |
| 160 policy_.policy_data().clear_request_token(); | |
| 161 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); | |
| 162 } | |
| 163 | |
| 164 TEST_F(CloudPolicyValidatorTest, ErrorInvalidRequestToken) { | |
| 165 policy_.policy_data().set_request_token("invalid"); | |
| 166 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); | |
| 167 } | |
| 168 | |
| 169 TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyValue) { | |
| 170 policy_.clear_payload(); | |
| 171 Validate( | |
| 172 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); | |
| 173 } | |
| 174 | |
| 175 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPolicyValue) { | |
| 176 policy_.clear_payload(); | |
| 177 policy_.policy_data().set_policy_value("invalid"); | |
| 178 Validate( | |
| 179 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); | |
| 180 } | |
| 181 | |
| 182 TEST_F(CloudPolicyValidatorTest, ErrorNoUsername) { | |
| 183 policy_.policy_data().clear_username(); | |
| 184 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); | |
| 185 } | |
| 186 | |
| 187 TEST_F(CloudPolicyValidatorTest, ErrorInvalidUsername) { | |
| 188 policy_.policy_data().set_username("invalid"); | |
| 189 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); | |
| 190 } | |
| 191 | |
| 192 TEST_F(CloudPolicyValidatorTest, ErrorErrorMessage) { | |
| 193 policy_.policy().set_error_message("error"); | |
| 194 Validate( | |
| 195 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); | |
| 196 } | |
| 197 | |
| 198 TEST_F(CloudPolicyValidatorTest, ErrorErrorCode) { | |
| 199 policy_.policy().set_error_code(42); | |
| 200 Validate( | |
| 201 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); | |
| 202 } | |
| 203 | |
| 204 TEST_F(CloudPolicyValidatorTest, ErrorNoSignature) { | |
| 205 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 206 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 207 policy_.policy().clear_policy_data_signature(); | |
| 208 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 209 } | |
| 210 | |
| 211 TEST_F(CloudPolicyValidatorTest, ErrorInvalidSignature) { | |
| 212 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 213 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 214 policy_.policy().set_policy_data_signature("invalid"); | |
| 215 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 216 } | |
| 217 | |
| 218 TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKey) { | |
| 219 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 220 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 221 policy_.policy().clear_new_public_key(); | |
| 222 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 223 } | |
| 224 | |
| 225 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKey) { | |
| 226 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 227 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 228 policy_.policy().set_new_public_key("invalid"); | |
| 229 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 230 } | |
| 231 | |
| 232 TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKeySignature) { | |
| 233 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 234 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 235 policy_.policy().clear_new_public_key_signature(); | |
| 236 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 237 } | |
| 238 | |
| 239 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKeySignature) { | |
| 240 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 241 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 242 policy_.policy().set_new_public_key_signature("invalid"); | |
| 243 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 244 } | |
| 245 | |
| 246 TEST_F(CloudPolicyValidatorTest, ErrorNoRotationAllowed) { | |
| 247 allow_key_rotation_ = false; | |
| 248 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 249 } | |
| 250 | |
| 251 TEST_F(CloudPolicyValidatorTest, NoRotation) { | |
| 252 allow_key_rotation_ = false; | |
| 253 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 254 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); | |
| 255 } | |
| 256 | |
| 257 } // namespace | |
| 258 | |
| 259 } // namespace policy | |
| OLD | NEW |