| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- //
- // ClientAccessPolicyParser.cs
- //
- // Authors:
- // Atsushi Enomoto <[email protected]>
- // Moonlight List ([email protected])
- //
- // Copyright (C) 2009-2010 Novell, Inc. http://www.novell.com
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- #if MOBILE
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Xml;
- /*
- default namespace = ""
- grammar {
- start = access-policy
- access-policy = element access-policy {
- element cross-domain-access {
- element policy { allow-from, grant-to }
- }
- }
- allow-from = element allow-from {
- attribute http-request-headers { text },
- element domain {
- attribute uri { text }
- }
- }
- grant-to = element grant-to {
- (resource | socket-resource)+
- }
- resource = element resource {
- attribute path { text },
- attribute include-subpaths { "true" | "false" }
- }
- socket-resource = element socket-resource {
- attribute port { text },
- attribute protocol { text }
- }
- }
- */
- namespace System.Net.Policy {
- partial class ClientAccessPolicy {
- static bool IsNonElement (XmlReader reader)
- {
- return (reader.NodeType != XmlNodeType.Element);
- }
- static bool IsNonEmptyElement (XmlReader reader)
- {
- return (reader.IsEmptyElement || IsNonElement (reader));
- }
- static public ICrossDomainPolicy FromStream (Stream stream)
- {
- ClientAccessPolicy cap = new ClientAccessPolicy ();
- // Silverlight accepts whitespaces before the XML - which is invalid XML
- StreamReader sr = new StreamReader (stream);
- while (Char.IsWhiteSpace ((char) sr.Peek ()))
- sr.Read ();
- XmlReaderSettings policy_settings = new XmlReaderSettings ();
- policy_settings.DtdProcessing = DtdProcessing.Ignore;
- using (XmlReader reader = XmlReader.Create (sr, policy_settings)) {
- reader.MoveToContent ();
- if (reader.IsEmptyElement) {
- reader.Skip ();
- return null;
- }
- reader.ReadStartElement ("access-policy", String.Empty);
- for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
- if (IsNonEmptyElement (reader) || (reader.LocalName != "cross-domain-access")) {
- reader.Skip ();
- continue;
- }
- reader.ReadStartElement ("cross-domain-access", String.Empty);
- for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
- if (IsNonEmptyElement (reader) || (reader.Name != "policy")) {
- reader.Skip ();
- continue;
- }
- ReadPolicyElement (reader, cap);
- }
- reader.ReadEndElement ();
- }
- reader.ReadEndElement ();
- }
- return cap;
- }
- static void ReadPolicyElement (XmlReader reader, ClientAccessPolicy cap)
- {
- if (reader.HasAttributes || reader.IsEmptyElement) {
- reader.Skip ();
- return;
- }
- var policy = new AccessPolicy ();
- bool valid = true;
- reader.ReadStartElement ("policy", String.Empty);
- for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
- if (IsNonElement (reader)) {
- reader.Skip ();
- continue;
- }
- switch (reader.LocalName) {
- case "allow-from":
- ReadAllowFromElement (reader, policy);
- break;
- case "grant-to":
- ReadGrantToElement (reader, policy);
- break;
- default:
- valid = false;
- reader.Skip ();
- break;
- }
- }
- if (valid)
- cap.AccessPolicyList.Add (policy);
- reader.ReadEndElement ();
- }
- static void ReadAllowFromElement (XmlReader reader, AccessPolicy policy)
- {
- if (IsNonEmptyElement (reader)) {
- reader.Skip ();
- return;
- }
- bool valid = true;
- string headers = null;
- string methods = null; // new in SL3
- if (reader.HasAttributes) {
- int n = reader.AttributeCount;
- headers = reader.GetAttribute ("http-request-headers");
- if (headers != null)
- n--;
- methods = reader.GetAttribute ("http-methods");
- if (methods != null)
- n--;
- valid = (n == 0);
- }
- var v = new AllowFrom ();
- v.HttpRequestHeaders.SetHeaders (headers);
- v.AllowAnyMethod = (methods == "*"); // only legal value defined, otherwise restricted to GET and POST
- reader.ReadStartElement ("allow-from", String.Empty);
- for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
- if (IsNonElement (reader) || !String.IsNullOrEmpty (reader.NamespaceURI)) {
- reader.Skip ();
- continue;
- }
- switch (reader.LocalName) {
- case "domain":
- var d = reader.GetAttribute ("uri");
- if (d == "*")
- v.AllowAnyDomain = true;
- else
- v.Domains.Add (d);
- reader.Skip ();
- break;
- default:
- valid = false;
- reader.Skip ();
- continue;
- }
- }
- if (valid)
- policy.AllowedServices.Add (v);
- reader.ReadEndElement ();
- }
- // only "path" and "include-subpaths" attributes are allowed - anything else is not considered
- static Resource CreateResource (XmlReader reader)
- {
- int n = reader.AttributeCount;
- string path = reader.GetAttribute ("path");
- if (path != null)
- n--;
- string subpaths = reader.GetAttribute ("include-subpaths");
- if (subpaths != null)
- n--;
- if ((n != 0) || !reader.IsEmptyElement)
- return null;
- return new Resource () {
- Path = path,
- IncludeSubpaths = subpaths == null ? false : XmlConvert.ToBoolean (subpaths)
- };
- }
- static void ReadGrantToElement (XmlReader reader, AccessPolicy policy)
- {
- var v = new GrantTo ();
- bool valid = true;
- if (reader.HasAttributes || reader.IsEmptyElement) {
- reader.Skip ();
- return;
- }
- reader.ReadStartElement ("grant-to", String.Empty);
- for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
- if (IsNonElement (reader) || !String.IsNullOrEmpty (reader.NamespaceURI)) {
- reader.Skip ();
- continue;
- }
- switch (reader.LocalName) {
- case "resource":
- var r = CreateResource (reader);
- if (r == null)
- valid = false;
- else
- v.Resources.Add (r);
- break;
- case "socket-resource":
- // ignore everything that is not TCP
- if (reader.GetAttribute ("protocol") != "tcp")
- break;
- // we can merge them all together inside a policy
- policy.PortMask |= ParsePorts (reader.GetAttribute ("port"));
- break;
- default:
- valid = false;
- break;
- }
- reader.Skip ();
- }
- if (valid)
- policy.GrantedResources.Add (v);
- reader.ReadEndElement ();
- }
- // e.g. reserved ? 4534-4502
- static long ParsePorts (string ports)
- {
- long mask = 0;
- int sep = ports.IndexOf ('-');
- if (sep >= 0) {
- // range
- ushort from = ParsePort (ports.Substring (0, sep));
- ushort to = ParsePort (ports.Substring (sep + 1));
- for (int port = from; port <= to; port++)
- mask |= (long) (1ul << (port - AccessPolicy.MinPort));
- } else {
- // single
- ushort port = ParsePort (ports);
- mask |= (long) (1ul << (port - AccessPolicy.MinPort));
- }
- return mask;
- }
- static ushort ParsePort (string s)
- {
- ushort port;
- if (!UInt16.TryParse (s, out port) || (port < AccessPolicy.MinPort) || (port > AccessPolicy.MaxPort))
- throw new XmlException ("Invalid port");
- return port;
- }
- }
- }
- #endif
|