def prepare(self): """Prepare to handler reply.""" self.set_header('Content-Type', 'application/json') # get requests do not require authentication if self.request.method == "GET": return accounts_manager = srv_or_die("accountsmanager") projects_manager = srv_or_die("projectsmanager") auth_header = self.request.headers.get('Authorization') if auth_header is None or not auth_header.startswith('Basic '): self.set_header('WWW-Authenticate', 'Basic realm=Restricted') self.send_error(401, message="Missing authorization header") return auth_bytes = bytes(auth_header[6:], 'utf-8') auth_decoded = base64.b64decode(auth_bytes).decode() username, password = auth_decoded.split(':', 2) # account does not exists if not accounts_manager.check_permission(username, password): self.send_error(401, message="Invalid username/password combination") return account = accounts_manager.accounts[username] # root can do everything if account.username == "root": return # check if logged user is accessing his/her own account if self.request.uri.startswith("/api/v1/accounts"): pattern = re.compile("/api/v1/accounts/([a-zA-Z0-9:-]*)/?") match = pattern.match(self.request.uri) if match and match.group(1): username = match.group(1) if username == account.username: return # check if logged user is accessing one of his/her projects if self.request.uri.startswith("/api/v1/projects"): pattern = re.compile("/api/v1/projects/([a-zA-Z0-9-]*)/?") match = pattern.match(self.request.uri) if match and match.group(1): project_id = UUID(match.group(1)) if project_id in projects_manager.projects: project = projects_manager.projects[project_id] if account.username == project.owner: return self.send_error(401, message="URI not authorized")
def start_service(self, service_id, name, params, storage=None): """Start a service.""" # wait we are trying to start a service that already exists, abort if service_id in self.services: raise ValueError("Service %s is already running" % service_id) # this will look for the launch method and call it self.manager.log.info("Loading service: %s (%s)", name, service_id) self.manager.log.info(" - params: %s", params) service = self.load_service(service_id, name, params) # add to service list self.services[service.service_id] = service # set storage service.set_storage(storage) # register handlers for handler in service.HANDLERS: api_manager = srv_or_die("apimanager") api_manager.register_handler(handler) handler.service = service # start service self.manager.log.info("Starting service: %s (%s)", name, service_id) service.start() return service
def update_vaps(self): """Update active VAPs.""" for project in srv_or_die("projectsmanager").projects.values(): # project does not have wifi_props if not project.wifi_props: continue # project does not use shared VAPs if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue for block in self.device.blocks.values(): bssid = project.generate_bssid(block.hwaddr) # vap has already been created if bssid in self.manager.vaps: continue vap = VAP(bssid, block, project.wifi_props.ssid) self.send_add_vap(vap) self.manager.vaps[bssid] = vap
def create(self, desc, project_id, owner, wifi_props=None, lte_props=None, lora_props=None): """Create new project.""" if project_id in self.projects: raise ValueError("Project %s already defined" % project_id) accounts_manager = srv_or_die("accountsmanager") if owner not in accounts_manager.accounts: raise KeyError("Username %s not found" % owner) project = Project(project_id=project_id, desc=desc, owner=owner) if wifi_props: project.wifi_props = EmbeddedWiFiProps(**wifi_props) if lte_props: project.lte_props = EmbeddedLTEProps(**lte_props) if lora_props: project.lora_props = EmbeddedLoraProps(**lora_props) project.save() self.projects[project_id] = project project.upsert_wifi_slice(slice_id=0) project.upsert_lte_slice(slice_id=0) self.projects[project_id].start_services() return self.projects[project_id]
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # List of services in this Env/Project self.services = {} # Save pointer to EnvManager self.manager = srv_or_die("envmanager")
def blocks(self, blocks): """Assign a list of block to the LVAP. Assign a list of blocks to the LVAP. Accepts as input either a list or a ResourceBlock. If the list has more than one ResourceBlocks, then the first one is assigned to the downlink and the remaining are assigned to the uplink. Args: blocks: A list of ResourceBlocks or a ResourceBlock """ if self.pending: raise ValueError("Handover in progress") if not blocks: return if isinstance(blocks, list): pool = blocks elif isinstance(blocks, ResourceBlock): pool = [] pool.append(blocks) else: raise TypeError("Invalid type: %s" % type(blocks)) for block in pool: if not isinstance(block, ResourceBlock): raise TypeError("Invalid type: %s" % type(block)) # If LVAP is associated to a shared tenant, then reset LVAP project = srv_or_die("projectsmanager").load_project_by_ssid(self.ssid) if project and project.wifi_props and \ project.wifi_props.bssid_type == prj.T_BSSID_TYPE_SHARED: # check if tenant is available at target block bssid = project.generate_bssid(pool[0].hwaddr) # if not ignore request if bssid not in project.vaps: return # otherwise reset lvap self.ssid = None self.association_state = False self.authentication_state = False # save target blocks self.target_blocks = pool if self.state is None: self.state = PROCESS_SPAWNING elif self.state == PROCESS_RUNNING: self.state = PROCESS_REMOVING else: IOError("Setting blocks on invalid state: %s" % self.state)
def ueqs(self): """Return the UEs.""" if not self.lte_props: return {} ueqs = { k: v for k, v in srv_or_die("vbspmanager").ueqs.items() if v.plmnid == self.lte_props.plmnid } return ueqs
def vaps(self): """Return the VAPs.""" if not self.wifi_props: return {} vaps = { k: v for k, v in srv_or_die("lvappmanager").vaps.items() if v.ssid == self.wifi_props.ssid } return vaps
def update_slices(self): """Update active Slices.""" # send slices configuration for project in srv_or_die("projectsmanager").projects.values(): # project does not have wifi_props if not project.wifi_props: continue for slc in project.wifi_slices.values(): for block in self.device.blocks.values(): self.device.connection.send_set_slice(project, slc, block)
def post(self): """Process login credentials.""" username = self.get_argument("username", "") password = self.get_argument("password", "") accounts_manager = srv_or_die("accountsmanager") if accounts_manager.check_permission(username, password): self.set_secure_cookie("username", username) self.redirect("/index.html") else: self.clear_cookie("username") self.redirect("/auth/login?error=Wrong credentials!")
def get_project(self): """Get the current project or return None if not project is set.""" # check if a project has been selected project_id = self.get_secure_cookie("project_id") if not project_id: return None project_id = UUID(project_id.decode('UTF-8')) projects_manager = srv_or_die("projectsmanager") if project_id not in projects_manager.projects: self.clear_cookie("project_id") return None return projects_manager.projects[project_id]
def start_service(self, service_id, name, params, configuration=None, callbacks=None): """Start a service.""" # wait we are trying to start a service that already exists, abort if service_id in self.services: raise ValueError("Service %s is already running" % service_id) # this will look for the launch method and call it self.manager.log.info("Loading service: %s (%s)", name, service_id) self.manager.log.info(" - params: %s", params) service = self.load_service(service_id, name, params) if not service: self.manager.log.error("Unable to start service id %s name %s", service_id, name) return # add to service list self.services[service.service_id] = service # set configuration if configuration: for entry in configuration: setattr(service, entry, configuration[entry]) # set callbacks if callbacks: service.callbacks = callbacks # register handlers for handler in service.HANDLERS: api_manager = srv_or_die("apimanager") api_manager.register_handler(handler) handler.service = service # start service self.manager.log.info("Starting service: %s (%s)", name, service_id) service.start() return service
def _handle_slice_status_response(self, status): """Handle an incoming SLICE_STATUS_RESPONSE message.""" iface_id = status.iface_id slice_id = str(status.slice_id) ssid = SSID(status.ssid) project = srv_or_die("projectsmanager").load_project_by_ssid(ssid) block = self.device.blocks[iface_id] if not project: self.log.warning("Slice status from unknown SSID %s", ssid) return if slice_id not in project.wifi_slices: self.log.warning("Slice %s not found. Removing slice.", slice_id) self.send_del_slice(project, int(slice_id), block) return slc = project.wifi_slices[slice_id] if slc.properties['quantum'] != status.quantum: if self.device.addr not in slc.devices: slc.devices[self.device.addr] = dict() slc.devices[self.device.addr]['quantum'] = status.quantum amsdu_aggregation = bool(status.flags.amsdu_aggregation) if slc.properties['amsdu_aggregation'] != amsdu_aggregation: if self.device.addr not in slc.devices: slc.devices[self.device.addr] = dict() slc.devices[self.device.addr]['amsdu_aggregation'] = \ amsdu_aggregation if slc.properties['sta_scheduler'] != status.sta_scheduler: if self.device.addr not in slc.devices: slc.devices[self.device.addr] = dict() slc.devices[self.device.addr]['sta_scheduler'] = \ status.sta_scheduler project.save() project.refresh_from_db() self.log.info("Slice status: %s", slc)
def get(self): """Set the active project.""" username = self.get_secure_cookie("username").decode('UTF-8') # if root deselect project if username == "root": self.clear_cookie("project_id") self.redirect('/') return # check if the project id is in the URL project_id = self.get_argument("project_id", None) # reset project selected if not project_id: self.clear_cookie("project_id") self.redirect('/') return try: # set project project_id = UUID(project_id) projects_manager = srv_or_die("projectsmanager") project = projects_manager.projects[project_id] if project.owner != username: self.clear_cookie("project_id") self.redirect('/') return self.set_secure_cookie("project_id", str(project.project_id)) except KeyError: self.clear_cookie("project_id") except ValueError: self.clear_cookie("project_id") self.redirect('/')
def get(self, args=None): """Render index page.""" try: username = self.get_secure_cookie("username").decode('UTF-8') accounts_manager = srv_or_die("accountsmanager") account = accounts_manager.accounts[username] page = "index.html" if not args else "%s.html" % args self.render(page, username=account.username, password=account.password, name=account.name, email=account.email, project=self.get_project()) except KeyError as ex: self.send_error(404, message=str(ex)) except ValueError as ex: self.send_error(400, message=str(ex))
def _handle_vap_status_response(self, status): """Handle an incoming STATUS_VAP message.""" bssid = EtherAddress(status.bssid) ssid = SSID(status.ssid) project = srv_or_die("projectsmanager").load_project_by_ssid(ssid) if not project: self.log.warning("Unable to find SSID %s", ssid) self.send_del_vap(bssid) return # If the VAP does not exists, then create a new one if bssid not in self.manager.vaps: incoming = self.device.blocks[status.iface_id] self.manager.vaps[bssid] = VAP(bssid, incoming, project.wifi_props.ssid) vap = self.manager.vaps[bssid] self.log.info("VAP status: %s", vap)
def _handle_auth_request(self, request): """Handle an incoming AUTH_REQUEST message.""" sta = EtherAddress(request.sta) if sta not in self.manager.lvaps: self.log.info("Auth request from unknown LVAP %s", sta) return lvap = self.manager.lvaps[sta] incoming_bssid = EtherAddress(request.bssid) # The request bssid is the lvap current bssid, then just reply if lvap.bssid == incoming_bssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return # Otherwise check if the requested BSSID belongs to a unique tenant for project in srv_or_die("projectsmanager").projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED: continue bssid = project.generate_bssid(lvap.addr) if bssid == incoming_bssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return # Finally check if this is a shared bssid for project in srv_or_die("projectsmanager").projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue if incoming_bssid in project.vaps: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return self.log.info("Auth request from unknown BSSID %s", incoming_bssid)
def vaps(self): """Return the VAPs.""" return srv_or_die("lvappmanager").vaps
def wtps(self): """Return the WTPs.""" return srv_or_die("lvappmanager").devices
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Save pointer to ProjectManager self.manager = srv_or_die("projectsmanager")
def lnss(self): """Return LNSs registered in this project context.""" lnspd_manager = srv_or_die("lnspdmanager") return lnspd_manager.lnss
def lenddevs(self): """Return lEndDevs registered in this project context.""" lnsp_manager = srv_or_die("lnspmanager") return lnsp_manager.lenddevs
def lgtws(self): """Return lGTWs registered in this project context.""" lnsp_manager = srv_or_die("lnspmanager") return lnsp_manager.lgtws
def query(self, query): """Do a query to time-series manager.""" ts_manager = srv_or_die("tsmanager") return ts_manager.query(query)
def _handle_assoc_request(self, request): """Handle an incoming ASSOC_REQUEST message.""" sta = EtherAddress(request.sta) ht_caps = request.flags.ht_caps ht_caps_info = dict(request.ht_caps_info) del ht_caps_info['_io'] if sta not in self.manager.lvaps: self.log.info("Assoc request from unknown LVAP %s", sta) return lvap = self.manager.lvaps[sta] incoming_bssid = EtherAddress(request.bssid) if lvap.bssid != incoming_bssid: self.log.info("Assoc request for invalid BSSID %s", incoming_bssid) return incoming_ssid = SSID(request.ssid) # Check if the requested SSID is from a unique project for project in srv_or_die("projectsmanager").projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED: continue bssid = project.generate_bssid(lvap.addr) if bssid != incoming_bssid: self.log.info("Invalid BSSID %s", incoming_bssid) continue if project.wifi_props.ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info lvap.commit() self.send_assoc_response(lvap) return # Check if the requested SSID is from a unique project for project in srv_or_die("projectsmanager").projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue if incoming_bssid not in project.vaps: self.log.info("Invalid BSSID %s", incoming_bssid) continue if project.wifi_props.ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info lvap.commit() self.send_assoc_response(lvap) return self.log.info("Unable to find SSID %s", incoming_ssid)
def _handle_probe_request(self, request): """Handle an incoming PROBE_REQUEST message.""" # Get station sta = EtherAddress(request.sta) # Incoming incoming_ssid = SSID(request.ssid) iface_id = request.iface_id ht_caps = request.flags.ht_caps ht_caps_info = dict(request.ht_caps_info) del ht_caps_info['_io'] block = self.device.blocks[request.iface_id] msg = "Probe request from %s ssid %s iface_id %u ht_caps %u" if not incoming_ssid: self.log.debug(msg, sta, "Broadcast", iface_id, ht_caps) else: self.log.debug(msg, sta, incoming_ssid, iface_id, ht_caps) # Check is station is in ACL of any networks networks = \ srv_or_die("projectsmanager").get_available_ssids(sta, block) if not networks: self.log.debug("No SSID available at this device") return # If lvap does not exist then create it. Otherwise just refresh the # list of available networks if sta not in self.manager.lvaps: # spawn new LVAP self.log.info("Spawning new LVAP %s on %s", sta, self.device.addr) assoc_id = randint(1, 2007) lvap = LVAP(sta, assoc_id=assoc_id) lvap.networks = networks lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info # this will trigger an LVAP ADD message lvap.blocks = block # save LVAP in the runtime self.manager.lvaps[sta] = lvap # Send probe response self.send_probe_response(lvap, incoming_ssid) return lvap = self.manager.lvaps[sta] # If this probe request is not coming from the same interface on which # this LVAP is currenly running then ignore the probe if lvap.blocks[0].block_id != iface_id: return # If LVAP is not running then ignore if not lvap.is_running(): return # Update list of available networks lvap.networks = networks lvap.commit() # Send probe response self.send_probe_response(lvap, incoming_ssid)
def write_points(self, points): """Write points to time-series manager.""" ts_manager = srv_or_die("tsmanager") ts_manager.write_points(points)
def vbses(self): """Return the VBSes.""" return srv_or_die("vbspmanager").devices