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/strings/string_util.h" 11#include "chrome/browser/policy/cloud/cloud_policy_constants.h" 12#include "chrome/browser/policy/cloud/cloud_policy_validator.h" 13#include "chrome/browser/policy/cloud/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 19namespace em = enterprise_management; 20 21using testing::Invoke; 22using testing::Mock; 23 24namespace policy { 25 26namespace { 27 28ACTION_P(CheckStatus, expected_status) { 29 EXPECT_EQ(expected_status, arg0->status()); 30}; 31 32class 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 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_.SetDefaultNewSigningKey(); 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 base::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 111TEST_F(CloudPolicyValidatorTest, SuccessfulValidation) { 112 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); 113} 114 115TEST_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 122TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidationWithNoExistingDMToken) { 123 existing_dm_token_.clear(); 124 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); 125} 126 127TEST_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 134TEST_F(CloudPolicyValidatorTest, UsernameCanonicalization) { 135 policy_.policy_data().set_username( 136 StringToUpperASCII(std::string(PolicyBuilder::kFakeUsername))); 137 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); 138} 139 140TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyType) { 141 policy_.policy_data().clear_policy_type(); 142 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); 143} 144 145TEST_F(CloudPolicyValidatorTest, ErrorWrongPolicyType) { 146 policy_.policy_data().set_policy_type("invalid"); 147 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); 148} 149 150TEST_F(CloudPolicyValidatorTest, ErrorNoTimestamp) { 151 policy_.policy_data().clear_timestamp(); 152 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); 153} 154 155TEST_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 161TEST_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 168TEST_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 175TEST_F(CloudPolicyValidatorTest, ErrorNoRequestToken) { 176 policy_.policy_data().clear_request_token(); 177 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); 178} 179 180TEST_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 188TEST_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 196TEST_F(CloudPolicyValidatorTest, ErrorInvalidRequestToken) { 197 policy_.policy_data().set_request_token("invalid"); 198 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); 199} 200 201TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyValue) { 202 policy_.clear_payload(); 203 Validate( 204 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); 205} 206 207TEST_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 214TEST_F(CloudPolicyValidatorTest, ErrorNoUsername) { 215 policy_.policy_data().clear_username(); 216 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); 217} 218 219TEST_F(CloudPolicyValidatorTest, ErrorInvalidUsername) { 220 policy_.policy_data().set_username("invalid"); 221 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); 222} 223 224TEST_F(CloudPolicyValidatorTest, ErrorErrorMessage) { 225 policy_.policy().set_error_message("error"); 226 Validate( 227 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); 228} 229 230TEST_F(CloudPolicyValidatorTest, ErrorErrorCode) { 231 policy_.policy().set_error_code(42); 232 Validate( 233 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); 234} 235 236TEST_F(CloudPolicyValidatorTest, ErrorNoSignature) { 237 policy_.UnsetSigningKey(); 238 policy_.UnsetNewSigningKey(); 239 policy_.policy().clear_policy_data_signature(); 240 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 241} 242 243TEST_F(CloudPolicyValidatorTest, ErrorInvalidSignature) { 244 policy_.UnsetSigningKey(); 245 policy_.UnsetNewSigningKey(); 246 policy_.policy().set_policy_data_signature("invalid"); 247 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 248} 249 250TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKey) { 251 policy_.UnsetSigningKey(); 252 policy_.UnsetNewSigningKey(); 253 policy_.policy().clear_new_public_key(); 254 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 255} 256 257TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKey) { 258 policy_.UnsetSigningKey(); 259 policy_.UnsetNewSigningKey(); 260 policy_.policy().set_new_public_key("invalid"); 261 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 262} 263 264TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKeySignature) { 265 policy_.UnsetSigningKey(); 266 policy_.UnsetNewSigningKey(); 267 policy_.policy().clear_new_public_key_signature(); 268 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 269} 270 271TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKeySignature) { 272 policy_.UnsetSigningKey(); 273 policy_.UnsetNewSigningKey(); 274 policy_.policy().set_new_public_key_signature("invalid"); 275 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 276} 277 278TEST_F(CloudPolicyValidatorTest, ErrorNoRotationAllowed) { 279 allow_key_rotation_ = false; 280 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 281} 282 283TEST_F(CloudPolicyValidatorTest, NoRotation) { 284 allow_key_rotation_ = false; 285 policy_.UnsetNewSigningKey(); 286 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); 287} 288 289} // namespace 290 291} // namespace policy 292