def validate_python(self, form_fields, state): lc_id = form_fields.get('id', None) email_address = form_fields['email'] user_name = form_fields['lusername'] try: User.by_email_address(email_address) except NoResultFound: email_is_used = False else: email_is_used = True if User.by_user_name(user_name): new_user = False else: new_user = True if not lc_id: labcontroller = None luser = None else: labcontroller = LabController.by_id(lc_id) luser = labcontroller.user try: if not labcontroller and email_is_used: # New LC using dupe email raise ValueError if new_user and email_is_used: #New user using dupe email raise ValueError if luser: _check_user_email(email_address, luser.user_id) except ValueError: error = {'email' : self.message('not_unique', state)} raise Invalid('Email address is not unique', form_fields, state, error_dict=error)
def remove_account(self, username, newowner=None): """ Remove a user account. Removing a user account cancels any running job(s), returns all the systems in use by the user, modifies the ownership of the systems owned to the admin closing the account, and disables the account for further login. :param username: An existing username :param newowner: An optional username to assign all systems to. :type username: string """ kwargs = {} try: user = User.by_user_name(username) except InvalidRequestError: raise BX(_('Invalid User %s ' % username)) if newowner: owner = User.by_user_name(newowner) if owner is None: raise BX(_('Invalid user name for owner %s' % newowner)) kwargs['newowner'] = owner if user.removed: raise BX(_('User already removed %s' % username)) self._remove(user=user, method='XMLRPC', **kwargs)
def grant_owner(self, group_id=None, id=None, **kw): if group_id is not None and id is not None: group = Group.by_id(group_id) user = User.by_id(id) service = 'WEBUI' else: group = Group.by_name(kw['group_name']) user = User.by_user_name(kw['member_name']) service = 'XMLRPC' if group.ldap: raise GroupOwnerModificationForbidden('An LDAP group does not have an owner') if not group.can_edit(identity.current.user): raise GroupOwnerModificationForbidden('You are not an owner of the group %s' % group) if user not in group.users: raise GroupOwnerModificationForbidden('User is not a group member') else: for assoc in group.user_group_assocs: if assoc.user == user: if not assoc.is_owner: assoc.is_owner = True group.record_activity(user=identity.current.user, service=service, field=u'Owner', action='Added', old=u'', new=user.user_name) return ''
def _try_autocreate(user_name): """ If the necessary WSGI environment variables are populated, automatically creates a new Beaker user account based on their values and returns it. Otherwise returns None. """ from bkr.server.model import session, User if not flask.request.environ.get('REMOTE_USER_FULLNAME'): log.debug('User autocreation attempted for %r but ' 'REMOTE_USER_FULLNAME env var was not populated', user_name) return if not flask.request.environ.get('REMOTE_USER_EMAIL'): log.debug('User autocreation attempted for %r but ' 'REMOTE_USER_EMAIL env var was not populated', user_name) return user = User() user.user_name = user_name.decode('utf8') user.display_name = flask.request.environ['REMOTE_USER_FULLNAME'].decode('utf8') user.email_address = flask.request.environ['REMOTE_USER_EMAIL'].decode('utf8') session.add(user) session.flush() log.debug('Autocreated user %s', user) return user
def revoke_owner(self, group_id=None, id=None, **kw): if group_id is not None and id is not None: group = Group.by_id(group_id) user = User.by_id(id) service = 'WEBUI' else: group = Group.by_name(kw['group_name']) user = User.by_user_name(kw['member_name']) service = 'XMLRPC' if group.ldap: raise GroupOwnerModificationForbidden('An LDAP group does not have an owner') if not group.can_edit(identity.current.user): raise GroupOwnerModificationForbidden('You are not an owner of group %s' % group) if user not in group.users: raise GroupOwnerModificationForbidden('User is not a group member') if len(group.owners())==1 and not identity.current.user.is_admin(): raise GroupOwnerModificationForbidden('Cannot remove the only owner') else: for assoc in group.user_group_assocs: if assoc.user == user: if assoc.is_owner: assoc.is_owner = False group.record_activity(user=identity.current.user, service=service, field=u'Owner', action='Removed', old=user.user_name, new=u'') # hack to return the user removing this owner # so that if the user was logged in as a group # owner, he/she can be redirected appropriately return str(identity.current.user.user_id)
def revoke_owner(self, group_id=None, id=None, **kw): if group_id is not None and id is not None: group = Group.by_id(group_id) user = User.by_id(id) service = 'WEBUI' else: group = Group.by_name(kw['group_name']) user = User.by_user_name(kw['member_name']) service = 'XMLRPC' if group.membership_type == GroupMembershipType.ldap: raise GroupOwnerModificationForbidden('An LDAP group does not have an owner') if not group.can_edit(identity.current.user): raise GroupOwnerModificationForbidden('You are not an owner of group %s' % group) if user not in group.users: raise GroupOwnerModificationForbidden('User is not a group member') if len(group.owners())==1 and not identity.current.user.is_admin(): raise GroupOwnerModificationForbidden('Cannot remove the only owner') else: group.revoke_ownership(user=user, agent=identity.current.user, service=service) # hack to return the user removing this owner # so that if the user was logged in as a group # owner, he/she can be redirected appropriately return str(identity.current.user.user_id)
def find_user_or_create(user_name): user = User.by_user_name(user_name) if user is None: user = User(user_name=user_name) user.user_name = user_name session.add(user) return user
def remove_account(self, username, newowner=None): """ Removes a Beaker user account. When the account is removed: * it is removed from all groups and access policies * any running jobs owned by the account are cancelled * any systems reserved by or loaned to the account are returned * any systems and system pools owned by the account are transferred to the admin running this command, or some other user if specified using the *newowner* parameter * the account is disabled for further login :param username: An existing username :param newowner: An optional username to assign all systems to. :type username: string """ kwargs = {} try: user = User.by_user_name(username) except InvalidRequestError: raise BX(_('Invalid User %s ' % username)) if newowner: owner = User.by_user_name(newowner) if owner is None: raise BX(_('Invalid user name for owner %s' % newowner)) kwargs['newowner'] = owner if user.removed: raise BX(_('User already removed %s' % username)) _remove(user=user, method='XMLRPC', **kwargs)
def login_password(self, username, password, proxy_user=None): """ Authenticates the current session using the given username and password. The caller may act as a proxy on behalf of another user by passing the *proxy_user* argument. This requires that the caller has 'proxy_auth' permission. :param proxy_user: username on whose behalf the caller is proxying :type proxy_user: string or None """ user = User.by_user_name(username) if user is None: raise LoginException(_(u'Invalid username or password')) if not user.can_log_in(): raise LoginException(_(u'Invalid username or password')) if not user.check_password(password): raise LoginException(_(u'Invalid username or password')) if proxy_user: if not user.has_permission(u'proxy_auth'): raise LoginException(_(u'%s does not have proxy_auth permission') % user.user_name) proxied_user = User.by_user_name(proxy_user) if proxied_user is None: raise LoginException(_(u'Proxy user %s does not exist') % proxy_user) identity.set_authentication(proxied_user, proxied_by=user) else: identity.set_authentication(user) return user.user_name
def setUp(self): self.distro = data_setup.create_distro() self.distro_tree1 = data_setup.create_distro_tree(distro=self.distro, arch='x86_64') self.distro_tree2 = data_setup.create_distro_tree(distro=self.distro, arch='i386') self.distro_tree1.activity.append(DistroTreeActivity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'testdata', field_name=u'Nonesente', old_value=u'sdfas', new_value=u'sdfa', action='Added')) self.distro_tree2.activity.append(DistroTreeActivity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'testdata', field_name=u'Noneseonce', old_value=u'bsdf', new_value=u'sdfas', action='Added')) self.distro.activity.append(DistroActivity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'testdata', action=u'Nothing', field_name=u'Nonsense', old_value=u'asdf', new_value=u'omgwtfbbq')) self.system = data_setup.create_system() self.system.activity.append(SystemActivity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'testdata', action=u'Nothing', field_name=u'Nonsense', old_value=u'asdf', new_value=u'omgwtfbbq')) self.group2 = data_setup.create_group() self.group = data_setup.create_group() self.group.activity.append(GroupActivity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'testdata', action=u'Nothing', field_name=u'Nonsense', old_value=u'asdf', new_value=u'omgwtfbbq')) self.browser = self.get_browser()
def test_system_pool_activity(self): with session.begin(): pool1 = data_setup.create_system_pool() act1 = pool1.record_activity(service=u'testdata', user=User.by_user_name(data_setup.ADMIN_USER), action=u'Nothing', field=u'Nonsense', old=u'asdf', new=u'omgwtfbbq') pool2 = data_setup.create_system_pool() act2 = pool2.record_activity(service=u'testdata', user=User.by_user_name(data_setup.ADMIN_USER), action=u'Nothing', field=u'Nonsense', old=u'asdf', new=u'lollercopter') b = self.browser b.get(get_server_base() + 'activity/pool') b.find_element_by_class_name('search-query').send_keys( 'pool.name:%s' % pool1.name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2]) # search by pool owner b.get(get_server_base() + 'activity/pool') b.find_element_by_class_name('search-query').send_keys( 'pool.owner.user_name:%s' % pool2.owner.user_name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act2], absent=[act1]) with session.begin(): pool1.owning_user = None pool1.owning_group = data_setup.create_group() b.get(get_server_base() + 'activity/pool') b.find_element_by_class_name('search-query').send_keys( 'pool.owner.group_name:%s' % pool1.owner.group_name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2])
def _check_user_email(email_address, user_id): try: user_by_email = User.by_email_address(email_address) except NoResultFound: # Email not being used pass else: #raise ValueError user_by_id = User.by_id(user_id) if user_by_id != user_by_email: # An existing email that is not theirs raise ValueError
def check_authentication(): """ Checks the current request for: * REMOTE_USER in the WSGI environment, indicating that the container has already authenticated the request for us; or * a valid signed token, indicating that the user has authenticated to us successfully on a previous request. Sets up the "current identity" state according to what's found. """ from bkr.server.model import User if 'REMOTE_USER' in flask.request.environ: # strip realm if present user_name, _, realm = flask.request.environ['REMOTE_USER'].partition('@') user = User.by_user_name(user_name.decode('utf8')) if user is None and config.get('identity.autocreate', True): # handle automatic user creation if possible user = _try_autocreate(user_name) if user is None: log.debug('REMOTE_USER %r does not exist', user_name) return proxied_by_user = None elif _token_cookie_name in flask.request.cookies: token = flask.request.cookies[_token_cookie_name] if token == 'deleted': return token_value = _check_token(token) if not token_value or 'user_name' not in token_value: return user_name = token_value['user_name'] user = User.by_user_name(user_name.decode('utf8')) if user is None: log.warning('Token claimed to be for non-existent user %r', user_name) return # handle "proxy authentication" support proxied_by_user_name = token_value.get('proxied_by_user_name', None) if proxied_by_user_name: proxied_by_user = User.by_user_name(proxied_by_user_name.decode('utf8')) if proxied_by_user is None: log.warning('Token for %r claimed to be proxied by non-existent user %r', user_name, proxied_by_user_name) return if not proxied_by_user.can_log_in(): log.debug('Denying login for %r proxied by disabled user %r', user_name, proxied_by_user_name) return else: proxied_by_user = None else: return if not user.can_log_in(): log.debug('Denying login for disabled user %s', user) return flask.g._beaker_validated_user = user flask.g._beaker_proxied_by_user = proxied_by_user
def login_krbV(self, krb_request, proxy_user=None): """ Authenticates the current session using Kerberos. The caller may act as a proxy on behalf of another user by passing the *proxy_user* argument. This requires that the caller has 'proxy_auth' permission. :param krb_request: KRB_AP_REQ message containing client credentials, as produced by :c:func:`krb5_mk_req` :type krb_request: base64-encoded string :param proxy_user: username on whose behalf the caller is proxying :type proxy_user: string or None This method is also available under the alias :meth:`auth.login_krbv`, for compatibility with `Kobo`_. """ import krbV import base64 context = krbV.default_context() server_principal = krbV.Principal(name=self.KRB_AUTH_PRINCIPAL, context=context) server_keytab = krbV.Keytab(name=self.KRB_AUTH_KEYTAB, context=context) auth_context = krbV.AuthContext(context=context) auth_context.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME auth_context.addrs = (socket.gethostbyname(cherrypy.request.remote_host), 0, cherrypy.request.remote_addr, 0) # decode and read the authentication request decoded_request = base64.decodestring(krb_request) auth_context, opts, server_principal, cache_credentials = context.rd_req(decoded_request, server=server_principal, keytab=server_keytab, auth_context=auth_context, options=krbV.AP_OPTS_MUTUAL_REQUIRED) cprinc = cache_credentials[2] # remove @REALM username = cprinc.name.split("@")[0] user = User.by_user_name(username) if user is None: raise LoginException(_(u'Invalid username')) if not user.can_log_in(): raise LoginException(_(u'Invalid username')) if proxy_user: if not user.has_permission(u'proxy_auth'): raise LoginException(_(u'%s does not have proxy_auth permission') % user.user_name) proxied_user = User.by_user_name(proxy_user) if proxied_user is None: raise LoginException(_(u'Proxy user %s does not exist') % proxy_user) identity.set_authentication(proxied_user, proxied_by=user) else: identity.set_authentication(user) return username
def save(self, **kw): if kw.get('id'): labcontroller = LabController.by_id(kw['id']) else: labcontroller = LabController() session.add(labcontroller) if labcontroller.fqdn != kw['fqdn']: activity = LabControllerActivity(identity.current.user, 'WEBUI', 'Changed', 'FQDN', labcontroller.fqdn, kw['fqdn']) labcontroller.fqdn = kw['fqdn'] labcontroller.write_activity.append(activity) # labcontroller.user is used by the lab controller to login here try: # pick up an existing user if it exists. luser = User.query.filter_by(user_name=kw['lusername']).one() except InvalidRequestError: # Nope, create from scratch luser = User() if labcontroller.user != luser: if labcontroller.user is None: old_user_name = None else: old_user_name = labcontroller.user.user_name activity = LabControllerActivity(identity.current.user, 'WEBUI', 'Changed', 'User', old_user_name, unicode(kw['lusername'])) labcontroller.user = luser labcontroller.write_activity.append(activity) # Make sure user is a member of lab_controller group group = Group.by_name(u'lab_controller') if group not in luser.groups: luser.groups.append(group) luser.display_name = kw['fqdn'] luser.email_address = kw['email'] luser.user_name = kw['lusername'] if kw['lpassword']: luser.password = kw['lpassword'] if labcontroller.disabled != kw['disabled']: activity = LabControllerActivity(identity.current.user, 'WEBUI', 'Changed', 'Disabled', unicode(labcontroller.disabled), unicode(kw['disabled'])) labcontroller.disabled = kw['disabled'] labcontroller.write_activity.append(activity) flash( _(u"%s saved" % labcontroller.fqdn) ) redirect(".")
def test_release_system(self): with session.begin(): system = data_setup.create_system( owner=User.by_user_name(data_setup.ADMIN_USER), status=u'Manual', shared=True) user = data_setup.create_user(password=u'password') system.reserve_manually(service=u'testdata', user=user) server = self.get_server() server.auth.login_password(user.user_name, 'password') server.systems.release(system.fqdn) with session.begin(): session.refresh(system) session.refresh(system.reservations[0]) self.assert_(system.user is None) self.assertEquals(system.reservations[0].user, user) assert_datetime_within(system.reservations[0].finish_time, tolerance=datetime.timedelta(seconds=10), reference=datetime.datetime.utcnow()) assert_durations_not_overlapping(system.reservations) released_activity = system.activity[0] self.assertEqual(released_activity.action, 'Returned') self.assertEqual(released_activity.field_name, 'User') self.assertEqual(released_activity.user, user) self.assertEqual(released_activity.old_value, user.user_name) self.assertEqual(released_activity.new_value, '') self.assertEqual(released_activity.service, 'XMLRPC')
def test_refresh_ldap_group_membership(self): with session.begin(): group = Group(group_name=u'alp', display_name=u'Australian Labor Party', membership_type=GroupMembershipType.ldap) old_member = data_setup.create_user(user_name=u'krudd') group.add_member(old_member) run_command('refresh_ldap.py', 'beaker-refresh-ldap') with session.begin(): session.expire_all() self.assertEquals(group.users, [User.by_user_name(u'jgillard')]) # second time is a no-op run_command('refresh_ldap.py', 'beaker-refresh-ldap') with session.begin(): session.expire_all() self.assertEquals(group.users, [User.by_user_name(u'jgillard')])
def add_system_access_policy_rule(fqdn): system = _get_system_by_FQDN(fqdn) if not system.can_edit_policy(identity.current.user): raise Forbidden403('Cannot edit system policy') if system.custom_access_policy: policy = system.custom_access_policy else: policy = system.custom_access_policy = SystemAccessPolicy() rule = read_json_request(request) if rule['user']: user = User.by_user_name(rule['user']) if not user: raise BadRequest400("User '%s' does not exist" % rule['user']) else: user = None if rule['group']: try: group = Group.by_name(rule['group']) except NoResultFound: raise BadRequest400("Group '%s' does not exist" % rule['group']) else: group = None try: permission = SystemPermission.from_string(rule['permission']) except ValueError: raise BadRequest400 new_rule = policy.add_rule(user=user, group=group, everybody=rule['everybody'], permission=permission) system.record_activity(user=identity.current.user, service=u'HTTP', field=u'Access Policy Rule', action=u'Added', new=repr(new_rule)) return '', 204
def save_system_access_policy(fqdn): system = _get_system_by_FQDN(fqdn) if not system.can_edit_policy(identity.current.user): raise Forbidden403('Cannot edit system policy') if system.custom_access_policy: policy = system.custom_access_policy else: policy = system.custom_access_policy = SystemAccessPolicy() data = read_json_request(request) # Figure out what is added, what is removed. # Rules are immutable, so if it has an id it is unchanged, # if it has no id it is new. kept_rule_ids = frozenset(r['id'] for r in data['rules'] if 'id' in r) removed = [] for old_rule in policy.rules: if old_rule.id not in kept_rule_ids: removed.append(old_rule) for old_rule in removed: system.record_activity(user=identity.current.user, service=u'HTTP', field=u'Access Policy Rule', action=u'Removed', old=repr(old_rule)) policy.rules.remove(old_rule) for rule in data['rules']: if 'id' not in rule: user = User.by_user_name(rule['user']) if rule['user'] else None group = Group.by_name(rule['group']) if rule['group'] else None permission = SystemPermission.from_string(rule['permission']) new_rule = policy.add_rule(user=user, group=group, everybody=rule['everybody'], permission=permission) system.record_activity(user=identity.current.user, service=u'HTTP', field=u'Access Policy Rule', action=u'Added', new=repr(new_rule)) return '', 204
def add_ssh_public_key(username): """ Adds a new SSH public key for the given user account. Accepts mimetype:`text/plain` request bodies containing the SSH public key in the conventional OpenSSH format: <keytype> <key> <ident>. :param username: The user's username. """ user = User.by_user_name(username) if user is None: raise NotFound404('User %s does not exist' % username) if not user.can_edit(identity.current.user): raise Forbidden403('Cannot edit user %s' % user) if request.mimetype != 'text/plain': raise UnsupportedMediaType415('Request content type must be text/plain') with convert_internal_errors(): keytext = request.data.strip() if '\n' in keytext: raise ValueError('SSH public keys may not contain newlines') elements = keytext.split(None, 2) if len(elements) != 3: raise ValueError('Invalid SSH public key') key = SSHPubKey(*elements) user.sshpubkeys.append(key) session.flush() # to populate id return jsonify(key.__json__())
def test_can_search_custom_service(self): with session.begin(): distro_tree = data_setup.create_distro_tree() act1 = distro_tree.record_activity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'TESTSERVICE', field=u'Nonesente', old=u'sdfas', new=u'sdfa', action=u'Removed') act2 = distro_tree.record_activity( user=User.by_user_name(data_setup.ADMIN_USER), service=u'TESTSERVICE2', field=u'Noneseonce', old=u'bsdf', new=u'sdfas', action=u'Removed') b = self.browser b.get(get_server_base() + 'activity/distrotree') b.find_element_by_class_name('search-query').send_keys('service:TESTSERVICE') b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2])
def test_power_quiescent_period_statefulness_not_elapsed(self): if daemons_running_externally(): raise SkipTest('cannot examine logs of remote beaker-provision') provision_process, = [p for p in processes if p.name == \ 'beaker-provision'] # Initial lookup of this system will reveal no state, so will delay # for the whole quiescent period try: provision_process.start_output_capture() with session.begin(): system = data_setup.create_system(lab_controller=self.get_lc()) system.power.power_type = PowerType.lazy_create(name=u'dummy') system.power.power_quiescent_period = 1 system.power.power_id = u'' # make power script not sleep system.power.delay_until = None system.action_power(action=u'off', service=u'testdata') wait_for_commands_to_finish(system, timeout=10) finally: provision_output = provision_process.finish_output_capture() self.assertIn('Entering quiescent period, delaying 1 seconds for ' 'command %s' % system.command_queue[0].id, provision_output) # Increase the quiescent period, to ensure we enter it try: provision_process.start_output_capture() with session.begin(): system = System.by_id(system.id, User.by_user_name('admin')) system.power.power_quiescent_period = 10 system.action_power(action=u'on', service=u'testdata') wait_for_commands_to_finish(system, timeout=15) finally: provision_output = provision_process.finish_output_capture() self.assertIn('Entering quiescent period', provision_output)
def tearDown(self): admin_user = User.by_user_name(data_setup.ADMIN_USER) if getattr(self,'recipe_id', None): with session.begin(): recipe = Recipe.by_id(self.recipe_id) if recipe.resource.system.open_reservation: recipe.resource.release()
def process_xmljob(self, xmljob, user, ignore_missing_tasks=False): # We start with the assumption that the owner == 'submitting user', until # we see otherwise. submitter = user if user.rootpw_expired: raise BX(_('Your root password has expired, please change or clear it in order to submit jobs.')) owner_name = xmljob.get_xml_attr('user', unicode, None) if owner_name: owner = User.by_user_name(owner_name) if owner is None: raise ValueError('%s is not a valid user name' % owner_name) if not submitter.is_delegate_for(owner): raise ValueError('%s is not a valid submission delegate for %s' % (submitter, owner)) else: owner = user group_name = xmljob.get_xml_attr('group', unicode, None) group = None if group_name: try: group = Group.by_name(group_name) except NoResultFound, e: raise ValueError('%s is not a valid group' % group_name) if group not in owner.groups: raise BX(_(u'User %s is not a member of group %s' % (owner.user_name, group.group_name)))
def test_refresh_ldap_group_membership(self): with session.begin(): group = Group(group_name=u'alp', display_name=u'Australian Labor Party', ldap=True) old_member = data_setup.create_user(user_name=u'krudd') group.users.append(old_member) from bkr.server.tools.refresh_ldap import refresh_ldap refresh_ldap() with session.begin(): session.expire_all() self.assertEquals(group.users, [User.by_user_name(u'jgillard')]) # second time is a no-op refresh_ldap() with session.begin(): session.expire_all() self.assertEquals(group.users, [User.by_user_name(u'jgillard')])
def test_ldap_group(self): group_name = 'wyfp' display_name = 'My LDAP Group' out = run_client(['bkr', 'group-create', '--ldap', '--display-name', display_name, group_name]) group = Group.by_name(group_name) self.assertEquals(group.ldap, True) self.assertEquals(group.users, [User.by_user_name(u'asaha')]) with session.begin(): rand_user = data_setup.create_user(password = '******') rand_client_config = create_client_config(username=rand_user.user_name, password='******') group_name = 'alp' display_name = 'ALP' try: out = run_client(['bkr', 'group-create', '--ldap', '--display-name', display_name, group_name], config = rand_client_config) self.fail('Must fail or die') except ClientError, e: self.assert_('Only admins can create LDAP groups' in e.stderr_output)
def test_ldap_group(self): if not config.get("identity.ldap.enabled", False): raise SkipTest('Server is not configured for LDAP') group_name = u'wyfp' display_name = u'My LDAP Group' out = run_client(['bkr', 'group-create', '--ldap', '--display-name', display_name, group_name]) group = Group.by_name(group_name) self.assertEquals(group.membership_type, GroupMembershipType.ldap) self.assertEquals(group.users, [User.by_user_name(u'asaha')]) with session.begin(): rand_user = data_setup.create_user(password = '******') rand_client_config = create_client_config(username=rand_user.user_name, password='******') group_name = u'alp' display_name = u'ALP' try: out = run_client(['bkr', 'group-create', '--ldap', '--display-name', display_name, group_name], config = rand_client_config) self.fail('Must fail or die') except ClientError, e: self.assert_('Only admins can create LDAP groups' in e.stderr_output)
def test_reject_expired_root_password(self): with session.begin(): ConfigItem.by_name('root_password_validity').set(90, user=User.by_user_name(data_setup.ADMIN_USER)) self.user.root_password = '******' self.user.rootpw_changed = datetime.datetime.utcnow() - datetime.timedelta(days=99) job_xml = ''' <job> <whiteboard>job for user with expired password</whiteboard> <recipeSet> <recipe> <distroRequires> <distro_name op="=" value="BlueShoeLinux5-5" /> <distro_arch op="=" value="i386" /> </distroRequires> <hostRequires/> <task name="/distribution/install" /> <task name="/distribution/reservesys" /> </recipe> </recipeSet> </job> ''' try: self.server.jobs.upload(job_xml) self.fail('should raise') except xmlrpclib.Fault, e: self.assert_('root password has expired' in e.faultString)
def login_oauth2(self, access_token, proxy_user=None): """ Authenticates the current session using OAuth2. The caller may act as a proxy on behalf of another user by passing the *proxy_user* argument. This requires that the caller has 'proxy_auth' permission. :param access_token: The OAuth2 access token :type access_token: string :param proxy_user: username on whose behalf the caller is proxying :type proxy_user: string or None """ token_info_resp = requests.post( self.OAUTH2_TOKEN_INFO_URL, timeout=get('identity.soldapprovider.timeout'), data={'client_id': self.OAUTH2_CLIENT_ID, 'client_secret': self.OAUTH2_CLIENT_SECRET, 'token': access_token}) token_info_resp.raise_for_status() token_info = token_info_resp.json() if not token_info['active']: raise LoginException(_(u'Invalid token')) if not 'https://beaker-project.org/oidc/scope' in token_info.get('scope', '').split(' '): raise LoginException(_(u'Token missing required scope')) username = token_info.get('sub') if not username: raise LoginException(_(u'Token missing subject')) user = User.by_user_name(username) if user is None: raise LoginException(_(u'Invalid username')) if not user.can_log_in(): raise LoginException(_(u'Invalid username')) if proxy_user: if not user.has_permission(u'proxy_auth'): raise LoginException(_(u'%s does not have proxy_auth permission') % user.user_name) proxied_user = User.by_user_name(proxy_user) if proxied_user is None: raise LoginException(_(u'Proxy user %s does not exist') % proxy_user) identity.set_authentication(proxied_user, proxied_by=user) else: identity.set_authentication(user) return username
def validate_python(self, form_fields, state): user_id = form_fields.get('user_id') email_address = form_fields['email_address'] try: if not user_id: # New user try: User.by_email_address(email_address) except NoResultFound: pass else: raise ValueError else: _check_user_email(email_address, user_id) except ValueError: error = {'email_address' : self.message('not_unique', state)} raise Invalid('Email address is not unique', form_fields, state, error_dict=error)
def validate_python(self, form_fields, state): user_id = form_fields['user_id'] user_name = form_fields['user_name'] existing_user = User.by_user_name(user_name) try: if not user_id: # New user if existing_user: # with a duplicate name raise ValueError else: if existing_user: current_user = User.by_id(user_id) if current_user != existing_user: raise ValueError except ValueError: error = {'user_name': self.message('not_unique', state)} raise Invalid('Login name is not unique', form_fields, state, error_dict=error)
def check_authentication(): """ Checks the current request for: * REMOTE_USER in the WSGI environment, indicating that the container has already authenticated the request for us; or * a valid signed token, indicating that the user has authenticated to us successfully on a previous request. Sets up the "current identity" state according to what's found. """ if 'REMOTE_USER' in flask.request.environ: # strip realm if present user_name, _, realm = flask.request.environ['REMOTE_USER'].partition( '@') proxied_by_user_name = None elif _token_cookie_name in flask.request.cookies: token = flask.request.cookies[_token_cookie_name] if token == 'deleted': return token_value = _check_token(token) if not token_value or 'user_name' not in token_value: return user_name = token_value['user_name'] proxied_by_user_name = token_value.get('proxied_by_user_name', None) else: return from bkr.server.model import User user = User.by_user_name(user_name.decode('utf8')) if user is None: return if not user.can_log_in(): return if proxied_by_user_name is not None: proxied_by_user = User.by_user_name( proxied_by_user_name.decode('utf8')) if proxied_by_user is None: return if not proxied_by_user.can_log_in(): return else: proxied_by_user = None flask.g._beaker_validated_user = user flask.g._beaker_proxied_by_user = proxied_by_user
def run(self): with app.test_request_context('/RPC2'): session.begin() self.ready_evt.set() self.start_evt.wait() lc_user = User.by_user_name(self.lc_user_name) identity.set_authentication(lc_user) controller.add_distro_tree(self.distro_data) self.commit_evt.wait() session.commit() self.success = True
def unremove(self, id, **kw): try: user = User.by_id(id) except InvalidRequestError: flash(_(u'Invalid user id %s' % id)) raise redirect('.') flash(_(u'%s Re-Added') % user.display_name) try: self._unremove(user=user) except BX, e: flash(_(u'Failed to Re-Add User %s, due to %s' % e))
def test_list_policy_filter_mine(self): with session.begin(): self.system.custom_access_policy.add_rule( permission=SystemPermission.edit_system, user=\ User.by_user_name(data_setup.ADMIN_USER)) out = run_client(['bkr', 'policy-list', '--mine', self.system.fqdn]) expected_output = self.gen_expected_pretty_table( (['edit_system', 'admin', 'X', 'No'], )) + '\n' self.assertEquals(out, expected_output)
def test_cannot_provision_automated_system(self): with session.begin(): system = data_setup.create_system( owner=User.by_user_name(data_setup.ADMIN_USER), status=u'Automated', shared=True) user = data_setup.create_user(password=u'password') self.server.auth.login_password(user.user_name, 'password') try: self.server.systems.provision(system.fqdn, 'distro') except xmlrpclib.Fault, e: self.assertIn('Reserve a system before provisioning', e.faultString)
def remove(self, id, **kw): try: user = User.by_id(id) except InvalidRequestError: flash(_(u'Invalid user id %s' % id)) raise redirect('.') try: self._remove(user=user, method='WEBUI') except BX, e: flash( _(u'Failed to remove User %s, due to %s' % (user.user_name, e))) raise redirect('.')
def test_system_pool_activity(self): with session.begin(): pool1 = data_setup.create_system_pool() act1 = pool1.record_activity(service=u'testdata', user=User.by_user_name( data_setup.ADMIN_USER), action=u'Nothing', field=u'Nonsense', old=u'asdf', new=u'omgwtfbbq') pool2 = data_setup.create_system_pool() act2 = pool2.record_activity(service=u'testdata', user=User.by_user_name( data_setup.ADMIN_USER), action=u'Nothing', field=u'Nonsense', old=u'asdf', new=u'lollercopter') b = self.browser b.get(get_server_base() + 'activity/pool') b.find_element_by_class_name('search-query').send_keys('pool.name:%s' % pool1.name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2]) # search by pool owner b.get(get_server_base() + 'activity/pool') b.find_element_by_class_name('search-query').send_keys( 'pool.owner.user_name:%s' % pool2.owner.user_name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act2], absent=[act1]) with session.begin(): pool1.owning_user = None pool1.owning_group = data_setup.create_group() b.get(get_server_base() + 'activity/pool') b.find_element_by_class_name('search-query').send_keys( 'pool.owner.group_name:%s' % pool1.owner.group_name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2])
def test_create_system_set_condition(self): fqdn = data_setup.unique_name(u'mysystem%s') with session.begin(): lc = data_setup.create_labcontroller() run_client([ 'bkr', 'system-create', fqdn, '--lab-controller', str(lc.fqdn), '--condition=Automated' ]) with session.begin(): system = System.by_fqdn(fqdn, User.by_user_name(u'admin')) self.assertTrue(system.lab_controller, lc) self.assertEquals(str(system.status), u'Automated')
def create_user(): """ Creates a new user account in Beaker. """ data = read_json_request(request) with convert_internal_errors(): new_user_name = data.get('user_name', '').strip() existing_user = User.by_user_name(new_user_name) if existing_user is not None: raise Conflict409('User %s already exists' % new_user_name) new_display_name = data.get('display_name', '').strip() new_email_address = data.get('email_address', '').strip() user = User(user_name=new_user_name, display_name=new_display_name, email_address=new_email_address) session.add(user) session.flush() # to populate id response = jsonify(user_full_json(user)) response.status_code = 201 response.headers.add('Location', absolute_url(user.href)) return response
def test_cannot_reserve_system_in_use(self): with session.begin(): user = data_setup.create_user(password=u'password') system = data_setup.create_system(owner=user, status=u'Manual', shared=True) system.user = User.by_user_name(data_setup.ADMIN_USER) server = self.get_server() server.auth.login_password(user.user_name, 'password') try: server.systems.reserve(system.fqdn) self.fail('should raise') except xmlrpclib.Fault, e: self.assertIn('already reserved', e.faultString)
def setup_openstack(): with session.begin(): data_setup.create_openstack_region() session.flush() # Use a distinctive guest name prefix to give us a greater chance of # tracking instances back to the test run which created them. admin_user = User.by_user_name(data_setup.ADMIN_USER) guest_name_prefix = u'beaker-testsuite-%s-%s-' % ( datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S'), socket.gethostname()) ConfigItem.by_name(u'guest_name_prefix').set(guest_name_prefix, user=admin_user) ipxe_image.upload_image(_glance(), visibility=u'private')
def login_password(): """ Authenticates the current session using the given username and password. The caller may act as a proxy on behalf of another user by passing the *proxy_user* key. This requires that the caller has 'proxy_auth' permission. The request body must be a JSON object containing username and password. Proxy_user is optional. :jsonparam string username: Username :jsonparam string password: Password :jsonparam string proxy_user: Username on whose behalf the caller is proxying """ payload = read_json_request(request) username = payload.get('username') password = payload.get('password') proxy_user = payload.get('proxy_user') user = User.by_user_name(username) if user is None: raise Unauthorised401(u'Invalid username or password') if not user.can_log_in(): raise Unauthorised401(u'Invalid username or password') if not user.check_password(password): raise Unauthorised401(u'Invalid username or password') if proxy_user: if not user.has_permission(u'proxy_auth'): raise Unauthorised401(u'%s does not have proxy_auth permission' % user.user_name) proxied_user = User.by_user_name(proxy_user) if proxied_user is None: raise Unauthorised401(u'Proxy user %s does not exist' % proxy_user) identity.set_authentication(proxied_user, proxied_by=user) else: identity.set_authentication(user) return jsonify({'username': user.user_name})
def revoke_owner(self, group_id=None, id=None, **kw): if group_id is not None and id is not None: group = Group.by_id(group_id) user = User.by_id(id) service = 'WEBUI' else: group = Group.by_name(kw['group_name']) user = User.by_user_name(kw['member_name']) service = 'XMLRPC' if group.ldap: raise GroupOwnerModificationForbidden( 'An LDAP group does not have an owner') if not group.can_edit(identity.current.user): raise GroupOwnerModificationForbidden( 'You are not an owner of group %s' % group) if user not in group.users: raise GroupOwnerModificationForbidden('User is not a group member') if len(group.owners()) == 1 and not identity.current.user.is_admin(): raise GroupOwnerModificationForbidden( 'Cannot remove the only owner') else: for assoc in group.user_group_assocs: if assoc.user == user: if assoc.is_owner: assoc.is_owner = False group.record_activity(user=identity.current.user, service=service, field=u'Owner', action='Removed', old=user.user_name, new=u'') # hack to return the user removing this owner # so that if the user was logged in as a group # owner, he/she can be redirected appropriately return str(identity.current.user.user_id)
def test_create_user(self): s = requests.Session() requests_login(s) response = post_json(get_server_base() + 'users/', session=s, data={ 'user_name': 'fbaggins', 'display_name': 'Frodo Baggins', 'email_address': '*****@*****.**'}) response.raise_for_status() with session.begin(): session.expire_all() user = User.by_user_name(u'fbaggins') self.assertEqual(response.json()['id'], user.user_id) self.assertEqual(response.json()['user_name'], 'fbaggins')
def add_submission_delegate(self, **kwargs): user = identity.current.user new_delegate_name = kwargs['user']['text'] new_delegate = User.by_user_name(new_delegate_name) if not new_delegate: flash(_(u'%s is not a valid user' % new_delegate_name)) redirect('.') try: user.add_submission_delegate(new_delegate, u'WEBUI') except NoChangeException, e: flash(_(unicode(e))) redirect('.')
def grant_owner(self, group_id=None, id=None, **kw): if group_id is not None and id is not None: group = Group.by_id(group_id) user = User.by_id(id) service = 'WEBUI' else: group = Group.by_name(kw['group_name']) user = User.by_user_name(kw['member_name']) service = 'XMLRPC' if group.membership_type == GroupMembershipType.ldap: raise GroupOwnerModificationForbidden('An LDAP group does not have an owner') if not group.can_edit(identity.current.user): raise GroupOwnerModificationForbidden('You are not an owner of the group %s' % group) if user not in group.users: raise GroupOwnerModificationForbidden('User is not a group member') else: group.grant_ownership(user=user, agent=identity.current.user, service=service) return ''
def users_typeahead(): if 'q' in request.args: ldap = (len(request.args['q']) >= 3) # be nice to the LDAP server users = User.list_by_name(request.args['q'], find_anywhere=False, find_ldap_users=ldap) else: # not sure if this is wise, the response may be several hundred KB... users = User.query.filter(User.removed == None)\ .values(User.user_name, User.display_name) data = [{'user_name': user_name, 'display_name': display_name, 'tokens': [user_name]} for user_name, display_name in users] return jsonify(data=data)
def test_create_pool(self): b = self.browser login(b) b.get(get_server_base() + 'pools/') b.find_element_by_xpath('//button[normalize-space(string(.))="Create"]')\ .click() modal = b.find_element_by_class_name('modal') modal.find_element_by_name('name').send_keys('inflatable') modal.find_element_by_tag_name('form').submit() b.find_element_by_xpath('//title[text()="inflatable"]') with session.begin(): pool = SystemPool.by_name(u'inflatable') self.assertEquals(pool.owner, User.by_user_name(data_setup.ADMIN_USER))
def test_can_search_custom_service(self): with session.begin(): distro_tree = data_setup.create_distro_tree() act1 = distro_tree.record_activity(user=User.by_user_name( data_setup.ADMIN_USER), service=u'TESTSERVICE', field=u'Nonesente', old=u'sdfas', new=u'sdfa', action=u'Removed') act2 = distro_tree.record_activity(user=User.by_user_name( data_setup.ADMIN_USER), service=u'TESTSERVICE2', field=u'Noneseonce', old=u'bsdf', new=u'sdfas', action=u'Removed') b = self.browser b.get(get_server_base() + 'activity/distrotree') b.find_element_by_class_name('search-query').send_keys( 'service:TESTSERVICE') b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2])
def test_cannot_provision_system_in_use(self): with session.begin(): system = data_setup.create_system( owner=User.by_user_name(data_setup.ADMIN_USER), status=SystemStatus.manual, shared=True) user = data_setup.create_user(password=u'password') other_user = data_setup.create_user() system.user = other_user self.server.auth.login_password(user.user_name, 'password') try: self.server.systems.provision(system.fqdn, 'distro') except xmlrpclib.Fault, e: self.assert_('Reserve a system before provisioning' in e.faultString)
def delete_submission_delegate(username): """ Deletes a public SSH public key belonging to the given user account. :param username: The user's username. :param id: Database id of the SSH public key to be deleted. """ user = User.by_user_name(username) #XXX lockmode='update' if user is None: raise NotFound404('User %s does not exist' % username) if not user.can_edit(identity.current.user): raise Forbidden403('Cannot edit user %s' % user) if 'user_name' not in request.args: raise MethodNotAllowed405 submission_delegate = User.by_user_name(request.args['user_name']) if submission_delegate is None: raise NotFound404('Submission delegate %s does not exist' % request.args['user_name']) if not submission_delegate.is_delegate_for(user): raise Conflict409('User %s is not a submission delegate for %s' % (submission_delegate, user)) user.remove_submission_delegate(submission_delegate) return '', 204
def test_provision_expired_user_root_password(self): system = self.usable_system user = system.user with session.begin(): user.root_password = '******' user.rootpw_changed = datetime.datetime.utcnow() - datetime.timedelta(days=99) ConfigItem.by_name('root_password_validity')\ .set(90, user=User.by_user_name(data_setup.ADMIN_USER)) self.server.auth.login_password(user.user_name, 'password') try: self.server.systems.provision(system.fqdn, self.distro_tree.id) self.fail('should raise') except xmlrpclib.Fault, e: self.assert_('root password has expired' in e.faultString, e.faultString)
def test_cannot_release_when_not_current_user(self): with session.begin(): system = data_setup.create_system( owner=User.by_user_name(data_setup.ADMIN_USER), status=u'Manual', shared=True) user = data_setup.create_user(password=u'password') other_user = data_setup.create_user() system.reserve_manually(service=u'testdata', user=other_user) server = self.get_server() server.auth.login_password(user.user_name, 'password') try: server.systems.release(system.fqdn) self.fail('should raise') except xmlrpclib.Fault, e: self.assertIn('cannot unreserve system', e.faultString)
def remove_submission_delegate_by_name(self, delegate_name, service=u'XMLRPC'): user = identity.current.user try: submission_delegate = User.by_user_name(delegate_name) except NoResultFound: raise BX(_(u'%s is not a valid user name' % delegate_name)) try: user.remove_submission_delegate(submission_delegate, service=service) except ValueError: raise BX(_(u'%s is not a submission delegate of %s' % \ (delegate_name, user))) return delegate_name
def test_create_ldap_group(self): login(self.browser) b = self.browser b.get(get_server_base() + 'groups/new') b.find_element_by_name('group_name').send_keys('my_ldap_group') b.find_element_by_name('display_name').send_keys('My LDAP group') self.assertEquals(b.find_element_by_name('ldap').is_selected(), False) b.find_element_by_name('ldap').click() b.find_element_by_id('Group').submit() self.assertEquals(b.find_element_by_class_name('flash').text, 'OK') with session.begin(): group = Group.by_name(u'my_ldap_group') self.assertEquals(group.ldap, True) self.assertEquals(group.users, [User.by_user_name(u'my_ldap_user')])
def test_can_search_by_distro_tree_specifics(self): with session.begin(): tree1 = data_setup.create_distro_tree(arch=u'i386') act1 = tree1.record_activity(user=User.by_user_name( data_setup.ADMIN_USER), service=u'TESTSERVICE', field=u'Nonesente', old=u'sdfas', new=u'sdfa', action=u'Added') tree2 = data_setup.create_distro_tree(arch=u'x86_64') act2 = tree2.record_activity(user=User.by_user_name( data_setup.ADMIN_USER), service=u'TESTSERVICE2', field=u'Noneseonce', old=u'bsdf', new=u'sdfas', action=u'Added') b = self.browser b.get(get_server_base() + 'activity/distrotree') b.find_element_by_class_name('search-query').send_keys( 'distro_tree.arch:i386') b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2])
def test_double_release(self): with session.begin(): system = data_setup.create_system( owner=User.by_user_name(data_setup.ADMIN_USER), status=u'Manual', shared=True) user = data_setup.create_user(password=u'password') system.reserve_manually(service=u'testdata', user=user) server = self.get_server() server.auth.login_password(user.user_name, 'password') server.systems.release(system.fqdn) try: server.systems.release(system.fqdn) self.fail('should raise') except xmlrpclib.Fault, e: self.assert_('System %s is not currently reserved' % system.fqdn in e.faultString)
def test_loaned_not_free(self): with session.begin(): lc1 = data_setup.create_labcontroller() self.system_one.lab_controller = lc1 b = self.browser b.get(get_server_base() + 'free') self.assertEquals(b.title, 'Free Systems') check_system_search_results(b, present=[], absent=[self.system_one]) with session.begin(): self.system_one.loaned = User.by_user_name(data_setup.ADMIN_USER) b.get(get_server_base() + 'free') self.assertEquals(b.title, 'Free Systems') check_system_search_results(b, present=[self.system_one])
def test_can_search_by_distro_name(self): with session.begin(): distro1 = data_setup.create_distro() act1 = distro1.record_activity(service=u'testdata', user=User.by_user_name( data_setup.ADMIN_USER), action=u'Nothing', field=u'Nonsense', old=u'asdf', new=u'omgwtfbbq') distro2 = data_setup.create_distro() act2 = distro2.record_activity(service=u'testdata', user=User.by_user_name( data_setup.ADMIN_USER), action=u'Nothing', field=u'Nonsense', old=u'asdf', new=u'lollercopter') b = self.browser b.get(get_server_base() + 'activity/distro') b.find_element_by_class_name('search-query').send_keys( 'distro.name:%s' % distro1.name) b.find_element_by_class_name('grid-filter').submit() check_activity_search_results(b, present=[act1], absent=[act2])