async def get(self, indx): indx = await s_stormtypes.toint(indx) mesg = await self.runt.snap.core.getUserNotif(indx) if mesg[0] != self.runt.user.iden and not self.runt.isAdmin(): mesg = 'You may only get notifications which belong to you.' raise s_exc.AuthDeny(mesg=mesg) return mesg
async def getRoleInfo(self, name): role = await self.cell.auth.reqRoleByName(name) if self.user.isAdmin() or role.iden in self.user.info.get('roles', ()): return role.pack() mesg = 'getRoleInfo denied for non-admin and non-member' raise s_exc.AuthDeny(mesg=mesg)
async def _reqUserAllowed(self, perm): ''' Helper method that subclasses can use for user permission checking. Args: perm: permission path components to check Notes: This can be used to require a permission; and will throw an exception if the permission is not allowed. Examples: Implement an API that requires a user to have a specific permission in order to execute it:: async def makeWidget(self, wvalu, wtype): # This will throw if the user doesn't have the appropriate widget permission await self._reqUserAllowed(('widget', wtype)) return await self.cell.makeWidget((wvalu, wtype)) Returns: None: This API does not return anything. It only throws an exception on failure. Raises: s_exc.AuthDeny: If the permission is not allowed. ''' if not await self.allowed(perm): perm = '.'.join(perm) mesg = f'User must have permission {perm}' raise s_exc.AuthDeny(mesg=mesg, perm=perm, user=self.user.name)
async def _funcMacroSet(self, name, storm): ''' Add or modify an existing Storm Macro in the Cortex. Args: name (str): Name of the Storm Macro to add or modify. storm (str): The Storm query to add to the macro. Returns: None: Returns None. ''' name = await s_stormtypes.tostr(name) storm = await s_stormtypes.tostr(storm) # validation await self.runt.getStormQuery(storm) path = ('cortex', 'storm', 'macros', name) user = self.runt.user mdef = await self.runt.snap.core.getHiveKey(path) if mdef is not None: if mdef['user'] != user.iden and not user.isAdmin(): mesg = 'Macro belongs to a different user' raise s_exc.AuthDeny(mesg=mesg) mdef = { 'user': user.iden, 'storm': storm, 'edited': s_common.now(), } await self.runt.snap.core.setHiveKey(path, mdef)
def reqLayerAllowed(self, perms): if self._allowed(perms, ask_layer=True): return perm = '.'.join(perms) mesg = f'User must have permission {perm} on write layer' raise s_exc.AuthDeny(mesg=mesg, perm=perm, user=self.user.name)
async def execStormCmd(self, runt, genr): if self.opts.force: if runt.user is not None and not runt.user.admin: mesg = '--force requires admin privs.' raise s_exc.AuthDeny(mesg=mesg) i = 0 async for node, path in genr: # make sure we can delete the tags... for tag in node.tags.keys(): runt.allowed('tag:del', *tag.split('.')) runt.allowed('node:del', node.form.name) await node.delete(force=self.opts.force) i += 1 # Yield to other tasks occasionally if not i % 1000: await asyncio.sleep(0) # a bit odd, but we need to be detected as a generator if False: yield
def _confirm(self, user, perms): layriden = self.layers[0].iden if user.allowed(perms, gateiden=layriden): return perm = '.'.join(perms) mesg = f'User must have permission {perm} on write layer {layriden} of view {self.iden}' raise s_exc.AuthDeny(mesg=mesg, perm=perm, user=user.name)
def _getCellUser(self, link, mesg): auth = mesg[1].get('auth') if auth is None: raise s_exc.AuthDeny(mesg='Unable to find cell user') name, info = auth user = self.auth.users.get(name) if user is None: raise s_exc.AuthDeny(mesg='User not present in link', user=name) # passwd None always fails... passwd = info.get('passwd') if not user.tryPasswd(passwd): raise s_exc.AuthDeny(mesg='Invalid password', user=user.name) return user
def _getCellUser(self, mesg): auth = mesg[1].get('auth') if auth is None: raise s_exc.AuthDeny(mesg='Unable to find cell user') name, info = auth user = self.auth.getUserByName(name) if user is None: raise s_exc.NoSuchUser(name=name, mesg=f'No such user: {name}.') # passwd None always fails... passwd = info.get('passwd') if not user.tryPasswd(passwd): raise s_exc.AuthDeny(mesg='Invalid password', user=user.name) return user
async def setUserPasswd(self, name, passwd): user = await self.cell.auth.getUserByName(name) if user is None: raise s_exc.NoSuchUser(user=name) if not (self.user.isAdmin() or self.user.iden == user.iden): raise s_exc.AuthDeny(mesg='Cannot change user password.', user=user.name) await user.setPasswd(passwd) await self.cell.fire('user:mod', act='setpasswd', name=name)
def func(*args, **kwargs): if args[0].user is not None and not args[0].user.admin: raise s_exc.AuthDeny(mesg='User is not an admin.', user=args[0].user.name) logger.info('Executing [%s] as [%s] with args [%s][%s]', f.__qualname__, args[0].user.name, args[1:], kwargs) return f(*args, **kwargs)
async def getUserInfo(self, name): user = await self.cell.auth.reqUserByName(name) if self.user.isAdmin() or self.user.iden == user.iden: info = user.pack() info['roles'] = [ self.cell.auth.role(r).name for r in info['roles'] ] return info mesg = 'getUserInfo denied for non-admin and non-self' raise s_exc.AuthDeny(mesg=mesg)
def reqAllowed(self, perms): ''' Raise AuthDeny if user doesn't have global permissions and write layer permissions ''' if self._allowed(perms): return perm = '.'.join(perms) mesg = f'User must have permission {perm}' raise s_exc.AuthDeny(mesg=mesg, perm=perm, user=self.user.name)
async def _reqUserAllowed(self, hiveuser, perm): ''' Raise AuthDeny if hiveuser does not have permissions perm Note: async for consistency with CellApi._reqUserAllowed ''' if not self.allowed(hiveuser, perm): perm = '.'.join(perm) mesg = f'User must have permission {perm} for {self.iden}' raise s_exc.AuthDeny(mesg=mesg, perm=perm, user=hiveuser.name)
def wrapped(*args, **kwargs): if args[0].user is not None and not args[0].user.isAdmin(): raise s_exc.AuthDeny(mesg='User is not an admin.', user=args[0].user.name) if log: logger.info('Executing [%s] as [%s] with args [%s][%s]', func.__qualname__, args[0].user.name, args[1:], kwargs) return func(*args, **kwargs)
async def storNodeEdits(self, edits, meta): if not self.allowedits: mesg = 'storNodeEdits() not allowed without node permission on layer.' raise s_exc.AuthDeny(mesg=mesg) if meta is None: meta = {} meta['time'] = s_common.now() meta['user'] = self.user.iden return await self.view.storNodeEdits(edits, meta)
def _f(*args, **kwargs): auth = getattr(args[0], attr, None) # type: s_auth.Auth if not auth: raise s_exc.ReqConfOpt(mesg='requires attr on local object', attr=attr) uname = whoami() uobj = auth.reqUser(uname) if not uobj.admin: raise s_exc.AuthDeny(mesg='Operation requires admin', name=f.__qualname__, user=uname) logger.info('Executing [%s][%s][%s] as [%s]', f.__qualname__, args, kwargs, uname) return f(*args, **kwargs)
async def _funcMacroDel(self, name): name = await s_stormtypes.tostr(name) path = ('cortex', 'storm', 'macros', name) mdef = await self.runt.snap.core.getHiveKey(path) if mdef is None: mesg = f'Macro name not found: {name}' raise s_exc.NoSuchName(mesg) user = self.runt.user if mdef['user'] != user.iden and not user.isAdmin(): mesg = 'Macro belongs to a different user' raise s_exc.AuthDeny(mesg=mesg) await self.runt.snap.core.popHiveKey(path)
async def _trimNexsLog(self, consumers=None, timeout=30): if not self.runt.isAdmin(): mesg = '$lib.cell.trimNexsLog() requires admin privs.' raise s_exc.AuthDeny(mesg=mesg) timeout = await s_stormtypes.toint(timeout, noneok=True) if consumers is not None: consumers = [ await s_stormtypes.tostr(turl) async for turl in s_stormtypes.toiter(consumers) ] return await self.runt.snap.core.trimNexsLog(consumers=consumers, timeout=timeout)
async def kill(self, iden): admin = self.user.admin logger.info(f'User [{self.user.name}] Requesting task kill: {iden}') task = self.cell.boss.get(iden) if task is None: logger.info(f'Task does not exist: {iden}') return False if admin or task.user == self.user: logger.info(f'Killing task: {iden}') await task.kill() logger.info(f'Task killed: {iden}') return True raise s_exc.AuthDeny(mesg='Caller must own task or be admin.', task=iden, user=str(self.user))
def setCellUser(self, iden): ''' Switch to another user (admin only). This API allows remote admin/service accounts to impersonate a user. Used mostly by services that manage their own authentication/sessions. ''' if not self.user.admin: mesg = 'setCellUser() caller must be admin.' raise s_exc.AuthDeny(mesg=mesg) user = self.cell.auth.user(iden) if user is None: raise s_exc.NoSuchUser(iden=iden) self.user = user return True
def allowed(self, *args): # a user will be set by auth subsystem if enabled if self.user is None: return if self.user.admin: return if self.elevated: return if self.user.allowed(args): return # fails will not be cached... perm = '.'.join(args) raise s_exc.AuthDeny(perm=perm, user=self.user.name)
async def _hotFixesCheck(self): if not self.runt.isAdmin(): mesg = '$lib.cell.stormFixesCheck() requires admin privs.' raise s_exc.AuthDeny(mesg=mesg) curv = await self.runt.snap.core.getStormVar(runtime_fixes_key, default=(0, 0, 0)) dowork = False for vers, info in hotfixes: if vers <= curv: continue dowork = True desc = info.get('desc') await self.runt.printf(f'Would apply fix {vers} for [{desc}]') return dowork
def _stormOperSudo(self, query, oper): core = self.getStormCore() if core.auth is None: return name = query.user if name is None: name = s_auth.whoami() user = core.auth.users.get(name) if user is None: raise s_exc.NoSuchUser(user=name) if not user.admin: raise s_exc.AuthDeny(mesg='sudo() user is not admin', user=name) query.elev = True
async def kill(self, iden): perm = ('task', 'del') isallowed = await self.allowed(perm) logger.info(f'User [{self.user.name}] Requesting task kill: {iden}') task = self.cell.boss.get(iden) if task is None: logger.info(f'Task does not exist: {iden}') return False if (task.user == self.user) or isallowed: logger.info(f'Killing task: {iden}') await task.kill() logger.info(f'Task killed: {iden}') return True perm = '.'.join(perm) raise s_exc.AuthDeny(mesg=f'User must have permission {perm} or own the task', task=iden, user=str(self.user), perm=perm)
def allowed(self, *args): # a user will be set by auth subsystem if enabled if self.user is None: return if self.user.admin: return if self.elevated: return if self.user.allowed(args): return # fails will not be cached... perm = '.'.join(args) mesg = f'User must have permission {perm}' raise s_exc.AuthDeny(mesg=mesg, perm=perm, user=self.user.name)
async def getTeleApi(self, link, mesg, path): auth = await self.getHiveAuth() if not self.conf.get('auth:en'): user = auth.getUserByName('root') return await HiveApi.anit(self, user) name, info = mesg[1].get('auth') user = auth.getUserByName(name) if user is None: raise s_exc.NoSuchUser(name=name) # passwd None always fails... passwd = info.get('passwd') if not user.tryPasswd(passwd): raise s_exc.AuthDeny(mesg='Invalid password', user=user.name) return await HiveApi.anit(self, user)
async def _funcMacroSet(self, name, storm): name = await s_stormtypes.tostr(name) storm = await s_stormtypes.tostr(storm) # validation await self.runt.getStormQuery(storm) path = ('cortex', 'storm', 'macros', name) user = self.runt.user mdef = await self.runt.snap.core.getHiveKey(path) if mdef is not None: if mdef['user'] != user.iden and not user.isAdmin(): mesg = 'Macro belongs to a different user' raise s_exc.AuthDeny(mesg=mesg) mdef = { 'user': user.iden, 'storm': storm, 'edited': s_common.now(), } await self.runt.snap.core.setHiveKey(path, mdef)
async def _funcMacroDel(self, name): ''' Delete a Storm Macro by name from the Cortex. Args: name (str): The name of the macro to delete. Returns: dict: The macro definition which has been removed from the Cortex. ''' name = await s_stormtypes.tostr(name) path = ('cortex', 'storm', 'macros', name) mdef = await self.runt.snap.core.getHiveKey(path) if mdef is None: mesg = f'Macro name not found: {name}' raise s_exc.NoSuchName(mesg) user = self.runt.user if mdef['user'] != user.iden and not user.isAdmin(): mesg = 'Macro belongs to a different user' raise s_exc.AuthDeny(mesg=mesg) await self.runt.snap.core.popHiveKey(path)
async def _hotFixesApply(self): if not self.runt.isAdmin(): mesg = '$lib.cell.stormFixesApply() requires admin privs.' raise s_exc.AuthDeny(mesg=mesg) curv = await self.runt.snap.core.getStormVar(runtime_fixes_key, default=(0, 0, 0)) for vers, info in hotfixes: if vers <= curv: continue desc = info.get('desc') text = info.get('query') vars = info.get('vars', {}) assert text is not None assert desc is not None assert vars is not None await self.runt.printf(f'Applying fix {vers} for [{desc}]') try: query = await self.runt.getStormQuery(text) async with self.runt.getSubRuntime(query, opts={'vars': vars}) as runt: async for item in runt.execute(): pass except asyncio.CancelledError: raise except Exception as e: logger.exception(f'Error applying stormfix {vers}') raise else: await self.runt.snap.core.setStormVar(runtime_fixes_key, vers) await self.runt.printf(f'Applied fix {vers}') curv = vers return curv