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 |