def start(self, node, uri, tunnel=False, external_uri=None): """ If not tunnel, start listening on uri and handle http requests. If tunnel, setup a tunnel to uri and handle requests. """ self.node = node self.security = Security(self.node) schema, _ = uri.split(':', 1) if tunnel: # Connect to tunnel server self.tunnel_client = CalvinControlTunnelClient(uri, self) else: url = urlparse(uri) self.port = int(url.port) self.host = url.hostname if external_uri is not None: self.external_host = urlparse(external_uri).hostname else: self.external_host = self.host _log.info("Control API listening on: %s:%s" % (self.host, self.port)) self.server = server_connection.ServerProtocolFactory( self.handle_request, "http", node_name=node.node_name) self.server.start(self.host, self.port) # Create tunnel server self.tunnel_server = CalvinControlTunnelServer(self.node)
def add_node(self, node, cb=None): """ Add node to storage """ self.set(prefix="node-", key=node.id, value={"uri": node.external_uri, "control_uri": node.external_control_uri, "authz_server": node.authorization.authz_server_id, "attributes": {'public': node.attributes.get_public(), 'indexed_public': node.attributes.get_indexed_public(as_list=False)}}, cb=cb) self._add_node_index(node) # Store all actors on this node in storage GlobalStore(node=node, security=Security(node) if security_enabled() else None, verify=False).export()
def new_from_migration(self, actor_type, state, prev_connections=None, connection_list=None, callback=None): """Instantiate an actor of type 'actor_type' and apply the 'state' to the actor.""" try: _log.analyze(self.node.id, "+", state) subject_attributes = state['security'].pop('_subject_attributes', None) migration_info = state['private'].pop('_migration_info', None) try: state['security'].remove('_subject_attributes') state['private'].remove('_migration_info') except: pass if security_enabled(): security = Security(self.node) security.set_subject_attributes(subject_attributes) else: security = None actor_def, signer = self.lookup_and_verify(actor_type, security) requirements = actor_def.requires if hasattr( actor_def, "requires") else [] self.check_requirements_and_sec_policy( requirements, security, state['private']['_id'], signer, migration_info, CalvinCB(self.new, actor_type, None, state, prev_connections=prev_connections, connection_list=connection_list, callback=callback, actor_def=actor_def, security=security)) except Exception: # Still want to create shadow actor. self.new(actor_type, None, state, prev_connections=prev_connections, connection_list=connection_list, callback=callback, shadow_actor=True)
def compile_script_check_security(data, filename, cb, security=None, content=None, verify=True, node=None, signature=None): """ Compile a script and return a tuple (deployable, errors, warnings). 'credentials' are optional security credentials(?) 'verify' is deprecated and will be removed 'node' is the runtime performing security check(?) 'cb' is a CalvinCB callback N.B. If callback 'cb' is given, this method calls cb(deployable, errors, warnings) and returns None N.B. If callback 'cb' is given, and method runs to completion, cb is called with additional parameter 'security' (?) """ def _exit_with_error(callback): """Helper method to generate a proper error""" it = IssueTracker() it.add_error("UNAUTHORIZED", info={'status': 401}) callback({}, it) return def _handle_policy_decision(data, appname, verify, access_decision, org_cb, security=None): if not access_decision: _log.error("Access denied") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(org_cb) return if 'app_info' not in data and 'script' in data: deployable, issuetracker = compile_script(data['script'], appname) elif 'app_info' in data: deployable = data['app_info'] issuetracker = IssueTracker() else: _log.error("Neither app_info or script supplied") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(org_cb) return org_cb(deployable, issuetracker, security=security) # # Actual code for compile_script # appname = appname_from_filename(filename) # FIXME: if node is None we bypass security even if enabled. Is that the intention? if node is not None and security_enabled(): # FIXME: If cb is None, we will return from this method with None instead of a tuple, failing silently if security: sec = security else: sec = Security(node) verified, signer = sec.verify_signature_content(content, "application") if not verified: # Verification not OK if sign or cert not OK. _log.error("Failed application verification") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(cb) return sec.check_security_policy(CalvinCB(_handle_policy_decision, data, appname, verify, security=security, org_cb=cb), element_type="application", element_value=signer) return # # We get here if node is None, or security is disabled # # This used to be # _handle_policy_decision(data, filename, verify, access_decision=True, security=None, org_cb=cb) # but since _handle_policy_decision is called with access_decision=True, security=None only compile_script would be called if 'app_info' not in data and 'script' in data: deployable, issuetracker = compile_script(data['script'], appname) elif 'app_info' in data: deployable = data['app_info'] issuetracker = IssueTracker() else: _log.error("Neither app_info or script supplied") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(org_cb) return cb(deployable, issuetracker, security=None)
def compile_script_check_security(source_text, filename, cb, credentials=None, verify=True, node=None): """ Compile a script and return a tuple (deployable, errors, warnings). 'credentials' are optional security credentials(?) 'verify' is deprecated and will be removed 'node' is the runtime performing security check(?) 'cb' is a CalvinCB callback N.B. If callback 'cb' is given, this method calls cb(deployable, errors, warnings) and returns None N.B. If callback 'cb' is given, and method runs to completion, cb is called with additional parameter 'security' (?) """ def _exit_with_error(callback): """Helper method to generate a proper error""" it = IssueTracker() it.add_error("UNAUTHORIZED", info={'status': 401}) callback({}, it) def _handle_authentication_decision(source_text, appname, verify, authentication_decision, security, org_cb, content=None): if not authentication_decision: _log.error("Authentication failed") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(org_cb) verified, signer = security.verify_signature_content( content, "application") if not verified: # Verification not OK if sign or cert not OK. _log.error("Failed application verification") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(org_cb) security.check_security_policy(CalvinCB(_handle_policy_decision, source_text, appname, verify, security=security, org_cb=org_cb), "application", signer=signer) def _handle_policy_decision(source_text, appname, verify, access_decision, org_cb, security=None): if not access_decision: _log.error("Access denied") # This error reason is detected in calvin control and gives proper REST response _exit_with_error(org_cb) deployable, issutracker = compile_script(source_text, appname) org_cb(deployable, issutracker, security=security) # # Actual code for compile_script # appname = appname_from_filename(filename) # FIXME: if node is None we bypass security even if enabled. Is that the intention? if node is not None and security_enabled(): if credentials: content = Security.verify_signature_get_files(filename, skip_file=True) # content is ALWAYS a dict if skip_file is True content['file'] = source_text else: content = None # FIXME: If cb is None, we will return from this method with None instead of a tuple, failing silently sec = Security(node) sec.authenticate_subject(credentials, callback=CalvinCB( _handle_authentication_decision, source_text, appname, verify, security=sec, org_cb=cb, content=content)) return # # We get here if node is None, or security is disabled # # This used to be # _handle_policy_decision(source_text, filename, verify, access_decision=True, security=None, org_cb=cb) # but since _handle_policy_decision is called with access_decision=True, security=None only compile_script would be called deployable, issuetracker = compile_script(source_text, appname) cb(deployable, issuetracker, security=None)