ubernostrum / django-flashpolicies
An application for managing cross-domain access policies for Flash.
Clone this repository (size: 127.0 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/ubernostrum/django-flashpolicies/
| commit 79: | 83e7bc0c7856 |
| parent 78: | e777a4e4294a |
| branch: | default |
Metapolicy of 'none' should clear all previously-granted access, and forbid any new access.
9 months ago
django-flashpolicies /
flashpolicies
/
policies.py
| r79:83e7bc0c7856 | 163 loc | 6.5 KB | embed / history / annotate / raw / |
|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | """
Utilities for generating Flash cross-domain policy files.
"""
import xml.dom
minidom = xml.dom.getDOMImplementation('minidom')
#
# Acceptable values for the "permitted-cross-domain-policies"
# attribute of "site-control" elements. See section 3(b)(i) of the
# Adobe crossdomain.xml spec.
#
SITE_CONTROL_ALL = "all"
SITE_CONTROL_BY_CONTENT_TYPE = "by-content-type"
SITE_CONTROL_BY_FTP_FILENAME = "by-ftp-filename"
SITE_CONTROL_MASTER_ONLY = "master-only"
SITE_CONTROL_NONE = "none"
VALID_SITE_CONTROL = (SITE_CONTROL_ALL,
SITE_CONTROL_BY_CONTENT_TYPE,
SITE_CONTROL_BY_FTP_FILENAME,
SITE_CONTROL_MASTER_ONLY,
SITE_CONTROL_NONE)
class Policy(object):
"""
Wrapper object for creating and manipulating a Flash cross-domain
policy.
In the simplest case -- specifying one or more domains to allow
access from -- simply pass the domains to the constructor. For
example::
my_policy = Policy('media.example.com', 'api.example.com')
The property ``xml_dom`` of the returned ``Policy`` object will be
an ``xml.dom.minidom.Document`` representing the resulting policy,
and can be serialized for writing to a file or returning via HTTP.
Consult the documentation for the various methods of this class
for more advanced uses.
"""
def __init__(self, *domains):
self.site_control = None
self.domains = {}
self.header_domains = {}
for domain in domains:
self.allow_domain(domain)
def allow_domain(self, domain, to_ports=None, secure=True):
"""
Allow access from ``domain``, which may be either a full
domain name, or a wildcard (e.g., ``*.example.com``, or simply
``*``). Due to security concerns, it is strongly recommended
that you use explicit domains rather than wildcards.
For socket policy files, pass a list of ports or port ranges
as the keyword argument ``to_ports``. As with ``domain``, a
wildcard value -- ``*`` -- will allow all ports.
To disable Flash's requirement of security matching (e.g.,
retrieving a policy via HTTPS will require that SWFs also be
retrieved via HTTPS), pass ``secure=False``. Due to security
concerns, it is strongly recommended that you not disable
this.
"""
if self.site_control == SITE_CONTROL_NONE:
raise TypeError("Metapolicy currently forbids all access; to allow a domain, change the metapolicy.")
self.domains[domain] = {'to_ports': to_ports,
'secure': secure}
def metapolicy(self, permitted):
"""
Set meta-policy to ``permitted``. (only applicable to master
policy files). Acceptable values correspond to those listed in
Section 3(b)(i) of the crossdomain.xml specification, and are
also available as a set of constants defined in this module.
By default, Flash assumes a value of ``master-only`` for all
policies except socket policies, (which assume a default of
``all``) so if this is desired (and, for security, it
typically is), this method does not need to be called.
"""
if permitted not in VALID_SITE_CONTROL:
raise TypeError('"%s" is not a valid value for the "permitted-cross-domain-policies" attribute of a site-control element' % permitted)
if permitted == SITE_CONTROL_NONE:
# Metapolicy 'none' means no access is permitted.
self.domains = {}
self.header_domains = {}
self.site_control = permitted
def allow_headers(self, domain, headers, secure=True):
"""
Allow ``domain`` to push data via the HTTP headers named in
``headers``.
As with ``allow_domain``, ``domain`` may be either a full
domain name or a wildcard. Again, use of wildcards is
discouraged for security reasons.
The value for ``headers`` should be a list of header names.
To disable Flash's requirement of security matching (e.g.,
retrieving a policy via HTTPS will require that SWFs also be
retrieved via HTTPS), pass ``secure=False``. Due to security
concerns, it is strongly recommended that you not disable
this.
"""
if self.site_control == SITE_CONTROL_NONE:
raise TypeError("Metapolicy currently forbids all access; to allow headers from a domain, change the metapolicy.")
self.header_domains[domain] = {'headers': headers,
'secure': secure}
def _get_xml_dom(self):
"""
Collect all options set so far, and produce and return an
``xml.dom.minidom.Document`` representing the corresponding
XML.
Note that the various elements appear inside the XML document
in a specific order to ensure validity, so use caution when
manipulating the returned ``Document``.
"""
policy_type = minidom.createDocumentType(qualifiedName='cross-domain-policy',
publicId=None,
systemId='http://www.adobe.com/xml/dtds/cross-domain-policy.dtd')
policy = minidom.createDocument(None, 'cross-domain-policy', policy_type)
if self.site_control is not None:
control_element = policy.createElement('site-control')
control_element.setAttribute('permitted-cross-domain-policies', self.site_control)
policy.documentElement.appendChild(control_element)
for domain, attrs in self.domains.items():
domain_element = policy.createElement('allow-access-from')
domain_element.setAttribute('domain', domain)
if attrs['to_ports'] is not None:
domain_element.setAttribute('to-ports', ','.join(attrs['to_ports']))
if not attrs['secure']:
domain_element.setAttribute('secure', 'false')
policy.documentElement.appendChild(domain_element)
for domain, attrs in self.header_domains.items():
header_element = policy.createElement('allow-http-request-headers-from')
header_element.setAttribute('domain', domain)
header_element.setAttribute('headers', ','.join(attrs['headers']))
if not attrs['secure']:
header_element.setAttribute('secure', 'false')
policy.documentElement.appendChild(header_element)
return policy
xml_dom = property(_get_xml_dom)
|
