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