def features(self): ''' Tests the routers available features''' result = xmlobjects.TestFunctions() info = self.device.info if (not RouterError.hasError(info)): result.parseXML(info) objs = [self] for value in vars(self).values(): if issubclass(type(value), RouterObject): objs.append(value) #Iterate through get_api calls for val in GET_APIS: cls = val[0] f = val[1] api = val[2] func = None #find function for ob in objs: if ob.__class__.__name__ == cls and hasattr(ob, f): if isinstance(getattr(type(ob), f, None), property): prop = getattr(type(ob), f, None) result.addFunction(ob, f, api, prop.__get__(ob, type(ob))) else: func = getattr(ob, f) result.addFunction(ob, f, api, func()) return result.buildXmlResponse()
def logout(self): '''Logout user''' with self.__lock: logger.info('LOGOUT for user [%s]', self.username) response = self.api('user/logout', {'Logout': 1}) if RouterError.hasError(response): raise RouterError(response) self.__is_logged_in = False
def __get_server_token(self): """ retrieves server token """ url = "http://%s/api/webserver/token" % self.router token_response = self.__get(url).text if RouterError.hasError(token_response): raise RouterError(token_response) root = ET.fromstring(token_response) return root.findall('./token')[0].text
def addFunction(self, obj, name, url, response): func = Function(obj.__class__.__name__, name, url) if (RouterError.hasError(response)): error = Error() error.parseXML(response) func.Error = error.code + ": " + error.message self.Failed.append(func) else: self.Passed.append(func)
def __api_challenge(self): self.__setup_session() token = self.__get_server_token() url = "http://%s/api/user/challenge_login" % self.router self.clientnonce = crypto.generate_nonce() xml = xmlobjects.CustomXml({ 'username': self.username, 'firstnonce': self.clientnonce, 'mode': 1 }).buildXML() headers = {'Content-type': 'text/html', self.REQUEST_TOKEN: token[32:]} response = self.__post(url=url, data=xml, headers=headers) if RouterError.hasError(response.text): raise RouterError(response.text) return response
def api(self, url, data=None, encrypted=False): """ Handles all api calls to the router """ #Check if the session has timed out, and login again if it has timed_out = datetime.now() - self.__last_login if (timed_out.total_seconds() >= self.__timeout and self.__is_logged_in): with self.__lock: if (timed_out.total_seconds() >= self.__timeout and self.__is_logged_in): logger.debug('Session timeout - establishing new login...') self.__login() verification_token = self.__get_server_token()[32:] if isinstance(data, dict): data = xmlobjects.CustomXml(data).buildXML() elif isinstance(data, xmlobjects.XmlObject): data = data.buildXML() url = "http://%s/api/%s" % (self.router, url) headers = {} headers[self.REQUEST_TOKEN] = verification_token if (encrypted): headers[ 'Content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8;enc' else: headers[ 'Content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8' #print(data) if data is None or data == '': response = self.__get(url, headers).text else: if encrypted: data = crypto.rsa_encrypt(self.__rsae, self.__rsan, data) response = self.__post(url, data, headers).text #print(response) #Add error message if known and missing if RouterError.hasError(response): error = xmlobjects.Error() error.parseXML(response) response = error.buildXmlError() return response
def __login(self): """ logs in to the router using SCRAM method of authentication """ logger.info('LOGIN for user [%s]' % self.username) response = self.__api_challenge() verification_token = response.headers[self.REQUEST_TOKEN] scram_data = ET.fromstring(response.text) servernonce = scram_data.findall('./servernonce')[0].text salt = scram_data.findall('./salt')[0].text iterations = int(scram_data.findall('./iterations')[0].text) client_proof = crypto.get_client_proof(self.clientnonce, servernonce, self.__password, salt, iterations).decode('UTF-8') login_request = xmlobjects.CustomXml({ 'clientproof': client_proof, 'finalnonce': servernonce }).buildXML() headers = { 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', self.REQUEST_TOKEN: verification_token } url = "http://%s/api/user/authentication_login" % self.router result = self.__post(url=url, data=login_request, headers=headers) if RouterError.hasError(result.text): raise RouterError(result.text) verification_token = result.headers[self.REQUEST_TOKEN] self.__last_login = datetime.now() ''' The SCRAM protocol would normally validate the server signatures We're assuming this is ok e.g. var serverProof = scram.serverProof(psd, salt, iter, authMsg); if (ret.response.serversignature == serverProof) { var publicKeySignature = scram.signature(CryptoJS.enc.Hex.parse(ret.response.rsan), CryptoJS.enc.Hex.parse(serverKey)).toString(); if (ret.response.rsapubkeysignature == publicKeySignature) { ''' xml = ET.fromstring(result.text) self.__rsae = xml.find('.//rsae').text self.__rsan = xml.find('.//rsan').text self.__is_logged_in = True