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_expiring_objects
|
||||
cors
|
||||
crossdomain
|
||||
associated_projects
|
||||
|
||||
Developer Documentation
|
||||
|
1
setup.py
1
setup.py
@ -89,6 +89,7 @@ setup(
|
||||
],
|
||||
'paste.filter_factory': [
|
||||
'healthcheck=swift.common.middleware.healthcheck:filter_factory',
|
||||
'crossdomain=swift.common.middleware.crossdomain:filter_factory',
|
||||
'memcache=swift.common.middleware.memcache:filter_factory',
|
||||
'ratelimit=swift.common.middleware.ratelimit: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