OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 #include "base/callback.h" | 6 #include "base/callback.h" |
7 #include "base/files/file_path.h" | 7 #include "base/files/file_path.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "base/values.h" | 10 #include "base/values.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 const char kFakeONC[] = | 64 const char kFakeONC[] = |
65 "{ \"NetworkConfigurations\": [" | 65 "{ \"NetworkConfigurations\": [" |
66 " { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\"," | 66 " { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\"," |
67 " \"Type\": \"WiFi\"," | 67 " \"Type\": \"WiFi\"," |
68 " \"Name\": \"My WiFi Network\"," | 68 " \"Name\": \"My WiFi Network\"," |
69 " \"WiFi\": {" | 69 " \"WiFi\": {" |
70 " \"SSID\": \"ssid-none\"," | 70 " \"SSID\": \"ssid-none\"," |
71 " \"Security\": \"None\" }" | 71 " \"Security\": \"None\" }" |
72 " }" | 72 " }" |
73 " ]," | 73 " ]," |
| 74 " \"GlobalNetworkConfiguration\": {" |
| 75 " \"AllowOnlyPolicyNetworksToAutoconnect\": true," |
| 76 " }," |
74 " \"Certificates\": [" | 77 " \"Certificates\": [" |
75 " { \"GUID\": \"{f998f760-272b-6939-4c2beffe428697ac}\"," | 78 " { \"GUID\": \"{f998f760-272b-6939-4c2beffe428697ac}\"," |
76 " \"PKCS12\": \"abc\"," | 79 " \"PKCS12\": \"abc\"," |
77 " \"Type\": \"Client\" }" | 80 " \"Type\": \"Client\" }" |
78 " ]," | 81 " ]," |
79 " \"Type\": \"UnencryptedConfiguration\"" | 82 " \"Type\": \"UnencryptedConfiguration\"" |
80 "}"; | 83 "}"; |
81 | 84 |
82 std::string ValueToString(const base::Value* value) { | 85 std::string ValueToString(const base::Value& value) { |
83 std::stringstream str; | 86 std::stringstream str; |
84 str << *value; | 87 str << value; |
85 return str.str(); | 88 return str.str(); |
86 } | 89 } |
87 | 90 |
| 91 void AppendAll(const base::ListValue& from, base::ListValue* to) { |
| 92 for (base::ListValue::const_iterator it = from.begin(); it != from.end(); |
| 93 ++it) { |
| 94 to->Append((*it)->DeepCopy()); |
| 95 } |
| 96 } |
| 97 |
88 // Matcher to match base::Value. | 98 // Matcher to match base::Value. |
89 MATCHER_P(IsEqualTo, | 99 MATCHER_P(IsEqualTo, |
90 value, | 100 value, |
91 std::string(negation ? "isn't" : "is") + " equal to " + | 101 std::string(negation ? "isn't" : "is") + " equal to " + |
92 ValueToString(value)) { | 102 ValueToString(*value)) { |
93 return value->Equals(&arg); | 103 return value->Equals(&arg); |
94 } | 104 } |
95 | 105 |
| 106 MATCHER(IsEmpty, std::string(negation ? "isn't" : "is") + " empty.") { |
| 107 return arg.empty(); |
| 108 } |
| 109 |
96 ACTION_P(SetCertificateList, list) { | 110 ACTION_P(SetCertificateList, list) { |
97 if (arg2) | 111 if (arg2) |
98 *arg2 = list; | 112 *arg2 = list; |
99 return true; | 113 return true; |
100 } | 114 } |
101 | 115 |
102 } // namespace | 116 } // namespace |
103 | 117 |
104 class NetworkConfigurationUpdaterTest : public testing::Test { | 118 class NetworkConfigurationUpdaterTest : public testing::Test { |
105 protected: | 119 protected: |
106 NetworkConfigurationUpdaterTest() { | 120 NetworkConfigurationUpdaterTest() { |
107 } | 121 } |
108 | 122 |
109 virtual void SetUp() OVERRIDE { | 123 virtual void SetUp() OVERRIDE { |
110 EXPECT_CALL(provider_, IsInitializationComplete(_)) | 124 EXPECT_CALL(provider_, IsInitializationComplete(_)) |
111 .WillRepeatedly(Return(true)); | 125 .WillRepeatedly(Return(true)); |
112 provider_.Init(); | 126 provider_.Init(); |
113 PolicyServiceImpl::Providers providers; | 127 PolicyServiceImpl::Providers providers; |
114 providers.push_back(&provider_); | 128 providers.push_back(&provider_); |
115 policy_service_.reset(new PolicyServiceImpl(providers)); | 129 policy_service_.reset(new PolicyServiceImpl(providers)); |
116 | 130 |
117 empty_network_configs_.reset(new base::ListValue); | |
118 empty_certificates_.reset(new base::ListValue); | |
119 | |
120 scoped_ptr<base::DictionaryValue> fake_toplevel_onc = | 131 scoped_ptr<base::DictionaryValue> fake_toplevel_onc = |
121 chromeos::onc::ReadDictionaryFromJson(kFakeONC); | 132 chromeos::onc::ReadDictionaryFromJson(kFakeONC); |
122 | 133 |
123 scoped_ptr<base::Value> network_configs_value; | |
124 base::ListValue* network_configs = NULL; | 134 base::ListValue* network_configs = NULL; |
125 fake_toplevel_onc->RemoveWithoutPathExpansion( | 135 fake_toplevel_onc->GetListWithoutPathExpansion( |
126 onc::toplevel_config::kNetworkConfigurations, &network_configs_value); | 136 onc::toplevel_config::kNetworkConfigurations, &network_configs); |
127 network_configs_value.release()->GetAsList(&network_configs); | 137 AppendAll(*network_configs, &fake_network_configs_); |
128 fake_network_configs_.reset(network_configs); | |
129 | 138 |
130 scoped_ptr<base::Value> certs_value; | 139 base::DictionaryValue* global_config = NULL; |
| 140 fake_toplevel_onc->GetDictionaryWithoutPathExpansion( |
| 141 onc::toplevel_config::kGlobalNetworkConfiguration, &global_config); |
| 142 fake_global_network_config_.MergeDictionary(global_config); |
| 143 |
131 base::ListValue* certs = NULL; | 144 base::ListValue* certs = NULL; |
132 fake_toplevel_onc->RemoveWithoutPathExpansion( | 145 fake_toplevel_onc->GetListWithoutPathExpansion( |
133 onc::toplevel_config::kCertificates, &certs_value); | 146 onc::toplevel_config::kCertificates, &certs); |
134 certs_value.release()->GetAsList(&certs); | 147 AppendAll(*certs, &fake_certificates_); |
135 fake_certificates_.reset(certs); | |
136 | 148 |
137 certificate_importer_ = | 149 certificate_importer_ = |
138 new StrictMock<chromeos::onc::MockCertificateImporter>(); | 150 new StrictMock<chromeos::onc::MockCertificateImporter>(); |
139 certificate_importer_owned_.reset(certificate_importer_); | 151 certificate_importer_owned_.reset(certificate_importer_); |
140 } | 152 } |
141 | 153 |
142 virtual void TearDown() OVERRIDE { | 154 virtual void TearDown() OVERRIDE { |
143 network_configuration_updater_.reset(); | 155 network_configuration_updater_.reset(); |
144 provider_.Shutdown(); | 156 provider_.Shutdown(); |
145 base::RunLoop().RunUntilIdle(); | 157 base::RunLoop().RunUntilIdle(); |
(...skipping 19 matching lines...) Expand all Loading... |
165 } | 177 } |
166 | 178 |
167 void CreateNetworkConfigurationUpdaterForDevicePolicy() { | 179 void CreateNetworkConfigurationUpdaterForDevicePolicy() { |
168 network_configuration_updater_ = | 180 network_configuration_updater_ = |
169 NetworkConfigurationUpdater::CreateForDevicePolicy( | 181 NetworkConfigurationUpdater::CreateForDevicePolicy( |
170 certificate_importer_owned_.Pass(), | 182 certificate_importer_owned_.Pass(), |
171 policy_service_.get(), | 183 policy_service_.get(), |
172 &network_config_handler_); | 184 &network_config_handler_); |
173 } | 185 } |
174 | 186 |
175 scoped_ptr<base::ListValue> empty_network_configs_; | 187 base::ListValue fake_network_configs_; |
176 scoped_ptr<base::ListValue> empty_certificates_; | 188 base::DictionaryValue fake_global_network_config_; |
177 scoped_ptr<base::ListValue> fake_network_configs_; | 189 base::ListValue fake_certificates_; |
178 scoped_ptr<base::ListValue> fake_certificates_; | |
179 StrictMock<chromeos::MockManagedNetworkConfigurationHandler> | 190 StrictMock<chromeos::MockManagedNetworkConfigurationHandler> |
180 network_config_handler_; | 191 network_config_handler_; |
181 | 192 |
182 // Ownership of certificate_importer_owned_ is passed to the | 193 // Ownership of certificate_importer_owned_ is passed to the |
183 // NetworkConfigurationUpdater. When that happens, |certificate_importer_| | 194 // NetworkConfigurationUpdater. When that happens, |certificate_importer_| |
184 // continues to point to that instance but |certificate_importer_owned_| is | 195 // continues to point to that instance but |certificate_importer_owned_| is |
185 // released. | 196 // released. |
186 StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer_; | 197 StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer_; |
187 scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer_owned_; | 198 scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer_owned_; |
188 | 199 |
(...skipping 11 matching lines...) Expand all Loading... |
200 | 211 |
201 scoped_ptr<base::DictionaryValue> onc_repaired = | 212 scoped_ptr<base::DictionaryValue> onc_repaired = |
202 chromeos::onc::test_utils::ReadTestDictionary( | 213 chromeos::onc::test_utils::ReadTestDictionary( |
203 "repaired_toplevel_partially_invalid.onc"); | 214 "repaired_toplevel_partially_invalid.onc"); |
204 | 215 |
205 base::ListValue* network_configs_repaired = NULL; | 216 base::ListValue* network_configs_repaired = NULL; |
206 onc_repaired->GetListWithoutPathExpansion( | 217 onc_repaired->GetListWithoutPathExpansion( |
207 onc::toplevel_config::kNetworkConfigurations, &network_configs_repaired); | 218 onc::toplevel_config::kNetworkConfigurations, &network_configs_repaired); |
208 ASSERT_TRUE(network_configs_repaired); | 219 ASSERT_TRUE(network_configs_repaired); |
209 | 220 |
| 221 base::DictionaryValue* global_config_repaired = NULL; |
| 222 onc_repaired->GetDictionaryWithoutPathExpansion( |
| 223 onc::toplevel_config::kGlobalNetworkConfiguration, |
| 224 &global_config_repaired); |
| 225 ASSERT_TRUE(global_config_repaired); |
| 226 |
210 PolicyMap policy; | 227 PolicyMap policy; |
211 policy.Set(key::kOpenNetworkConfiguration, | 228 policy.Set(key::kOpenNetworkConfiguration, |
212 POLICY_LEVEL_MANDATORY, | 229 POLICY_LEVEL_MANDATORY, |
213 POLICY_SCOPE_USER, | 230 POLICY_SCOPE_USER, |
214 new base::StringValue(onc_policy), | 231 new base::StringValue(onc_policy), |
215 NULL); | 232 NULL); |
216 UpdateProviderPolicy(policy); | 233 UpdateProviderPolicy(policy); |
217 | 234 |
218 EXPECT_CALL( | 235 EXPECT_CALL(network_config_handler_, |
219 network_config_handler_, | 236 SetPolicy(onc::ONC_SOURCE_USER_POLICY, |
220 SetPolicy( | 237 _, |
221 onc::ONC_SOURCE_USER_POLICY, _, IsEqualTo(network_configs_repaired))); | 238 IsEqualTo(network_configs_repaired), |
| 239 IsEqualTo(global_config_repaired))); |
222 EXPECT_CALL(*certificate_importer_, | 240 EXPECT_CALL(*certificate_importer_, |
223 ImportCertificates(_, onc::ONC_SOURCE_USER_POLICY, _)); | 241 ImportCertificates(_, onc::ONC_SOURCE_USER_POLICY, _)); |
224 | 242 |
225 CreateNetworkConfigurationUpdaterForUserPolicy( | 243 CreateNetworkConfigurationUpdaterForUserPolicy( |
226 false /* do not allow trusted certs from policy */ ); | 244 false /* do not allow trusted certs from policy */ ); |
227 } | 245 } |
228 | 246 |
229 TEST_F(NetworkConfigurationUpdaterTest, | 247 TEST_F(NetworkConfigurationUpdaterTest, |
230 DoNotAllowTrustedCertificatesFromPolicy) { | 248 DoNotAllowTrustedCertificatesFromPolicy) { |
231 net::CertificateList cert_list; | 249 net::CertificateList cert_list; |
232 cert_list = | 250 cert_list = |
233 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), | 251 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), |
234 "ok_cert.pem", | 252 "ok_cert.pem", |
235 net::X509Certificate::FORMAT_AUTO); | 253 net::X509Certificate::FORMAT_AUTO); |
236 ASSERT_EQ(1u, cert_list.size()); | 254 ASSERT_EQ(1u, cert_list.size()); |
237 | 255 |
238 EXPECT_CALL(network_config_handler_, | 256 EXPECT_CALL(network_config_handler_, |
239 SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _)); | 257 SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _)); |
240 EXPECT_CALL(*certificate_importer_, ImportCertificates(_, _, _)) | 258 EXPECT_CALL(*certificate_importer_, ImportCertificates(_, _, _)) |
241 .WillRepeatedly(SetCertificateList(cert_list)); | 259 .WillRepeatedly(SetCertificateList(cert_list)); |
242 | 260 |
243 UserNetworkConfigurationUpdater* updater = | 261 UserNetworkConfigurationUpdater* updater = |
244 CreateNetworkConfigurationUpdaterForUserPolicy( | 262 CreateNetworkConfigurationUpdaterForUserPolicy( |
245 false /* do not allow trusted certs from policy */); | 263 false /* do not allow trusted certs from policy */); |
246 | 264 |
247 // Certificates with the "Web" trust flag set should not be forwarded to the | 265 // Certificates with the "Web" trust flag set should not be forwarded to the |
248 // trust provider. | 266 // trust provider. |
249 policy::PolicyCertVerifier cert_verifier(( | 267 policy::PolicyCertVerifier cert_verifier(( |
250 base::Closure() /* no policy cert trusted callback */)); | 268 base::Closure() /* no policy cert trusted callback */)); |
251 updater->SetPolicyCertVerifier(&cert_verifier); | 269 updater->SetPolicyCertVerifier(&cert_verifier); |
252 base::RunLoop().RunUntilIdle(); | 270 base::RunLoop().RunUntilIdle(); |
253 EXPECT_TRUE(cert_verifier.GetAdditionalTrustAnchors().empty()); | 271 EXPECT_TRUE(cert_verifier.GetAdditionalTrustAnchors().empty()); |
254 | 272 |
255 // |cert_verifier| must outlive the updater. | 273 // |cert_verifier| must outlive the updater. |
256 network_configuration_updater_.reset(); | 274 network_configuration_updater_.reset(); |
257 } | 275 } |
258 | 276 |
259 TEST_F(NetworkConfigurationUpdaterTest, AllowTrustedCertificatesFromPolicy) { | 277 TEST_F(NetworkConfigurationUpdaterTest, AllowTrustedCertificatesFromPolicy) { |
260 net::CertificateList cert_list; | 278 net::CertificateList cert_list; |
261 cert_list = | 279 cert_list = |
262 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), | 280 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), |
263 "ok_cert.pem", | 281 "ok_cert.pem", |
264 net::X509Certificate::FORMAT_AUTO); | 282 net::X509Certificate::FORMAT_AUTO); |
265 ASSERT_EQ(1u, cert_list.size()); | 283 ASSERT_EQ(1u, cert_list.size()); |
266 | 284 |
267 EXPECT_CALL(network_config_handler_, | 285 EXPECT_CALL(network_config_handler_, |
268 SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _)); | 286 SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _)); |
269 EXPECT_CALL(*certificate_importer_, | 287 EXPECT_CALL(*certificate_importer_, |
270 ImportCertificates(_, onc::ONC_SOURCE_USER_POLICY, _)) | 288 ImportCertificates(_, onc::ONC_SOURCE_USER_POLICY, _)) |
271 .WillRepeatedly(SetCertificateList(cert_list)); | 289 .WillRepeatedly(SetCertificateList(cert_list)); |
272 | 290 |
273 UserNetworkConfigurationUpdater* updater = | 291 UserNetworkConfigurationUpdater* updater = |
274 CreateNetworkConfigurationUpdaterForUserPolicy( | 292 CreateNetworkConfigurationUpdaterForUserPolicy( |
275 true /* allow trusted certs from policy */); | 293 true /* allow trusted certs from policy */); |
276 | 294 |
277 // Certificates with the "Web" trust flag set should be forwarded to the | 295 // Certificates with the "Web" trust flag set should be forwarded to the |
278 // trust provider. | 296 // trust provider. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 | 336 |
319 TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) { | 337 TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) { |
320 PolicyMap policy; | 338 PolicyMap policy; |
321 policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, | 339 policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, |
322 new base::StringValue(kFakeONC), NULL); | 340 new base::StringValue(kFakeONC), NULL); |
323 UpdateProviderPolicy(policy); | 341 UpdateProviderPolicy(policy); |
324 | 342 |
325 EXPECT_CALL(network_config_handler_, | 343 EXPECT_CALL(network_config_handler_, |
326 SetPolicy(CurrentONCSource(), | 344 SetPolicy(CurrentONCSource(), |
327 ExpectedUsernameHash(), | 345 ExpectedUsernameHash(), |
328 IsEqualTo(fake_network_configs_.get()))); | 346 IsEqualTo(&fake_network_configs_), |
| 347 IsEqualTo(&fake_global_network_config_))); |
329 EXPECT_CALL(*certificate_importer_, | 348 EXPECT_CALL(*certificate_importer_, |
330 ImportCertificates( | 349 ImportCertificates( |
331 IsEqualTo(fake_certificates_.get()), CurrentONCSource(), _)); | 350 IsEqualTo(&fake_certificates_), CurrentONCSource(), _)); |
332 | 351 |
333 CreateNetworkConfigurationUpdater(); | 352 CreateNetworkConfigurationUpdater(); |
334 } | 353 } |
335 | 354 |
336 | 355 |
337 TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) { | 356 TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) { |
338 // Ignore the initial updates. | 357 // Ignore the initial updates. |
339 EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _)).Times(AtLeast(1)); | 358 EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _)).Times(AtLeast(1)); |
340 EXPECT_CALL(*certificate_importer_, ImportCertificates(_, _, _)) | 359 EXPECT_CALL(*certificate_importer_, ImportCertificates(_, _, _)) |
341 .Times(AtLeast(1)); | 360 .Times(AtLeast(1)); |
342 CreateNetworkConfigurationUpdater(); | 361 CreateNetworkConfigurationUpdater(); |
343 Mock::VerifyAndClearExpectations(&network_config_handler_); | 362 Mock::VerifyAndClearExpectations(&network_config_handler_); |
344 Mock::VerifyAndClearExpectations(certificate_importer_); | 363 Mock::VerifyAndClearExpectations(certificate_importer_); |
345 | 364 |
346 // The Updater should update if policy changes. | 365 // The Updater should update if policy changes. |
347 EXPECT_CALL( | 366 EXPECT_CALL(network_config_handler_, |
348 network_config_handler_, | 367 SetPolicy(CurrentONCSource(), |
349 SetPolicy(CurrentONCSource(), _, IsEqualTo(fake_network_configs_.get()))); | 368 _, |
| 369 IsEqualTo(&fake_network_configs_), |
| 370 IsEqualTo(&fake_global_network_config_))); |
350 EXPECT_CALL(*certificate_importer_, | 371 EXPECT_CALL(*certificate_importer_, |
351 ImportCertificates( | 372 ImportCertificates( |
352 IsEqualTo(fake_certificates_.get()), CurrentONCSource(), _)); | 373 IsEqualTo(&fake_certificates_), CurrentONCSource(), _)); |
353 | 374 |
354 PolicyMap policy; | 375 PolicyMap policy; |
355 policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, | 376 policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, |
356 new base::StringValue(kFakeONC), NULL); | 377 new base::StringValue(kFakeONC), NULL); |
357 UpdateProviderPolicy(policy); | 378 UpdateProviderPolicy(policy); |
358 Mock::VerifyAndClearExpectations(&network_config_handler_); | 379 Mock::VerifyAndClearExpectations(&network_config_handler_); |
359 Mock::VerifyAndClearExpectations(certificate_importer_); | 380 Mock::VerifyAndClearExpectations(certificate_importer_); |
360 | 381 |
361 // Another update is expected if the policy goes away. | 382 // Another update is expected if the policy goes away. |
362 EXPECT_CALL( | 383 EXPECT_CALL(network_config_handler_, |
363 network_config_handler_, | 384 SetPolicy(CurrentONCSource(), _, IsEmpty(), IsEmpty())); |
364 SetPolicy( | |
365 CurrentONCSource(), _, IsEqualTo(empty_network_configs_.get()))); | |
366 EXPECT_CALL(*certificate_importer_, | 385 EXPECT_CALL(*certificate_importer_, |
367 ImportCertificates( | 386 ImportCertificates(IsEmpty(), CurrentONCSource(), _)); |
368 IsEqualTo(empty_certificates_.get()), CurrentONCSource(), _)); | |
369 | 387 |
370 policy.Erase(GetParam()); | 388 policy.Erase(GetParam()); |
371 UpdateProviderPolicy(policy); | 389 UpdateProviderPolicy(policy); |
372 } | 390 } |
373 | 391 |
374 INSTANTIATE_TEST_CASE_P(NetworkConfigurationUpdaterTestWithParamInstance, | 392 INSTANTIATE_TEST_CASE_P(NetworkConfigurationUpdaterTestWithParamInstance, |
375 NetworkConfigurationUpdaterTestWithParam, | 393 NetworkConfigurationUpdaterTestWithParam, |
376 testing::Values(key::kDeviceOpenNetworkConfiguration, | 394 testing::Values(key::kDeviceOpenNetworkConfiguration, |
377 key::kOpenNetworkConfiguration)); | 395 key::kOpenNetworkConfiguration)); |
378 | 396 |
379 } // namespace policy | 397 } // namespace policy |
OLD | NEW |