1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include "gtest/gtest.h"
5 #include "mozilla/BasePrincipal.h"
6 #include "mozilla/ContentPrincipal.h"
7 #include "mozilla/NullPrincipal.h"
8 #include "mozilla/SystemPrincipal.h"
9 #include "mozilla/ExpandedPrincipal.h"
10 
11 using mozilla::BasePrincipal;
12 using mozilla::ContentPrincipal;
13 using mozilla::NullPrincipal;
14 using mozilla::SystemPrincipal;
15 
16 // None of these tests work in debug due to assert guards
17 #ifndef MOZ_DEBUG
18 
19 // calling toJson() twice with the same string arg
20 // (ensure that we truncate correctly where needed)
TEST(PrincipalSerialization,ReusedJSONArgument)21 TEST(PrincipalSerialization, ReusedJSONArgument)
22 {
23   nsCOMPtr<nsIScriptSecurityManager> ssm =
24       nsScriptSecurityManager::GetScriptSecurityManager();
25 
26   nsAutoCString spec("https://mozilla.com");
27   nsCOMPtr<nsIPrincipal> principal;
28   nsresult rv =
29       ssm->CreateContentPrincipalFromOrigin(spec, getter_AddRefs(principal));
30   ASSERT_EQ(rv, NS_OK);
31 
32   nsAutoCString JSON;
33   rv = BasePrincipal::Cast(principal)->ToJSON(JSON);
34   ASSERT_EQ(rv, NS_OK);
35   ASSERT_TRUE(JSON.EqualsLiteral("{\"1\":{\"0\":\"https://mozilla.com/\"}}"));
36 
37   nsAutoCString spec2("https://example.com");
38   nsCOMPtr<nsIPrincipal> principal2;
39   rv = ssm->CreateContentPrincipalFromOrigin(spec2, getter_AddRefs(principal2));
40   ASSERT_EQ(rv, NS_OK);
41 
42   // Reuse JSON without truncation to check the code is doing this
43   rv = BasePrincipal::Cast(principal2)->ToJSON(JSON);
44   ASSERT_EQ(rv, NS_OK);
45   ASSERT_TRUE(JSON.EqualsLiteral("{\"1\":{\"0\":\"https://example.com/\"}}"));
46 }
47 
48 // Assure that calling FromProperties() with an empty array list always returns
49 // a nullptr The exception here is SystemPrincipal which doesn't have fields but
50 // it also doesn't implement FromProperties These are overly cautious checks
51 // that we don't try to create a principal in reality FromProperties is only
52 // called with a populated array.
TEST(PrincipalSerialization,FromPropertiesEmpty)53 TEST(PrincipalSerialization, FromPropertiesEmpty)
54 {
55   nsTArray<ContentPrincipal::KeyVal> resContent;
56   nsCOMPtr<nsIPrincipal> contentPrincipal =
57       ContentPrincipal::FromProperties(resContent);
58   ASSERT_EQ(nullptr, contentPrincipal);
59 
60   nsTArray<ExpandedPrincipal::KeyVal> resExpanded;
61   nsCOMPtr<nsIPrincipal> expandedPrincipal =
62       ExpandedPrincipal::FromProperties(resExpanded);
63   ASSERT_EQ(nullptr, expandedPrincipal);
64 
65   nsTArray<NullPrincipal::KeyVal> resNull;
66   nsCOMPtr<nsIPrincipal> nullprincipal = NullPrincipal::FromProperties(resNull);
67   ASSERT_EQ(nullptr, nullprincipal);
68 }
69 
70 // Double check that if we have two valid principals in a serialized JSON that
71 // nullptr is returned
TEST(PrincipalSerialization,TwoKeys)72 TEST(PrincipalSerialization, TwoKeys)
73 {
74   // Sanity check that this returns a system principal
75   nsCOMPtr<nsIPrincipal> systemPrincipal =
76       BasePrincipal::FromJSON("{\"3\":{}}"_ns);
77   ASSERT_EQ(BasePrincipal::Cast(systemPrincipal)->Kind(),
78             BasePrincipal::eSystemPrincipal);
79 
80   // Sanity check that this returns a content principal
81   nsCOMPtr<nsIPrincipal> contentPrincipal =
82       BasePrincipal::FromJSON("{\"1\":{\"0\":\"https://mozilla.com\"}}"_ns);
83   ASSERT_EQ(BasePrincipal::Cast(contentPrincipal)->Kind(),
84             BasePrincipal::eContentPrincipal);
85 
86   // Check both combined don't return a principal
87   nsCOMPtr<nsIPrincipal> combinedPrincipal = BasePrincipal::FromJSON(
88       "{\"1\":{\"0\":\"https://mozilla.com\"},\"3\":{}}"_ns);
89   ASSERT_EQ(nullptr, combinedPrincipal);
90 }
91 
92 #endif  // ifndef MOZ_DEBUG
93 
TEST(PrincipalSerialization,ExpandedPrincipal)94 TEST(PrincipalSerialization, ExpandedPrincipal)
95 {
96   // Check basic Expandedprincipal works without OA
97   nsCOMPtr<nsIScriptSecurityManager> ssm =
98       nsScriptSecurityManager::GetScriptSecurityManager();
99 
100   uint32_t length = 2;
101   nsTArray<nsCOMPtr<nsIPrincipal> > allowedDomains(length);
102   allowedDomains.SetLength(length);
103 
104   nsAutoCString spec("https://mozilla.com");
105   nsCOMPtr<nsIPrincipal> principal;
106   nsresult rv =
107       ssm->CreateContentPrincipalFromOrigin(spec, getter_AddRefs(principal));
108   ASSERT_EQ(rv, NS_OK);
109   ASSERT_EQ(BasePrincipal::Cast(principal)->Kind(),
110             BasePrincipal::eContentPrincipal);
111   allowedDomains[0] = principal;
112 
113   nsAutoCString spec2("https://mozilla.org");
114   nsCOMPtr<nsIPrincipal> principal2;
115   rv = ssm->CreateContentPrincipalFromOrigin(spec2, getter_AddRefs(principal2));
116   ASSERT_EQ(rv, NS_OK);
117   ASSERT_EQ(BasePrincipal::Cast(principal2)->Kind(),
118             BasePrincipal::eContentPrincipal);
119   allowedDomains[1] = principal2;
120 
121   OriginAttributes attrs;
122   RefPtr<ExpandedPrincipal> result =
123       ExpandedPrincipal::Create(allowedDomains, attrs);
124   ASSERT_EQ(BasePrincipal::Cast(result)->Kind(),
125             BasePrincipal::eExpandedPrincipal);
126 
127   nsAutoCString JSON;
128   rv = BasePrincipal::Cast(result)->ToJSON(JSON);
129   ASSERT_EQ(rv, NS_OK);
130   ASSERT_STREQ(
131       JSON.get(),
132       "{\"2\":{\"0\":\"eyIxIjp7IjAiOiJodHRwczovL21vemlsbGEuY29tLyJ9fQ==,"
133       "eyIxIjp7IjAiOiJodHRwczovL21vemlsbGEub3JnLyJ9fQ==\"}}");
134 
135   nsCOMPtr<nsIPrincipal> returnedPrincipal = BasePrincipal::FromJSON(JSON);
136   auto outPrincipal = BasePrincipal::Cast(returnedPrincipal);
137   ASSERT_EQ(outPrincipal->Kind(), BasePrincipal::eExpandedPrincipal);
138 
139   ASSERT_TRUE(outPrincipal->FastSubsumesIgnoringFPD(principal));
140   ASSERT_TRUE(outPrincipal->FastSubsumesIgnoringFPD(principal2));
141 
142   nsAutoCString specDev("https://mozilla.dev");
143   nsCOMPtr<nsIPrincipal> principalDev;
144   rv = ssm->CreateContentPrincipalFromOrigin(specDev,
145                                              getter_AddRefs(principalDev));
146   ASSERT_EQ(rv, NS_OK);
147   ASSERT_EQ(BasePrincipal::Cast(principalDev)->Kind(),
148             BasePrincipal::eContentPrincipal);
149 
150   ASSERT_FALSE(outPrincipal->FastSubsumesIgnoringFPD(principalDev));
151 }
152 
TEST(PrincipalSerialization,ExpandedPrincipalOA)153 TEST(PrincipalSerialization, ExpandedPrincipalOA)
154 {
155   // Check Expandedprincipal works with top level OA
156   nsCOMPtr<nsIScriptSecurityManager> ssm =
157       nsScriptSecurityManager::GetScriptSecurityManager();
158 
159   uint32_t length = 2;
160   nsTArray<nsCOMPtr<nsIPrincipal> > allowedDomains(length);
161   allowedDomains.SetLength(length);
162 
163   nsAutoCString spec("https://mozilla.com");
164   nsCOMPtr<nsIPrincipal> principal;
165   nsresult rv =
166       ssm->CreateContentPrincipalFromOrigin(spec, getter_AddRefs(principal));
167   ASSERT_EQ(rv, NS_OK);
168   ASSERT_EQ(BasePrincipal::Cast(principal)->Kind(),
169             BasePrincipal::eContentPrincipal);
170   allowedDomains[0] = principal;
171 
172   nsAutoCString spec2("https://mozilla.org");
173   nsCOMPtr<nsIPrincipal> principal2;
174   rv = ssm->CreateContentPrincipalFromOrigin(spec2, getter_AddRefs(principal2));
175   ASSERT_EQ(rv, NS_OK);
176   ASSERT_EQ(BasePrincipal::Cast(principal2)->Kind(),
177             BasePrincipal::eContentPrincipal);
178   allowedDomains[1] = principal2;
179 
180   OriginAttributes attrs;
181   nsAutoCString suffix("^userContextId=1");
182   bool ok = attrs.PopulateFromSuffix(suffix);
183   ASSERT_TRUE(ok);
184 
185   RefPtr<ExpandedPrincipal> result =
186       ExpandedPrincipal::Create(allowedDomains, attrs);
187   ASSERT_EQ(BasePrincipal::Cast(result)->Kind(),
188             BasePrincipal::eExpandedPrincipal);
189 
190   nsAutoCString JSON;
191   rv = BasePrincipal::Cast(result)->ToJSON(JSON);
192   ASSERT_EQ(rv, NS_OK);
193   ASSERT_STREQ(
194       JSON.get(),
195       "{\"2\":{\"0\":\"eyIxIjp7IjAiOiJodHRwczovL21vemlsbGEuY29tLyJ9fQ==,"
196       "eyIxIjp7IjAiOiJodHRwczovL21vemlsbGEub3JnLyJ9fQ==\",\"1\":\"^"
197       "userContextId=1\"}}");
198 
199   nsCOMPtr<nsIPrincipal> returnedPrincipal = BasePrincipal::FromJSON(JSON);
200   auto outPrincipal = BasePrincipal::Cast(returnedPrincipal);
201   ASSERT_EQ(outPrincipal->Kind(), BasePrincipal::eExpandedPrincipal);
202 
203   ASSERT_TRUE(outPrincipal->FastSubsumesIgnoringFPD(principal));
204   ASSERT_TRUE(outPrincipal->FastSubsumesIgnoringFPD(principal2));
205 
206   nsAutoCString specDev("https://mozilla.dev");
207   nsCOMPtr<nsIPrincipal> principalDev;
208   rv = ssm->CreateContentPrincipalFromOrigin(specDev,
209                                              getter_AddRefs(principalDev));
210   ASSERT_EQ(rv, NS_OK);
211   ASSERT_EQ(BasePrincipal::Cast(principalDev)->Kind(),
212             BasePrincipal::eContentPrincipal);
213 
214   ASSERT_FALSE(outPrincipal->FastSubsumesIgnoringFPD(principalDev));
215 }
216