- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / policy / cloud / cloud_policy_validator_unittest.cc
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