def isAuthorized(self, username, account, cloudspace=None, machine=None): """ Check if a user has the authorization to access a resource :param username: username of the user to be checked :param machine: machine object if authorization should be done on machine level :param cloudspace: cloudspace object if authorization should be done on cloudspace level :param account: account object if authorization should be done on account level :return: True if username is authorized to access the resource, False otherwise """ userobj = j.core.portal.active.auth.getUserInfo(username) if not userobj or not userobj.active: raise exceptions.Forbidden( 'User is not allowed to execute action while status is ' 'inactive.') groups = userobj.groups # add brokeradmin access if 'admin' in groups: return True if self.groups: groups = set() if userobj: groups = set(userobj.groups) if not groups.intersection(self.groups): raise exceptions.Forbidden( 'User %s has no access. If you would like to gain access please contact your adminstrator' % username) if 'account' in self.acl and account: grantedaccountacl = self.expandAclFromAccount( username, groups, account) if self.acl['account'].issubset(grantedaccountacl): self.checkAccountStatus(self.acl['account'], account) return True if 'cloudspace' in self.acl and cloudspace: grantedcloudspaceacl = self.expandAclFromCloudspace( username, groups, cloudspace) if self.acl['cloudspace'].issubset(grantedcloudspaceacl): self.checkAccountStatus(self.acl['cloudspace'], account) self.checkCloudspaceStatus(self.acl['cloudspace'], cloudspace) return True if 'machine' in self.acl and machine: grantedmachineacl = self.expandAclFromVMachine( username, groups, machine) if self.acl['machine'].issubset(grantedmachineacl): self.checkAccountStatus(self.acl['machine'], account) self.checkCloudspaceStatus(self.acl['machine'], cloudspace) return True return False
def wrapper(*args, **kwargs): self.tags_str = ' '.join( ["%s:%s" % (k, kwargs[v]) for k, v in self.tags.iteritems()]) if 'ctx' not in kwargs: # call is not performed over rest let it pass return func(*args, **kwargs) ctx = kwargs['ctx'] if self.tags: ctx.env['tags'] = self.tags_str user = ctx.env['beaker.session']['user'] if self.groups: userobj = j.core.portal.active.auth.getUserInfo(user) groups = set() if userobj: groups = set(userobj.groups) if not groups.intersection(self.groups): raise exceptions.Forbidden( 'User %s has no access. If you would like to gain access please contact your adminstrator' % user) if self.audit: ctx.env['write_audit']() return func(*args, **kwargs)
def checkCloudspaceStatus(self, requiredaccessrights, cloudspace): """ Check if the required action can be executed on a cloudspace. If cloudspace is 'DESTROYED' then a 404 NotFound will be returned, else if an action requires a permission other than READ, the call will fail with 403 Forbidden if cloudspace is not in any of the statuses 'VIRTUAL', 'DEPLOYING' or'DEPLOYED' :param requiredaccessrights: the required access rights to access an cloudspace or one of its machines :param cloudspace: the cloudspace object its status should be checked :raise Exception with 404 if destroyed or 403 Forbidden if non-read action cannot be performed on cloudspace or one of its machines """ if cloudspace.status == resourcestatus.Cloudspace.DESTROYED: raise exceptions.NotFound('Could not find an accessible resource.') elif cloudspace.status == resourcestatus.Cloudspace.DELETED and requiredaccessrights != set( 'D'): raise exceptions.NotFound('Could not find an accessible resource.') elif requiredaccessrights != set('R') and cloudspace.status not in [ resourcestatus.Cloudspace.VIRTUAL, resourcestatus.Cloudspace.DEPLOYING, resourcestatus.Cloudspace.DEPLOYED ]: raise exceptions.Forbidden( 'Only READ actions can be executed on cloudspace ' '(or one of its machines) with status %s.' % cloudspace.status)
def checkAccountStatus(self, requiredaccessrights, account): """ Check if the required action can be executed on an account. If account is 'DISABLED', 'DESTROYED', 'ERROR' and action requires a permission other than READ, the call should fail with 403 Forbidden Check if the required action can be executed on an account. If account is 'DESTROYED' then a 404 NotFound will be returned, else if an action requires a permission other than READ, the call will fail with 403 Forbidden if account is not 'CONFIRMED' :param requiredaccessrights: the required access rights to access an account or one of its cloudspaces or machines :param account: the account object its status should be checked :raise Exception with 403 Forbidden if action cannot be performed on account or one of its cloduspaces or machines :raise Exception with 404 if destroyed or 403 Forbidden if non-read action cannot be performed on account or one of its cloudspace or machines """ if account.status == 'DESTROYED': raise exceptions.NotFound('Could not find an accessible resource.') elif requiredaccessrights != set( 'R') and account.status != 'CONFIRMED': raise exceptions.Forbidden( 'Only READ actions can be executed on account ' '(or one of its cloudspace or machines) with status %s.' % account.status)
def wrapper(*args, **kwargs): if 'ctx' not in kwargs: # call is not performed over rest let it pass return func(*args, **kwargs) ctx = kwargs['ctx'] user = ctx.env['beaker.session']['user'] if self.groups: userobj = j.core.portal.active.auth.getUserInfo(user) if userobj: groups = set(userobj.groups) if not groups.intersection(self.groups): raise exceptions.Forbidden( 'User %s has no access. If you would like to gain access please contact your adminstrator' % user) ctx.env['JS_AUDIT'] = self.audit return func(*args, **kwargs)
def deleteImage(self, imageId, permanently): image = self.models.image.get(imageId) if image.status == resourcestatus.Image.DESTROYED: return True references = self.models.vmachine.count({'imageId': imageId, 'status': {'$ne': resourcestatus.Machine.DESTROYED}}) if references and permanently: raise exceptions.Conflict("Can not delete an image which is still used") if image.status != resourcestatus.Image.DELETED: if image.status != resourcestatus.Image.CREATED: raise exceptions.Forbidden("Can not delete an image which is not created yet.") deleted_state = resourcestatus.Image.DELETED if permanently: deleted_state = resourcestatus.Image.DESTROYED provider = self.cb.getProviderByGID(image.gid) provider.ex_delete_template(image.referenceId) self.models.image.updateSearch({'id': imageId}, {'$set': {'status': deleted_state, 'deletionTime': int(time.time())}}) self.models.stack.updateSearch({'images': imageId}, {'$pull': {'images': imageId}}) return True
def authorize(self, **kwargs): ctx = kwargs['ctx'] code = kwargs.get('code') if not code: raise exceptions.Forbidden('Not Authorized -- Code is missing') state = kwargs.get('state') if not state: return exceptions.Forbidden('Not Authorized -- State is missing') cache = j.clients.redis.getByInstance('system') cache_result = cache.get(state) if not cache_result: unauthorized_redirect_url = '%s?%s' % ( '/restmachine/system/oauth/authenticate', urllib.urlencode({ 'type': j.core.portal.active.force_oauth_instance or 'github' })) msg = 'Not Authorized -- Invalid or expired state' j.logger.log(msg) raise exceptions.Redirect(unauthorized_redirect_url) cache_result = json.loads(cache_result) client = j.clients.oauth.get(instance=cache_result['type']) payload = { 'code': code, 'client_id': client.id, 'client_secret': client.secret, 'redirect_uri': client.redirect_url, 'grant_type': 'authorization_code' } result = requests.post(client.accesstokenaddress, data=payload, headers={'Accept': 'application/json'}) if not result.ok or 'error' in result.json(): msg = 'Not Authorized -- %s' % result.json()['error'] j.logger.log(msg) raise exceptions.Forbidden(msg) result = result.json() access_token = result['access_token'] params = {'access_token': access_token} userinfo = requests.get( '%s?%s' % (client.user_info_url, urllib.urlencode(params))).json() username = userinfo['login'] email = userinfo['email'] osis = j.clients.osis.getByInstance('main') user = j.clients.osis.getCategory(osis, "system", "user") users = user.search({'id': username})[1:] if not users: # register user u = user.new() u.id = username u.emails = [email] user.set(u) else: u = users[0] if email not in u['emails']: raise exceptions.BadRequest( 'User with same name already exists') session = ctx.env['beaker.session'] session['user'] = username session['email'] = email session['oauth'] = { 'authorized': True, 'type': str(cache_result['type']), 'logout_url': client.logout_url } session.save() raise exceptions.Redirect(str(cache_result['redirect']))
def wrapper(*args, **kwargs): if 'ctx' not in kwargs: # call is not performed over rest let it pass return func(*args, **kwargs) ctx = kwargs['ctx'] if not self.skipversioncheck and sysmodels.version.count( {'status': 'INSTALLING'}) != 0: raise exceptions.ServiceUnavailable( 'Can not call API during upgrade') tags = j.core.tags.getObject(ctx.env['tags']) user = ctx.env['beaker.session']['user'] account = None cloudspace = None machine = None if 'machineId' in kwargs and kwargs['machineId']: machine = self.models.vmachine.get(int(kwargs['machineId'])) cloudspace = self.models.cloudspace.get(machine.cloudspaceId) account = self.models.account.get(cloudspace.accountId) elif 'diskId' in kwargs and kwargs['diskId']: disk = self.models.disk.get(int(kwargs['diskId'])) machinedict = self.models.vmachine.searchOne({ 'disks': disk.id, 'status': { '$ne': resourcestatus.Machine.DESTROYED } }) if machinedict: machine = self.models.vmachine.new() machine.load(machinedict) cloudspace = self.models.cloudspace.get( machine.cloudspaceId) accountId = disk.accountId if accountId: account = self.models.account.get(accountId) elif 'cloudspaceId' in kwargs and kwargs['cloudspaceId']: cloudspace = self.models.cloudspace.get( int(kwargs['cloudspaceId'])) account = self.models.account.get(cloudspace.accountId) elif 'accountId' in kwargs and kwargs['accountId']: account = self.models.account.get(int(kwargs['accountId'])) for key, value in (('accountId', account), ('cloudspaceId', cloudspace), ('machineId', machine)): if value is not None: tags.tagSet(key, str(value.id)) if 'nid' in kwargs and kwargs['nid']: tags.tagSet('nodeId', str(kwargs['nid'])) tagstr = str(tags) if 'nids' in kwargs and kwargs['nids']: for nid in kwargs['nids']: tagstr += " nodeId:{}".format(nid) ctx.env['tags'] = tagstr ctx.env['write_audit']() if self.isAuthorized(user, account, cloudspace, machine): return func(*args, **kwargs) else: raise exceptions.Forbidden( '''User: "******" isn't allowed to execute this action. Not enough permissions''' % user)
def wrapper(*args, **kwargs): if "ctx" not in kwargs: # call is not performed over rest let it pass return func(*args, **kwargs) ctx = kwargs["ctx"] if ( not self.skipversioncheck and sysmodels.version.count({"status": "INSTALLING"}) != 0 ): raise exceptions.ServiceUnavailable("Can not call API during upgrade") tags = j.core.tags.getObject(ctx.env["tags"]) user = ctx.env["beaker.session"]["user"] account = None cloudspace = None machine = None if "machineId" in kwargs and kwargs["machineId"]: machine = self.models.vmachine.get(int(kwargs["machineId"])) cloudspace = self.models.cloudspace.get(machine.cloudspaceId) account = self.models.account.get(cloudspace.accountId) elif "diskId" in kwargs and kwargs["diskId"]: disk = self.models.disk.get(int(kwargs["diskId"])) machinedict = self.models.vmachine.searchOne( { "disks": disk.id, "status": {"$ne": resourcestatus.Machine.DESTROYED}, } ) if machinedict: machine = self.models.vmachine.new() machine.load(machinedict) cloudspace = self.models.cloudspace.get(machine.cloudspaceId) accountId = disk.accountId if accountId: account = self.models.account.get(accountId) elif "cloudspaceId" in kwargs and kwargs["cloudspaceId"]: cloudspace = self.models.cloudspace.get(int(kwargs["cloudspaceId"])) account = self.models.account.get(cloudspace.accountId) elif "accountId" in kwargs and kwargs["accountId"]: account = self.models.account.get(int(kwargs["accountId"])) for key, value in ( ("accountId", account), ("cloudspaceId", cloudspace), ("machineId", machine), ): if value is not None: tags.tagSet(key, str(value.id)) if "nid" in kwargs and kwargs["nid"]: tags.tagSet("nodeId", str(kwargs["nid"])) tagstr = str(tags) if "nids" in kwargs and kwargs["nids"]: for nid in kwargs["nids"]: tagstr += " nodeId:{}".format(nid) ctx.env["tags"] = tagstr ctx.env["write_audit"]() if self.isAuthorized(user, account, cloudspace, machine): return func(*args, **kwargs) else: raise exceptions.Forbidden( """User: "******" isn't allowed to execute this action. Not enough permissions""" % user )