1 //------------------------------------------------------------------------------ 2 // <copyright file="WebPermission.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 8 namespace System.Net { 9 10 using System.Collections; 11 using System.Security; 12 using System.Security.Permissions; 13 using System.Text.RegularExpressions; 14 using System.Globalization; 15 using System.Runtime.Serialization; 16 17 //NOTE: While WebPermissionAttribute resides in System.DLL, 18 // no classes from that DLL are able to make declarative usage of WebPermission. 19 20 21 // THE syntax of this attribute is as followed 22 // [WebPermission(SecurityAction.Assert, Connect="http://hostname/path/url", Accept="http://localhost/path/url")] 23 // [WebPermission(SecurityAction.Assert, ConnectPattern="http://hostname/www\.microsoft\.*/url/*", AcceptPattern="http://localhost/*")] 24 25 // WHERE: 26 //======= 27 // - 'Connect' and 'Accept' keywords allow you to specify the final URI 28 // - 'ConnectPattern' and 'AcceptPattern' keywords allow you to specify a set of URI in escaped Regex form 29 // - They take '.*' as special "everything" indicators, which are fast-pathed. 30 31 [ AttributeUsage( AttributeTargets.Method | AttributeTargets.Constructor | 32 AttributeTargets.Class | AttributeTargets.Struct | 33 AttributeTargets.Assembly, 34 AllowMultiple = true, Inherited = false )] 35 36 [Serializable()] sealed public class WebPermissionAttribute: CodeAccessSecurityAttribute 37 { 38 private object m_accept = null; 39 private object m_connect = null; 40 WebPermissionAttribute( SecurityAction action )41 public WebPermissionAttribute( SecurityAction action ): base( action ) 42 { 43 } 44 45 public string Connect { 46 get { return m_connect as string;} 47 set { 48 if (m_connect != null) { 49 throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "Connect", value), "value"); 50 } 51 m_connect = value; 52 } 53 } 54 55 public string Accept { 56 get { return m_accept as string; } 57 set { 58 if (m_accept != null) { 59 throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "Accept", value), "value"); 60 } 61 m_accept = value; 62 } 63 } 64 65 public string ConnectPattern { 66 get 67 { 68 return m_connect is DelayedRegex ? m_connect.ToString() : m_connect is bool && (bool) m_connect ? WebPermission.MatchAll : null; 69 } 70 71 set { 72 if (m_connect != null) { 73 throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "ConnectPatern", value), "value"); 74 } 75 if (value == WebPermission.MatchAll) 76 { 77 m_connect = true; 78 } 79 else 80 { 81 m_connect = new DelayedRegex(value); 82 } 83 } 84 } 85 86 public string AcceptPattern { 87 get 88 { 89 return m_accept is DelayedRegex ? m_accept.ToString() : m_accept is bool && (bool) m_accept ? WebPermission.MatchAll : null; 90 } 91 92 set 93 { 94 if (m_accept != null) { 95 throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "AcceptPattern", value), "value"); 96 } 97 if (value == WebPermission.MatchAll) 98 { 99 m_accept = true; 100 } 101 else 102 { 103 m_accept = new DelayedRegex(value); 104 } 105 } 106 } 107 108 /* 109 public bool ConnectAll 110 { 111 get 112 { 113 return m_connect is bool ? (bool) m_connect : false; 114 } 115 116 set 117 { 118 if (m_connect != null) 119 { 120 throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "ConnectAll", value), "value"); 121 } 122 m_connect = value; 123 } 124 } 125 126 public bool AcceptAll 127 { 128 get 129 { 130 return m_accept is bool ? (bool) m_accept : false; 131 } 132 133 set 134 { 135 if (m_accept != null) 136 { 137 throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "AcceptAll", value), "value"); 138 } 139 m_accept = value; 140 } 141 } 142 */ 143 CreatePermission()144 public override IPermission CreatePermission() 145 { 146 WebPermission perm = null; 147 if (Unrestricted) { 148 perm = new WebPermission( PermissionState.Unrestricted); 149 } 150 else { 151 NetworkAccess access = (NetworkAccess) 0; 152 if (m_connect is bool) 153 { 154 if ((bool) m_connect) 155 { 156 access |= NetworkAccess.Connect; 157 } 158 m_connect = null; 159 } 160 if (m_accept is bool) 161 { 162 if ((bool) m_accept) 163 { 164 access |= NetworkAccess.Accept; 165 } 166 m_accept = null; 167 } 168 perm = new WebPermission(access); 169 if (m_accept != null) { 170 if (m_accept is DelayedRegex) { 171 perm.AddAsPattern(NetworkAccess.Accept, (DelayedRegex)m_accept); 172 } 173 else { 174 perm.AddPermission(NetworkAccess.Accept, (string)m_accept); 175 } 176 } 177 if (m_connect != null) { 178 if (m_connect is DelayedRegex) { 179 perm.AddAsPattern(NetworkAccess.Connect, (DelayedRegex)m_connect); 180 } 181 else { 182 perm.AddPermission(NetworkAccess.Connect, (string)m_connect); 183 } 184 } 185 } 186 return perm; 187 } 188 189 } 190 191 [Serializable] 192 internal class DelayedRegex 193 { 194 private Regex _AsRegex; 195 private string _AsString; 196 DelayedRegex(string regexString)197 internal DelayedRegex(string regexString) 198 { 199 if (regexString == null) 200 throw new ArgumentNullException("regexString"); 201 202 _AsString = regexString; 203 } 204 DelayedRegex(Regex regex)205 internal DelayedRegex(Regex regex) 206 { 207 if (regex == null) 208 throw new ArgumentNullException("regex"); 209 210 _AsRegex = regex; 211 } 212 213 internal Regex AsRegex 214 { 215 get 216 { 217 if (_AsRegex == null) 218 { 219 _AsRegex = new Regex(_AsString + "[/]?", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant); 220 } 221 return _AsRegex; 222 } 223 } 224 ToString()225 public override string ToString() 226 { 227 return _AsString != null ? _AsString : (_AsString = _AsRegex.ToString()); 228 } 229 } 230 231 /// <devdoc> 232 /// <para> 233 /// Controls rights to make or accept connections on a Web address. 234 /// </para> 235 /// </devdoc> 236 [Serializable] 237 public sealed class WebPermission : CodeAccessPermission, IUnrestrictedPermission { 238 239 private bool m_noRestriction; 240 [OptionalField] private bool m_UnrestrictedConnect; 241 [OptionalField] private bool m_UnrestrictedAccept; 242 private ArrayList m_connectList = new ArrayList(); 243 private ArrayList m_acceptList = new ArrayList(); 244 245 internal const string MatchAll = ".*"; 246 private static volatile Regex s_MatchAllRegex; 247 internal static Regex MatchAllRegex 248 { 249 get 250 { 251 if (s_MatchAllRegex == null) 252 { 253 s_MatchAllRegex = new Regex(".*"); 254 } 255 return s_MatchAllRegex; 256 } 257 } 258 259 /// <devdoc> 260 /// <para> 261 /// Returns the enumeration of permissions to connect a remote URI. 262 /// </para> 263 /// </devdoc> 264 public IEnumerator ConnectList { 265 get { 266 if (m_UnrestrictedConnect) 267 { 268 return (new Regex[] { MatchAllRegex }).GetEnumerator(); 269 } 270 271 ArrayList cloned = new ArrayList(m_connectList.Count); 272 273 for (int i = 0; i < m_connectList.Count; ++i) 274 cloned.Add(m_connectList[i] is DelayedRegex? (object)((DelayedRegex)m_connectList[i]).AsRegex : 275 m_connectList[i] is Uri? (object)((Uri)m_connectList[i]).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped) : 276 m_connectList[i]); 277 278 return cloned.GetEnumerator(); 279 } 280 } 281 282 /// <devdoc> 283 /// <para> 284 /// Returns the enumeration of permissions to export a local URI. 285 /// </para> 286 /// </devdoc> 287 public IEnumerator AcceptList { 288 get { 289 if (m_UnrestrictedAccept) 290 { 291 return (new Regex[] { MatchAllRegex }).GetEnumerator(); 292 } 293 294 ArrayList cloned = new ArrayList(m_acceptList.Count); 295 296 for (int i = 0; i < m_acceptList.Count; ++i) 297 cloned.Add(m_acceptList[i] is DelayedRegex? (object)((DelayedRegex)m_acceptList[i]).AsRegex : 298 m_acceptList[i] is Uri? (object)((Uri)m_acceptList[i]).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped) : 299 m_acceptList[i]); 300 301 return cloned.GetEnumerator(); 302 } 303 } 304 305 /// <devdoc> 306 /// <para> 307 /// Creates a new instance of the <see cref='System.Net.WebPermission'/> 308 /// class that passes all demands or 309 /// that fails all demands. 310 /// </para> 311 /// </devdoc> WebPermission(PermissionState state)312 public WebPermission(PermissionState state) { 313 m_noRestriction = (state == PermissionState.Unrestricted); 314 } 315 WebPermission(bool unrestricted)316 internal WebPermission(bool unrestricted) { 317 m_noRestriction = unrestricted; 318 } 319 320 /// <devdoc> 321 /// <para> 322 /// Creates a new instance of the <see cref='System.Net.WebPermission'/> class. 323 /// </para> 324 /// </devdoc> WebPermission()325 public WebPermission() { 326 } 327 WebPermission(NetworkAccess access)328 internal WebPermission(NetworkAccess access) 329 { 330 m_UnrestrictedConnect = (access & NetworkAccess.Connect) != 0; 331 m_UnrestrictedAccept = (access & NetworkAccess.Accept) != 0; 332 } 333 334 /// <devdoc> 335 /// <para> 336 /// Creates a new instance of the <see cref='System.Net.WebPermission'/> 337 /// class with the specified access rights for 338 /// the specified URI Pattern. 339 /// Suitable only for WebPermission policy object construction 340 /// </para> 341 /// </devdoc> WebPermission(NetworkAccess access, Regex uriRegex)342 public WebPermission(NetworkAccess access, Regex uriRegex) { 343 AddPermission(access, uriRegex); 344 } 345 346 /// <devdoc> 347 /// <para> 348 /// Creates a new instance of the <see cref='System.Net.WebPermission'/> 349 /// class with the specified access rights for 350 /// the specified Uniform Resource Identifier . 351 /// Suitable for requesting particular WebPermission 352 /// </para> 353 /// </devdoc> 354 // < WebPermission(NetworkAccess access, String uriString)355 public WebPermission(NetworkAccess access, String uriString) { 356 AddPermission(access, uriString); 357 } 358 // 359 // < WebPermission(NetworkAccess access, Uri uri)360 internal WebPermission(NetworkAccess access, Uri uri) { 361 AddPermission(access, uri); 362 } 363 364 // Methods specific to this class 365 /// <devdoc> 366 /// <para> 367 /// Adds a new instance of the WebPermission 368 /// class with the specified access rights for the particular Uniform Resource Identifier. 369 /// </para> 370 /// </devdoc> 371 // < AddPermission(NetworkAccess access, String uriString)372 public void AddPermission(NetworkAccess access, String uriString) { 373 if (uriString == null) { 374 throw new ArgumentNullException("uriString"); 375 } 376 377 if (m_noRestriction) 378 { 379 return; 380 } 381 382 Uri uri; 383 if (Uri.TryCreate(uriString, UriKind.Absolute, out uri)) 384 AddPermission(access, uri); 385 else 386 { 387 ArrayList lists = new ArrayList(); 388 if ((access & NetworkAccess.Connect) != 0 && !m_UnrestrictedConnect) 389 lists.Add(m_connectList); 390 if ((access & NetworkAccess.Accept) != 0 && !m_UnrestrictedAccept) 391 lists.Add(m_acceptList); 392 393 foreach (ArrayList list in lists) 394 { 395 // avoid duplicated uris in the list 396 bool found = false; 397 foreach (object obj in list) { 398 string str = obj as string; 399 if (str != null && string.Compare(str, uriString, StringComparison.OrdinalIgnoreCase ) == 0) 400 { 401 found = true; 402 break; 403 } 404 } 405 406 if (!found) { 407 list.Add(uriString); 408 } 409 } 410 } 411 } 412 413 // < AddPermission(NetworkAccess access, Uri uri)414 internal void AddPermission(NetworkAccess access, Uri uri) { 415 if (uri == null) { 416 throw new ArgumentNullException("uri"); 417 } 418 419 if (m_noRestriction) 420 { 421 return; 422 } 423 424 ArrayList lists = new ArrayList(); 425 if ((access & NetworkAccess.Connect) != 0 && !m_UnrestrictedConnect) 426 lists.Add(m_connectList); 427 if ((access & NetworkAccess.Accept) != 0 && !m_UnrestrictedAccept) 428 lists.Add(m_acceptList); 429 430 foreach (ArrayList list in lists) 431 { 432 // avoid duplicated uris in the list 433 bool found = false; 434 foreach (object permObj in list) { 435 if ((permObj is Uri) && uri.Equals(permObj)) 436 { 437 found = true; 438 break; 439 } 440 } 441 if (!found) { 442 list.Add(uri); 443 } 444 } 445 } 446 447 /// <devdoc> 448 /// <para>Adds a new instance of the <see cref='System.Net.WebPermission'/> 449 /// class with the specified access rights for the specified URI Pattern. 450 /// Should be used during a policy object creation and not for particular URI permission check</para> 451 /// </devdoc> AddPermission(NetworkAccess access, Regex uriRegex)452 public void AddPermission(NetworkAccess access, Regex uriRegex) { 453 if (uriRegex == null) { 454 throw new ArgumentNullException("uriRegex"); 455 } 456 457 if (m_noRestriction) 458 { 459 return; 460 } 461 462 if (uriRegex.ToString() == MatchAll) 463 { 464 if (!m_UnrestrictedConnect && (access & NetworkAccess.Connect) != 0) 465 { 466 m_UnrestrictedConnect = true; 467 m_connectList.Clear(); 468 } 469 if (!m_UnrestrictedAccept && (access & NetworkAccess.Accept) != 0) 470 { 471 m_UnrestrictedAccept = true; 472 m_acceptList.Clear(); 473 } 474 return; 475 } 476 477 AddAsPattern(access, new DelayedRegex(uriRegex)); 478 } 479 480 // Overloaded form using string inputs 481 // Enforces case-insensitive matching 482 /// Adds a new instance of the System.Net.WebPermission 483 /// class with the specified access rights for the specified URI Pattern AddAsPattern(NetworkAccess access, DelayedRegex uriRegexPattern)484 internal void AddAsPattern(NetworkAccess access, DelayedRegex uriRegexPattern) 485 { 486 ArrayList lists = new ArrayList(); 487 if ((access & NetworkAccess.Connect) != 0 && !m_UnrestrictedConnect) 488 lists.Add(m_connectList); 489 if ((access & NetworkAccess.Accept) != 0 && !m_UnrestrictedAccept) 490 lists.Add(m_acceptList); 491 492 foreach (ArrayList list in lists) 493 { 494 // avoid duplicated regexes in the list 495 bool found = false; 496 foreach (object obj in list) { 497 if ((obj is DelayedRegex) && (string.Compare(uriRegexPattern.ToString(), obj.ToString(), StringComparison.OrdinalIgnoreCase ) == 0)) { 498 found = true; 499 break; 500 } 501 } 502 503 if (!found) { 504 list.Add(uriRegexPattern); 505 } 506 } 507 } 508 509 // IUnrestrictedPermission interface methods 510 /// <devdoc> 511 /// <para> 512 /// Checks the overall permisison state of the object. 513 /// </para> 514 /// </devdoc> IsUnrestricted()515 public bool IsUnrestricted() { 516 return m_noRestriction; 517 } 518 519 // IPermission interface methods 520 /// <devdoc> 521 /// <para> 522 /// Creates a copy of a <see cref='System.Net.WebPermission'/> instance. 523 /// </para> 524 /// </devdoc> Copy()525 public override IPermission Copy() { 526 if (m_noRestriction) 527 { 528 return new WebPermission(true); 529 } 530 531 WebPermission wp = new WebPermission((m_UnrestrictedConnect ? NetworkAccess.Connect : (NetworkAccess) 0) | 532 (m_UnrestrictedAccept ? NetworkAccess.Accept : (NetworkAccess)0)); 533 wp.m_acceptList = (ArrayList)m_acceptList.Clone(); 534 wp.m_connectList = (ArrayList)m_connectList.Clone(); 535 return wp; 536 } 537 538 /// <devdoc> 539 /// <para>Compares two <see cref='System.Net.WebPermission'/> instances.</para> 540 /// </devdoc> IsSubsetOf(IPermission target)541 public override bool IsSubsetOf(IPermission target) { 542 // Pattern suggested by security engine 543 if (target == null) { 544 return !m_noRestriction && !m_UnrestrictedConnect && !m_UnrestrictedAccept && m_connectList.Count == 0 && m_acceptList.Count == 0; 545 } 546 547 WebPermission other = target as WebPermission; 548 if (other == null) { 549 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target"); 550 } 551 552 if (other.m_noRestriction) 553 { 554 return true; 555 } 556 else if (m_noRestriction) 557 { 558 return false; 559 } 560 561 // 562 // Besides SPECIAL case, this method is restricted to only final URIs (strings) on 563 // the current object. 564 // The restriction comes from the problem of finding a Regex to be a subset of another Regex 565 // 566 DelayedRegex regex = null; 567 568 if (!other.m_UnrestrictedAccept) 569 { 570 if (m_UnrestrictedAccept) 571 { 572 return false; 573 } 574 else if (m_acceptList.Count != 0) 575 { 576 if (other.m_acceptList.Count == 0) 577 { 578 return false; 579 } 580 foreach(object obj in this.m_acceptList) { 581 regex = obj as DelayedRegex; 582 if(regex != null) { 583 if(isSpecialSubsetCase(obj.ToString(), other.m_acceptList)) 584 continue; 585 throw new NotSupportedException(SR.GetString(SR.net_perm_both_regex)); 586 } 587 if(!isMatchedURI(obj, other.m_acceptList)) 588 return false; 589 } 590 } 591 } 592 593 if (!other.m_UnrestrictedConnect) 594 { 595 if (m_UnrestrictedConnect) 596 { 597 return false; 598 } 599 else if (m_connectList.Count != 0) 600 { 601 if (other.m_connectList.Count == 0) 602 { 603 return false; 604 } 605 foreach(object obj in this.m_connectList) { 606 regex = obj as DelayedRegex; 607 if(regex != null) { 608 if(isSpecialSubsetCase(obj.ToString(), other.m_connectList)) 609 continue; 610 throw new NotSupportedException(SR.GetString(SR.net_perm_both_regex)); 611 } 612 if(!isMatchedURI(obj, other.m_connectList)) 613 return false; 614 } 615 } 616 } 617 618 return true; 619 } 620 621 //Checks special case when testing Regex to be a subset of other Regex 622 //Support only the case when both Regexes are identical as strings. isSpecialSubsetCase(String regexToCheck, ArrayList permList)623 private static bool isSpecialSubsetCase(String regexToCheck, ArrayList permList) { 624 625 Uri uri; 626 foreach(object uriPattern in permList) { 627 DelayedRegex regex = uriPattern as DelayedRegex; 628 if(regex != null) { 629 //regex parameter against regex permission 630 if (String.Compare(regexToCheck, regex.ToString(), StringComparison.OrdinalIgnoreCase ) == 0) 631 return true; 632 } 633 else if ((uri = uriPattern as Uri) != null) { 634 //regex parameter against Uri permission 635 if (String.Compare(regexToCheck, Regex.Escape(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped)), StringComparison.OrdinalIgnoreCase ) == 0) 636 return true; 637 } 638 else if (String.Compare(regexToCheck, Regex.Escape(uriPattern.ToString()), StringComparison.OrdinalIgnoreCase ) == 0) { 639 //regex parameter against string permission 640 return true; 641 } 642 643 } 644 645 return false; 646 } 647 648 // The union of two web permissions is formed by concatenating 649 // the list of allowed regular expressions. There is no check 650 // for duplicates/overlaps 651 /// <devdoc> 652 /// <para>Returns the logical union between two <see cref='System.Net.WebPermission'/> instances.</para> 653 /// </devdoc> Union(IPermission target)654 public override IPermission Union(IPermission target) { 655 // Pattern suggested by Security engine 656 if (target==null) { 657 return this.Copy(); 658 } 659 WebPermission other = target as WebPermission; 660 if(other == null) { 661 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target"); 662 } 663 664 if (m_noRestriction || other.m_noRestriction) 665 { 666 return new WebPermission(true); 667 } 668 669 WebPermission result = new WebPermission(); 670 671 if (m_UnrestrictedConnect || other.m_UnrestrictedConnect) 672 { 673 result.m_UnrestrictedConnect = true; 674 } 675 else 676 { 677 result.m_connectList = (ArrayList) other.m_connectList.Clone(); 678 679 for (int i = 0; i < m_connectList.Count; i++) { 680 DelayedRegex uriPattern = m_connectList[i] as DelayedRegex; 681 if(uriPattern == null) 682 if (m_connectList[i] is string) 683 result.AddPermission(NetworkAccess.Connect, (string)m_connectList[i]); 684 else 685 result.AddPermission(NetworkAccess.Connect, (Uri)m_connectList[i]); 686 else 687 result.AddAsPattern(NetworkAccess.Connect, uriPattern); 688 } 689 } 690 691 if (m_UnrestrictedAccept || other.m_UnrestrictedAccept) 692 { 693 result.m_UnrestrictedAccept = true; 694 } 695 else 696 { 697 result.m_acceptList = (ArrayList) other.m_acceptList.Clone(); 698 699 for (int i = 0; i < m_acceptList.Count; i++) { 700 DelayedRegex uriPattern = m_acceptList[i] as DelayedRegex; 701 if(uriPattern == null) 702 if (m_acceptList[i] is string) 703 result.AddPermission(NetworkAccess.Accept, (string)m_acceptList[i]); 704 else 705 result.AddPermission(NetworkAccess.Accept, (Uri)m_acceptList[i]); 706 else 707 result.AddAsPattern(NetworkAccess.Accept, uriPattern); 708 } 709 } 710 711 return result; 712 } 713 714 /// <devdoc> 715 /// <para>Returns the logical intersection between two <see cref='System.Net.WebPermission'/> instances.</para> 716 /// </devdoc> Intersect(IPermission target)717 public override IPermission Intersect(IPermission target) { 718 // Pattern suggested by Security engine 719 if (target == null) { 720 return null; 721 } 722 723 WebPermission other = target as WebPermission; 724 if(other == null) { 725 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target"); 726 } 727 728 if (m_noRestriction) 729 { 730 return other.Copy(); 731 } 732 if (other.m_noRestriction) 733 { 734 return Copy(); 735 } 736 737 WebPermission result = new WebPermission(); 738 739 if (m_UnrestrictedConnect && other.m_UnrestrictedConnect) 740 { 741 result.m_UnrestrictedConnect = true; 742 } 743 else if (m_UnrestrictedConnect || other.m_UnrestrictedConnect) 744 { 745 result.m_connectList = (ArrayList) (m_UnrestrictedConnect ? other : this).m_connectList.Clone(); 746 } 747 else 748 { 749 intersectList(m_connectList, other.m_connectList, result.m_connectList); 750 } 751 752 if (m_UnrestrictedAccept && other.m_UnrestrictedAccept) 753 { 754 result.m_UnrestrictedAccept = true; 755 } 756 else if (m_UnrestrictedAccept || other.m_UnrestrictedAccept) 757 { 758 result.m_acceptList = (ArrayList) (m_UnrestrictedAccept ? other : this).m_acceptList.Clone(); 759 } 760 else 761 { 762 intersectList(m_acceptList, other.m_acceptList, result.m_acceptList); 763 } 764 765 // return null if resulting permission is restricted and empty 766 if (!result.m_UnrestrictedConnect && !result.m_UnrestrictedAccept && 767 result.m_connectList.Count == 0 && result.m_acceptList.Count == 0) { 768 return null; 769 } 770 return result; 771 } 772 773 /// <devdoc> 774 /// </devdoc> FromXml(SecurityElement securityElement)775 public override void FromXml(SecurityElement securityElement) { 776 if (securityElement == null) { 777 778 // 779 // null SecurityElement 780 // 781 782 throw new ArgumentNullException("securityElement"); 783 } 784 if (!securityElement.Tag.Equals("IPermission")) { 785 786 // 787 // SecurityElement must be a permission element 788 // 789 790 throw new ArgumentException(SR.GetString(SR.net_not_ipermission), "securityElement"); 791 } 792 793 string className = securityElement.Attribute("class"); 794 795 if (className == null) { 796 797 // 798 // SecurityElement must be a permission element for this type 799 // 800 801 throw new ArgumentException(SR.GetString(SR.net_no_classname), "securityElement"); 802 } 803 if (className.IndexOf(this.GetType().FullName) < 0) { 804 805 // 806 // SecurityElement must be a permission element for this type 807 // 808 809 throw new ArgumentException(SR.GetString(SR.net_no_typename), "securityElement"); 810 } 811 812 String str = securityElement.Attribute("Unrestricted"); 813 814 m_connectList = new ArrayList(); 815 m_acceptList = new ArrayList(); 816 m_UnrestrictedAccept = m_UnrestrictedConnect = false; 817 818 if (str != null && string.Compare(str, "true", StringComparison.OrdinalIgnoreCase ) == 0) 819 { 820 m_noRestriction = true; 821 return; 822 } 823 824 m_noRestriction = false; 825 826 SecurityElement et = securityElement.SearchForChildByTag("ConnectAccess"); 827 string uriPattern; 828 829 if (et != null) { 830 831 foreach(SecurityElement uriElem in et.Children) { 832 //NOTE: Any stuff coming from XML is treated as URI PATTERN! 833 if (uriElem.Tag.Equals("URI")) { 834 try { 835 uriPattern = uriElem.Attribute("uri"); 836 } 837 catch { 838 uriPattern = null; 839 } 840 if (uriPattern == null) { 841 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val_in_element), "ConnectAccess"); 842 } 843 if (uriPattern == MatchAll) 844 { 845 m_UnrestrictedConnect = true; 846 m_connectList = new ArrayList(); 847 break; 848 } 849 else 850 { 851 AddAsPattern(NetworkAccess.Connect, new DelayedRegex(uriPattern)); 852 } 853 } 854 else { 855 // improper tag found, just ignore 856 } 857 } 858 } 859 860 et = securityElement.SearchForChildByTag("AcceptAccess"); 861 if (et != null) { 862 863 foreach(SecurityElement uriElem in et.Children) { 864 //NOTE: Any stuff coming from XML is treated as URI PATTERN! 865 if (uriElem.Tag.Equals("URI")) { 866 try { 867 uriPattern = uriElem.Attribute("uri"); 868 } 869 catch { 870 uriPattern = null; 871 } 872 if (uriPattern == null) { 873 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val_in_element), "AcceptAccess"); 874 } 875 if (uriPattern == MatchAll) 876 { 877 m_UnrestrictedAccept = true; 878 m_acceptList = new ArrayList(); 879 break; 880 } 881 else 882 { 883 AddAsPattern(NetworkAccess.Accept, new DelayedRegex(uriPattern)); 884 } 885 } 886 else { 887 // improper tag found, just ignore 888 } 889 } 890 } 891 } 892 893 /// <devdoc> 894 /// <para>[To be supplied.]</para> 895 /// </devdoc> ToXml()896 public override SecurityElement ToXml() { 897 898 SecurityElement securityElement = new SecurityElement("IPermission"); 899 900 securityElement.AddAttribute( "class", this.GetType().FullName + ", " + this.GetType().Module.Assembly.FullName.Replace( '\"', '\'' ) ); 901 securityElement.AddAttribute( "version", "1" ); 902 903 if (!IsUnrestricted()) { 904 String tempStr=null; 905 906 if (m_UnrestrictedConnect || m_connectList.Count > 0) 907 { 908 SecurityElement connectElement = new SecurityElement( "ConnectAccess" ); 909 910 if (m_UnrestrictedConnect) 911 { 912 SecurityElement uripattern = new SecurityElement("URI"); 913 uripattern.AddAttribute("uri", SecurityElement.Escape(MatchAll)); 914 connectElement.AddChild(uripattern); 915 } 916 else 917 { 918 //NOTE All strings going to XML will become URI PATTERNS i.e. escaped to Regex 919 foreach(object obj in m_connectList) { 920 Uri uri = obj as Uri; 921 if(uri != null) 922 tempStr=Regex.Escape(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped)); 923 else 924 tempStr=obj.ToString(); 925 926 if (obj is string) 927 tempStr = Regex.Escape(tempStr); 928 929 SecurityElement uripattern = new SecurityElement("URI"); 930 uripattern.AddAttribute("uri", SecurityElement.Escape(tempStr)); 931 connectElement.AddChild(uripattern); 932 } 933 } 934 935 securityElement.AddChild( connectElement ); 936 } 937 938 if (m_UnrestrictedAccept || m_acceptList.Count > 0) 939 { 940 SecurityElement acceptElement = new SecurityElement("AcceptAccess"); 941 942 if (m_UnrestrictedAccept) 943 { 944 SecurityElement uripattern = new SecurityElement("URI"); 945 uripattern.AddAttribute("uri", SecurityElement.Escape(MatchAll)); 946 acceptElement.AddChild(uripattern); 947 } 948 else 949 { 950 //NOTE All strings going to XML will become URI PATTERNS i.e. escaped to Regex 951 foreach(object obj in m_acceptList) { 952 Uri uri = obj as Uri; 953 if(uri != null) 954 tempStr=Regex.Escape(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped)); 955 else 956 tempStr=obj.ToString(); 957 958 if (obj is string) 959 tempStr = Regex.Escape(tempStr); 960 961 SecurityElement uripattern = new SecurityElement("URI"); 962 uripattern.AddAttribute("uri", SecurityElement.Escape(tempStr)); 963 acceptElement.AddChild(uripattern); 964 } 965 } 966 967 securityElement.AddChild( acceptElement ); 968 } 969 } 970 else { 971 securityElement.AddAttribute( "Unrestricted", "true" ); 972 } 973 return securityElement; 974 } 975 976 // Verifies a single Uri against a set of regular expressions isMatchedURI(object uriToCheck, ArrayList uriPatternList)977 private static bool isMatchedURI(object uriToCheck, ArrayList uriPatternList) { 978 979 string stringUri = uriToCheck as string; 980 981 foreach(object uriPattern in uriPatternList) { 982 DelayedRegex R = uriPattern as DelayedRegex; 983 984 //perform case insensitive comparison of final URIs or strings, a Uri is never equal compares a string (strings are invalid Uris) 985 if(R == null) { 986 if (uriToCheck.GetType() == uriPattern.GetType()) 987 { 988 if (stringUri != null && string.Compare(stringUri, (string)uriPattern, StringComparison.OrdinalIgnoreCase ) == 0) { 989 return true; 990 } 991 else if(stringUri == null && uriToCheck.Equals(uriPattern)) { 992 return true; 993 } 994 } 995 continue; 996 } 997 998 //Otherwise trying match final URI against given Regex pattern 999 string s = stringUri != null? stringUri: ((Uri)uriToCheck).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped); 1000 Match M = R.AsRegex.Match(s); 1001 if ((M != null) // Found match for the regular expression? 1002 && (M.Index == 0) // ... which starts at the begining 1003 && (M.Length == s.Length)) { // ... and the whole string matched 1004 return true; 1005 } 1006 1007 if (stringUri != null) 1008 continue; 1009 // 1010 // check if the URI was presented in non-canonical form 1011 // 1012 s = ((Uri)uriToCheck).GetComponents(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); 1013 M = R.AsRegex.Match(s); 1014 if ((M != null) // Found match for the regular expression? 1015 && (M.Index == 0) // ... which starts at the begining 1016 && (M.Length == s.Length)) { // ... and the whole string matched 1017 return true; 1018 } 1019 } 1020 return false; 1021 } 1022 1023 // We should keep the result as compact as possible since otherwise even 1024 // simple scenarios in Policy Wizard won;t work due to repeated Union/Intersect calls 1025 // The issue comes from the "hard" Regex.IsSubsetOf(Regex) problem. intersectList(ArrayList A, ArrayList B, ArrayList result)1026 private static void intersectList(ArrayList A, ArrayList B, ArrayList result) { 1027 bool[] aDone = new bool[A.Count]; 1028 bool[] bDone = new bool[B.Count]; 1029 int ia=0, ib; 1030 1031 // The optimization is done according to the following truth 1032 // (A|B|C) intersect (B|C|E|D)) == B|C|(A inter E)|(A inter D) 1033 // 1034 // We also check on any duplicates in the result 1035 1036 // Round 1st 1037 // Getting rid of same permissons in the input arrays (assuming X /\ X = X) 1038 foreach (object a in A) { 1039 ib = 0; 1040 foreach (object b in B) { 1041 1042 // check to see if b is in the result already 1043 if (!bDone[ib]) { 1044 1045 //if both are regexes or both are Uris or both are strings 1046 if (a.GetType() == b.GetType()) 1047 { 1048 if (a is Uri) 1049 { 1050 // both are uris 1051 if (a.Equals(b)) 1052 { 1053 result.Add(a); 1054 aDone[ia]=bDone[ib]=true; 1055 //since permissions are ORed we can break and go to the next A 1056 break; 1057 } 1058 } 1059 else 1060 { 1061 // regexes and strings uses ToString() output 1062 if (string.Compare(a.ToString(), b.ToString(), StringComparison.OrdinalIgnoreCase ) == 0) 1063 { 1064 result.Add(a); 1065 aDone[ia]=bDone[ib]=true; 1066 //since permissions are ORed we can break and go to the next A 1067 break; 1068 } 1069 } 1070 } 1071 } 1072 ++ib; 1073 } //foreach b in B 1074 ++ia; 1075 } //foreach a in A 1076 1077 ia = 0; 1078 // Round second 1079 // Grab only intersections of objects not found in both A and B 1080 foreach (object a in A) { 1081 1082 if (!aDone[ia]) { 1083 ib = 0; 1084 foreach(object b in B) { 1085 1086 if (!bDone[ib]) { 1087 bool resultUri; 1088 object intesection = intersectPair(a, b, out resultUri); 1089 1090 if (intesection != null) { 1091 bool found = false; 1092 // check to see if we already have the same result 1093 foreach (object obj in result) { 1094 if (resultUri == (obj is Uri)) 1095 { 1096 if(resultUri 1097 ? intesection.Equals(obj) 1098 : string.Compare(obj.ToString(), intesection.ToString(), StringComparison.OrdinalIgnoreCase ) == 0) 1099 { 1100 found = true; 1101 break; 1102 } 1103 } 1104 } 1105 1106 if (!found) { 1107 result.Add(intesection); 1108 } 1109 } 1110 } 1111 ++ib; 1112 } 1113 } 1114 ++ia; 1115 } 1116 } 1117 intersectPair(object L, object R, out bool isUri)1118 private static object intersectPair(object L, object R, out bool isUri) { 1119 1120 //VERY OLD OPTION: return new Regex("(?=(" + ((Regex)X[i]).ToString()+ "))(" + ((Regex)Y[j]).ToString() + ")","i"); 1121 //STILL OLD OPTION: return new Regex("(?=.*?(" + L.ToString() + "))" + "(?=.*?(" + R.ToString() + "))"); 1122 // check RegexSpec.doc 1123 //CURRENT OPTION: return new Regex("(?=(" + L.ToString() + "))(" + R.ToString() + ")", RegexOptions.IgnoreCase ); 1124 isUri = false; 1125 DelayedRegex L_Pattern =L as DelayedRegex; 1126 DelayedRegex R_Pattern =R as DelayedRegex; 1127 1128 if(L_Pattern != null && R_Pattern != null) { //both are Regex 1129 return new DelayedRegex("(?=(" + L_Pattern.ToString() + "))(" + R_Pattern.ToString() + ")"); 1130 } 1131 else if(L_Pattern != null && R_Pattern == null) { //only L is a Regex 1132 isUri = R is Uri; 1133 string uriString = isUri? ((Uri)R).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped): R.ToString(); 1134 1135 Match M = L_Pattern.AsRegex.Match(uriString); 1136 if ((M != null) // Found match for the regular expression? 1137 && (M.Index == 0) // ... which starts at the begining 1138 && (M.Length == uriString.Length)) { // ... and the whole string matched 1139 return R; 1140 } 1141 return null; 1142 } 1143 else if(L_Pattern == null && R_Pattern != null) { //only R is a Regex 1144 isUri = L is Uri; 1145 string uriString = isUri? ((Uri)L).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped): L.ToString(); 1146 Match M = R_Pattern.AsRegex.Match(uriString); 1147 if ((M != null) // Found match for the regular expression? 1148 && (M.Index == 0) // ... which starts at the begining 1149 && (M.Length == uriString.Length)) { // ... and the whole string matched 1150 return L; 1151 } 1152 return null; 1153 } 1154 //both are Uris or strings 1155 isUri = L is Uri; 1156 if (isUri) 1157 return L.Equals(R)? L : null; 1158 else 1159 return string.Compare(L.ToString(), R.ToString(), StringComparison.OrdinalIgnoreCase ) == 0? L : null; 1160 } 1161 } // class WebPermission 1162 } // namespace System.Net 1163