Add crossdomain.xml middleware
Allows client-side technologies such as Flash, Java and Silverlight running on web pages served elsewhere to interact with the Swift API. Bug #1159960 Change-Id: I7d0533a0aaf189ac452abbd983469acb064fdca4
This commit is contained in:
parent
7f534fac38
commit
eb4b29d243
55
doc/source/crossdomain.xml
Normal file
55
doc/source/crossdomain.xml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
========================
|
||||||
|
Cross-domain Policy File
|
||||||
|
========================
|
||||||
|
|
||||||
|
A cross-domain policy file allows web pages hosted elsewhere to use client
|
||||||
|
side technologies such as Flash, Java and Silverlight to interact
|
||||||
|
with the Swift API.
|
||||||
|
|
||||||
|
See http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html for
|
||||||
|
a description of the purpose and structure of the cross-domain policy
|
||||||
|
file. The cross-domain policy file is installed in the root of a web
|
||||||
|
server (i.e., the path is /crossdomain.xml).
|
||||||
|
|
||||||
|
The crossdomain middleware responds to a path of /crossdomain.xml with an
|
||||||
|
XML document such as::
|
||||||
|
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd" >
|
||||||
|
<cross-domain-policy>
|
||||||
|
<allow-access-from domain="*" secure="false" />
|
||||||
|
</cross-domain-policy>
|
||||||
|
|
||||||
|
You should use a policy appropriate to your site. The examples and the
|
||||||
|
default policy are provided to indicate how to syntactically construct
|
||||||
|
a cross domain policy file -- they are not recommendations.
|
||||||
|
|
||||||
|
-------------
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
To enable this middleware, add it to the pipeline in your proxy-server.conf
|
||||||
|
file. It should be added before any authentication (e.g., tempauth or
|
||||||
|
keystone) middleware. In this example ellipsis (...) indicate other
|
||||||
|
middleware you may have chosen to use::
|
||||||
|
|
||||||
|
[pipeline:main]
|
||||||
|
pipeline = ... crossdomain ... authtoken ... proxy-server
|
||||||
|
|
||||||
|
And add a filter section, such as::
|
||||||
|
|
||||||
|
[filter:crossdomain]
|
||||||
|
use = egg:swift#crossdomain
|
||||||
|
cross_domain_policy = <allow-access-from domain="*.example.com" />
|
||||||
|
<allow-access-from domain="www.example.com" secure="false" />
|
||||||
|
|
||||||
|
For continuation lines, put some whitespace before the continuation
|
||||||
|
text. Ensure you put a completely blank line to terminate the
|
||||||
|
cross_domain_policy value.
|
||||||
|
|
||||||
|
The cross_domain_policy name/value is optional. If omited, the policy
|
||||||
|
defaults as if you had specified::
|
||||||
|
|
||||||
|
cross_domain_policy = <allow-access-from domain="*" secure="false" />
|
||||||
|
|
||||||
|
|
@ -54,6 +54,7 @@ Overview and Concepts
|
|||||||
overview_container_sync
|
overview_container_sync
|
||||||
overview_expiring_objects
|
overview_expiring_objects
|
||||||
cors
|
cors
|
||||||
|
crossdomain
|
||||||
associated_projects
|
associated_projects
|
||||||
|
|
||||||
Developer Documentation
|
Developer Documentation
|
||||||
|
1
setup.py
1
setup.py
@ -89,6 +89,7 @@ setup(
|
|||||||
],
|
],
|
||||||
'paste.filter_factory': [
|
'paste.filter_factory': [
|
||||||
'healthcheck=swift.common.middleware.healthcheck:filter_factory',
|
'healthcheck=swift.common.middleware.healthcheck:filter_factory',
|
||||||
|
'crossdomain=swift.common.middleware.crossdomain:filter_factory',
|
||||||
'memcache=swift.common.middleware.memcache:filter_factory',
|
'memcache=swift.common.middleware.memcache:filter_factory',
|
||||||
'ratelimit=swift.common.middleware.ratelimit:filter_factory',
|
'ratelimit=swift.common.middleware.ratelimit:filter_factory',
|
||||||
'cname_lookup=swift.common.middleware.cname_lookup:filter_factory',
|
'cname_lookup=swift.common.middleware.cname_lookup:filter_factory',
|
||||||
|
90
swift/common/middleware/crossdomain.py
Normal file
90
swift/common/middleware/crossdomain.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from swift.common.swob import Request, Response
|
||||||
|
|
||||||
|
|
||||||
|
class CrossDomainMiddleware(object):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Cross domain middleware used to respond to requests for cross domain
|
||||||
|
policy information.
|
||||||
|
|
||||||
|
If the path is /crossdomain.xml it will respond with an xml cross domain
|
||||||
|
policy document. This allows web pages hosted elsewhere to use client
|
||||||
|
side technologies such as Flash, Java and Silverlight to interact
|
||||||
|
with the Swift API.
|
||||||
|
|
||||||
|
To enable this middleware, add it to the pipeline in your proxy-server.conf
|
||||||
|
file. It should be added before any authentication (e.g., tempauth or
|
||||||
|
keystone) middleware. In this example ellipsis (...) indicate other
|
||||||
|
middleware you may have chosen to use::
|
||||||
|
|
||||||
|
[pipeline:main]
|
||||||
|
pipeline = ... crossdomain ... authtoken ... proxy-server
|
||||||
|
|
||||||
|
And add a filter section, such as::
|
||||||
|
|
||||||
|
[filter:crossdomain]
|
||||||
|
use = egg:swift#crossdomain
|
||||||
|
cross_domain_policy = <allow-access-from domain="*.example.com" />
|
||||||
|
<allow-access-from domain="www.example.com" secure="false" />
|
||||||
|
|
||||||
|
For continuation lines, put some whitespace before the continuation
|
||||||
|
text. Ensure you put a completely blank line to terminate the
|
||||||
|
cross_domain_policy value.
|
||||||
|
|
||||||
|
The cross_domain_policy name/value is optional. If omited, the policy
|
||||||
|
defaults as if you had specified::
|
||||||
|
|
||||||
|
cross_domain_policy = <allow-access-from domain="*" secure="false" />
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, app, conf, *args, **kwargs):
|
||||||
|
self.app = app
|
||||||
|
self.conf = conf
|
||||||
|
default_domain_policy = '<allow-access-from domain="*"' \
|
||||||
|
' secure="false" />'
|
||||||
|
self.cross_domain_policy = self.conf.get('cross_domain_policy',
|
||||||
|
default_domain_policy)
|
||||||
|
|
||||||
|
def GET(self, req):
|
||||||
|
"""Returns a 200 response with cross domain policy information """
|
||||||
|
body = '<?xml version="1.0"?>\n' \
|
||||||
|
'<!DOCTYPE cross-domain-policy SYSTEM ' \
|
||||||
|
'"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd" >\n' \
|
||||||
|
'<cross-domain-policy>\n' \
|
||||||
|
'%s\n' \
|
||||||
|
'</cross-domain-policy>' % self.cross_domain_policy
|
||||||
|
return Response(request=req, body=body,
|
||||||
|
content_type="application/xml")
|
||||||
|
|
||||||
|
def __call__(self, env, start_response):
|
||||||
|
req = Request(env)
|
||||||
|
if req.path == '/crossdomain.xml' and req.method == 'GET':
|
||||||
|
return self.GET(req)(env, start_response)
|
||||||
|
else:
|
||||||
|
return self.app(env, start_response)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_factory(global_conf, **local_conf):
|
||||||
|
conf = global_conf.copy()
|
||||||
|
conf.update(local_conf)
|
||||||
|
|
||||||
|
def crossdomain_filter(app):
|
||||||
|
return CrossDomainMiddleware(app, conf)
|
||||||
|
return crossdomain_filter
|
85
test/unit/common/middleware/test_crossdomain.py
Normal file
85
test/unit/common/middleware/test_crossdomain.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Copyright (c) 2013 OpenStack Foundation.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from swift.common.swob import Request, Response
|
||||||
|
|
||||||
|
from swift.common.middleware import crossdomain
|
||||||
|
|
||||||
|
|
||||||
|
class FakeApp(object):
|
||||||
|
|
||||||
|
def __call__(self, env, start_response):
|
||||||
|
return "FAKE APP"
|
||||||
|
|
||||||
|
|
||||||
|
def start_response(*args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestCrossDomain(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.app = crossdomain.CrossDomainMiddleware(FakeApp(), {})
|
||||||
|
|
||||||
|
# GET of /crossdomain.xml (default)
|
||||||
|
def test_crossdomain_default(self):
|
||||||
|
expectedResponse = '<?xml version="1.0"?>\n' \
|
||||||
|
'<!DOCTYPE cross-domain-policy SYSTEM ' \
|
||||||
|
'"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd" >\n' \
|
||||||
|
'<cross-domain-policy>\n' \
|
||||||
|
'<allow-access-from domain="*" secure="false" />\n' \
|
||||||
|
'</cross-domain-policy>'
|
||||||
|
|
||||||
|
req = Request.blank('/crossdomain.xml',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'})
|
||||||
|
resp = self.app(req.environ, start_response)
|
||||||
|
self.assertEquals(resp, [expectedResponse])
|
||||||
|
|
||||||
|
# GET of /crossdomain.xml (custom)
|
||||||
|
def test_crossdomain_custom(self):
|
||||||
|
conf = {'cross_domain_policy': '<dummy 1>\n<dummy 2>'}
|
||||||
|
self.app = crossdomain.CrossDomainMiddleware(FakeApp(), conf)
|
||||||
|
expectedResponse = '<?xml version="1.0"?>\n' \
|
||||||
|
'<!DOCTYPE cross-domain-policy SYSTEM ' \
|
||||||
|
'"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd" >\n' \
|
||||||
|
'<cross-domain-policy>\n' \
|
||||||
|
'<dummy 1>\n' \
|
||||||
|
'<dummy 2>\n' \
|
||||||
|
'</cross-domain-policy>'
|
||||||
|
|
||||||
|
req = Request.blank('/crossdomain.xml',
|
||||||
|
environ={'REQUEST_METHOD': 'GET'})
|
||||||
|
resp = self.app(req.environ, start_response)
|
||||||
|
self.assertEquals(resp, [expectedResponse])
|
||||||
|
|
||||||
|
# GET to a different resource should be passed on
|
||||||
|
def test_crossdomain_pass(self):
|
||||||
|
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'})
|
||||||
|
resp = self.app(req.environ, start_response)
|
||||||
|
self.assertEquals(resp, 'FAKE APP')
|
||||||
|
|
||||||
|
# Only GET is allowed on the /crossdomain.xml resource
|
||||||
|
def test_crossdomain_get_only(self):
|
||||||
|
for method in ['HEAD', 'PUT', 'POST', 'COPY', 'OPTIONS']:
|
||||||
|
req = Request.blank('/crossdomain.xml',
|
||||||
|
environ={'REQUEST_METHOD': method})
|
||||||
|
resp = self.app(req.environ, start_response)
|
||||||
|
self.assertEquals(resp, 'FAKE APP')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user