1// Copyright 2014 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 <UIKit/UIKit.h> 6 7#include "base/basictypes.h" 8#include "base/callback.h" 9#include "base/files/file_path.h" 10#include "base/ios/ios_util.h" 11#include "base/strings/sys_string_conversions.h" 12#include "base/test/test_simple_task_runner.h" 13#include "base/values.h" 14#include "components/policy/core/common/async_policy_provider.h" 15#include "components/policy/core/common/configuration_policy_provider_test.h" 16#include "components/policy/core/common/policy_bundle.h" 17#include "components/policy/core/common/policy_loader_ios.h" 18#include "components/policy/core/common/policy_map.h" 19#include "components/policy/core/common/policy_test_utils.h" 20#include "testing/gtest/include/gtest/gtest.h" 21 22namespace policy { 23 24namespace { 25 26// Key in the NSUserDefaults that contains the managed app configuration. 27NSString* const kConfigurationKey = @"com.apple.configuration.managed"; 28 29class TestHarness : public PolicyProviderTestHarness { 30 public: 31 // If |use_encoded_key| is true then AddPolicies() serializes and encodes 32 // the policies, and publishes them under the EncodedChromePolicy key. 33 explicit TestHarness(bool use_encoded_key); 34 virtual ~TestHarness(); 35 36 virtual void SetUp() OVERRIDE; 37 38 virtual ConfigurationPolicyProvider* CreateProvider( 39 SchemaRegistry* registry, 40 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE; 41 42 virtual void InstallEmptyPolicy() OVERRIDE; 43 virtual void InstallStringPolicy(const std::string& policy_name, 44 const std::string& policy_value) OVERRIDE; 45 virtual void InstallIntegerPolicy(const std::string& policy_name, 46 int policy_value) OVERRIDE; 47 virtual void InstallBooleanPolicy(const std::string& policy_name, 48 bool policy_value) OVERRIDE; 49 virtual void InstallStringListPolicy( 50 const std::string& policy_name, 51 const base::ListValue* policy_value) OVERRIDE; 52 virtual void InstallDictionaryPolicy( 53 const std::string& policy_name, 54 const base::DictionaryValue* policy_value) OVERRIDE; 55 56 static PolicyProviderTestHarness* Create(); 57 static PolicyProviderTestHarness* CreateWithEncodedKey(); 58 59 private: 60 // Merges the policies in |policy| into the current policy dictionary 61 // in NSUserDefaults, after making sure that the policy dictionary 62 // exists. 63 void AddPolicies(NSDictionary* policy); 64 void AddChromePolicy(NSDictionary* policy); 65 void AddEncodedChromePolicy(NSDictionary* policy); 66 67 bool use_encoded_key_; 68 69 DISALLOW_COPY_AND_ASSIGN(TestHarness); 70}; 71 72TestHarness::TestHarness(bool use_encoded_key) 73 : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE), 74 use_encoded_key_(use_encoded_key) {} 75 76TestHarness::~TestHarness() { 77 // Cleanup any policies left from the test. 78 [[NSUserDefaults standardUserDefaults] removeObjectForKey:kConfigurationKey]; 79} 80 81void TestHarness::SetUp() { 82 // Make sure there is no pre-existing policy present. 83 [[NSUserDefaults standardUserDefaults] removeObjectForKey:kConfigurationKey]; 84} 85 86ConfigurationPolicyProvider* TestHarness::CreateProvider( 87 SchemaRegistry* registry, 88 scoped_refptr<base::SequencedTaskRunner> task_runner) { 89 scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderIOS(task_runner)); 90 return new AsyncPolicyProvider(registry, loader.Pass()); 91} 92 93void TestHarness::InstallEmptyPolicy() { 94 AddPolicies(@{}); 95} 96 97void TestHarness::InstallStringPolicy(const std::string& policy_name, 98 const std::string& policy_value) { 99 NSString* key = base::SysUTF8ToNSString(policy_name); 100 NSString* value = base::SysUTF8ToNSString(policy_value); 101 AddPolicies(@{ 102 key: value 103 }); 104} 105 106void TestHarness::InstallIntegerPolicy(const std::string& policy_name, 107 int policy_value) { 108 NSString* key = base::SysUTF8ToNSString(policy_name); 109 AddPolicies(@{ 110 key: [NSNumber numberWithInt:policy_value] 111 }); 112} 113 114void TestHarness::InstallBooleanPolicy(const std::string& policy_name, 115 bool policy_value) { 116 NSString* key = base::SysUTF8ToNSString(policy_name); 117 AddPolicies(@{ 118 key: [NSNumber numberWithBool:policy_value] 119 }); 120} 121 122void TestHarness::InstallStringListPolicy(const std::string& policy_name, 123 const base::ListValue* policy_value) { 124 NSString* key = base::SysUTF8ToNSString(policy_name); 125 base::ScopedCFTypeRef<CFPropertyListRef> value(ValueToProperty(policy_value)); 126 AddPolicies(@{ 127 key: static_cast<NSArray*>(value.get()) 128 }); 129} 130 131void TestHarness::InstallDictionaryPolicy( 132 const std::string& policy_name, 133 const base::DictionaryValue* policy_value) { 134 NSString* key = base::SysUTF8ToNSString(policy_name); 135 base::ScopedCFTypeRef<CFPropertyListRef> value(ValueToProperty(policy_value)); 136 AddPolicies(@{ 137 key: static_cast<NSDictionary*>(value.get()) 138 }); 139} 140 141// static 142PolicyProviderTestHarness* TestHarness::Create() { 143 return new TestHarness(false); 144} 145 146// static 147PolicyProviderTestHarness* TestHarness::CreateWithEncodedKey() { 148 if (base::ios::IsRunningOnIOS7OrLater()) 149 return new TestHarness(true); 150 // Earlier versions of iOS don't have the APIs to support this test. 151 // Unfortunately it's not possible to conditionally run this harness using 152 // gtest, so we just fallback to running the non-encoded version. 153 NSLog(@"Skipping test"); 154 return new TestHarness(false); 155} 156 157void TestHarness::AddPolicies(NSDictionary* policy) { 158 if (use_encoded_key_) 159 AddEncodedChromePolicy(policy); 160 else 161 AddChromePolicy(policy); 162} 163 164void TestHarness::AddChromePolicy(NSDictionary* policy) { 165 NSString* key = @"ChromePolicy"; 166 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 167 base::scoped_nsobject<NSMutableDictionary> chromePolicy( 168 [[NSMutableDictionary alloc] init]); 169 170 NSDictionary* previous = [defaults dictionaryForKey:key]; 171 if (previous) 172 [chromePolicy addEntriesFromDictionary:previous]; 173 174 [chromePolicy addEntriesFromDictionary:policy]; 175 176 NSDictionary* wrapper = @{ 177 key: chromePolicy 178 }; 179 [[NSUserDefaults standardUserDefaults] setObject:wrapper 180 forKey:kConfigurationKey]; 181} 182 183void TestHarness::AddEncodedChromePolicy(NSDictionary* policy) { 184 NSString* key = @"EncodedChromePolicy"; 185 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 186 187 base::scoped_nsobject<NSMutableDictionary> chromePolicy( 188 [[NSMutableDictionary alloc] init]); 189 190 NSString* previous = [defaults stringForKey:key]; 191 if (previous) { 192 base::scoped_nsobject<NSData> data( 193 [[NSData alloc] initWithBase64EncodedString:previous options:0]); 194 NSDictionary* properties = [NSPropertyListSerialization 195 propertyListWithData:data.get() 196 options:NSPropertyListImmutable 197 format:NULL 198 error:NULL]; 199 [chromePolicy addEntriesFromDictionary:properties]; 200 } 201 202 [chromePolicy addEntriesFromDictionary:policy]; 203 204 NSData* data = [NSPropertyListSerialization 205 dataWithPropertyList:chromePolicy 206 format:NSPropertyListXMLFormat_v1_0 207 options:0 208 error:NULL]; 209 NSString* encoded = [data base64EncodedStringWithOptions:0]; 210 211 NSDictionary* wrapper = @{ 212 key: encoded 213 }; 214 [[NSUserDefaults standardUserDefaults] setObject:wrapper 215 forKey:kConfigurationKey]; 216} 217 218} // namespace 219 220INSTANTIATE_TEST_CASE_P( 221 PolicyProviderIOSChromePolicyTest, 222 ConfigurationPolicyProviderTest, 223 testing::Values(TestHarness::Create)); 224 225INSTANTIATE_TEST_CASE_P( 226 PolicyProviderIOSEncodedChromePolicyTest, 227 ConfigurationPolicyProviderTest, 228 testing::Values(TestHarness::CreateWithEncodedKey)); 229 230TEST(PolicyProviderIOSTest, ChromePolicyOverEncodedChromePolicy) { 231 // This test verifies that if the "ChromePolicy" key is present then the 232 // "EncodedChromePolicy" key is ignored. 233 234 if (!base::ios::IsRunningOnIOS7OrLater()) { 235 // Skip this test if running on a version earlier than iOS 7. 236 NSLog(@"Skipping test"); 237 return; 238 } 239 240 NSDictionary* policy = @{ 241 @"shared": @"wrong", 242 @"key1": @"value1", 243 }; 244 NSData* data = [NSPropertyListSerialization 245 dataWithPropertyList:policy 246 format:NSPropertyListXMLFormat_v1_0 247 options:0 248 error:NULL]; 249 NSString* encodedChromePolicy = [data base64EncodedStringWithOptions:0]; 250 251 NSDictionary* chromePolicy = @{ 252 @"shared": @"right", 253 @"key2": @"value2", 254 }; 255 256 NSDictionary* wrapper = @{ 257 @"ChromePolicy": chromePolicy, 258 @"EncodedChromePolicy": encodedChromePolicy, 259 }; 260 261 [[NSUserDefaults standardUserDefaults] setObject:wrapper 262 forKey:kConfigurationKey]; 263 264 PolicyBundle expected; 265 PolicyMap& expectedMap = 266 expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, "")); 267 expectedMap.Set("shared", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, 268 new base::StringValue("right"), NULL); 269 expectedMap.Set("key2", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, 270 new base::StringValue("value2"), NULL); 271 272 scoped_refptr<base::TestSimpleTaskRunner> taskRunner = 273 new base::TestSimpleTaskRunner(); 274 PolicyLoaderIOS loader(taskRunner); 275 scoped_ptr<PolicyBundle> bundle = loader.Load(); 276 ASSERT_TRUE(bundle); 277 EXPECT_TRUE(bundle->Equals(expected)); 278} 279 280} // namespace policy 281