diff --git a/fas/client/fas.conf b/fas/client/fas.conf index d878c7a..cf4fbcf 100644 --- a/fas/client/fas.conf +++ b/fas/client/fas.conf @@ -17,16 +17,17 @@ password = admin ; in 'groups' ; groups that should have a shell account on this system. -groups = accounts,fedorabugs +groups = sysadmin-main ; groups that should have a restricted account on this system. ; restricted accounts use the restricted_shell value in [users] -restricted_groups = sysadmin +restricted_groups = ; ssh_restricted_groups: groups that should be restricted by ssh key. You will ; need to disable password based logins in order for this value to have any -; security meaning -ssh_restricted_groups = sysadmin-web +; security meaning. Group types can be placed here as well, for example +; @hg,@git,@svn +ssh_restricted_groups = ; aliases_template: Gets prepended to the aliases file when it is generated by ; fasClient diff --git a/fas/client/fasClient b/fas/client/fasClient index 18f0cff..8acfa62 100755 --- a/fas/client/fasClient +++ b/fas/client/fasClient @@ -128,6 +128,7 @@ class MakeShellAccounts(BaseClient): emails = None group_mapping = {} valid_groups = {} + usernames = {} def mk_tempdir(self): self.temp = tempfile.mkdtemp('-tmp', 'fas-', config.get('global', 'temp').strip('"')) @@ -165,6 +166,10 @@ class MakeShellAccounts(BaseClient): def valid_user(self, username): ''' Is the user valid on this system ''' + if not self.valid_groups: + self.valid_groups() + if not self.group_mapping: + self.get_group_mapping() try: for restriction in self.valid_groups: for group in self.valid_groups[restriction]: @@ -238,7 +243,7 @@ class MakeShellAccounts(BaseClient): shadow_file = codecs.open(self.temp + '/shadow.txt', mode='w', encoding='utf-8') os.chmod(self.temp + '/shadow.txt', 00400) if not self.people: - self.people = self.people_list() + self.people_list() for person in self.people: username = person['username'] if self.valid_user(username): @@ -267,7 +272,7 @@ class MakeShellAccounts(BaseClient): return True return False - def usernames(self): + def get_usernames(self): usernames = {} if not self.people: self.people_list() @@ -276,35 +281,58 @@ class MakeShellAccounts(BaseClient): if self.valid_user_group(uid): username = person['username'] usernames[uid] = username - return usernames + self.usernames = usernames - def groups_text(self, groups=None, people=None): - i = 0 - file = open(self.temp + '/group.txt', 'w') - if not groups: - groups = self.group_list() - if not people: - people = self.people_list() - - ''' First create all of our users/groups combo ''' - for person in people: - uid = person['id'] - if self.valid_user_group(uid): - username = person['username'] - file.write("=%i %s:x:%i:\n" % (uid, username, uid)) - file.write("0%i %s:x:%i:\n" % (i, username, uid)) - file.write(".%s %s:x:%i:\n" % (username, username, uid)) - i = i + 1 - - usernames = self.usernames() - for group in groups: + def get_group_mapping(self): + if not self.usernames: + self.get_usernames() + for group in self.groups: gid = group['id'] name = group['name'] try: ''' Shoot me now I know this isn't right ''' members = [] for member in self.memberships[name]: - members.append(usernames[member['person_id']]) + members.append(self.usernames[member['person_id']]) + memberships = ','.join(members) + self.group_mapping[name] = members + except KeyError: + ''' No users exist in the group ''' + pass + + + def groups_text(self, groups=None, people=None): + i = 0 + file = open(self.temp + '/group.txt', 'w') + if not self.groups: + self.group_list() + if not self.people: + self.people_list() + if not self.usernames: + self.get_usernames() + if not self.group_mapping: + self.get_group_mapping() + ''' First create all of our users/groups combo ''' + for person in self.people: + uid = person['id'] + try: + if self.valid_user(self.usernames[uid]): + username = person['username'] + file.write("=%i %s:x:%i:\n" % (uid, username, uid)) + file.write("0%i %s:x:%i:\n" % (i, username, uid)) + file.write(".%s %s:x:%i:\n" % (username, username, uid)) + i = i + 1 + except KeyError: + continue + + for group in self.groups: + gid = group['id'] + name = group['name'] + try: + ''' Shoot me now I know this isn't right ''' + members = [] + for member in self.memberships[name]: + members.append(self.usernames[member['person_id']]) memberships = ','.join(members) self.group_mapping[name] = members except KeyError: @@ -314,21 +342,27 @@ class MakeShellAccounts(BaseClient): file.write("0%i %s:x:%i:%s\n" % (i, name, gid, memberships)) file.write(".%s %s:x:%i:%s\n" % (name, name, gid, memberships)) i = i + 1 - file.close() def group_list(self, search='*'): params = {'search' : search} request = self.send_request('group/list', auth=True, input=params) self.groups = request['groups'] - self.memberships = request['memberships'] + memberships = {} + for group in self.groups: + memberships[group['name']] = [] + try: + for member in request['memberships'][u'%s' % group['id']]: + memberships[group['name']].append({'person_id': member}) + except KeyError: + pass + self.memberships = memberships self.valid_groups() return self.groups def people_list(self, search='*'): params = {'search' : search} self.people = self.send_request('user/list', auth=True, input=params)['people'] - return self.people def email_list(self, search='*'): params = {'search' : search} diff --git a/fas/fas.spec b/fas/fas.spec index 2fea542..9e177fb 100644 --- a/fas/fas.spec +++ b/fas/fas.spec @@ -1,7 +1,7 @@ %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} Name: fas -Version: 0.1 +Version: 0.2 Release: 1%{?dist} Summary: Fedora Account System @@ -17,8 +17,12 @@ BuildRequires: python-setuptools-devel BuildRequires: TurboGears Requires: TurboGears >= 1.0.4 Requires: python-sqlalchemy >= 0.4 -Requires: python-turbomail +Requires: python-TurboMail Requires: python-fedora-infrastructure >= 0.2.99.2 +Requires: babel +Requires: pygpgme +Requires: python-babel +Requires: pytz %description The Fedora Account System is a web application that manages the accounts of @@ -51,11 +55,17 @@ mkdir -p $RPM_BUILD_ROOT%{_sbindir} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir} mv $RPM_BUILD_ROOT%{_bindir}/start-fas $RPM_BUILD_ROOT%{_sbindir} # Unreadable by others because it's going to contain a database password. -install -m 0600 fas.cfg $RPM_BUILD_ROOT%{_sysconfdir} +install fas.cfg $RPM_BUILD_ROOT%{_sysconfdir} %clean rm -rf $RPM_BUILD_ROOT +%pre +/usr/sbin/groupadd -r fas &>/dev/null || : +/usr/sbin/useradd -r -s /sbin/nologin -d /usr/share/fas -M \ + -c 'Fedora Acocunt System user' -g fas fas &>/dev/null || : + + %files %defattr(-,root,root,-) @@ -63,11 +73,14 @@ rm -rf $RPM_BUILD_ROOT %{python_sitelib}/* %{_datadir}/fas/ %{_sbindir}/start-fas -%config(noreplace) %{_sysconfdir}/* +%attr(0640,root,apache) %config(noreplace) %{_sysconfdir}/fas.cfg %files clients %{_bindir}/* %changelog +* Mon Mar 10 2008 Mike McGrath - 0.2-1 +- Added fas user/group + * Mon Mar 10 2008 Toshio Kuratomi - 0.1-1 - Initial Build. diff --git a/fas/fas/group.py b/fas/fas/group.py index 909a070..553fe73 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -3,6 +3,7 @@ from turbogears import controllers, expose, paginate, identity, redirect, widget from turbogears.database import session import cherrypy +import sqlalchemy import fas from fas.auth import * @@ -253,10 +254,17 @@ class Group(controllers.Controller): groups = [] re_search = re.sub(r'\*', r'%', search).lower() results = Groups.query.filter(Groups.name.like(re_search)).order_by('name').all() + if self.jsonRequest(): + membersql = sqlalchemy.select([PersonRoles.c.person_id, PersonRoles.c.group_id]).order_by(PersonRoles.c.group_id) + members = membersql.execute() + for member in members: + try: + memberships[member[1]].append(member[0]) + except KeyError: + memberships[member[1]]=[member[0]] for group in results: if canViewGroup(person, group): groups.append(group) - memberships[group.name] = group.approved_roles if not len(groups): turbogears.flash(_("No Groups found matching '%s'") % search) return dict(groups=groups, search=search, memberships=memberships) diff --git a/fas/fas/templates/group/dump.txt b/fas/fas/templates/group/dump.txt index 6679e3e..565811b 100644 --- a/fas/fas/templates/group/dump.txt +++ b/fas/fas/templates/group/dump.txt @@ -1,3 +1,3 @@ #for role in sorted(group.approved_roles) -${role.member.username},${role.member.emails['primary']},${role.member.human_name},${role.role_type} +${role.member.username},${role.member.emails['primary']},${role.member.human_name},${role.role_type},0 #end diff --git a/fas/fas/user.py b/fas/fas/user.py index cf8bb4e..7d0cead 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -5,6 +5,8 @@ import cherrypy import turbomail +import sqlalchemy + import os import re import gpgme @@ -280,10 +282,23 @@ class User(controllers.Controller): def list(self, search="a*"): '''List users ''' + re_search = re.sub(r'\*', r'%', search).lower() - people = People.query.filter(People.username.like(re_search)).order_by('username') - if people.count() < 0: - turbogears.flash(_("No users found matching '%s'") % search) + if self.jsonRequest(): + people = [] + peoplesql = sqlalchemy.select([People.c.id, People.c.username, People.c.human_name, People.c.ssh_key, People.c.password]) + persons = peoplesql.execute() + for person in persons: + people.append({ + 'id' : person[0], + 'username' : person[1], + 'human_name' : person[2], + 'ssh_key' : person[3], + 'password' : person[4]}) + else: + people = People.query.filter(People.username.like(re_search)).order_by('username') + if people.count() < 0: + turbogears.flash(_("No users found matching '%s'") % search) return dict(people=people, search=search) @identity.require(turbogears.identity.not_anonymous())