def write_file(self): try: with open(self.file, 'w') as outfile: yaml.dump(self.data, outfile, default_flow_style=False) except OSError as err: logger.error(err) sys.exit(1)
def delete_project(self, pParameters): ''' Deletes a project from db :param list pParameters: a list of optional parameters ''' if self.client.check_item("Klambda_projects", { 'name': self.project['name'], 'author': self.project['author'] }): item = self.client.get_item("Klambda_projects", { 'name': self.project['name'], 'author': self.project['author'] }) self.validate_user( item) # verify if current user can perfom this action self.client.delete_item("Klambda_projects", { 'name': self.project['name'], 'author': self.project['author'] }) destination_path = self.project['name'] + "-" + self.project[ 'author'] self.__s3_client.delete_object('klambda', destination_path) logger.info("The project %s deleted succesfully" % self.project['name']) else: logger.error("The project %s doesn't exist" % self.project['name'])
def update_password(self, user_id, new_password, old_password=None, key=None): """Change the user password. Uses the admin bind or the user bind if the old password is provided. Args: user_id: user id password: new password old_password: old password of the user (optional) Returns: True if the change was successful, False otherwise """ if old_password is not None: return super(MozillaAuth, self).update_password(user_id, new_password, old_password=old_password) if not key: logger.error("Calling update password without password or key") return False payload = {'reset_code': key, 'password': new_password} username = self._get_username(user_id) result = self._proxy('POST', self.generate_url(username, 'password'), payload) return result.get('success', False)
def update_password(self, user_id, password, old_password=None, key=None): """Change the user password Args: user_id: user id password: new password Returns: True if the change was successful, False otherwise """ if old_password is None: if key: #using a key, therefore we should check it if self._get_reset_code(user_id) == key: self.clear_reset_code(user_id) else: logger.error("bad key used for update password") return False else: return False password_hash = ssha256(password) query = update(users).where(users.c.id == user_id) res = safe_execute(self._engine, query.values(password_hash=password_hash)) return res.rowcount == 1
def create_lambdas(self, pParameters): ''' Uploads a function information and creates it on the db from the klambda file :param list pParameters: a list of function names to create ''' if len(pParameters) == 0: # if not function listed gets all the functions from klambda file functions = self.get_lambdas() else: functions = pParameters for function in self.functions_list: function_name = next(iter(function)) # get first key of dict if function_name in functions: if self.validate_function(function[function_name]): self.validate_user(function[function_name]['author']) # validates the user logged in if not self.client.check_item("Klambda_functions", {'name': function_name, 'author': function[function_name]['author']}): function[function_name]['name'] = function_name function[function_name]['version'] = str(function[function_name]['version']) function[function_name]['created_on'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") function[function_name]['last_update'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") function[function_name]['checksum'] = hashlib.sha256(json.dumps(function[function_name]).encode('utf-8')).hexdigest() self.client.put_item("Klambda_functions",function[function_name]) self.write_data(function[function_name], function_name) # stores checksum on klambda file logger.info("The function %s created succesfully from the author %s" % (function_name, function[function_name]['author'])) else: logger.error("The function %s already exists for the author %s" % (function_name, function[function_name]['author'])) else: logger.error("The function %s information is incomplete" % function_name)
def object_exists(self, pBucketName, pObjectPath): try: self.__client.head_object(Bucket=pBucketName, Key=pObjectPath) return True except botocore.exceptions.ClientError as err: logger.error(err) exit()
def edit_lambdas(self, pParameters): ''' Edits a function information on the db from the klambda file :param list pParameters: a list of function names to download ''' if len(pParameters) == 0: # if not function listed gets all the functions from klambda file functions = self.get_lambdas() else: functions = pParameters for function in self.functions_list: function_name = next(iter(function)) # get first key of dict if function_name in functions: if self.validate_function(function[function_name]): if self.client.check_item("Klambda_functions", {'name': function_name, 'author': function[function_name]['author']}): item = self.client.get_item("Klambda_functions", {'name': function_name, 'author': function[function_name]['author']}) self.validate_user(item['author']) # verify if current user can perfom this action item['runtime'] = function[function_name]['runtime'] item['description'] = function[function_name]['description'] item['category'] = function[function_name]['category'] item['version'] = str(function[function_name]['version']) item['repo_url'] = function[function_name]['repo_url'] item['folder_path'] = function[function_name]['folder_path'] item['last_update'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") item['checksum'] = hashlib.md5(json.dumps(item).encode('utf-8')).hexdigest() self.client.put_item("Klambda_functions", item) self.write_data(item, function_name) # stores checksum on klambda file logger.info("The function %s edited succesfully under %s runtime" % (function_name, function[function_name]['runtime'])) else: logger.error("The function %s does not exist under %s runtime" % (function_name, function[function_name]['runtime'])) else: logger.error("The function %s information is incomplete" % function_name)
def update_password(self, user_id, new_password, old_password=None, key=None): """Change the user password. Uses the admin bind or the user bind if the old password is provided. Args: user_id: user id password: new password old_password: old password of the user (optional) key: the reset code Returns: True if the change was successful, False otherwise """ if old_password is not None: return super(MozillaAuth, self).update_password(user_id, new_password, old_password=old_password) if not key: logger.error("Calling update password without password or key") return False payload = {'reset_code': key, 'password': new_password} username = self._get_username(user_id) url = self.generate_url(username, 'password') status, body = self._proxy('POST', url, payload) if status == 200: return body == 0 elif status == 400: if body == WEAVE_INVALID_RESET_CODE: raise InvalidCodeError() raise BackendError()
def get_user_info(self, uid): try: return self._user_db.find_one({u'uid': uid}) except OperationFailure, ofe: logger.error("Could not fetch info for uid [%s], [%s]" % (uid, str(ofe))) raise OIDStorageException()
def edit_project(self, pParameters): ''' Edits a project in db with klambda file info :param list pParameters: a list of optional parameters ''' if self.client.check_item("Klambda_projects", { 'name': self.project['name'], 'author': self.project['author'] }): item = self.client.get_item("Klambda_projects", { 'name': self.project['name'], 'author': self.project['author'] }) self.validate_user( item) # verify if current user can perfom this action item['users'] = self.project['users'] item['description'] = self.project['description'] item['repo_url'] = self.project['repo_url'] item['files'] = self.project['files'] item['last_update'] = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") self.client.put_item("Klambda_projects", item) destination_path = self.project['name'] + "-" + self.project[ 'author'] self.__s3_client.delete_object( 'klambda', destination_path) # deletes the project folder self.upload_files( self.project['files']) # uploads listed files on S3 logger.info("The project %s edited succesfully" % self.project['name']) else: logger.error("The project %s doesn't exist" % self.project['name'])
def execute(self, pCommandName, pParameter): # executes a commands by name and set the parameter if pCommandName in self.commands.keys(): self.commands[pCommandName].parameter = pParameter self.commands[pCommandName].execute() else: logger.error("Command [{pCommandName}] not recognised")
def _set_cached_size(self, user_id, size): key = _key(user_id, 'size') # if this fail it's not a big deal try: # we store the size in bytes in memcached self.cache.set(key, size * _KB) except BackendError: logger.error('Could not write to memcached')
def validate_user(self, pUsername): ''' Validates if current user logged can perform actions on function :param str pUsername: username ''' if self.credentials.data['USERNAME'] != pUsername: logger.error("Wrong username %s for lambda" % pUsername) exit()
def load_file(self): ''' Opends the .yml file with the path provided ''' try: with open(self.file, 'r') as yaml_file: self.data = yaml.safe_load(yaml_file) except OSError: logger.error("Not a Klambda folder project, please create one") sys.exit(1)
def safe_execute(engine, *args, **kwargs): """Execution wrapper that will raise a HTTPServiceUnavailableError on any OperationalError errors and log it. """ try: return engine.execute(*args, **kwargs) except OperationalError: err = traceback.format_exc() logger.error(err) raise BackendError()
def __init__(self, config): if _NO_CAPTCHA_LIB: raise ImportError('Recaptcha lib is not installed') self.use = config.get('use', False) self.private_key = config.get('private_key') self.public_key = config.get('public_key') self.use_ssl = config.get('use_ssl', True) if self.use and (self.private_key is None or self.public_key is None): logger.error("No key defined for captcha!") raise BackendError()
def update_function(self, pFunctionName): ''' Updates the folder of a function from a repository ::param str pFunctionName: the function name ''' if os.path.isdir('./'+pFunctionName): l = local.LocalClient('./'+pFunctionName) l.update('./'+pFunctionName) logger.info("The function %s updated succesfully" % pFunctionName) else: logger.error("The function %s is not configured in your project" % pFunctionName)
def update_password(self, user_id, new_password, old_password=None, key=None): """Change the user password. Uses the admin bind or the user bind if the old password is provided. Args: user_id: user id new_password: new password old_password: old password of the user (optional) Returns: True if the change was successful, False otherwise """ user_name = self._get_username(user_id) user_dn = self._get_dn(user_name) if old_password is None: if key: #using a key, therefore we should check it if self.verify_reset_code(user_id, key): self.clear_reset_code(user_id) else: logger.error("bad key used for update password") return False # we will use admin auth dn = self.admin_user ldap_password = self.admin_password else: # user auth dn = user_dn ldap_password = old_password # we need a password password_hash = ssha(new_password) user = [(ldap.MOD_REPLACE, 'userPassword', [password_hash])] try: with self._conn(dn, ldap_password) as conn: try: res, __ = conn.modify_s(user_dn, user) except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: logger.debug('Could not update the password in ldap.') raise BackendError(str(e)) except ldap.INVALID_CREDENTIALS: return False self._purge_conn(user_dn, new_password) return res == ldap.RES_MODIFY
def confirm_user(self, pUsername): ''' Confirms user sign up to user pool :param str pUsername: username :raises Botocore Client Exception ''' try: self.__client.admin_confirm_sign_up(UserPoolId=self.pool_user_id, Username=pUsername) except botocore.exceptions.ClientError as err: logger.error(err) exit()
def download_function(self, pUrl, pFunctionName): ''' Downloads the folder of a function from a repository :param str pUrl: the downloads url direction of the repository :param str pFunctionName: the function name ''' r = remote.RemoteClient(pUrl) if not os.path.isdir('./'+pFunctionName): r.checkout('./'+pFunctionName) logger.info("The function %s downloaded succesfully" % pFunctionName) else: logger.error("The function %s is already configured in your project, please update in order to get last changes" % pFunctionName)
def init_multidevices(self, devices_mac_list): self.device_list = [] for device_mac in devices_mac_list: device = MetaWear(device_mac) try: device.connect() except WarbleException: logger.error(f"connect error: {device_mac}") print("Connected to " + device.address) state_device = State(device, self.strage) self.device_list.append(state_device) self.init_device(state_device) sleep(5.5)
def check(self, request): # check if captcha info are provided if not self.use: return True challenge = request.params.get('recaptcha_challenge_field') response = request.params.get('recaptcha_response_field') if challenge is not None and response is not None: resp = captcha.submit(challenge, response, self.private_key, remoteip=request.remote_addr) return resp.is_valid logger.error('captcha submitted with no challenge or response') return False
def add_validation(self, uid, email): rtoken = ''.join([randchar() for i in range(26)]) validation_record = {'uid': uid, 'created': time.time(), 'email': email} user_info = self._db.get('%s%s' % (self.USER_DB, uid)) if user_info is None: logger.error("Could not find user record for uid %s" % uid) raise OIDStorageException("uid not found") try: user = cjson.decode(user_info) except (TypeError, EOFError), ex: logger.error("Unpickling error %s " % ex) raise (OIDStorageException("Storage error"))
def _lookup(self, tag): """ Perform a reverse sentence lookup given its tag. :param tag: a unique sentence identifier :return sent: the target sentence """ sentence = "Sorry, could not find any matching result" try: obj = list(db.sentences.find({"tag": tag}))[0] sentence = " ".join(obj.get("sentence")) except Exception: # this should never happen logger.error("Failed to do reverse sentence lookup") return sentence
def put_item(self, pTableName, pItem): ''' Adds data to a table (idempotent: if item already exists edits existing one) :param str pTableName: name of table to add item :param dict pItem: dictionary containing the data to add :return: None :raises Botocore Client Exception ''' try: table = self.__dynamoDB.Table(pTableName) # gets the table table.put_item(Item=pItem) # puts item on table except botocore.exceptions.ClientError as err: logger.error(err) exit()
def delete_item(self, pTableName, pKey): ''' Deletes data from a table :param str pTableName: name of table to add item :param dict pKey: dictionary containing the partition and/or sort key :return: None :raises Botocore Client Exception ''' try: table = self.__dynamoDB.Table(pTableName) # gets the table table.delete_item(Key=pKey) # delets item with given key except botocore.exceptions.ClientError as err: logger.error(err) exit()
def delete_object(self, pBucketName, pObjectPath): ''' Deletes an object from S3 bucket :param str pBucketName: name of the bucket :param str pObjectPath: path of file in S3 :raises Botocore Client Exception ''' try: klambda_bucket = self.__resource.Bucket(pBucketName) klambda_bucket.objects.filter(Prefix=pObjectPath).delete() logger.info("Object %s deleted succesfully from %s" % (pObjectPath, klambda_bucket)) except botocore.exceptions.ClientError as err: logger.error(err) exit()
def check_validation(self, uid, token): try: record = self._validate_db.find_one({u'_id': token}) if record is not None and record.get('uid') == uid: user = self._user_db.get(uid) if user is not None: email = record['email'] user['emails'].append(email) del user['emails'][email] self._validate_db.remove({u'_id': token}) self.set_user_info(uid, user) return True except (KeyError), ofe: logger.error("Could not validate token %s [%s]", token, str(ofe)) raise OIDStorageException("Could not validate token")
def resend_code(self, pClientId, pUsername): ''' Register a user in a user pool, with given attributes :param str pClientId: id of user pool app client :param object pKlambdaUser: KlambdaUser object :raises Botocore Client Exception ''' try: self.__client.resend_confirmation_code(ClientId=pClientId, Username=pUsername) except botocore.exceptions.ClientError as err: logger.error(err) exit() else: logger.info("Code resent...")
def update_lambdas(self, pParameters): ''' Updates the folder of the lambda function from the repository :param list pParameters: a list of function names to download ''' if len(pParameters) == 0: # if not function listed gets all the functions from klambda file functions = self.get_lambdas() else: functions = pParameters for function in self.functions_list: function_name = next(iter(function)) # get first key of dict if function_name in functions: if self.client.check_item("Klambda_functions", {'name': function_name, 'author': function[function_name]['author']}): self.update_function(function_name) else: logger.error("The function %s does not exist from the author %s" % (function_name, function[function_name]['author']))
def _proxy(self, method, url, data=None, headers=None): """Proxies and return the result from the other server. - scheme: http or https - netloc: proxy location """ if data is not None: data = json.dumps(data) status, headers, body = get_url(url, method, data, headers) if body: try: body = json.loads(body) except Exception: logger.error("bad json body from sreg (%s): %s" % (url, body)) return status, body
def verify_email(self, pAccessToken, pCode): ''' Register a user in a user pool, with given attributes :param str pClientId: id of user pool app client :param object pKlambdaUser: KlambdaUser object :raises Botocore Client Exception ''' try: self.__client.verify_user_attribute(AccessToken=pAccessToken, AttributeName='email', Code=pCode) except botocore.exceptions.ClientError as err: logger.error(err) exit() else: logger.info("Your email verified correctly")
def upload_object(self, pBucketName, pObjectPath, pDestPath): ''' Uploads an object to S3 bucket :param str pBucketName: name of the bucket :param str pObjectPath: path of file to upload :param str pDestPath: path to upload file :raises Botocore Client Exception ''' try: klambda_bucket = self.__resource.Bucket(pBucketName) klambda_bucket.upload_file(pObjectPath, pDestPath) logger.info("Object %s successfully uploaded to %s" % (klambda_bucket, pDestPath)) except botocore.exceptions.ClientError as err: logger.error(err) exit()
def _dispatch_request_with_match(self, request, match): """Dispatch a request according to a URL routing match.""" function = self._get_function(match['controller'], match['action']) if function is None: raise HTTPNotFound('Unknown URL %r' % request.path_info) # extracting all the info from the headers and the url request.sync_info = match # creating a user object to be passed around the request, if one hasn't # already been set if not hasattr(request, 'user'): request.user = User() if 'username' in request.sync_info: request.user['username'] = request.sync_info['username'] if 'user_id' in request.sync_info: request.user['userid'] = request.sync_info['user_id'] params = self._get_params(request) try: result = function(request, **params) except BackendError as err: err_info = str(err) err_trace = traceback.format_exc() extra_info = ['%s: %s' % (key, value) for key, value in self.get_infos(request).items()] extra_info = '\n'.join(extra_info) error_log = '%s\n%s\n%s' % (err_info, err_trace, extra_info) hash = create_hash(error_log) logger.error(hash) logger.error(error_log) msg = json.dumps("application error: crash id %s" % hash) if err.retry_after is not None: if err.retry_after == 0: retry_after = None else: retry_after = err.retry_after else: retry_after = self.retry_after raise HTTPJsonServiceUnavailable(msg, retry_after=retry_after) # create the response object in case we get back a string response = self._create_response(request, result, function) return response
def info_lambdas(self, pParameters): ''' Gets and prints the information of a function :param list pParameters: a list of function names to download ''' if len(pParameters) == 0: # if not function listed gets all the functions from klambda file functions = self.get_lambdas() else: functions = pParameters for function in self.functions_list: function_name = next(iter(function)) # get first key of dict if function_name in functions: if self.client.check_item("Klambda_functions", {'name': function_name, 'author': function[function_name]['author']}): item = self.client.get_item("Klambda_functions",{'name': function_name, 'author': function[function_name]['author']}) self.info_function(item) else: logger.error("The function %s does not exist under %s runtime" % (function_name, function[function_name]['runtime']))
def check_item(self, pTableName, pKey): ''' Checks if item exists on table :param str pTableName: name of table to add item :param dict pKey: dictionary containing the partition and/or sort key :return: None :raises Botocore Client Exception ''' try: table = self.__dynamoDB.Table(pTableName) # gets the table response = table.get_item(Key=pKey) # gets the item with given key if 'Item' in response: return True # if item exists return True return False except botocore.exceptions.ClientError as err: logger.error(err) exit()
def check_validation(self, uid, token): try: record = self._validate_db.get(token, None) if record is not None and record.get('uid') == uid: user = self._user_db.get(uid) if user is not None: email = record['email'] # only deal with 'pending' records. if user['emails'][email].get('state', None) == 'pending': user['emails'][email]['state'] = 'verified' # Remove the old valiation code if 'conf_code' in user['emails'][email]: del user['emails'][email]['conf_code'] del self._validate_db[token] self._user_db[uid] = user return True except (KeyError), ofe: logger.error("Could not validate token %s [%s]", token, str(ofe)) raise OIDStorageException("Could not validate token")
def test_graberrors(self): # simpler case: services logger, error level with capture_logs() as errors: logger.error("Yeah") self.assertEqual(errors.read(), "Yeah\n") # services logger, warning level with capture_logs(level=logging.WARNING) as wrn: logger.debug("Yeah") logger.warning("Yeah2") self.assertEqual(wrn.read(), "Yeah2\n") # root logger, warning root = logging.getLogger() with capture_logs(logger="root", level=logging.WARNING) as wrn: root.debug("Yeah") root.warning("Yeah2") self.assertEqual(wrn.read(), "Yeah2\n")
def admin_update_password(self, user_id, new_password, key): """Change the user password. Uses the admin bind or the user bind if the old password is provided. Args: user_id: user id new_password: new password key: password reset key Returns: True if the change was successful, False otherwise """ user_dn = self._userid2dn(user_id) if user_dn is None: raise BackendError('Unknown user "%s"' % user_id) # using a key, therefore we should check it if self.verify_reset_code(user_id, key): self.clear_reset_code(user_id) else: logger.error("bad key used for update password") return False password_hash = ssha(new_password) user = [(ldap.MOD_REPLACE, 'userPassword', [password_hash])] try: with self._conn(self.admin_user, self.admin_password) as conn: try: res, __ = conn.modify_s(user_dn, user) except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: logger.debug('Could not update the password in ldap.') raise BackendError(str(e)) except ldap.INVALID_CREDENTIALS: return False self._purge_conn(user_dn, new_password) return res == ldap.RES_MODIFY
def _get_next_user_id(self): """ Does a ldap delete, atomically followed by an ldap add. This is so the delete will fail if you have a race condition and someone else incremented between the read and write. Args: none Returns: the next user id """ dn = 'cn=maxuid,ou=users,dc=mozilla' #these two variables are for loop control. #count loops so we can kill an infinite flag = 0 #since it's a race condition, we'd expect the value to change. previous_loop_value = None while flag < 10: # get the value try: with self._conn() as conn: record = conn.search_st(dn, ldap.SCOPE_BASE, attrlist=['uidNumber'], timeout=self.ldap_timeout) except (ldap.NO_SUCH_OBJECT, ldap.INVALID_CREDENTIALS): raise BackendError("No record found to get next id") except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e: raise BackendError("LDAP problem getting next id: %s" % str(e)) if record is None: raise BackendError("No record found to get next id") value = record[0][1]['uidNumber'][0] if value == previous_loop_value: # this is bad. It means the problem isn't a race condition. # Bail. logger.error('failed uid increment, loop value is unchanged') raise BackendError('unable to generate new account') previous_loop_value = value new_value = int(value) + 1 #remove the old value (which will fail if it isn't there) and #atomically add the new one old = (ldap.MOD_DELETE, 'uidNumber', value) new = (ldap.MOD_ADD, 'uidNumber', str(new_value)) with self._conn() as conn: try: conn.modify_s(dn, [old, new]) #if we don't bomb out here, we have a valid id return int(value) except ldap.NO_SUCH_ATTRIBUTE, e: logger.error('collision on getting next id. %i' \ % new_value) flag = flag + 1 continue except ldap.LDAPError, e: raise BackendError(str(e))
def __call__(self, request): if request.method in ('HEAD',): raise HTTPBadRequest('"%s" not supported' % request.method) request.server_time = round_time() # gets request-specific config request.config = self._host_specific(request.host, self.config) # pre-hook before_headers = self._before_call(request) # XXX # removing the trailing slash - ambiguity on client side url = request.path_info.rstrip('/') if url != '': request.environ['PATH_INFO'] = request.path_info = url if (self.heartbeat_page is not None and url == '/%s' % self.heartbeat_page): return self._heartbeat(request) if self.debug_page is not None and url == '/%s' % self.debug_page: return self._debug(request) match = self.mapper.routematch(environ=request.environ) if match is None: return HTTPNotFound() match, __ = match # authentication control if self.auth is not None: self.auth.check(request, match) function = self._get_function(match['controller'], match['action']) if function is None: raise HTTPNotFound('Unkown URL %r' % request.path_info) # extracting all the info from the headers and the url request.sync_info = match # the GET mapping is filled on GET and DELETE requests if request.method in ('GET', 'DELETE'): params = dict(request.GET) else: params = {} try: result = function(request, **params) except BackendError: err = traceback.format_exc() logger.error(err) raise HTTPServiceUnavailable(retry_after=self.retry_after) if isinstance(result, basestring): response = getattr(request, 'response', None) if response is None: response = Response(result) elif isinstance(result, str): response.body = result else: # if it's not str it's unicode, which really shouldn't happen module = getattr(function, '__module__', 'unknown') name = getattr(function, '__name__', 'unknown') logger.warn('Unicode response returned from: %s - %s' % (module, name)) response.unicode_body = result else: # result is already a Response response = result # setting up the X-Weave-Timestamp response.headers['X-Weave-Timestamp'] = str(request.server_time) response.headers.update(before_headers) return response