def __call__(self, req): if req.path == '/info': # Ensure /info requests get the freshest results self.register_info() return self.app try: (version, acc, cont, obj) = req.split_path(3, 4, True) bad_path = False except ValueError: bad_path = True # use of bad_path bool is to avoid recursive tracebacks if bad_path or not valid_api_version(version): return self.app # validate container-sync metdata update info = get_container_info(req.environ, self.app, swift_source='CS') sync_to = req.headers.get('x-container-sync-to') if req.method in ('PUT', 'POST') and cont and not obj: versions_cont = info.get('sysmeta', {}).get('versions-container') if sync_to and versions_cont: raise HTTPBadRequest( 'Cannot configure container sync on a container ' 'with object versioning configured.', request=req) if not self.allow_full_urls: if sync_to and not sync_to.startswith('//'): raise HTTPBadRequest( body='Full URLs are not allowed for X-Container-Sync-To ' 'values. Only realm values of the format ' '//realm/cluster/account/container are allowed.\n', request=req) auth = req.headers.get('x-container-sync-auth') if auth: valid = False auth = auth.split() if len(auth) != 3: req.environ.setdefault('swift.log_info', []).append('cs:not-3-args') else: realm, nonce, sig = auth realm_key = self.realms_conf.key(realm) realm_key2 = self.realms_conf.key2(realm) if not realm_key: req.environ.setdefault('swift.log_info', []).append('cs:no-local-realm-key') else: user_key = info.get('sync_key') if not user_key: req.environ.setdefault( 'swift.log_info', []).append('cs:no-local-user-key') else: # x-timestamp headers get shunted by gatekeeper if 'x-backend-inbound-x-timestamp' in req.headers: req.headers['x-timestamp'] = req.headers.pop( 'x-backend-inbound-x-timestamp') expected = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key, user_key) expected2 = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key2, user_key) if realm_key2 else expected if not streq_const_time(sig, expected) and \ not streq_const_time(sig, expected2): req.environ.setdefault('swift.log_info', []).append('cs:invalid-sig') else: req.environ.setdefault('swift.log_info', []).append('cs:valid') valid = True if not valid: exc = HTTPUnauthorized( body='X-Container-Sync-Auth header not valid; ' 'contact cluster operator for support.', headers={'content-type': 'text/plain'}, request=req) exc.headers['www-authenticate'] = ' '.join([ 'SwiftContainerSync', exc.www_authenticate().split(None, 1)[1] ]) raise exc else: req.environ['swift.authorize_override'] = True # An SLO manifest will already be in the internal manifest # syntax and might be synced before its segments, so stop SLO # middleware from performing the usual manifest validation. req.environ['swift.slo_override'] = True # Similar arguments for static symlinks req.environ['swift.symlink_override'] = True return self.app
def __call__(self, req): if not self.allow_full_urls: sync_to = req.headers.get('x-container-sync-to') if sync_to and not sync_to.startswith('//'): raise HTTPBadRequest( body='Full URLs are not allowed for X-Container-Sync-To ' 'values. Only realm values of the format ' '//realm/cluster/account/container are allowed.\n', request=req) auth = req.headers.get('x-container-sync-auth') if auth: valid = False auth = auth.split() if len(auth) != 3: req.environ.setdefault('swift.log_info', []).append('cs:not-3-args') else: realm, nonce, sig = auth realm_key = self.realms_conf.key(realm) realm_key2 = self.realms_conf.key2(realm) if not realm_key: req.environ.setdefault('swift.log_info', []).append('cs:no-local-realm-key') else: info = get_container_info(req.environ, self.app, swift_source='CS') user_key = info.get('sync_key') if not user_key: req.environ.setdefault( 'swift.log_info', []).append('cs:no-local-user-key') else: expected = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key, user_key) expected2 = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key2, user_key) if realm_key2 else expected if not streq_const_time(sig, expected) and \ not streq_const_time(sig, expected2): req.environ.setdefault('swift.log_info', []).append('cs:invalid-sig') else: req.environ.setdefault('swift.log_info', []).append('cs:valid') valid = True if not valid: exc = HTTPUnauthorized( body='X-Container-Sync-Auth header not valid; ' 'contact cluster operator for support.', headers={'content-type': 'text/plain'}, request=req) exc.headers['www-authenticate'] = ' '.join([ 'SwiftContainerSync', exc.www_authenticate().split(None, 1)[1] ]) raise exc else: req.environ['swift.authorize_override'] = True if req.path == '/info': # Ensure /info requests get the freshest results dct = {} for realm in self.realms_conf.realms(): clusters = self.realms_conf.clusters(realm) if clusters: dct[realm] = {'clusters': dict((c, {}) for c in clusters)} register_swift_info('container_sync', realms=dct) return self.app
def __call__(self, req): if not self.allow_full_urls: sync_to = req.headers.get('x-container-sync-to') if sync_to and not sync_to.startswith('//'): raise HTTPBadRequest( body='Full URLs are not allowed for X-Container-Sync-To ' 'values. Only realm values of the format ' '//realm/cluster/account/container are allowed.\n', request=req) auth = req.headers.get('x-container-sync-auth') if auth: valid = False auth = auth.split() if len(auth) != 3: req.environ.setdefault('swift.log_info', []).append( 'cs:not-3-args') else: realm, nonce, sig = auth realm_key = self.realms_conf.key(realm) realm_key2 = self.realms_conf.key2(realm) if not realm_key: req.environ.setdefault('swift.log_info', []).append( 'cs:no-local-realm-key') else: info = get_container_info( req.environ, self.app, swift_source='CS') user_key = info.get('sync_key') if not user_key: req.environ.setdefault('swift.log_info', []).append( 'cs:no-local-user-key') else: # x-timestamp headers get shunted by gatekeeper if 'x-backend-inbound-x-timestamp' in req.headers: req.headers['x-timestamp'] = req.headers.pop( 'x-backend-inbound-x-timestamp') expected = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key, user_key) expected2 = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key2, user_key) if realm_key2 else expected if not streq_const_time(sig, expected) and \ not streq_const_time(sig, expected2): req.environ.setdefault( 'swift.log_info', []).append('cs:invalid-sig') else: req.environ.setdefault( 'swift.log_info', []).append('cs:valid') valid = True if not valid: exc = HTTPUnauthorized( body='X-Container-Sync-Auth header not valid; ' 'contact cluster operator for support.', headers={'content-type': 'text/plain'}, request=req) exc.headers['www-authenticate'] = ' '.join([ 'SwiftContainerSync', exc.www_authenticate().split(None, 1)[1]]) raise exc else: req.environ['swift.authorize_override'] = True # An SLO manifest will already be in the internal manifest # syntax and might be synced before its segments, so stop SLO # middleware from performing the usual manifest validation. req.environ['swift.slo_override'] = True if req.path == '/info': # Ensure /info requests get the freshest results self.register_info() return self.app
def __call__(self, req): if not self.allow_full_urls: sync_to = req.headers.get('x-container-sync-to') if sync_to and not sync_to.startswith('//'): raise HTTPBadRequest( body='Full URLs are not allowed for X-Container-Sync-To ' 'values. Only realm values of the format ' '//realm/cluster/account/container are allowed.\n', request=req) auth = req.headers.get('x-container-sync-auth') if auth: valid = False auth = auth.split() if len(auth) != 3: req.environ.setdefault('swift.log_info', []).append( 'cs:not-3-args') else: realm, nonce, sig = auth realm_key = self.realms_conf.key(realm) realm_key2 = self.realms_conf.key2(realm) if not realm_key: req.environ.setdefault('swift.log_info', []).append( 'cs:no-local-realm-key') else: info = get_container_info( req.environ, self.app, swift_source='CS') user_key = info.get('sync_key') if not user_key: req.environ.setdefault('swift.log_info', []).append( 'cs:no-local-user-key') else: expected = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key, user_key) expected2 = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key2, user_key) if realm_key2 else expected if not streq_const_time(sig, expected) and \ not streq_const_time(sig, expected2): req.environ.setdefault( 'swift.log_info', []).append('cs:invalid-sig') else: req.environ.setdefault( 'swift.log_info', []).append('cs:valid') valid = True if not valid: exc = HTTPUnauthorized( body='X-Container-Sync-Auth header not valid; ' 'contact cluster operator for support.', headers={'content-type': 'text/plain'}, request=req) exc.headers['www-authenticate'] = ' '.join([ 'SwiftContainerSync', exc.www_authenticate().split(None, 1)[1]]) raise exc else: req.environ['swift.authorize_override'] = True if req.path == '/info': # Ensure /info requests get the freshest results dct = {} for realm in self.realms_conf.realms(): clusters = self.realms_conf.clusters(realm) if clusters: dct[realm] = {'clusters': dict((c, {}) for c in clusters)} register_swift_info('container_sync', realms=dct) return self.app
def __call__(self, req): if not self.allow_full_urls: sync_to = req.headers.get('x-container-sync-to') if sync_to and not sync_to.startswith('//'): raise HTTPBadRequest( body='Full URLs are not allowed for X-Container-Sync-To ' 'values. Only realm values of the format ' '//realm/cluster/account/container are allowed.\n', request=req) auth = req.headers.get('x-container-sync-auth') if auth: valid = False auth = auth.split() if len(auth) != 3: req.environ.setdefault('swift.log_info', []).append('cs:not-3-args') else: realm, nonce, sig = auth realm_key = self.realms_conf.key(realm) realm_key2 = self.realms_conf.key2(realm) if not realm_key: req.environ.setdefault('swift.log_info', []).append('cs:no-local-realm-key') else: info = get_container_info(req.environ, self.app, swift_source='CS') user_key = info.get('sync_key') if not user_key: req.environ.setdefault( 'swift.log_info', []).append('cs:no-local-user-key') else: # x-timestamp headers get shunted by gatekeeper if 'x-backend-inbound-x-timestamp' in req.headers: req.headers['x-timestamp'] = req.headers.pop( 'x-backend-inbound-x-timestamp') expected = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key, user_key) expected2 = self.realms_conf.get_sig( req.method, req.path, req.headers.get('x-timestamp', '0'), nonce, realm_key2, user_key) if realm_key2 else expected if not streq_const_time(sig, expected) and \ not streq_const_time(sig, expected2): req.environ.setdefault('swift.log_info', []).append('cs:invalid-sig') else: req.environ.setdefault('swift.log_info', []).append('cs:valid') valid = True if not valid: exc = HTTPUnauthorized( body='X-Container-Sync-Auth header not valid; ' 'contact cluster operator for support.', headers={'content-type': 'text/plain'}, request=req) exc.headers['www-authenticate'] = ' '.join([ 'SwiftContainerSync', exc.www_authenticate().split(None, 1)[1] ]) raise exc else: req.environ['swift.authorize_override'] = True # An SLO manifest will already be in the internal manifest # syntax and might be synced before its segments, so stop SLO # middleware from performing the usual manifest validation. req.environ['swift.slo_override'] = True if req.path == '/info': # Ensure /info requests get the freshest results self.register_info() return self.app