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 |