""" Unit tests for ``galaxy.web.framework.webapp`` """ import os import imp import unittest import logging log = logging.getLogger( __name__ ) test_utils = imp.load_source( 'test_utils', os.path.join( os.path.dirname( __file__), '../../unittest_utils/utility.py' ) ) import galaxy_mock import re from galaxy.web.framework import webapp as Webapp import galaxy.config class StubGalaxyWebTransaction( Webapp.GalaxyWebTransaction ): def _ensure_valid_session( self, session_cookie, create=True ): pass class CORSParsingMockConfig( galaxy_mock.MockAppConfig ): # we can't use the actual Configuration for parsing*, so steal the parser for the mock instead # *It causes problems when it's change to tempfile.tempdir persists across tests _parse_allowed_origin_hostnames = galaxy.config.Configuration._parse_allowed_origin_hostnames.__func__ def __init__( self, **kwargs ): super( CORSParsingMockConfig, self ).__init__( **kwargs ) self.allowed_origin_hostnames = self._parse_allowed_origin_hostnames( kwargs ) class GalaxyWebTransaction_Headers_TestCase( test_utils.unittest.TestCase ): def _new_trans( self, allowed_origin_hostnames=None ): app = galaxy_mock.MockApp() app.config = CORSParsingMockConfig( allowed_origin_hostnames=allowed_origin_hostnames ) webapp = galaxy_mock.MockWebapp() environ = galaxy_mock.buildMockEnviron() trans = StubGalaxyWebTransaction( environ, app, webapp ) return trans def assert_cors_header_equals( self, headers, should_be ): self.assertEqual( headers.get( 'access-control-allow-origin', None ), should_be ) def assert_cors_header_missing( self, headers ): self.assertFalse( 'access-control-allow-origin' in headers ) def test_parse_allowed_origin_hostnames( self ): """Should return a list of (possibly) mixed strings and regexps""" config = CORSParsingMockConfig() # falsy listify value should return None self.assertEqual( config._parse_allowed_origin_hostnames({ "allowed_origin_hostnames" : "" }), None ) # should parse regex if using fwd slashes, string otherwise hostnames = config._parse_allowed_origin_hostnames({ "allowed_origin_hostnames" : "/host\d{2}/,geocities.com,miskatonic.edu" }) self.assertTrue( isinstance( hostnames[0], re._pattern_type ) ) self.assertTrue( isinstance( hostnames[1], str ) ) self.assertTrue( isinstance( hostnames[2], str ) ) def test_default_set_cors_headers( self ): """No CORS headers should be set (or even checked) by default""" trans = self._new_trans( allowed_origin_hostnames=None ) self.assertTrue( isinstance( trans, Webapp.GalaxyWebTransaction ) ) trans.request.headers[ 'Origin' ] = 'http://lisaskelprecipes.pinterest.com?id=kelpcake' trans.set_cors_headers() self.assert_cors_header_missing( trans.response.headers ) def test_set_cors_headers( self ): """Origin should be echo'd when it matches an allowed hostname""" # an asterisk is a special 'allow all' string trans = self._new_trans( allowed_origin_hostnames='*,beep.com' ) trans.request.headers[ 'Origin' ] = 'http://xxdarkhackerxx.disney.com' trans.set_cors_headers() self.assert_cors_header_equals( trans.response.headers, 'http://xxdarkhackerxx.disney.com' ) # subdomains should pass trans = self._new_trans( allowed_origin_hostnames='something.com,/^[\w\.]*beep\.com/' ) trans.request.headers[ 'Origin' ] = 'http://boop.beep.com' trans.set_cors_headers() self.assert_cors_header_equals( trans.response.headers, 'http://boop.beep.com' ) # ports should work trans = self._new_trans( allowed_origin_hostnames='somethingelse.com,/^[\w\.]*beep\.com/' ) trans.request.headers[ 'Origin' ] = 'http://boop.beep.com:8080' trans.set_cors_headers() self.assert_cors_header_equals( trans.response.headers, 'http://boop.beep.com:8080' ) # localhost should work trans = self._new_trans( allowed_origin_hostnames='/localhost/' ) trans.request.headers[ 'Origin' ] = 'http://localhost:8080' trans.set_cors_headers() self.assert_cors_header_equals( trans.response.headers, 'http://localhost:8080' ) # spoofing shouldn't be easy trans.response.headers = {} trans.request.headers[ 'Origin' ] = 'http://localhost.badstuff.tv' trans.set_cors_headers() self.assert_cors_header_missing( trans.response.headers ) # unicode should work trans = self._new_trans( allowed_origin_hostnames='/öbb\.at/' ) trans.request.headers[ 'Origin' ] = 'http://öbb.at' trans.set_cors_headers() self.assertEqual( trans.response.headers[ 'access-control-allow-origin' ], 'http://öbb.at' ) if __name__ == '__main__': unittest.main()