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