gitee.com/mysnapcore/mysnapd@v0.1.0/polkit/validate/validate_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2021 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package validate_test 21 22 import ( 23 "bytes" 24 "fmt" 25 "sort" 26 "testing" 27 28 . "gopkg.in/check.v1" 29 30 "gitee.com/mysnapcore/mysnapd/polkit/validate" 31 ) 32 33 type validateSuite struct{} 34 35 var _ = Suite(&validateSuite{}) 36 37 func Test(t *testing.T) { 38 TestingT(t) 39 } 40 41 func validateString(xml string) ([]string, error) { 42 return validate.ValidatePolicy(bytes.NewBufferString(xml)) 43 } 44 45 func (s *validateSuite) TestRootElement(c *C) { 46 // Extra elements after root 47 _, err := validateString("<policyconfig/><policyconfig/>") 48 c.Check(err, ErrorMatches, `invalid XML: additional data after root element`) 49 50 // Extra incomplete elements after root element 51 _, err = validateString("<policyconfig/><incomplete>") 52 c.Check(err, ErrorMatches, `invalid XML: additional data after root element`) 53 54 // Wrong root element 55 _, err = validateString("<xyz/>") 56 c.Check(err, ErrorMatches, `expected element type <policyconfig> but have <xyz>`) 57 58 // Wrong namespace for root element 59 _, err = validateString(`<policyconfig xmlns="http://example.org/ns"/>`) 60 c.Check(err, ErrorMatches, `root element must be <policyconfig>`) 61 62 // Invalid XML 63 _, err = validateString("<policyconfig>incomplete") 64 c.Check(err, ErrorMatches, `XML syntax error on line .*`) 65 } 66 67 func (s *validateSuite) TestPolicyConfigElement(c *C) { 68 _, err := validateString("<policyconfig/>") 69 c.Check(err, IsNil) 70 71 // Extra attributes are not allowed 72 _, err = validateString(`<policyconfig foo="bar"/>`) 73 c.Check(err, ErrorMatches, `<policyconfig> element contains unexpected attributes`) 74 75 // Unexpected child elements 76 _, err = validateString("<policyconfig><xyz/></policyconfig>") 77 c.Check(err, ErrorMatches, `<policyconfig> element contains unexpected children`) 78 79 // Unexpected character data 80 _, err = validateString("<policyconfig>xyz</policyconfig>") 81 c.Check(err, ErrorMatches, `<policyconfig> element contains unexpected character data`) 82 83 // Supports <vendor>, <vendor_url>, and <icon_name> parameters 84 _, err = validateString(`<policyconfig> 85 <vendor>vendor</vendor> 86 <vendor_url>url</vendor_url> 87 <icon_name>icon</icon_name> 88 </policyconfig>`) 89 c.Check(err, IsNil) 90 91 // Duplicates of those elements are not allowed 92 _, err = validateString(`<policyconfig> 93 <vendor>vendor</vendor> 94 <vendor>vendor</vendor> 95 </policyconfig>`) 96 c.Check(err, ErrorMatches, `multiple <vendor> elements found under <policyconfig>`) 97 98 _, err = validateString(`<policyconfig> 99 <vendor_url>url</vendor_url> 100 <vendor_url>url</vendor_url> 101 </policyconfig>`) 102 c.Check(err, ErrorMatches, `multiple <vendor_url> elements found under <policyconfig>`) 103 104 _, err = validateString(`<policyconfig> 105 <icon_name>icon</icon_name> 106 <icon_name>icon</icon_name> 107 </policyconfig>`) 108 c.Check(err, ErrorMatches, `multiple <icon_name> elements found under <policyconfig>`) 109 } 110 111 func validateAction(xml string) ([]string, error) { 112 return validateString("<policyconfig>" + xml + "</policyconfig>") 113 } 114 115 func (s *validateSuite) TestActionElement(c *C) { 116 // The ID of an action is extracted on successful validation 117 actionIDs, err := validateAction(`<action id="foo"> 118 <description>desc</description> 119 <message>msg</message> 120 </action>`) 121 c.Check(err, IsNil) 122 c.Check(actionIDs, DeepEquals, []string{"foo"}) 123 124 // Actions must have an ID 125 _, err = validateAction("<action/>") 126 c.Check(err, ErrorMatches, `<action> elements must have an ID`) 127 128 // Other attributes are not allowed 129 _, err = validateAction(`<action bar="foo"/>`) 130 c.Check(err, ErrorMatches, `<action> element contains unexpected attributes`) 131 132 // Unexpected child elements are not allowed 133 _, err = validateAction(`<action id="foo"><xyz/></action>`) 134 c.Check(err, ErrorMatches, `<action> element contains unexpected children`) 135 136 // Character data not allowed inside element 137 _, err = validateAction(`<action id="foo">xyz</action>`) 138 c.Check(err, ErrorMatches, `<action> element contains unexpected character data`) 139 140 // Action elements can also contain <vendor>, <vendor_url>, 141 // and <icon_name> elements. 142 _, err = validateAction(`<action id="foo"> 143 <description>desc</description><message>msg</message> 144 <vendor>vendor</vendor> 145 <vendor_url>url</vendor_url> 146 <icon_name>icon</icon_name> 147 </action>`) 148 c.Check(err, IsNil) 149 150 // Empty versions of those elements are not allowed 151 _, err = validateAction(`<action id="foo"> 152 <description>desc</description><message>msg</message> 153 <vendor/> 154 </action>`) 155 c.Check(err, ErrorMatches, `<vendor> element has no character data`) 156 157 // Duplicates of those elements are not allowed 158 _, err = validateAction(`<action id="foo"> 159 <description>desc</description><message>msg</message> 160 <vendor>vendor</vendor> 161 <vendor>vendor</vendor> 162 </action>`) 163 c.Check(err, ErrorMatches, `multiple <vendor> elements found under <action>`) 164 165 _, err = validateAction(`<action id="foo"> 166 <description>desc</description><message>msg</message> 167 <vendor_url>url</vendor_url> 168 <vendor_url>url</vendor_url> 169 </action>`) 170 c.Check(err, ErrorMatches, `multiple <vendor_url> elements found under <action>`) 171 172 _, err = validateAction(`<action id="foo"> 173 <description>desc</description><message>msg</message> 174 <icon_name>icon</icon_name> 175 <icon_name>icon</icon_name> 176 </action>`) 177 c.Check(err, ErrorMatches, `multiple <icon_name> elements found under <action>`) 178 179 // The <description> and <message> elements accept 180 // gettext-domain and xml:lang attributes 181 _, err = validateAction(`<action id="foo"> 182 <description gettext-domain="bar" xml:lang="en-GB">desc</description> 183 <message gettext-domain="bar" xml:lang="en-GB">desc</message> 184 </action>`) 185 c.Check(err, IsNil) 186 187 // Other attributes or child elements on <description> and 188 // <message> are forbidden 189 _, err = validateAction(`<action id="foo"> 190 <description bar="foo">desc</description> 191 <message>msg</message> 192 </action>`) 193 c.Check(err, ErrorMatches, `<description> element contains unexpected attributes`) 194 195 _, err = validateAction(`<action id="foo"> 196 <description>desc<xyz/></description> 197 <message>msg</message> 198 </action>`) 199 c.Check(err, ErrorMatches, `<description> element contains unexpected children`) 200 201 _, err = validateAction(`<action id="foo"> 202 <description>desc</description> 203 <message bar="foo">msg</message> 204 </action>`) 205 c.Check(err, ErrorMatches, `<message> element contains unexpected attributes`) 206 207 _, err = validateAction(`<action id="foo"> 208 <description>desc</description> 209 <message>msg<xyz/></message> 210 </action>`) 211 c.Check(err, ErrorMatches, `<message> element contains unexpected children`) 212 213 // Multiple <description> and <message> children are allowed 214 // children 215 _, err = validateAction(`<action id="foo"> 216 <description>desc</description> 217 <description>desc</description> 218 <description>desc</description> 219 <message>msg</message> 220 </action>`) 221 c.Check(err, IsNil) 222 223 _, err = validateAction(`<action id="foo"> 224 <description>desc</description> 225 <message>msg</message> 226 <message>msg</message> 227 <message>msg</message> 228 </action>`) 229 c.Check(err, IsNil) 230 231 // But at least one is required 232 _, err = validateAction(`<action id="foo"> 233 <message>msg</message> 234 </action>`) 235 c.Check(err, ErrorMatches, `<action> element missing <description> child`) 236 237 _, err = validateAction(`<action id="foo"> 238 <description>desc</description> 239 </action>`) 240 c.Check(err, ErrorMatches, `<action> element missing <message> child`) 241 } 242 243 func validateActionDefaults(xml string) error { 244 _, err := validateAction(fmt.Sprintf(`<action id="foo"> 245 <description>desc</description><message>msg</message> 246 %s 247 </action>`, xml)) 248 return err 249 } 250 251 func (s *validateSuite) TestDefaultsElement(c *C) { 252 // Actions can have a single <defaults> element 253 err := validateActionDefaults(`<defaults/>`) 254 c.Check(err, IsNil) 255 256 err = validateActionDefaults(`<defaults/><defaults/>`) 257 c.Check(err, ErrorMatches, `<action> element has multiple <defaults> children`) 258 259 // The <defaults> element does not accept attributes, unknown children or character data 260 err = validateActionDefaults(`<defaults foo="bar"/>`) 261 c.Check(err, ErrorMatches, `<defaults> element contains unexpected attributes`) 262 263 err = validateActionDefaults(`<defaults>xyz</defaults>`) 264 c.Check(err, ErrorMatches, `<defaults> element contains unexpected character data`) 265 266 err = validateActionDefaults(`<defaults><xyz/></defaults>`) 267 c.Check(err, ErrorMatches, `<defaults> element contains unexpected children`) 268 269 // The defaults section contains default access rules for the action 270 err = validateActionDefaults(`<defaults> 271 <allow_any>yes</allow_any> 272 <allow_inactive>yes</allow_inactive> 273 <allow_active>yes</allow_active> 274 </defaults>`) 275 c.Check(err, IsNil) 276 277 for _, mode := range []string{"allow_any", "allow_inactive", "allow_active"} { 278 // Only one instance of the element is allowed 279 err = validateActionDefaults(fmt.Sprintf(`<defaults> 280 <%s>yes</%s> 281 <%s>yes</%s> 282 </defaults>`, mode, mode, mode, mode)) 283 c.Check(err, ErrorMatches, fmt.Sprintf("multiple <%s> elements found under <defaults>", mode)) 284 285 // No attributes or child elements allowed 286 err = validateActionDefaults(fmt.Sprintf(`<defaults> 287 <%s foo="bar">yes</%s> 288 </defaults>`, mode, mode)) 289 c.Check(err, ErrorMatches, fmt.Sprintf("<%s> element contains unexpected attributes", mode)) 290 291 err = validateActionDefaults(fmt.Sprintf(`<defaults> 292 <%s>yes<xyz/></%s> 293 </defaults>`, mode, mode)) 294 c.Check(err, ErrorMatches, fmt.Sprintf("<%s> element contains unexpected children", mode)) 295 296 // Unknown or missing values are rejected 297 err = validateActionDefaults(fmt.Sprintf(`<defaults> 298 <%s>unknown</%s> 299 </defaults>`, mode, mode)) 300 c.Check(err, ErrorMatches, fmt.Sprintf(`invalid value for <%s>: "unknown"`, mode)) 301 302 err = validateActionDefaults(fmt.Sprintf(`<defaults> 303 <%s/> 304 </defaults>`, mode)) 305 c.Check(err, ErrorMatches, fmt.Sprintf(`invalid value for <%s>: ""`, mode)) 306 307 // Known values are accepted: 308 for _, value := range []string{"no", "yes", "auth_self", "auth_admin", "auth_self_keep", "auth_admin_keep"} { 309 err = validateActionDefaults(fmt.Sprintf(`<defaults> 310 <%s>%s</%s> 311 </defaults>`, mode, value, mode)) 312 c.Check(err, IsNil) 313 } 314 } 315 } 316 317 func validateAnnotation(xml string) ([]string, error) { 318 return validateAction(fmt.Sprintf(`<action id="action_id"> 319 <description>desc</description><message>msg</message> 320 %s 321 </action>`, xml)) 322 } 323 324 func (s *validateSuite) TestAnnotateElement(c *C) { 325 actionIDs, err := validateAnnotation(`<annotate key="org.freedesktop.policykit.imply">implied_id</annotate>`) 326 c.Check(err, IsNil) 327 sort.Strings(actionIDs) 328 c.Check(actionIDs, DeepEquals, []string{"action_id", "implied_id"}) 329 330 // <annotate> elements do not accept unknown attributes or 331 // child elements 332 _, err = validateAnnotation(`<annotate foo="bar"/>`) 333 c.Check(err, ErrorMatches, `<annotate> element contains unexpected attributes`) 334 _, err = validateAnnotation(`<annotate><xyz/></annotate>`) 335 c.Check(err, ErrorMatches, `<annotate> element contains unexpected children`) 336 337 // The key parameter is required 338 _, err = validateAnnotation(`<annotate/>`) 339 c.Check(err, ErrorMatches, `<annotate> elements must have a key attribute`) 340 341 // At present, only "imply" annotations are accepted 342 _, err = validateAnnotation(`<annotate key="xyz">foo</annotate>`) 343 c.Check(err, ErrorMatches, `unsupported annotation "xyz"`) 344 345 // "imply" annotations take a whitespace separated list of 346 // action IDs that are returned by the validation function 347 actionIDs, err = validateAnnotation(`<annotate key="org.freedesktop.policykit.imply">id1 id2 id3 id3</annotate>`) 348 c.Check(err, IsNil) 349 sort.Strings(actionIDs) 350 c.Check(actionIDs, DeepEquals, []string{"action_id", "id1", "id2", "id3"}) 351 352 // Annotation elements must not be empty 353 _, err = validateAnnotation(`<annotate key="org.freedesktop.policykit.imply"/>`) 354 c.Check(err, ErrorMatches, `<annotate> elements must contain character data`) 355 356 // Multiple <annotate> elements are accepted 357 actionIDs, err = validateAnnotation(` 358 <annotate key="org.freedesktop.policykit.imply">id1</annotate> 359 <annotate key="org.freedesktop.policykit.imply">id2</annotate>`) 360 c.Check(err, IsNil) 361 sort.Strings(actionIDs) 362 c.Check(actionIDs, DeepEquals, []string{"action_id", "id1", "id2"}) 363 } 364 365 func (s *validateSuite) TestActionIDExtraction(c *C) { 366 actionIDs, err := validateString(`<policyconfig> 367 <!-- a comment --> 368 <action id="action1"> 369 <description>desc1</description> 370 <message>msg1</message> 371 </action> 372 <action id="action2"> 373 <description>desc1</description> 374 <message>msg1</message> 375 <annotate key="org.freedesktop.policykit.imply">action3</annotate> 376 </action> 377 <action id="action3"> 378 <description>desc1</description> 379 <message>msg1</message> 380 <annotate key="org.freedesktop.policykit.imply">action2 action4</annotate> 381 </action> 382 </policyconfig>`) 383 c.Check(err, IsNil) 384 sort.Strings(actionIDs) 385 c.Check(actionIDs, DeepEquals, []string{"action1", "action2", "action3", "action4"}) 386 }