1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "gtest/gtest.h"
7 
8 #include "nsCOMPtr.h"
9 #include "nsContentUtils.h"
10 #include "nsIChannel.h"
11 #include "nsIContentPolicy.h"
12 #include "nsICookieJarSettings.h"
13 #include "nsILoadInfo.h"
14 #include "nsIURI.h"
15 #include "nsNetUtil.h"
16 #include "nsStringFwd.h"
17 
18 #include "mozilla/NullPrincipal.h"
19 #include "mozilla/Preferences.h"
20 #include "mozilla/RefPtr.h"
21 #include "mozilla/StoragePrincipalHelper.h"
22 
23 using mozilla::Preferences;
24 using namespace mozilla;
25 
26 /**
27  * Creates a test channel with CookieJarSettings which have a partitionKey set.
28  */
CreateMockChannel(nsIPrincipal * aPrincipal,bool isThirdParty,const nsACString & aPartitionKey,nsIChannel ** aChannel,nsICookieJarSettings ** aCookieJarSettings)29 nsresult CreateMockChannel(nsIPrincipal* aPrincipal, bool isThirdParty,
30                            const nsACString& aPartitionKey,
31                            nsIChannel** aChannel,
32                            nsICookieJarSettings** aCookieJarSettings) {
33   nsCOMPtr<nsIURI> mockUri;
34   nsresult rv = NS_NewURI(getter_AddRefs(mockUri), "http://example.com"_ns);
35   NS_ENSURE_SUCCESS(rv, rv);
36 
37   nsCOMPtr<nsIChannel> mockChannel;
38   nsCOMPtr<nsIIOService> service = do_GetIOService(&rv);
39   NS_ENSURE_SUCCESS(rv, rv);
40 
41   rv = service->NewChannelFromURI(mockUri, nullptr, aPrincipal, aPrincipal, 0,
42                                   nsContentPolicyType::TYPE_OTHER,
43                                   getter_AddRefs(mockChannel));
44   NS_ENSURE_SUCCESS(rv, rv);
45 
46   nsCOMPtr<nsILoadInfo> mockLoadInfo = mockChannel->LoadInfo();
47   rv = mockLoadInfo->SetIsThirdPartyContextToTopWindow(isThirdParty);
48   NS_ENSURE_SUCCESS(rv, rv);
49 
50   nsCOMPtr<nsICookieJarSettings> cjs;
51   rv = mockLoadInfo->GetCookieJarSettings(getter_AddRefs(cjs));
52   NS_ENSURE_SUCCESS(rv, rv);
53 
54   nsCOMPtr<nsIURI> partitionKeyUri;
55   rv = NS_NewURI(getter_AddRefs(partitionKeyUri), aPartitionKey);
56   NS_ENSURE_SUCCESS(rv, rv);
57 
58   rv = cjs->InitWithURI(partitionKeyUri, false);
59   NS_ENSURE_SUCCESS(rv, rv);
60 
61   cjs.forget(aCookieJarSettings);
62   mockChannel.forget(aChannel);
63   return NS_OK;
64 }
65 
TEST(TestStoragePrincipalHelper,TestCreateContentPrincipal)66 TEST(TestStoragePrincipalHelper, TestCreateContentPrincipal)
67 {
68   nsCOMPtr<nsIPrincipal> contentPrincipal =
69       BasePrincipal::CreateContentPrincipal("https://example.com"_ns);
70   EXPECT_TRUE(contentPrincipal);
71 
72   nsCOMPtr<nsIChannel> mockChannel;
73   nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
74   nsresult rv = CreateMockChannel(
75       contentPrincipal, false, "https://example.org"_ns,
76       getter_AddRefs(mockChannel), getter_AddRefs(cookieJarSettings));
77   ASSERT_EQ(rv, NS_OK) << "Could not create a mock channel";
78 
79   nsCOMPtr<nsIPrincipal> storagePrincipal;
80   rv = StoragePrincipalHelper::Create(mockChannel, contentPrincipal, true,
81                                       getter_AddRefs(storagePrincipal));
82   ASSERT_EQ(rv, NS_OK) << "Should not fail for ContentPrincipal";
83   EXPECT_TRUE(storagePrincipal);
84 
85   nsCOMPtr<nsIPrincipal> storagePrincipalSW;
86   rv = StoragePrincipalHelper::CreatePartitionedPrincipalForServiceWorker(
87       contentPrincipal, cookieJarSettings, getter_AddRefs(storagePrincipalSW));
88   ASSERT_EQ(rv, NS_OK) << "Should not fail for ContentPrincipal";
89   EXPECT_TRUE(storagePrincipalSW);
90 }
91 
TEST(TestStoragePrincipalHelper,TestCreateNullPrincipal)92 TEST(TestStoragePrincipalHelper, TestCreateNullPrincipal)
93 {
94   RefPtr<NullPrincipal> nullPrincipal =
95       NullPrincipal::CreateWithoutOriginAttributes();
96   EXPECT_TRUE(nullPrincipal);
97 
98   nsCOMPtr<nsIChannel> mockChannel;
99   nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
100   nsresult rv = CreateMockChannel(
101       nullPrincipal, false, "https://example.org"_ns,
102       getter_AddRefs(mockChannel), getter_AddRefs(cookieJarSettings));
103   ASSERT_EQ(rv, NS_OK) << "Could not create a mock channel";
104 
105   nsCOMPtr<nsIPrincipal> storagePrincipal;
106   rv = StoragePrincipalHelper::Create(mockChannel, nullPrincipal, true,
107                                       getter_AddRefs(storagePrincipal));
108   EXPECT_TRUE(NS_FAILED(rv)) << "Should fail for NullPrincipal";
109   EXPECT_FALSE(storagePrincipal);
110 
111   nsCOMPtr<nsIPrincipal> storagePrincipalSW;
112   rv = StoragePrincipalHelper::CreatePartitionedPrincipalForServiceWorker(
113       nullPrincipal, cookieJarSettings, getter_AddRefs(storagePrincipalSW));
114   EXPECT_TRUE(NS_FAILED(rv)) << "Should fail for NullPrincipal";
115   EXPECT_FALSE(storagePrincipal);
116 }
117 
TEST(TestStoragePrincipalHelper,TestGetPrincipalCookieBehavior4)118 TEST(TestStoragePrincipalHelper, TestGetPrincipalCookieBehavior4)
119 {
120   Preferences::SetInt("network.cookie.cookieBehavior", 4);
121 
122   nsCOMPtr<nsIPrincipal> contentPrincipal =
123       BasePrincipal::CreateContentPrincipal("https://example.com"_ns);
124   EXPECT_TRUE(contentPrincipal);
125 
126   for (auto isThirdParty : {false, true}) {
127     nsCOMPtr<nsIChannel> mockChannel;
128     nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
129     nsresult rv = CreateMockChannel(
130         contentPrincipal, isThirdParty, "https://example.org"_ns,
131         getter_AddRefs(mockChannel), getter_AddRefs(cookieJarSettings));
132     ASSERT_EQ(rv, NS_OK) << "Could not create a mock channel";
133 
134     nsCOMPtr<nsIPrincipal> testPrincipal;
135     rv = StoragePrincipalHelper::GetPrincipal(
136         mockChannel, StoragePrincipalHelper::eRegularPrincipal,
137         getter_AddRefs(testPrincipal));
138     ASSERT_EQ(rv, NS_OK) << "Could not get regular principal";
139     EXPECT_TRUE(testPrincipal);
140     EXPECT_TRUE(testPrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
141 
142     rv = StoragePrincipalHelper::GetPrincipal(
143         mockChannel, StoragePrincipalHelper::ePartitionedPrincipal,
144         getter_AddRefs(testPrincipal));
145     ASSERT_EQ(rv, NS_OK) << "Could not get partitioned principal";
146     EXPECT_TRUE(testPrincipal);
147     EXPECT_TRUE(
148         testPrincipal->OriginAttributesRef().mPartitionKey.EqualsLiteral(
149             "(https,example.org)"));
150 
151     // We should always get regular principal if the dFPI is disabled.
152     rv = StoragePrincipalHelper::GetPrincipal(
153         mockChannel, StoragePrincipalHelper::eForeignPartitionedPrincipal,
154         getter_AddRefs(testPrincipal));
155     ASSERT_EQ(rv, NS_OK) << "Could not get foreign partitioned principal";
156     EXPECT_TRUE(testPrincipal);
157     EXPECT_TRUE(testPrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
158 
159     // Note that we don't test eStorageAccessPrincipal here because it's hard to
160     // setup the right state for the storage access in gTest.
161   }
162 }
163 
TEST(TestStoragePrincipalHelper,TestGetPrincipalCookieBehavior5)164 TEST(TestStoragePrincipalHelper, TestGetPrincipalCookieBehavior5)
165 {
166   Preferences::SetInt("network.cookie.cookieBehavior", 5);
167 
168   nsCOMPtr<nsIPrincipal> contentPrincipal =
169       BasePrincipal::CreateContentPrincipal("https://example.com"_ns);
170   EXPECT_TRUE(contentPrincipal);
171 
172   for (auto isThirdParty : {false, true}) {
173     nsCOMPtr<nsIChannel> mockChannel;
174     nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
175     nsresult rv = CreateMockChannel(
176         contentPrincipal, isThirdParty, "https://example.org"_ns,
177         getter_AddRefs(mockChannel), getter_AddRefs(cookieJarSettings));
178     ASSERT_EQ(rv, NS_OK) << "Could not create a mock channel";
179 
180     nsCOMPtr<nsIPrincipal> testPrincipal;
181     rv = StoragePrincipalHelper::GetPrincipal(
182         mockChannel, StoragePrincipalHelper::eRegularPrincipal,
183         getter_AddRefs(testPrincipal));
184     ASSERT_EQ(rv, NS_OK) << "Could not get regular principal";
185     EXPECT_TRUE(testPrincipal);
186     EXPECT_TRUE(testPrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
187 
188     rv = StoragePrincipalHelper::GetPrincipal(
189         mockChannel, StoragePrincipalHelper::ePartitionedPrincipal,
190         getter_AddRefs(testPrincipal));
191     ASSERT_EQ(rv, NS_OK) << "Could not get partitioned principal";
192     EXPECT_TRUE(testPrincipal);
193     EXPECT_TRUE(
194         testPrincipal->OriginAttributesRef().mPartitionKey.EqualsLiteral(
195             "(https,example.org)"));
196 
197     // We should always get regular principal if the dFPI is disabled.
198     rv = StoragePrincipalHelper::GetPrincipal(
199         mockChannel, StoragePrincipalHelper::eForeignPartitionedPrincipal,
200         getter_AddRefs(testPrincipal));
201     ASSERT_EQ(rv, NS_OK) << "Could not get foreign partitioned principal";
202     EXPECT_TRUE(testPrincipal);
203     if (isThirdParty) {
204       EXPECT_TRUE(
205           testPrincipal->OriginAttributesRef().mPartitionKey.EqualsLiteral(
206               "(https,example.org)"));
207     } else {
208       EXPECT_TRUE(testPrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
209     }
210 
211     // Note that we don't test eStorageAccessPrincipal here because it's hard to
212     // setup the right state for the storage access in gTest.
213   }
214 }
215