| 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_(CloudPolicyValidatorBase::TIMESTAMP_REQUIRED), | |
| 40 ignore_missing_dm_token_(CloudPolicyValidatorBase::DM_TOKEN_REQUIRED), | |
| 41 allow_key_rotation_(true), | |
| 42 existing_dm_token_(PolicyBuilder::kFakeToken), | |
| 43 file_thread_(content::BrowserThread::FILE, &loop_) { | |
| 44 policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey()); | |
| 45 } | |
| 46 | |
| 47 void Validate(testing::Action<void(UserCloudPolicyValidator*)> check_action) { | |
| 48 // Create a validator. | |
| 49 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(); | |
| 50 | |
| 51 // Run validation and check the result. | |
| 52 EXPECT_CALL(*this, ValidationCompletion(validator.get())).WillOnce( | |
| 53 check_action); | |
| 54 validator.release()->StartValidation( | |
| 55 base::Bind(&CloudPolicyValidatorTest::ValidationCompletion, | |
| 56 base::Unretained(this))); | |
| 57 loop_.RunUntilIdle(); | |
| 58 Mock::VerifyAndClearExpectations(this); | |
| 59 } | |
| 60 | |
| 61 scoped_ptr<UserCloudPolicyValidator> CreateValidator() { | |
| 62 std::vector<uint8> public_key; | |
| 63 EXPECT_TRUE( | |
| 64 PolicyBuilder::CreateTestSigningKey()->ExportPublicKey(&public_key)); | |
| 65 policy_.Build(); | |
| 66 | |
| 67 UserCloudPolicyValidator* validator = | |
| 68 UserCloudPolicyValidator::Create(policy_.GetCopy()); | |
| 69 validator->ValidateTimestamp(timestamp_, timestamp_, | |
| 70 ignore_missing_timestamp_); | |
| 71 validator->ValidateUsername(PolicyBuilder::kFakeUsername); | |
| 72 validator->ValidateDomain(PolicyBuilder::kFakeDomain); | |
| 73 validator->ValidateDMToken(existing_dm_token_, ignore_missing_dm_token_); | |
| 74 validator->ValidatePolicyType(dm_protocol::kChromeUserPolicyType); | |
| 75 validator->ValidatePayload(); | |
| 76 validator->ValidateSignature(public_key, allow_key_rotation_); | |
| 77 if (allow_key_rotation_) | |
| 78 validator->ValidateInitialKey(); | |
| 79 return make_scoped_ptr(validator); | |
| 80 } | |
| 81 | |
| 82 | |
| 83 void CheckSuccessfulValidation(UserCloudPolicyValidator* validator) { | |
| 84 EXPECT_TRUE(validator->success()); | |
| 85 EXPECT_EQ(policy_.policy().SerializeAsString(), | |
| 86 validator->policy()->SerializeAsString()); | |
| 87 EXPECT_EQ(policy_.policy_data().SerializeAsString(), | |
| 88 validator->policy_data()->SerializeAsString()); | |
| 89 EXPECT_EQ(policy_.payload().SerializeAsString(), | |
| 90 validator->payload()->SerializeAsString()); | |
| 91 } | |
| 92 | |
| 93 MessageLoop loop_; | |
| 94 base::Time timestamp_; | |
| 95 CloudPolicyValidatorBase::ValidateTimestampOption ignore_missing_timestamp_; | |
| 96 CloudPolicyValidatorBase::ValidateDMTokenOption ignore_missing_dm_token_; | |
| 97 std::string signing_key_; | |
| 98 bool allow_key_rotation_; | |
| 99 std::string existing_dm_token_; | |
| 100 | |
| 101 UserPolicyBuilder policy_; | |
| 102 | |
| 103 private: | |
| 104 MOCK_METHOD1(ValidationCompletion, void(UserCloudPolicyValidator* validator)); | |
| 105 | |
| 106 content::TestBrowserThread file_thread_; | |
| 107 | |
| 108 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorTest); | |
| 109 }; | |
| 110 | |
| 111 TEST_F(CloudPolicyValidatorTest, SuccessfulValidation) { | |
| 112 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); | |
| 113 } | |
| 114 | |
| 115 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidation) { | |
| 116 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(); | |
| 117 // Run validation immediately (no background tasks). | |
| 118 validator->RunValidation(); | |
| 119 CheckSuccessfulValidation(validator.get()); | |
| 120 } | |
| 121 | |
| 122 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidationWithNoExistingDMToken) { | |
| 123 existing_dm_token_.clear(); | |
| 124 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); | |
| 125 } | |
| 126 | |
| 127 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidationWithNoDMTokens) { | |
| 128 existing_dm_token_.clear(); | |
| 129 policy_.policy_data().clear_request_token(); | |
| 130 ignore_missing_dm_token_ = CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED; | |
| 131 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); | |
| 132 } | |
| 133 | |
| 134 TEST_F(CloudPolicyValidatorTest, UsernameCanonicalization) { | |
| 135 policy_.policy_data().set_username( | |
| 136 StringToUpperASCII(std::string(PolicyBuilder::kFakeUsername))); | |
| 137 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); | |
| 138 } | |
| 139 | |
| 140 TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyType) { | |
| 141 policy_.policy_data().clear_policy_type(); | |
| 142 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); | |
| 143 } | |
| 144 | |
| 145 TEST_F(CloudPolicyValidatorTest, ErrorWrongPolicyType) { | |
| 146 policy_.policy_data().set_policy_type("invalid"); | |
| 147 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); | |
| 148 } | |
| 149 | |
| 150 TEST_F(CloudPolicyValidatorTest, ErrorNoTimestamp) { | |
| 151 policy_.policy_data().clear_timestamp(); | |
| 152 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); | |
| 153 } | |
| 154 | |
| 155 TEST_F(CloudPolicyValidatorTest, IgnoreMissingTimestamp) { | |
| 156 ignore_missing_timestamp_ = CloudPolicyValidatorBase::TIMESTAMP_NOT_REQUIRED; | |
| 157 policy_.policy_data().clear_timestamp(); | |
| 158 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); | |
| 159 } | |
| 160 | |
| 161 TEST_F(CloudPolicyValidatorTest, ErrorOldTimestamp) { | |
| 162 base::Time timestamp(timestamp_ - base::TimeDelta::FromMinutes(5)); | |
| 163 policy_.policy_data().set_timestamp( | |
| 164 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); | |
| 165 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); | |
| 166 } | |
| 167 | |
| 168 TEST_F(CloudPolicyValidatorTest, ErrorTimestampFromTheFuture) { | |
| 169 base::Time timestamp(timestamp_ + base::TimeDelta::FromMinutes(5)); | |
| 170 policy_.policy_data().set_timestamp( | |
| 171 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); | |
| 172 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); | |
| 173 } | |
| 174 | |
| 175 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestToken) { | |
| 176 policy_.policy_data().clear_request_token(); | |
| 177 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); | |
| 178 } | |
| 179 | |
| 180 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestTokenNotRequired) { | |
| 181 // Even though DMTokens are not required, if the existing policy has a token, | |
| 182 // we should still generate an error if the new policy has none. | |
| 183 policy_.policy_data().clear_request_token(); | |
| 184 ignore_missing_dm_token_ = CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED; | |
| 185 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); | |
| 186 } | |
| 187 | |
| 188 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestTokenNoTokenPassed) { | |
| 189 // Mimic the first fetch of policy (no existing DM token) - should still | |
| 190 // complain about not having any DMToken. | |
| 191 existing_dm_token_.clear(); | |
| 192 policy_.policy_data().clear_request_token(); | |
| 193 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); | |
| 194 } | |
| 195 | |
| 196 TEST_F(CloudPolicyValidatorTest, ErrorInvalidRequestToken) { | |
| 197 policy_.policy_data().set_request_token("invalid"); | |
| 198 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); | |
| 199 } | |
| 200 | |
| 201 TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyValue) { | |
| 202 policy_.clear_payload(); | |
| 203 Validate( | |
| 204 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); | |
| 205 } | |
| 206 | |
| 207 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPolicyValue) { | |
| 208 policy_.clear_payload(); | |
| 209 policy_.policy_data().set_policy_value("invalid"); | |
| 210 Validate( | |
| 211 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); | |
| 212 } | |
| 213 | |
| 214 TEST_F(CloudPolicyValidatorTest, ErrorNoUsername) { | |
| 215 policy_.policy_data().clear_username(); | |
| 216 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); | |
| 217 } | |
| 218 | |
| 219 TEST_F(CloudPolicyValidatorTest, ErrorInvalidUsername) { | |
| 220 policy_.policy_data().set_username("invalid"); | |
| 221 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); | |
| 222 } | |
| 223 | |
| 224 TEST_F(CloudPolicyValidatorTest, ErrorErrorMessage) { | |
| 225 policy_.policy().set_error_message("error"); | |
| 226 Validate( | |
| 227 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); | |
| 228 } | |
| 229 | |
| 230 TEST_F(CloudPolicyValidatorTest, ErrorErrorCode) { | |
| 231 policy_.policy().set_error_code(42); | |
| 232 Validate( | |
| 233 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); | |
| 234 } | |
| 235 | |
| 236 TEST_F(CloudPolicyValidatorTest, ErrorNoSignature) { | |
| 237 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 238 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 239 policy_.policy().clear_policy_data_signature(); | |
| 240 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 241 } | |
| 242 | |
| 243 TEST_F(CloudPolicyValidatorTest, ErrorInvalidSignature) { | |
| 244 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 245 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 246 policy_.policy().set_policy_data_signature("invalid"); | |
| 247 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 248 } | |
| 249 | |
| 250 TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKey) { | |
| 251 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 252 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 253 policy_.policy().clear_new_public_key(); | |
| 254 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 255 } | |
| 256 | |
| 257 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKey) { | |
| 258 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 259 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 260 policy_.policy().set_new_public_key("invalid"); | |
| 261 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 262 } | |
| 263 | |
| 264 TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKeySignature) { | |
| 265 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 266 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 267 policy_.policy().clear_new_public_key_signature(); | |
| 268 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 269 } | |
| 270 | |
| 271 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKeySignature) { | |
| 272 policy_.set_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 273 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 274 policy_.policy().set_new_public_key_signature("invalid"); | |
| 275 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 276 } | |
| 277 | |
| 278 TEST_F(CloudPolicyValidatorTest, ErrorNoRotationAllowed) { | |
| 279 allow_key_rotation_ = false; | |
| 280 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); | |
| 281 } | |
| 282 | |
| 283 TEST_F(CloudPolicyValidatorTest, NoRotation) { | |
| 284 allow_key_rotation_ = false; | |
| 285 policy_.set_new_signing_key(scoped_ptr<crypto::RSAPrivateKey>()); | |
| 286 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); | |
| 287 } | |
| 288 | |
| 289 } // namespace | |
| 290 | |
| 291 } // namespace policy | |
| OLD | NEW |