Merge branch 'master' of ssh://git.fedorahosted.org/git/fedora-infrastructure
* Fix conflict in controllers.py::logout() method.
This commit is contained in:
commit
803d0b5d2f
34 changed files with 2741 additions and 2742 deletions
1
fas/.gitignore
vendored
1
fas/.gitignore
vendored
|
@ -8,4 +8,5 @@ fas.log
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
*.swp
|
*.swp
|
||||||
|
*.mo
|
||||||
fas.egg-info
|
fas.egg-info
|
||||||
|
|
|
@ -27,7 +27,7 @@ Before you can get started, make sure to have the following packages installed
|
||||||
|
|
||||||
yum install git-core postgresql-plpython postgresql-server postgresql-python \
|
yum install git-core postgresql-plpython postgresql-server postgresql-python \
|
||||||
python-TurboMail TurboGears pygpgme python-sqlalchemy python-genshi \
|
python-TurboMail TurboGears pygpgme python-sqlalchemy python-genshi \
|
||||||
python-psycopg2
|
python-psycopg2 pytz
|
||||||
|
|
||||||
# Note: on RHEL5 you need postgresql-pl instead of postgresql-plpython
|
# Note: on RHEL5 you need postgresql-pl instead of postgresql-plpython
|
||||||
|
|
||||||
|
@ -123,4 +123,5 @@ To test, look and see if your groups or users show up with getent. For
|
||||||
example:
|
example:
|
||||||
|
|
||||||
getent passwd
|
getent passwd
|
||||||
getent group
|
getent group
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ from optparse import OptionParser
|
||||||
from shutil import move, rmtree
|
from shutil import move, rmtree
|
||||||
from rhpl.translate import _
|
from rhpl.translate import _
|
||||||
|
|
||||||
FAS_URL = 'http://localhost:8080/fas/'
|
FAS_URL = 'http://localhost:8088/fas/'
|
||||||
|
|
||||||
|
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
|
@ -78,20 +78,15 @@ class MakeShellAccounts(BaseClient):
|
||||||
temp = None
|
temp = None
|
||||||
|
|
||||||
def mk_tempdir(self):
|
def mk_tempdir(self):
|
||||||
self.temp = tempfile.mkdtemp('-tmp', 'fas-')
|
self.temp = tempfile.mkdtemp('-tmp', 'fas-', '/var/db')
|
||||||
os.chmod(self.temp, 00400)
|
|
||||||
|
|
||||||
def rm_tempdir(self):
|
def rm_tempdir(self):
|
||||||
rmtree(self.temp)
|
rmtree(self.temp)
|
||||||
|
|
||||||
def group_list(self, search='*'):
|
|
||||||
params = {'search' : search}
|
|
||||||
data = self.send_request('group/list', auth=True, input=params)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def shadow_text(self, people=None):
|
def shadow_text(self, people=None):
|
||||||
i = 0
|
i = 0
|
||||||
file = open(self.temp + '/shadow.txt', 'w')
|
file = open(self.temp + '/shadow.txt', 'w')
|
||||||
|
os.chmod(self.temp + '/shadow.txt', 00400)
|
||||||
if not people:
|
if not people:
|
||||||
people = self.people_list()
|
people = self.people_list()
|
||||||
for person in people:
|
for person in people:
|
||||||
|
@ -103,8 +98,6 @@ class MakeShellAccounts(BaseClient):
|
||||||
file.write(".%s %s:%s:99999:0:99999:7:::\n" % (username, username, password))
|
file.write(".%s %s:%s:99999:0:99999:7:::\n" % (username, username, password))
|
||||||
i = i + 1
|
i = i + 1
|
||||||
file.close()
|
file.close()
|
||||||
os.chmod(self.temp + '/shadow.txt', 00400)
|
|
||||||
|
|
||||||
|
|
||||||
def passwd_text(self, people=None):
|
def passwd_text(self, people=None):
|
||||||
i = 0
|
i = 0
|
||||||
|
@ -136,10 +129,10 @@ class MakeShellAccounts(BaseClient):
|
||||||
for person in people:
|
for person in people:
|
||||||
uid = person['id']
|
uid = person['id']
|
||||||
username = person['username']
|
username = person['username']
|
||||||
usernames['%s' % uid] = username
|
usernames[uid] = username
|
||||||
file.write("=%i %s:x:%i:\n" % (uid, username, uid))
|
file.write("=%i %s:x:%i:\n" % (uid, username, uid))
|
||||||
file.write( "0%i %s:x:%i:\n" % (i, username, uid))
|
file.write("0%i %s:x:%i:\n" % (i, username, uid))
|
||||||
file.write( ".%s %s:x:%i:\n" % (username, username, uid))
|
file.write(".%s %s:x:%i:\n" % (username, username, uid))
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
for group in groups['groups']:
|
for group in groups['groups']:
|
||||||
|
@ -149,18 +142,23 @@ class MakeShellAccounts(BaseClient):
|
||||||
try:
|
try:
|
||||||
''' Shoot me now I know this isn't right '''
|
''' Shoot me now I know this isn't right '''
|
||||||
members = []
|
members = []
|
||||||
for member in groups['memberships'][u'%s' % gid]:
|
for member in groups['memberships'][name]:
|
||||||
members.append(usernames['%s' % member['person_id']])
|
members.append(usernames[member['person_id']])
|
||||||
memberships = ','.join(members)
|
memberships = ','.join(members)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
''' No users exist in the group '''
|
''' No users exist in the group '''
|
||||||
pass
|
pass
|
||||||
file.write( "=%i %s:x:%i:%s\n" % (gid, name, gid, memberships))
|
file.write("=%i %s:x:%i:%s\n" % (gid, name, gid, memberships))
|
||||||
file.write("0%i %s:x:%i:%s\n" % (i, name, gid, memberships))
|
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))
|
file.write(".%s %s:x:%i:%s\n" % (name, name, gid, memberships))
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
def group_list(self, search='*'):
|
||||||
|
params = {'search' : search}
|
||||||
|
data = self.send_request('group/list', auth=True, input=params)
|
||||||
|
return data
|
||||||
|
|
||||||
def people_list(self, search='*'):
|
def people_list(self, search='*'):
|
||||||
params = {'search' : search}
|
params = {'search' : search}
|
||||||
|
@ -205,14 +203,11 @@ def enable():
|
||||||
if line.startswith('passwd') or line.startswith('shadow') or line.startswith('group'):
|
if line.startswith('passwd') or line.startswith('shadow') or line.startswith('group'):
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
if 'db' in parts:
|
if 'db' in parts:
|
||||||
new.write(line)
|
|
||||||
print "%s already has db enabled" % parts[0].split(':')[0]
|
print "%s already has db enabled" % parts[0].split(':')[0]
|
||||||
else:
|
else:
|
||||||
tmp = line.strip('\n')
|
line = line.strip('\n')
|
||||||
tmp = tmp + ' db\n'
|
line += ' db\n'
|
||||||
new.write(tmp)
|
new.write(line)
|
||||||
else:
|
|
||||||
new.write(line)
|
|
||||||
new.close()
|
new.close()
|
||||||
try:
|
try:
|
||||||
move('/tmp/.fas.nsswitch.conf', '/etc/nsswitch.conf')
|
move('/tmp/.fas.nsswitch.conf', '/etc/nsswitch.conf')
|
||||||
|
@ -226,13 +221,10 @@ def disable():
|
||||||
if line.startswith('passwd') or line.startswith('shadow') or line.startswith('group'):
|
if line.startswith('passwd') or line.startswith('shadow') or line.startswith('group'):
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
if 'db' in parts:
|
if 'db' in parts:
|
||||||
tmp = line.replace(' db', '')
|
line = line.replace(' db', '')
|
||||||
new.write(tmp)
|
|
||||||
else:
|
else:
|
||||||
print "%s already has db disabled" % parts[0].split(':')[0]
|
print "%s already has db disabled" % parts[0].split(':')[0]
|
||||||
new.write(line)
|
new.write(line)
|
||||||
else:
|
|
||||||
new.write(line)
|
|
||||||
new.close()
|
new.close()
|
||||||
try:
|
try:
|
||||||
move('/tmp/.fas.nsswitch.conf', '/etc/nsswitch.conf')
|
move('/tmp/.fas.nsswitch.conf', '/etc/nsswitch.conf')
|
||||||
|
@ -240,13 +232,7 @@ def disable():
|
||||||
print "ERROR: Could not write nsswitch.conf - %s" % e
|
print "ERROR: Could not write nsswitch.conf - %s" % e
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if opts.enable:
|
if opts.install:
|
||||||
enable()
|
|
||||||
sys.exit()
|
|
||||||
elif opts.disable:
|
|
||||||
disable()
|
|
||||||
sys.exit()
|
|
||||||
elif opts.install:
|
|
||||||
try:
|
try:
|
||||||
fas = MakeShellAccounts(FAS_URL, 'admin', 'admin', False)
|
fas = MakeShellAccounts(FAS_URL, 'admin', 'admin', False)
|
||||||
except AuthError, e:
|
except AuthError, e:
|
||||||
|
@ -263,5 +249,9 @@ if __name__ == '__main__':
|
||||||
if not opts.no_shadow:
|
if not opts.no_shadow:
|
||||||
fas.install_shadow_db()
|
fas.install_shadow_db()
|
||||||
fas.rm_tempdir()
|
fas.rm_tempdir()
|
||||||
else:
|
if opts.enable:
|
||||||
|
enable()
|
||||||
|
if opts.disable:
|
||||||
|
disable()
|
||||||
|
if not (opts.install or opts.enable or opts.disable):
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#mail.server = 'bastion.fedora.phx.redhat.com'
|
#mail.server = 'bastion.fedora.phx.redhat.com'
|
||||||
#base_url_filter.base_url = "http://192.168.2.101:8080"
|
#base_url_filter.base_url = "http://192.168.2.101:8080"
|
||||||
|
|
||||||
|
fas.url = 'http://localhost:8088/fas/'
|
||||||
mail.on = True
|
mail.on = True
|
||||||
mail.server = 'bastion.fedora.phx.redhat.com'
|
mail.server = 'bastion.fedora.phx.redhat.com'
|
||||||
mail.testmode = True
|
mail.testmode = True
|
||||||
|
|
|
@ -59,6 +59,8 @@ genshi.encoding="utf-8"
|
||||||
# i18n
|
# i18n
|
||||||
session_filter.on = True
|
session_filter.on = True
|
||||||
i18n.run_template_filter = True
|
i18n.run_template_filter = True
|
||||||
|
i18n.domain = 'fas'
|
||||||
|
i18n.locale_dir = 'po'
|
||||||
|
|
||||||
# VISIT TRACKING
|
# VISIT TRACKING
|
||||||
# Each visit to your application will be assigned a unique visit ID tracked via
|
# Each visit to your application will be assigned a unique visit ID tracked via
|
||||||
|
|
|
@ -5,6 +5,7 @@ from cherrypy import request, response
|
||||||
|
|
||||||
from turbogears import exception_handler
|
from turbogears import exception_handler
|
||||||
import turbogears
|
import turbogears
|
||||||
|
import cherrypy
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from fas.user import User
|
from fas.user import User
|
||||||
|
@ -24,6 +25,17 @@ def add_custom_stdvars(vars):
|
||||||
|
|
||||||
turbogears.view.variable_providers.append(add_custom_stdvars)
|
turbogears.view.variable_providers.append(add_custom_stdvars)
|
||||||
|
|
||||||
|
def get_locale(locale=None):
|
||||||
|
if locale:
|
||||||
|
return locale
|
||||||
|
if turbogears.identity.current.user_name:
|
||||||
|
person = People.by_username(turbogears.identity.current.user_name)
|
||||||
|
return person.locale
|
||||||
|
else:
|
||||||
|
return turbogears.i18n.utils._get_locale()
|
||||||
|
|
||||||
|
config.update({'i18n.get_locale': get_locale})
|
||||||
|
|
||||||
# from fas import json
|
# from fas import json
|
||||||
# import logging
|
# import logging
|
||||||
# log = logging.getLogger("fas.controllers")
|
# log = logging.getLogger("fas.controllers")
|
||||||
|
@ -38,7 +50,7 @@ class Root(controllers.RootController):
|
||||||
cla = CLA()
|
cla = CLA()
|
||||||
json = JsonRequest()
|
json = JsonRequest()
|
||||||
help = Help()
|
help = Help()
|
||||||
# openid = OpenID()
|
#openid = OpenID()
|
||||||
|
|
||||||
# TODO: Find a better place for this.
|
# TODO: Find a better place for this.
|
||||||
os.environ['GNUPGHOME'] = config.get('gpghome')
|
os.environ['GNUPGHOME'] = config.get('gpghome')
|
||||||
|
@ -110,3 +122,11 @@ class Root(controllers.RootController):
|
||||||
# is better.
|
# is better.
|
||||||
return dict(status=True)
|
return dict(status=True)
|
||||||
raise redirect(request.headers.get("Referer", "/"))
|
raise redirect(request.headers.get("Referer", "/"))
|
||||||
|
|
||||||
|
@expose()
|
||||||
|
def language(self, locale):
|
||||||
|
locale_key = config.get("i18n.session_key", "locale")
|
||||||
|
cherrypy.session[locale_key] = locale
|
||||||
|
raise redirect(request.headers.get("Referer", "/"))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,553 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Copyright © 2007 Red Hat, Inc. All rights reserved.
|
|
||||||
#
|
|
||||||
# This copyrighted material is made available to anyone wishing to use, modify,
|
|
||||||
# copy, or redistribute it subject to the terms and conditions of the GNU
|
|
||||||
# General Public License v.2. This program is distributed in the hope that it
|
|
||||||
# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
|
|
||||||
# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
# See the GNU General Public License for more details. You should have
|
|
||||||
# received a copy of the GNU General Public License along with this program;
|
|
||||||
# if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
# Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat trademarks that are
|
|
||||||
# incorporated in the source code or documentation are not subject to the GNU
|
|
||||||
# General Public License and may only be used or replicated with the express
|
|
||||||
# permission of Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# Author(s): Mike McGrath <mmcgrath@redhat.com>
|
|
||||||
# Toshio Kuratomi <tkuratom@redhat.com>
|
|
||||||
# Ricky Zhou <ricky@fedoraproject.org>
|
|
||||||
#
|
|
||||||
|
|
||||||
'''
|
|
||||||
python-fedora, python module to interact with Fedora Infrastructure Services
|
|
||||||
'''
|
|
||||||
|
|
||||||
import ldap
|
|
||||||
from ldap import modlist
|
|
||||||
import time
|
|
||||||
from random import Random
|
|
||||||
import sha
|
|
||||||
from base64 import b64encode
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
dbName = 'fastest'
|
|
||||||
|
|
||||||
class AuthError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def retrieve_db_info(dbKey):
|
|
||||||
'''Retrieve information to connect to the db from the filesystem.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
:dbKey: The string identifying the database entry in the config file.
|
|
||||||
|
|
||||||
Returns: A dictionary containing the values to use in connecting to the
|
|
||||||
database.
|
|
||||||
|
|
||||||
Exceptions:
|
|
||||||
:IOError: Returned if the config file is not on the system.
|
|
||||||
:AuthError: Returned if there is no record found for dbKey in the
|
|
||||||
config file.
|
|
||||||
'''
|
|
||||||
# Open a filehandle to the config file
|
|
||||||
if os.environ.has_key('HOME') and os.path.isfile(
|
|
||||||
os.path.join(os.environ.get('HOME'), '.fedora-db-access')):
|
|
||||||
fh = file(os.path.join(
|
|
||||||
os.environ.get('HOME'), '.fedora-db-access'), 'r')
|
|
||||||
elif os.path.isfile('/etc/sysconfig/fedora-db-access'):
|
|
||||||
fh = file('/etc/sysconfig/fedora-db-access', 'r')
|
|
||||||
else:
|
|
||||||
raise IOError, 'fedora-db-access file does not exist.'
|
|
||||||
|
|
||||||
# Read the file until we get the information for the requested db
|
|
||||||
dbInfo = None
|
|
||||||
for line in fh.readlines():
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
line = line.strip()
|
|
||||||
if not line or line[0] == '#':
|
|
||||||
continue
|
|
||||||
pieces = line.split(None, 1)
|
|
||||||
if len(pieces) < 2:
|
|
||||||
continue
|
|
||||||
if pieces[0] == dbKey:
|
|
||||||
dbInfo = eval(pieces[1])
|
|
||||||
break
|
|
||||||
|
|
||||||
if fh:
|
|
||||||
fh.close()
|
|
||||||
if not dbInfo:
|
|
||||||
raise AuthError, 'Authentication source "%s" not configured' % (dbKey,)
|
|
||||||
return dbInfo
|
|
||||||
|
|
||||||
class Server(object):
|
|
||||||
def __init__(self, server=None, who=None, password=None):
|
|
||||||
pass
|
|
||||||
#try:
|
|
||||||
#dbInfo = retrieve_db_info(dbName)
|
|
||||||
#except IOError:
|
|
||||||
#raise AuthError, 'Authentication config file fedora-db-access is' \
|
|
||||||
#' not available'
|
|
||||||
#server = server or dbInfo['host'] or 'localhost'
|
|
||||||
#who = 'cn=%s' % (who or dbInfo['user'])
|
|
||||||
## Some db connections have no password
|
|
||||||
#password = password or dbInfo.get('password')
|
|
||||||
|
|
||||||
#self.ldapConn = ldap.open(server)
|
|
||||||
#self.ldapConn.simple_bind_s(who, password)
|
|
||||||
|
|
||||||
def add(self, base, attributes):
|
|
||||||
''' Add a new group record to LDAP instance '''
|
|
||||||
self.ldapConn.add_s(base, attributes.items())
|
|
||||||
|
|
||||||
def delete(self, base):
|
|
||||||
''' Delete target base '''
|
|
||||||
self.ldapConn.delete_s(base)
|
|
||||||
|
|
||||||
def modify(self, base, attribute, new, old=None):
|
|
||||||
''' Modify an attribute, requires write access '''
|
|
||||||
if new is None:
|
|
||||||
return None
|
|
||||||
new = unicode(new).encode('utf-8')
|
|
||||||
if new == old:
|
|
||||||
return None
|
|
||||||
|
|
||||||
#o = { attribute : old }
|
|
||||||
#n = { attribute : new }
|
|
||||||
|
|
||||||
ldif = []
|
|
||||||
ldif.append((ldap.MOD_DELETE,attribute,None))
|
|
||||||
ldif.append((ldap.MOD_ADD,attribute,new))
|
|
||||||
|
|
||||||
#ldif = ldap.modlist.modifyModlist(o, n, ignore_oldexistent=1)
|
|
||||||
# commit
|
|
||||||
self.ldapConn.modify_s(base, ldif)
|
|
||||||
|
|
||||||
def search(self, base, ldapFilter, attributes=None):
|
|
||||||
''' Basic search function '''
|
|
||||||
scope = ldap.SCOPE_SUBTREE
|
|
||||||
count = 0
|
|
||||||
timeout = 2
|
|
||||||
result_set = []
|
|
||||||
try:
|
|
||||||
result_id = self.ldapConn.search(base, scope, ldapFilter, attributes)
|
|
||||||
while True:
|
|
||||||
result_type, result_data = self.ldapConn.result(result_id, timeout)
|
|
||||||
if (result_data == []):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if result_type == ldap.RES_SEARCH_ENTRY:
|
|
||||||
result_set.append(result_data)
|
|
||||||
if len(result_set) == 0:
|
|
||||||
return
|
|
||||||
except ldap.LDAPError, e:
|
|
||||||
raise
|
|
||||||
|
|
||||||
return result_set
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Group - Contains information about a specific group, 'sysadmin' would be
|
|
||||||
# an example of a Group
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
class Group(object):
|
|
||||||
''' Group abstraction class '''
|
|
||||||
|
|
||||||
__server = Server()
|
|
||||||
__base = 'ou=FedoraGroups,dc=fedoraproject,dc=org'
|
|
||||||
|
|
||||||
def __init__(self, cn, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupRequires, fedoraGroupJoinMsg):
|
|
||||||
self.cn = cn
|
|
||||||
self.fedoraGroupDesc = fedoraGroupDesc
|
|
||||||
self.fedoraGroupOwner = fedoraGroupOwner
|
|
||||||
self.fedoraGroupType = fedoraGroupType
|
|
||||||
self.fedoraGroupNeedsSponsor = fedoraGroupNeedsSponsor
|
|
||||||
self.fedoraGroupUserCanRemove = fedoraGroupUserCanRemove
|
|
||||||
self.fedoraGroupRequires = fedoraGroupRequires
|
|
||||||
self.fedoraGroupJoinMsg = fedoraGroupJoinMsg
|
|
||||||
|
|
||||||
def __json__(self):
|
|
||||||
return {'cn': self.cn,
|
|
||||||
'fedoraGroupDesc': self.fedoraGroupDesc,
|
|
||||||
'fedoraGroupOwner': self.fedoraGroupOwner,
|
|
||||||
'fedoraGroupType': self.fedoraGroupType,
|
|
||||||
'fedoraGroupNeedsSponsor': self.fedoraGroupNeedsSponsor,
|
|
||||||
'fedoraGroupUserCanRemove': self.fedoraGroupUserCanRemove,
|
|
||||||
'fedoraGroupRequires': self.fedoraGroupRequires,
|
|
||||||
'fedoraGroupJoinMsg': self.fedoraGroupJoinMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def newGroup(self, cn, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupRequires, fedoraGroupJoinMsg):
|
|
||||||
''' Create a new group '''
|
|
||||||
attributes = { 'cn' : cn.encode('utf-8'),
|
|
||||||
'objectClass' : ('fedoraGroup'),
|
|
||||||
'fedoraGroupDesc' : fedoraGroupDesc.encode('utf-8'),
|
|
||||||
'fedoraGroupOwner' : fedoraGroupOwner.encode('utf-8'),
|
|
||||||
'fedoraGroupType' : fedoraGroupType.encode('utf-8'),
|
|
||||||
'fedoraGroupNeedsSponsor' : fedoraGroupNeedsSponsor.encode('utf-8'),
|
|
||||||
'fedoraGroupUserCanRemove' : fedoraGroupUserCanRemove.encode('utf-8'),
|
|
||||||
'fedoraGroupRequires' : fedoraGroupRequires.encode('utf-8'),
|
|
||||||
'fedoraGroupJoinMsg' : fedoraGroupJoinMsg.encode('utf-8'),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.__server.add('cn=%s,%s' % (cn, self.__base), attributes)
|
|
||||||
# attributes = {
|
|
||||||
# 'objectClass' : ('organizationalUnit', 'top'),
|
|
||||||
# 'ou' : 'FedoraGroups'
|
|
||||||
# }
|
|
||||||
# self.__server.add('ou=FedoraGroups,cn=%s,%s' % (cn, self.__base), attributes)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# UserGroup - Determines information about a user in a group, when they joined
|
|
||||||
# who their sponsor is and their approval status are examples of
|
|
||||||
# things found in this group
|
|
||||||
###############################################################################
|
|
||||||
class UserGroup(object):
|
|
||||||
''' Individual User->Group abstraction class '''
|
|
||||||
def __init__(self, fedoraRoleApprovalDate=None, fedoraRoleSponsor=None, cn=None, fedoraRoleCreationDate=None, objectClass=None, fedoraRoleType=None, fedoraRoleStatus='Not a Member', fedoraRoleDomain=None):
|
|
||||||
self.fedoraRoleApprovalDate = fedoraRoleApprovalDate
|
|
||||||
self.fedoraRoleSponsor = fedoraRoleSponsor
|
|
||||||
self.cn = cn
|
|
||||||
self.fedoraRoleCreationDate = fedoraRoleCreationDate
|
|
||||||
self.objectClass = objectClass
|
|
||||||
self.fedoraRoleType = fedoraRoleType
|
|
||||||
self.fedoraRoleStatus = fedoraRoleStatus
|
|
||||||
self.fedoraRoleDomain = fedoraRoleDomain
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Groups - Returns actual information in a group. This class actual queries
|
|
||||||
# the LDAP database.
|
|
||||||
###############################################################################
|
|
||||||
class Groups(object):
|
|
||||||
''' Class contains group information '''
|
|
||||||
__server = Server()
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
### FIXME: I don't think the username should be used this way.
|
|
||||||
self.__userName = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def byUserName(self, cn, includeUnapproved=None, unapprovedOnly=None):
|
|
||||||
''' Return list of groups a certain user is in. Default excludes all non-approved groups'''
|
|
||||||
groups = {}
|
|
||||||
if includeUnapproved:
|
|
||||||
ldapFilter = 'objectClass=FedoraRole'
|
|
||||||
elif unapprovedOnly:
|
|
||||||
ldapFilter = '(&(!(fedoraRoleStatus=approved)) (objectClass=fedoraRole))'
|
|
||||||
else:
|
|
||||||
ldapFilter = '(&(fedoraRoleStatus=approved)(objectClass=FedoraRole))'
|
|
||||||
|
|
||||||
base = 'ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % cn
|
|
||||||
try:
|
|
||||||
groupsDict = self.__server.search(base, ldapFilter)
|
|
||||||
except ldap.NO_SUCH_OBJECT:
|
|
||||||
return dict()
|
|
||||||
if not groupsDict:
|
|
||||||
groupsDict = []
|
|
||||||
for group in groupsDict:
|
|
||||||
cn = group[0][1]['cn'][0]
|
|
||||||
groups[cn] = UserGroup(
|
|
||||||
fedoraRoleApprovalDate = group[0][1]['fedoraRoleApprovalDate'][0].decode('utf8'),
|
|
||||||
fedoraRoleSponsor = group[0][1]['fedoraRoleSponsor'][0].decode('utf8'),
|
|
||||||
cn = group[0][1]['cn'][0].decode('utf8'),
|
|
||||||
fedoraRoleCreationDate = group[0][1]['fedoraRoleCreationDate'][0].decode('utf8'),
|
|
||||||
objectClass = group[0][1]['objectClass'][0].decode('utf8'),
|
|
||||||
fedoraRoleType = group[0][1]['fedoraRoleType'][0].decode('utf8'),
|
|
||||||
fedoraRoleStatus = group[0][1]['fedoraRoleStatus'][0].decode('utf8'),
|
|
||||||
fedoraRoleDomain = group[0][1]['fedoraRoleDomain'][0].decode('utf8'),
|
|
||||||
)
|
|
||||||
### FIXME: userName shouldn't be shared this way
|
|
||||||
self.__userName = cn
|
|
||||||
return groups
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def groups(self, searchExpression='*', attributes=[]):
|
|
||||||
''' Return a list of available groups '''
|
|
||||||
groups = {}
|
|
||||||
ldapFilter = 'cn=%s' % (searchExpression)
|
|
||||||
base = 'ou=FedoraGroups,dc=fedoraproject,dc=org'
|
|
||||||
groupsDict = self.__server.search(base, ldapFilter, attributes)
|
|
||||||
if groupsDict:
|
|
||||||
for group in groupsDict:
|
|
||||||
name = group[0][1]['cn'][0].decode('utf8')
|
|
||||||
groups[name] = Group(
|
|
||||||
cn = group[0][1]['cn'][0].decode('utf8'),
|
|
||||||
fedoraGroupDesc = group[0][1]['fedoraGroupDesc'][0].decode('utf8'),
|
|
||||||
fedoraGroupOwner = group[0][1]['fedoraGroupOwner'][0].decode('utf8'),
|
|
||||||
fedoraGroupType = group[0][1]['fedoraGroupType'][0].decode('utf8'),
|
|
||||||
fedoraGroupNeedsSponsor = group[0][1]['fedoraGroupNeedsSponsor'][0].decode('utf8'),
|
|
||||||
fedoraGroupUserCanRemove = group[0][1]['fedoraGroupUserCanRemove'][0].decode('utf8'),
|
|
||||||
fedoraGroupRequires = group[0][1]['fedoraGroupRequires'][0].decode('utf8'),
|
|
||||||
fedoraGroupJoinMsg = group[0][1]['fedoraGroupJoinMsg'][0].decode('utf8'))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
return groups
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def remove(self, groupName, userName=None):
|
|
||||||
''' Remove user from a group '''
|
|
||||||
### FIXME: Should require the userName instead of sharing it this way
|
|
||||||
if not userName:
|
|
||||||
userName = self.__userName
|
|
||||||
try:
|
|
||||||
g = self.byUserName(userName, includeUnapproved=True)[groupName]
|
|
||||||
except:
|
|
||||||
raise TypeError, 'User not in group %s' % groupName
|
|
||||||
try:
|
|
||||||
self.__server.delete('cn=%s+fedoraRoleType=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (g.cn, g.fedoraRoleType, userName))
|
|
||||||
except ldap.NO_SUCH_OBJECT:
|
|
||||||
self.__server.delete('cn=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (g.cn, userName))
|
|
||||||
except:
|
|
||||||
raise TypeError, 'Could Not delete %s from %s' % (userName, g.cn)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def apply(self, groupName, userName=None):
|
|
||||||
''' Apply for a group '''
|
|
||||||
|
|
||||||
if not userName:
|
|
||||||
userName = self.__userName
|
|
||||||
|
|
||||||
if groupName in self.byUserName(userName):
|
|
||||||
# Probably shouldn't be 'TypeError'
|
|
||||||
raise TypeError, 'Already in that group'
|
|
||||||
try:
|
|
||||||
self.byGroupName(groupName)
|
|
||||||
except TypeError:
|
|
||||||
raise TypeError, 'Group "%s" does not exist' % groupName
|
|
||||||
|
|
||||||
now = time.time()
|
|
||||||
|
|
||||||
attributes = { 'cn' : groupName.encode('utf-8'),
|
|
||||||
'fedoraRoleApprovaldate' : 'None',
|
|
||||||
'fedoraRoleCreationDate' : str(now),
|
|
||||||
'fedoraRoleDomain' : 'None',
|
|
||||||
'fedoraRoleSponsor' : 'None',
|
|
||||||
'fedoraRoleStatus' : 'unapproved',
|
|
||||||
'fedoraRoleType' : 'user',
|
|
||||||
'objectClass' : ('fedoraRole')}
|
|
||||||
self.__server.add('cn=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (groupName, userName), attributes)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def byGroupName(cls, cn, includeUnapproved=None, unapprovedOnly=None):
|
|
||||||
''' List users in a group. Default does not show unapproved '''
|
|
||||||
self = cls()
|
|
||||||
users = {}
|
|
||||||
if includeUnapproved:
|
|
||||||
ldapFilter = 'cn=%s' % cn
|
|
||||||
elif unapprovedOnly:
|
|
||||||
ldapFilter = '(&(cn=%s) (objectClass=fedoraRole) (!(fedoraRoleStatus=approved)))' % cn
|
|
||||||
else:
|
|
||||||
ldapFilter = '(&(cn=%s) (objectClass=fedoraRole) (fedoraRoleStatus=approved))' % cn
|
|
||||||
base = 'ou=People,dc=fedoraproject,dc=org'
|
|
||||||
attributes = ['cn']
|
|
||||||
usersDict = self.__server.search(base, ldapFilter)
|
|
||||||
try:
|
|
||||||
for user in usersDict:
|
|
||||||
userName = user[0][0].split(',')[2].split('=')[1]
|
|
||||||
|
|
||||||
users[userName] = UserGroup(
|
|
||||||
fedoraRoleApprovalDate = user[0][1]['fedoraRoleApprovalDate'][0].decode('utf8'),
|
|
||||||
fedoraRoleSponsor = user[0][1]['fedoraRoleSponsor'][0].decode('utf8'),
|
|
||||||
cn = user[0][1]['cn'][0].decode('utf8'),
|
|
||||||
fedoraRoleCreationDate = user[0][1]['fedoraRoleCreationDate'][0].decode('utf8'),
|
|
||||||
objectClass = user[0][1]['objectClass'][0].decode('utf8'),
|
|
||||||
fedoraRoleType = user[0][1]['fedoraRoleType'][0].decode('utf8'),
|
|
||||||
fedoraRoleStatus = user[0][1]['fedoraRoleStatus'][0].decode('utf8'),
|
|
||||||
fedoraRoleDomain = user[0][1]['fedoraRoleDomain'][0].decode('utf8'),
|
|
||||||
)
|
|
||||||
except TypeError:
|
|
||||||
users = {}
|
|
||||||
return users
|
|
||||||
|
|
||||||
class Person(object):
|
|
||||||
'''Information and attributes about users '''
|
|
||||||
__base = 'ou=People,dc=fedoraproject,dc=org'
|
|
||||||
__server = Server()
|
|
||||||
def __init__(self):
|
|
||||||
### FIXME: Not sure what this is used for. It might be able to go
|
|
||||||
# away. It might need to be made a public attribute.
|
|
||||||
self.__filter = ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def newPerson(self, cn, givenName, mail, telephoneNumber, postalAddress):
|
|
||||||
''' Create a new user '''
|
|
||||||
now = time.time()
|
|
||||||
attributes = { 'cn' : cn.encode('utf-8'),
|
|
||||||
'objectClass' : ('fedoraPerson', 'inetOrgPerson', 'organizationalPerson', 'person', 'top'),
|
|
||||||
'displayName' : cn.encode('utf-8'),
|
|
||||||
'sn' : cn.encode('utf-8'),
|
|
||||||
'cn' : cn.encode('utf-8'),
|
|
||||||
'fedoraPersonSshKey' : '',
|
|
||||||
'facsimileTelephoneNumber' : '',
|
|
||||||
'fedoraPersonApprovalStatus' : 'approved',
|
|
||||||
'givenName' : givenName.encode('utf-8'),
|
|
||||||
'mail' : mail.encode('utf-8'),
|
|
||||||
'fedoraPersonKeyId' : '',
|
|
||||||
'fedoraPersonCertSerial' : '-1',
|
|
||||||
'description' : '',
|
|
||||||
'fedoraPersonCreationDate' : str(now),
|
|
||||||
'telephoneNumber' : telephoneNumber.encode('utf-8'),
|
|
||||||
'fedoraPersonBugzillaMail' : mail.encode('utf-8'),
|
|
||||||
'postalAddress' : postalAddress.encode('utf-8'),
|
|
||||||
'fedoraPersonIrcNick' : '',
|
|
||||||
'userPassword' : 'Disabled',
|
|
||||||
'fedoraPersonTimeZone' : 'UTC',
|
|
||||||
}
|
|
||||||
self.__server.add('cn=%s,%s' % (cn, self.__base), attributes)
|
|
||||||
attributes = {
|
|
||||||
'objectClass' : ('organizationalUnit', 'top'),
|
|
||||||
'ou' : 'Roles'
|
|
||||||
}
|
|
||||||
self.__server.add('ou=Roles,cn=%s,%s' % (cn, self.__base), attributes)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
### FIXME: Overriding __getattr__ and __setattr__ can be tricky and have
|
|
||||||
# performance penalties. If that's okay, you may also want to consider
|
|
||||||
# inheriting from dict as that might be a better access method.
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
if attr == '__filter':
|
|
||||||
return self.__filter
|
|
||||||
if attr == 'userName':
|
|
||||||
attr = 'cn'
|
|
||||||
try:
|
|
||||||
attributes = []
|
|
||||||
attributes.append(attr)
|
|
||||||
return self.__server.search(self.__base, self.__filter, attributes)[0][0][1][attr][0].decode('utf8')
|
|
||||||
except:
|
|
||||||
# Should probably raise here.
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __setattr__(self, attr, value):
|
|
||||||
if attr.startswith('_'):
|
|
||||||
#return setattr(self.__class__, attr, value)
|
|
||||||
self.__dict__[attr] = value
|
|
||||||
return
|
|
||||||
base = 'cn=%s,ou=People,dc=fedoraproject,dc=org' % self.__getattr__('cn')
|
|
||||||
|
|
||||||
if self.__getattr__(attr):
|
|
||||||
self.__server.modify(base, attr, value, self.__getattr__(attr))
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self.__server.modify(base, attr, value)
|
|
||||||
except:
|
|
||||||
self.__server.modify(base, attr, value, self.__getattr__(attr))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def users(self, searchExpression='*', findAttr='cn'):
|
|
||||||
''' Returns a list of users '''
|
|
||||||
users = []
|
|
||||||
ldapFilter = '(&(objectClass=top)(%s=%s))' % (findAttr, searchExpression)
|
|
||||||
attributes = ['cn']
|
|
||||||
usersDict = self.__server.search(self.__base, ldapFilter, attributes)
|
|
||||||
if usersDict:
|
|
||||||
for user in usersDict:
|
|
||||||
users.append(user[0][1]['cn'][0].decode('utf8'))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
return users
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def byFilter(cls, ldapFilter):
|
|
||||||
''' Returns only the first result in the search '''
|
|
||||||
self = cls()
|
|
||||||
self.__filter = ldapFilter
|
|
||||||
return self
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def byUserName(self, cn):
|
|
||||||
'''Wrapper for byFilter - search by cn'''
|
|
||||||
return self.byFilter('cn=%s' % cn)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def auth(self, who, password, ldapServer=None):
|
|
||||||
''' Basic Authentication Module '''
|
|
||||||
if not password:
|
|
||||||
raise AuthError
|
|
||||||
if not ldapServer:
|
|
||||||
s = Server()
|
|
||||||
ldapServer = s.ldapConn
|
|
||||||
who = 'cn=%s,ou=People,dc=fedoraproject,dc=org' % who
|
|
||||||
try:
|
|
||||||
ldapServer.simple_bind_s(who, password)
|
|
||||||
except:
|
|
||||||
raise AuthError
|
|
||||||
|
|
||||||
def upgrade(self, group):
|
|
||||||
''' Upgrade user in group '''
|
|
||||||
base = 'cn=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (group, self.cn)
|
|
||||||
g = Groups.byGroupName(group, includeUnapproved=True)[self.cn]
|
|
||||||
if not g.fedoraRoleStatus.lower() == 'approved':
|
|
||||||
'''User not approved or sponsored'''
|
|
||||||
raise TypeError, 'User is not approved'
|
|
||||||
if g.fedoraRoleType.lower() == 'administrator':
|
|
||||||
raise TypeError, 'User cannot be upgraded beyond administrator'
|
|
||||||
elif g.fedoraRoleType.lower() == 'sponsor':
|
|
||||||
self.__server.modify(base, 'fedoraRoleType', 'administrator', g.fedoraRoleType)
|
|
||||||
elif g.fedoraRoleType.lower() == 'user':
|
|
||||||
self.__server.modify(base, 'fedoraRoleType', 'sponsor', g.fedoraRoleType)
|
|
||||||
|
|
||||||
def downgrade(self, group):
|
|
||||||
''' Downgrade user in group '''
|
|
||||||
base = 'cn=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (group, self.cn)
|
|
||||||
g = Groups.byGroupName(group, includeUnapproved=True)[self.cn]
|
|
||||||
if not g.fedoraRoleStatus.lower() == 'approved':
|
|
||||||
'''User not approved or sponsored'''
|
|
||||||
raise TypeError, 'User is not approved'
|
|
||||||
if g.fedoraRoleType.lower() == 'user':
|
|
||||||
raise TypeError, 'User cannot be downgraded below user, did you mean remove?'
|
|
||||||
elif g.fedoraRoleType.lower() == 'sponsor':
|
|
||||||
self.__server.modify(base, 'fedoraRoleType', 'user', g.fedoraRoleType)
|
|
||||||
elif g.fedoraRoleType.lower() == 'administrator':
|
|
||||||
self.__server.modify(base, 'fedoraRoleType', 'sponsor', g.fedoraRoleType)
|
|
||||||
|
|
||||||
def sponsor(self, groupName, sponsor):
|
|
||||||
''' Sponsor current user '''
|
|
||||||
base = 'cn=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (groupName, self.cn)
|
|
||||||
g = Groups.byGroupName(groupName, includeUnapproved=True)[self.cn]
|
|
||||||
group = Groups.groups(groupName)[groupName]
|
|
||||||
now = time.time()
|
|
||||||
self.__server.modify(base, 'fedoraRoleApprovalDate', now)
|
|
||||||
if group.fedoraGroupNeedsSponsor.lower() == 'true':
|
|
||||||
self.__server.modify(base, 'fedoraRoleSponsor', sponsor)
|
|
||||||
else:
|
|
||||||
self.__server.modify(base, 'fedoraRoleSponsor', 'None')
|
|
||||||
self.__server.modify(base, 'fedoraRoleStatus', 'approved')
|
|
||||||
|
|
||||||
def generatePassword(self,password=None,length=14,salt=''):
|
|
||||||
''' Generate Password '''
|
|
||||||
secret = {} # contains both hash and password
|
|
||||||
|
|
||||||
if not password:
|
|
||||||
rand = Random()
|
|
||||||
password = ''
|
|
||||||
# Exclude 0,O and l,1
|
|
||||||
righthand = '23456qwertasdfgzxcvbQWERTASDFGZXCVB'
|
|
||||||
lefthand = '789yuiophjknmYUIPHJKLNM'
|
|
||||||
for i in range(length):
|
|
||||||
if i%2:
|
|
||||||
password = password + rand.choice(lefthand)
|
|
||||||
else:
|
|
||||||
password = password + rand.choice(righthand)
|
|
||||||
|
|
||||||
ctx = sha.new(password)
|
|
||||||
ctx.update(salt)
|
|
||||||
secret['hash'] = "{SSHA}%s" % b64encode(ctx.digest() + salt)
|
|
||||||
secret['pass'] = password
|
|
||||||
|
|
||||||
return secret
|
|
||||||
|
|
||||||
|
|
||||||
class UserAccount:
|
|
||||||
def __init__(self):
|
|
||||||
self.realName = ''
|
|
||||||
self.userName = ''
|
|
||||||
self.primaryEmail = ''
|
|
||||||
self.groups = []
|
|
111
fas/fas/group.py
111
fas/fas/group.py
|
@ -8,8 +8,6 @@ from fas.auth import *
|
||||||
|
|
||||||
from fas.user import KnownUser
|
from fas.user import KnownUser
|
||||||
|
|
||||||
from textwrap import dedent
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
class KnownGroup(validators.FancyValidator):
|
class KnownGroup(validators.FancyValidator):
|
||||||
|
@ -152,7 +150,7 @@ class Group(controllers.Controller):
|
||||||
@expose(template="fas.templates.group.new")
|
@expose(template="fas.templates.group.new")
|
||||||
def create(self, name, display_name, owner, group_type, needs_sponsor=0, user_can_remove=1, prerequisite='', joinmsg=''):
|
def create(self, name, display_name, owner, group_type, needs_sponsor=0, user_can_remove=1, prerequisite='', joinmsg=''):
|
||||||
'''Create a group'''
|
'''Create a group'''
|
||||||
|
|
||||||
groupname = name
|
groupname = name
|
||||||
person = People.by_username(turbogears.identity.current.user_name)
|
person = People.by_username(turbogears.identity.current.user_name)
|
||||||
person_owner = People.by_username(owner)
|
person_owner = People.by_username(owner)
|
||||||
|
@ -247,14 +245,16 @@ class Group(controllers.Controller):
|
||||||
username = turbogears.identity.current.user_name
|
username = turbogears.identity.current.user_name
|
||||||
person = People.by_username(username)
|
person = People.by_username(username)
|
||||||
|
|
||||||
re_search = re.sub(r'\*', r'%', search).lower()
|
|
||||||
groups = Groups.query.filter(Groups.name.like(re_search)).order_by('name')
|
|
||||||
groups = filter(lambda group: canViewGroup(person, group), groups)
|
|
||||||
if len(groups) <= 0:
|
|
||||||
turbogears.flash(_("No Groups found matching '%s'") % search)
|
|
||||||
memberships = {}
|
memberships = {}
|
||||||
for group in groups:
|
groups = []
|
||||||
memberships[group.id] = group.approved_roles
|
re_search = re.sub(r'\*', r'%', search).lower()
|
||||||
|
results = Groups.query.filter(Groups.name.like(re_search)).order_by('name').all()
|
||||||
|
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)
|
return dict(groups=groups, search=search, memberships=memberships)
|
||||||
|
|
||||||
@identity.require(turbogears.identity.not_anonymous())
|
@identity.require(turbogears.identity.not_anonymous())
|
||||||
|
@ -284,18 +284,19 @@ class Group(controllers.Controller):
|
||||||
{'user': target.username, 'group': group.name})
|
{'user': target.username, 'group': group.name})
|
||||||
else:
|
else:
|
||||||
import turbomail
|
import turbomail
|
||||||
|
|
||||||
|
# TODO: How do we handle gettext calls for these kinds of emails?
|
||||||
# TODO: CC to right place, put a bit more thought into how to most elegantly do this
|
# TODO: CC to right place, put a bit more thought into how to most elegantly do this
|
||||||
message = turbomail.Message(config.get('accounts_mail'), '%s-sponsors@fedoraproject.org' % group.name, \
|
message = turbomail.Message(config.get('accounts_mail'), '%s-sponsors@fedoraproject.org' % group.name, \
|
||||||
"Fedora '%(group)s' sponsor needed for %(user)s" % {'user': target.username, 'group': group.name})
|
"Fedora '%(group)s' sponsor needed for %(user)s" % {'user': target.username, 'group': group.name})
|
||||||
url = config.get('base_url_filter.base_url') + turbogears.url('/group/edit/%s' % groupname)
|
url = config.get('base_url_filter.base_url') + turbogears.url('/group/edit/%s' % groupname)
|
||||||
|
|
||||||
message.plain = dedent('''
|
message.plain = _('''
|
||||||
Fedora user %(user)s, aka %(name)s <%(email)s> has requested
|
Fedora user %(user)s, aka %(name)s <%(email)s> has requested
|
||||||
membership for %(applicant)s (%(applicant_name)s) in the %(group)s group and needs a sponsor.
|
membership for %(applicant)s (%(applicant_name)s) in the %(group)s group and needs a sponsor.
|
||||||
|
|
||||||
Please go to %(url)s to take action.
|
Please go to %(url)s to take action.
|
||||||
''' % {'user': person.username, 'name': person.human_name, 'applicant': target.username, 'applicant_name': target.human_name, 'email': person.emails['primary'].email, 'url': url, 'group': group.name} )
|
''') % {'user': person.username, 'name': person.human_name, 'applicant': target.username, 'applicant_name': target.human_name, 'email': person.emails['primary'].email, 'url': url, 'group': group.name}
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%(user)s has applied to %(group)s!') % \
|
turbogears.flash(_('%(user)s has applied to %(group)s!') % \
|
||||||
{'user': target.username, 'group': group.name})
|
{'user': target.username, 'group': group.name})
|
||||||
|
@ -326,13 +327,13 @@ class Group(controllers.Controller):
|
||||||
else:
|
else:
|
||||||
import turbomail
|
import turbomail
|
||||||
message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been sponsored" % group.name)
|
message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been sponsored" % group.name)
|
||||||
message.plain = dedent('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has sponsored you for membership in the %(group)s
|
%(name)s <%(email)s> has sponsored you for membership in the %(group)s
|
||||||
group of the Fedora account system. If applicable, this change should
|
group of the Fedora account system. If applicable, this change should
|
||||||
propagate into the e-mail aliases and CVS repository within an hour.
|
propagate into the e-mail aliases and CVS repository within an hour.
|
||||||
|
|
||||||
%(joinmsg)s
|
%(joinmsg)s
|
||||||
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email, 'joinmsg': group.joinmsg}
|
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email, 'joinmsg': group.joinmsg}
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_("'%s' has been sponsored!") % person.human_name)
|
turbogears.flash(_("'%s' has been sponsored!") % person.human_name)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
|
@ -364,12 +365,12 @@ class Group(controllers.Controller):
|
||||||
else:
|
else:
|
||||||
import turbomail
|
import turbomail
|
||||||
message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been removed" % group.name)
|
message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been removed" % group.name)
|
||||||
message.plain = dedent('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has removed you from the '%(group)s'
|
%(name)s <%(email)s> has removed you from the '%(group)s'
|
||||||
group of the Fedora Accounts System This change is effective
|
group of the Fedora Accounts System This change is effective
|
||||||
immediately for new operations, and should propagate into the e-mail
|
immediately for new operations, and should propagate into the e-mail
|
||||||
aliases within an hour.
|
aliases within an hour.
|
||||||
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email}
|
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email}
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%(name)s has been removed from %(group)s!') % \
|
turbogears.flash(_('%(name)s has been removed from %(group)s!') % \
|
||||||
{'name': target.username, 'group': group.name})
|
{'name': target.username, 'group': group.name})
|
||||||
|
@ -406,12 +407,12 @@ class Group(controllers.Controller):
|
||||||
# Should we make person.upgrade return this?
|
# Should we make person.upgrade return this?
|
||||||
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
||||||
status = role.role_type
|
status = role.role_type
|
||||||
message.plain = dedent('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has upgraded you to %(status)s status in the
|
%(name)s <%(email)s> has upgraded you to %(status)s status in the
|
||||||
'%(group)s' group of the Fedora Accounts System This change is
|
'%(group)s' group of the Fedora Accounts System This change is
|
||||||
effective immediately for new operations, and should propagate
|
effective immediately for new operations, and should propagate
|
||||||
into the e-mail aliases within an hour.
|
into the e-mail aliases within an hour.
|
||||||
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email, 'status': status}
|
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email, 'status': status}
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%s has been upgraded!') % target.username)
|
turbogears.flash(_('%s has been upgraded!') % target.username)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
|
@ -443,12 +444,12 @@ class Group(controllers.Controller):
|
||||||
message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been downgraded" % group.name)
|
message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been downgraded" % group.name)
|
||||||
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
||||||
status = role.role_type
|
status = role.role_type
|
||||||
message.plain = dedent('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has downgraded you to %(status)s status in the
|
%(name)s <%(email)s> has downgraded you to %(status)s status in the
|
||||||
'%(group)s' group of the Fedora Accounts System This change is
|
'%(group)s' group of the Fedora Accounts System This change is
|
||||||
effective immediately for new operations, and should propagate
|
effective immediately for new operations, and should propagate
|
||||||
into the e-mail aliases within an hour.
|
into the e-mail aliases within an hour.
|
||||||
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email, 'status': status}
|
''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email, 'status': status}
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%s has been downgraded!') % target.username)
|
turbogears.flash(_('%s has been downgraded!') % target.username)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
|
@ -493,22 +494,22 @@ class Group(controllers.Controller):
|
||||||
|
|
||||||
if isApproved(person, group):
|
if isApproved(person, group):
|
||||||
message = turbomail.Message(person.emails['primary'].email, target, _('Come join The Fedora Project!'))
|
message = turbomail.Message(person.emails['primary'].email, target, _('Come join The Fedora Project!'))
|
||||||
message.plain = _(dedent('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has invited you to join the Fedora
|
%(name)s <%(email)s> has invited you to join the Fedora
|
||||||
Project! We are a community of users and developers who produce a
|
Project! We are a community of users and developers who produce a
|
||||||
complete operating system from entirely free and open source software
|
complete operating system from entirely free and open source software
|
||||||
(FOSS). %(name)s thinks that you have knowledge and skills
|
(FOSS). %(name)s thinks that you have knowledge and skills
|
||||||
that make you a great fit for the Fedora community, and that you might
|
that make you a great fit for the Fedora community, and that you might
|
||||||
be interested in contributing.
|
be interested in contributing.
|
||||||
|
|
||||||
How could you team up with the Fedora community to use and develop your
|
How could you team up with the Fedora community to use and develop your
|
||||||
skills? Check out http://fedoraproject.org/join-fedora for some ideas.
|
skills? Check out http://fedoraproject.org/join-fedora for some ideas.
|
||||||
Our community is more than just software developers -- we also have a
|
Our community is more than just software developers -- we also have a
|
||||||
place for you whether you're an artist, a web site builder, a writer, or
|
place for you whether you're an artist, a web site builder, a writer, or
|
||||||
a people person. You'll grow and learn as you work on a team with other
|
a people person. You'll grow and learn as you work on a team with other
|
||||||
very smart and talented people.
|
very smart and talented people.
|
||||||
|
|
||||||
Fedora and FOSS are changing the world -- come be a part of it!''')) % {'name': person.human_name, 'email': person.emails['primary'].email}
|
Fedora and FOSS are changing the world -- come be a part of it!''') % {'name': person.human_name, 'email': person.emails['primary'].email}
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('Message sent to: %s') % target)
|
turbogears.flash(_('Message sent to: %s') % target)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
|
|
|
@ -9,8 +9,13 @@ class Help(controllers.Controller):
|
||||||
'user_ircnick' : ['IRC Nick (Optional)', '<p>IRC Nick is used to identify yourself on irc.freenode.net. Please register your nick on irc.freenode.net first, then fill this in so people can find you online when they need to</p>'],
|
'user_ircnick' : ['IRC Nick (Optional)', '<p>IRC Nick is used to identify yourself on irc.freenode.net. Please register your nick on irc.freenode.net first, then fill this in so people can find you online when they need to</p>'],
|
||||||
'user_primary_email' : ['Primary Email (Required)', '<p>This email address should be your prefered email contact and will be used to send various official emails to. This is also where your @fedoraproject.org email will get forwarded</p>'],
|
'user_primary_email' : ['Primary Email (Required)', '<p>This email address should be your prefered email contact and will be used to send various official emails to. This is also where your @fedoraproject.org email will get forwarded</p>'],
|
||||||
'user_human_name' : ['Full Name (Required)', '<p>Your Human Name or "real life" name</p>'],
|
'user_human_name' : ['Full Name (Required)', '<p>Your Human Name or "real life" name</p>'],
|
||||||
'user_gpg_keyid' : ['GPG Key', '<p>Only required for users signing the CLA. It is generally used to prove that a message or email came from you or to encrypt information so that only the recipients can read it. See http://fedoraproject.org/wiki/Infrastructure/AccountSystem/CLAHowTo for more information</p>'],
|
'user_gpg_keyid' : ['GPG Key', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. It is generally used to prove that a message or email came from you or to encrypt information so that only the recipients can read it. See the <a href="http://fedoraproject.org/wiki/Infrastructure/AccountSystem/CLAHowTo">CLAHowTo</a> for more information</p>'],
|
||||||
'user_telephone' : ['Telephone', '<p>Only required for users signing the <a href="">CLA</a>. Sometimes during a time of emergency someone from the Fedora Project may need to contact you. For more information see our <a href="">Privacy Policy</a></p>'],
|
'user_telephone' : ['Telephone', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. Sometimes during a time of emergency someone from the Fedora Project may need to contact you. For more information see our <a href="http://fedoraproject.org/wiki/Legal/PrivacyPolicy">Privacy Policy</a></p>'],
|
||||||
|
'user_postal_address': ['Postal Address', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. This should be a mailing address where you can be contacted. See our <a href="http://fedoraproject.org/wiki/Legal/PrivacyPolicy">Privacy Policy</a> about any concerns.</p>'],
|
||||||
|
'user_timezone': ['Timezone (Optional)', '<p>Please specify the time zone you are in.</p>'],
|
||||||
|
'user_comments': ['Comments (Optional)', '<p>Misc comments about yourself.</p>'],
|
||||||
|
'user_account_status': ['Account Status', '<p>Shows account status, possible values include<ul><li>Valid</li><li>Disabled</li><li>Expired</li></ul></p>'],
|
||||||
|
'user_cla' : ['CLA', '<p>In order to become a full Fedora contributor you must sign a <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">Contributor License Agreement</a>. This license is a legal agreement between you and Red Hat. Full status allows people to contribute content and code and is recommended for anyone interested in getting involved in the Fedora Project. To find out more, see the <a href="http://fedoraproject.org/wiki/Infrastructure/AccountSystem/CLAHowTo">CLAHowTo</a>.</p>'],
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
Model for the Fedora Account System
|
Model for the Fedora Account System
|
||||||
'''
|
'''
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import pytz
|
||||||
from turbogears.database import metadata, mapper, get_engine
|
from turbogears.database import metadata, mapper, get_engine
|
||||||
# import some basic SQLAlchemy classes for declaring the data model
|
# import some basic SQLAlchemy classes for declaring the data model
|
||||||
# (see http://www.sqlalchemy.org/docs/04/ormtutorial.html)
|
# (see http://www.sqlalchemy.org/docs/04/ormtutorial.html)
|
||||||
|
@ -80,7 +81,7 @@ UnApprovedRolesSelect = PersonRolesTable.select(and_(
|
||||||
|
|
||||||
visits_table = Table('visit', metadata,
|
visits_table = Table('visit', metadata,
|
||||||
Column('visit_key', String(40), primary_key=True),
|
Column('visit_key', String(40), primary_key=True),
|
||||||
Column('created', DateTime, nullable=False, default=datetime.now),
|
Column('created', DateTime, nullable=False, default=datetime.now(pytz.utc)),
|
||||||
Column('expiry', DateTime)
|
Column('expiry', DateTime)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -173,7 +174,7 @@ class People(SABase):
|
||||||
role = PersonRoles.query.filter_by(member=cls, group=group).one()
|
role = PersonRoles.query.filter_by(member=cls, group=group).one()
|
||||||
role.role_status = 'approved'
|
role.role_status = 'approved'
|
||||||
role.sponsor_id = requester.id
|
role.sponsor_id = requester.id
|
||||||
role.approval = datetime.now()
|
role.approval = datetime.now(pytz.utc)
|
||||||
|
|
||||||
def remove(cls, group, requester):
|
def remove(cls, group, requester):
|
||||||
role = PersonRoles.query.filter_by(member=cls, group=group).one()
|
role = PersonRoles.query.filter_by(member=cls, group=group).one()
|
||||||
|
|
|
@ -11,7 +11,10 @@ from openid.store.filestore import FileOpenIDStore
|
||||||
|
|
||||||
from fas.auth import *
|
from fas.auth import *
|
||||||
|
|
||||||
from fas.user import knownUser, userNameExists
|
from fas.user import KnownUser
|
||||||
|
|
||||||
|
class UserID(validators.Schema):
|
||||||
|
targetname = KnownUser
|
||||||
|
|
||||||
class OpenID(controllers.Controller):
|
class OpenID(controllers.Controller):
|
||||||
|
|
||||||
|
@ -28,8 +31,8 @@ class OpenID(controllers.Controller):
|
||||||
@expose(template="fas.templates.openid.about")
|
@expose(template="fas.templates.openid.about")
|
||||||
def about(self):
|
def about(self):
|
||||||
'''Display an explanatory message about the OpenID service'''
|
'''Display an explanatory message about the OpenID service'''
|
||||||
userName = turbogears.identity.current.user_name
|
username = turbogears.identity.current.user_name
|
||||||
return dict(userName=userName)
|
return dict(username=username)
|
||||||
|
|
||||||
@expose(template="genshi-text:fas.templates.openid.auth", format="text", content_type='text/plain; charset=utf-8')
|
@expose(template="genshi-text:fas.templates.openid.auth", format="text", content_type='text/plain; charset=utf-8')
|
||||||
def server(self, **query):
|
def server(self, **query):
|
||||||
|
@ -58,10 +61,10 @@ class OpenID(controllers.Controller):
|
||||||
else:
|
else:
|
||||||
openid_response = None
|
openid_response = None
|
||||||
if openid_request.mode in BROWSER_REQUEST_MODES:
|
if openid_request.mode in BROWSER_REQUEST_MODES:
|
||||||
userName = turbogears.identity.current.user_name;
|
username = turbogears.identity.current.user_name;
|
||||||
url = None
|
url = None
|
||||||
if userName is not None:
|
if username is not None:
|
||||||
url = config.get('base_url') + turbogears.url('/openid/id/%s' % userName)
|
url = config.get('base_url') + turbogears.url('/openid/id/%s' % username)
|
||||||
if openid_request.identity == url:
|
if openid_request.identity == url:
|
||||||
if openid_request.trust_root in session['openid_trusted']:
|
if openid_request.trust_root in session['openid_trusted']:
|
||||||
openid_response = openid_request.answer(True)
|
openid_response = openid_request.answer(True)
|
||||||
|
@ -95,16 +98,15 @@ class OpenID(controllers.Controller):
|
||||||
@expose()
|
@expose()
|
||||||
def login(self):
|
def login(self):
|
||||||
'''This exists only to make the user login and then redirect to /openid/server'''
|
'''This exists only to make the user login and then redirect to /openid/server'''
|
||||||
userName = turbogears.identity.current.user_name;
|
|
||||||
turbogears.redirect('/openid/server')
|
turbogears.redirect('/openid/server')
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
|
||||||
@expose(template="fas.templates.openid.id")
|
@expose(template="fas.templates.openid.id")
|
||||||
@validate(validators=userNameExists())
|
@validate(validators=UserID())
|
||||||
def id(self, userName):
|
def id(self, username):
|
||||||
'''The "real" OpenID URL'''
|
'''The "real" OpenID URL'''
|
||||||
user = Person.byUserName(userName)
|
person = Person.by_username(username)
|
||||||
server = config.get('base_url') + turbogears.url('/openid/server')
|
server = config.get('base_url') + turbogears.url('/openid/server')
|
||||||
return dict(user=user, server=server)
|
return dict(person=person, server=server)
|
||||||
|
|
||||||
|
|
|
@ -126,10 +126,6 @@ class SaFasIdentityProvider(SqlAlchemyIdentityProvider):
|
||||||
log.info(_("Loading: %(visitmod)s") % \
|
log.info(_("Loading: %(visitmod)s") % \
|
||||||
{'visitmod': visit_identity_class_path})
|
{'visitmod': visit_identity_class_path})
|
||||||
visit_identity_class = load_class(visit_identity_class_path)
|
visit_identity_class = load_class(visit_identity_class_path)
|
||||||
# Default encryption algorithm is to use plain text passwords
|
|
||||||
algorithm = config.get("identity.saprovider.encryption_algorithm", None)
|
|
||||||
self.encrypt_password = lambda pw: \
|
|
||||||
identity._encrypt_password(algorithm, pw)
|
|
||||||
|
|
||||||
def create_provider_model(self):
|
def create_provider_model(self):
|
||||||
'''
|
'''
|
||||||
|
@ -190,7 +186,6 @@ class SaFasIdentityProvider(SqlAlchemyIdentityProvider):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
return user.password == crypt.crypt(password, user.password)
|
return user.password == crypt.crypt(password, user.password)
|
||||||
return user.password == self.encrypt_password(password)
|
|
||||||
|
|
||||||
def load_identity(self, visit_key):
|
def load_identity(self, visit_key):
|
||||||
'''Lookup the principal represented by visit_key.
|
'''Lookup the principal represented by visit_key.
|
||||||
|
|
|
@ -189,6 +189,21 @@ a
|
||||||
background: #082C59;
|
background: #082C59;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#language
|
||||||
|
{
|
||||||
|
padding: 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#language label
|
||||||
|
{
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#language input
|
||||||
|
{
|
||||||
|
width: 4ex;
|
||||||
|
}
|
||||||
|
|
||||||
#content
|
#content
|
||||||
{
|
{
|
||||||
margin-left: 22ex;
|
margin-left: 22ex;
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
<?python
|
<?python
|
||||||
from fas import auth
|
from fas import auth
|
||||||
from fas.model import People
|
from fas.model import People
|
||||||
|
import pytz
|
||||||
person = People.by_username(tg.identity.user.username)
|
person = People.by_username(tg.identity.user.username)
|
||||||
|
timezone = pytz.timezone(person.timezone)
|
||||||
?>
|
?>
|
||||||
<h2>${group.display_name} (${group.name})</h2>
|
<h2>${group.display_name} (${group.name})</h2>
|
||||||
<h3>
|
<h3>
|
||||||
|
@ -70,12 +72,8 @@
|
||||||
<td><a href="${tg.url('/user/view/%s' % role.member.username)}">${role.member.username}</a></td>
|
<td><a href="${tg.url('/user/view/%s' % role.member.username)}">${role.member.username}</a></td>
|
||||||
<td py:if='not(role.member.username == "None")'><a href="${tg.url('/user/view/%s' % role.member.username)}">${role.member.username}</a></td>
|
<td py:if='not(role.member.username == "None")'><a href="${tg.url('/user/view/%s' % role.member.username)}">${role.member.username}</a></td>
|
||||||
<td py:if='role.member.username == "None"'>${_('None')}</td>
|
<td py:if='role.member.username == "None"'>${_('None')}</td>
|
||||||
<?python
|
<td>${role.creation.astimezone(timezone).strftime('%Y-%m-%d %H:%M:%S %Z')}</td>
|
||||||
from datetime import datetime
|
<td>${role.approval.astimezone(timezone).strftime('%Y-%m-%d %H:%M:%S %Z')}</td>
|
||||||
from pytz import timezone
|
|
||||||
?>
|
|
||||||
<td>${role.creation}</td>
|
|
||||||
<td>${role.approval}</td>
|
|
||||||
<td>${role.role_status}</td>
|
<td>${role.role_status}</td>
|
||||||
<td>${role.role_type}</td>
|
<td>${role.role_type}</td>
|
||||||
<!-- This section includes all action items -->
|
<!-- This section includes all action items -->
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
<head py:match="head" py:attrs="select('@*')">
|
<head py:match="head" py:attrs="select('@*')">
|
||||||
<link href="${tg.url('/static/css/style.css')}" rel="stylesheet" type="text/css" />
|
<link href="${tg.url('/static/css/style.css')}" rel="stylesheet" type="text/css" />
|
||||||
<meta py:replace="select('*|text()')" />
|
<meta py:replace="select('*|text()')" />
|
||||||
<script type="text/javascript" src="/static/js/prototype.js"></script>
|
<script type="text/javascript" src="${tg.url('/static/js/prototype.js')}"></script>
|
||||||
<script type="text/javascript" src="/static/js/prototype.improvements.js"></script>
|
<script type="text/javascript" src="${tg.url('/static/js/prototype.improvements.js')}"></script>
|
||||||
<script type="text/javascript" src="/static/js/scriptaculous.js"></script>
|
<script type="text/javascript" src="${tg.url('/static/js/scriptaculous.js?load=effects')}"></script>
|
||||||
<script type="text/javascript" language="JavaScript" src="/static/js/HelpBalloon.js"></script>
|
<script type="text/javascript" src="${tg.url('/static/js/HelpBalloon.js')}"></script>
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
@ -64,6 +64,13 @@
|
||||||
<li><a href="${tg.url('/group/list/A*')}">${_('Apply For a new Group')}</a></li>
|
<li><a href="${tg.url('/group/list/A*')}">${_('Apply For a new Group')}</a></li>
|
||||||
<li><a href="http://fedoraproject.org/wiki/FWN/LatestIssue">${_('News')}</a></li>
|
<li><a href="http://fedoraproject.org/wiki/FWN/LatestIssue">${_('News')}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div py:if="tg.identity.anonymous" id="language">
|
||||||
|
<form action="${tg.url('/language')}" method="get">
|
||||||
|
<label for="locale">${_('Locale:')}</label>
|
||||||
|
<input type="text" name="locale" id="locale" />
|
||||||
|
<input type="submit" value="${_('OK')}" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div py:if="tg_flash" class="flash">
|
<div py:if="tg_flash" class="flash">
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
<title>${_('Fedora Accounts System')}</title>
|
<title>${_('Fedora Accounts System')}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>${_{'Fedora Project OpenID Provider')}</h2>
|
<h2>${_('Fedora Project OpenID Provider')}</h2>
|
||||||
<p>
|
<p>
|
||||||
${Markup_('Description goes here, <a href="http://username.fedorapeople.org/">username.fedorapeople.org</a>'))}
|
${Markup_('Description goes here, <a href="http://username.fedorapeople.org/">username.fedorapeople.org</a>')}
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,13 +8,13 @@
|
||||||
<link rel="openid.server" href="${server}" />
|
<link rel="openid.server" href="${server}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>${_('User %s') % user.cn}</h2>
|
<h2>${_('User %s') % person.username}</h2>
|
||||||
<div class="userbox">
|
<div class="userbox">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>${_('Username:')}</dt>
|
<dt>${_('Username:')}</dt>
|
||||||
<dd>${user.cn}</dd>
|
<dd>${person.username}</dd>
|
||||||
<dt>${_('Name:')}</dt>
|
<dt>${_('Name:')}</dt>
|
||||||
<dd>${user.givenName}</dd>
|
<dd>${person.human_name}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<input type="hidden" id="url" name="url" value="${url}" />
|
<input type="hidden" id="url" name="url" value="${url}" />
|
||||||
<input type="checkbox" id="trusted" name="trusted" value="allow" />
|
<input type="checkbox" id="trusted" name="trusted" value="allow" />
|
||||||
<label for="trusted">${Markup(_('Allow <strong>%s</strong> to authenticate to your OpenID identity?') % url)}</label><br />
|
<label for="trusted">${Markup(_('Allow <strong>%s</strong> to authenticate to your OpenID identity?') % url)}</label><br />
|
||||||
<input type="submit" value="${_('Submit'}" />
|
<input type="submit" value="${_('Submit')}" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -41,7 +41,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="postal_address">${_('Postal Address')}:</label>
|
<label for="postal_address">${_('Postal Address')}:</label>
|
||||||
<textarea id="postal_address" name="postal_address">${target.postal_address}</textarea>
|
<textarea id="postal_address" name="postal_address">${target.postal_address}</textarea>
|
||||||
|
<script type="text/javascript">var hb6 = new HelpBalloon({dataURL: '/fas/help/get_help/user_postal_address'});</script>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="timezone">${_('Time Zone')}:</label>
|
<label for="timezone">${_('Time Zone')}:</label>
|
||||||
|
@ -51,10 +52,22 @@
|
||||||
?>
|
?>
|
||||||
<option py:for="tz in common_timezones" value="${tz}" py:attrs="{'selected': target.timezone == tz and 'selected' or None}">${tz}</option>
|
<option py:for="tz in common_timezones" value="${tz}" py:attrs="{'selected': target.timezone == tz and 'selected' or None}">${tz}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<script type="text/javascript">var hb7 = new HelpBalloon({dataURL: '/fas/help/get_help/user_timezone'});</script>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="locale">${_('Locale')}:</label>
|
||||||
|
<input type="text" id="locale" name="locale" value="${target.locale}" />
|
||||||
|
<!--
|
||||||
|
<select id="locale" name="locale">
|
||||||
|
option py:for="locale in available_locales" value="${locale}" py:attrs="{'selected': target.locale == locale and 'selected' or None}">${locale}</option>
|
||||||
|
</select>
|
||||||
|
-->
|
||||||
|
<!--<script type="text/javascript">var hb7 = new HelpBalloon({dataURL: '/fas/help/get_help/locale'});</script>-->
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="comments ">${_('Comments')}:</label>
|
<label for="comments ">${_('Comments')}:</label>
|
||||||
<textarea id="comments" name="comments">${target.comments}</textarea>
|
<textarea id="comments" name="comments">${target.comments}</textarea>
|
||||||
|
<script type="text/javascript">var hb8 = new HelpBalloon({dataURL: '/fas/help/get_help/user_comments'});</script>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<input type="submit" value="${_('Save!')}" />
|
<input type="submit" value="${_('Save!')}" />
|
||||||
|
|
|
@ -23,12 +23,14 @@
|
||||||
<dt>${_('Postal Address:')}</dt><dd>${person.postal_address} </dd>
|
<dt>${_('Postal Address:')}</dt><dd>${person.postal_address} </dd>
|
||||||
<dt>${_('Comments:')}</dt><dd>${person.comments} </dd>
|
<dt>${_('Comments:')}</dt><dd>${person.comments} </dd>
|
||||||
<dt>${_('Password:')}</dt><dd><span class="approved">${_('Valid')}</span> <a href="${tg.url('/user/changepass')}" py:if="personal">(change)</a></dd>
|
<dt>${_('Password:')}</dt><dd><span class="approved">${_('Valid')}</span> <a href="${tg.url('/user/changepass')}" py:if="personal">(change)</a></dd>
|
||||||
<dt>${_('Account Status:')}</dt><dd><span class="approved">${_('Valid')}</span></dd>
|
<dt>${_('Account Status:')}</dt><dd><span class="approved">${_('Valid')}</span>
|
||||||
|
<script type="text/javascript">var hb1 = new HelpBalloon({dataURL: '/fas/help/get_help/user_account_status'});</script></dd>
|
||||||
<!-- cla = {None, 'signed', 'clicked'} -->
|
<!-- cla = {None, 'signed', 'clicked'} -->
|
||||||
<dt>${_('CLA:')}</dt><dd>
|
<dt>${_('CLA:')}</dt><dd>
|
||||||
<span py:if="cla == 'signed'" class="approved">${_('Signed CLA')}</span>
|
<span py:if="cla == 'signed'" class="approved">${_('Signed CLA')}</span>
|
||||||
<span py:if="cla == 'clicked'" class="approved">${_('Click-through CLA')}<py:if test="personal">(<a href="${tg.url('/cla/')}">${_('GPG Sign it!')}</a></py:if>)</span>
|
<span py:if="cla == 'clicked'" class="approved">${_('Click-through CLA')}<py:if test="personal">(<a href="${tg.url('/cla/')}">${_('GPG Sign it!')}</a></py:if>)</span>
|
||||||
<span py:if="not cla" class="unapproved">${_('Not Done')}<py:if test="personal"> (<a href="${tg.url('/cla/')}">${_('Sign it!')}</a>)</py:if></span></dd>
|
<span py:if="not cla" class="unapproved">${_('Not Done')}<py:if test="personal"> (<a href="${tg.url('/cla/')}">${_('Sign it!')}</a>)</py:if></span>
|
||||||
|
<script type="text/javascript">var hb2 = new HelpBalloon({dataURL: '/fas/help/get_help/user_cla'});</script></dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<h3 py:if="personal">${_('Your Roles')}</h3>
|
<h3 py:if="personal">${_('Your Roles')}</h3>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
from fasLDAP import add, Groups, delete
|
|
||||||
|
|
||||||
attributes = { 'cn' : 'infrastructureTest',
|
|
||||||
'fedoraRoleApprovaldate' : 'None',
|
|
||||||
'fedoraRoleCreationDate' : 'None',
|
|
||||||
'fedoraRoleDomain' : 'None',
|
|
||||||
'fedoraRoleSponsor' : 'None',
|
|
||||||
'fedoraRoleStatus' : 'unapproved',
|
|
||||||
'fedoraRoleType' : 'user',
|
|
||||||
'objectClass' : ('fedoraRole')}
|
|
||||||
print "add('cn=infrastructureTest,ou=Roles,cn=mmcgrath,ou=People,dc=fedoraproject,dc=org', attributes)"
|
|
||||||
print "delete('cn=infrastructureTest,ou=Roles,cn=mmcgrath,ou=People,dc=fedoraproject,dc=org')"
|
|
||||||
|
|
108
fas/fas/user.py
108
fas/fas/user.py
|
@ -17,8 +17,6 @@ from fas.model import Log
|
||||||
|
|
||||||
from fas.auth import *
|
from fas.auth import *
|
||||||
|
|
||||||
from textwrap import dedent
|
|
||||||
|
|
||||||
from random import Random
|
from random import Random
|
||||||
import sha
|
import sha
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
|
@ -53,9 +51,9 @@ class UnknownUser(validators.FancyValidator):
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
raise validators.Invalid(_("Error: Could not create - '%s'") % value, value, state)
|
raise validators.Invalid(_("Error: Could not create - '%s'") % value, value, state)
|
||||||
|
|
||||||
raise validators.Invalid(_("'%s' already exists.") % value, value, state)
|
raise validators.Invalid(_("'%s' already exists.") % value, value, state)
|
||||||
|
|
||||||
class ValidUsername(validators.FancyValidator):
|
class ValidUsername(validators.FancyValidator):
|
||||||
'''Make sure that a username isn't blacklisted'''
|
'''Make sure that a username isn't blacklisted'''
|
||||||
def _to_python(self, value, state):
|
def _to_python(self, value, state):
|
||||||
|
@ -75,7 +73,7 @@ class UserSave(validators.Schema):
|
||||||
#fedoraPersonBugzillaMail = validators.Email(strip=True, max=128)
|
#fedoraPersonBugzillaMail = validators.Email(strip=True, max=128)
|
||||||
#fedoraPersonKeyId- Save this one for later :)
|
#fedoraPersonKeyId- Save this one for later :)
|
||||||
postal_address = validators.String(max=512)
|
postal_address = validators.String(max=512)
|
||||||
|
|
||||||
class UserCreate(validators.Schema):
|
class UserCreate(validators.Schema):
|
||||||
username = validators.All(
|
username = validators.All(
|
||||||
UnknownUser,
|
UnknownUser,
|
||||||
|
@ -103,7 +101,7 @@ class UserView(validators.Schema):
|
||||||
|
|
||||||
class UserEdit(validators.Schema):
|
class UserEdit(validators.Schema):
|
||||||
targetname = KnownUser
|
targetname = KnownUser
|
||||||
|
|
||||||
def generate_password(password=None, length=14):
|
def generate_password(password=None, length=14):
|
||||||
''' Generate Password '''
|
''' Generate Password '''
|
||||||
secret = {} # contains both hash and password
|
secret = {} # contains both hash and password
|
||||||
|
@ -114,7 +112,7 @@ def generate_password(password=None, length=14):
|
||||||
password = ''
|
password = ''
|
||||||
for i in xrange(length):
|
for i in xrange(length):
|
||||||
password += random.choice(chars)
|
password += random.choice(chars)
|
||||||
|
|
||||||
secret['hash'] = crypt.crypt(password, "$1$%s" % generate_salt(8))
|
secret['hash'] = crypt.crypt(password, "$1$%s" % generate_salt(8))
|
||||||
secret['pass'] = password
|
secret['pass'] = password
|
||||||
|
|
||||||
|
@ -206,7 +204,7 @@ class User(controllers.Controller):
|
||||||
@validate(validators=UserSave())
|
@validate(validators=UserSave())
|
||||||
@error_handler(error)
|
@error_handler(error)
|
||||||
@expose(template='fas.templates.user.edit')
|
@expose(template='fas.templates.user.edit')
|
||||||
def save(self, targetname, human_name, telephone, postal_address, email, ircnick=None, gpg_keyid=None, comments='', timezone='UTC'):
|
def save(self, targetname, human_name, telephone, postal_address, email, ircnick=None, gpg_keyid=None, comments='', locale='en', timezone='UTC'):
|
||||||
username = turbogears.identity.current.user_name
|
username = turbogears.identity.current.user_name
|
||||||
target = targetname
|
target = targetname
|
||||||
person = People.by_username(username)
|
person = People.by_username(username)
|
||||||
|
@ -225,6 +223,7 @@ class User(controllers.Controller):
|
||||||
target.telephone = telephone
|
target.telephone = telephone
|
||||||
target.postal_address = postal_address
|
target.postal_address = postal_address
|
||||||
target.comments = comments
|
target.comments = comments
|
||||||
|
target.locale = locale
|
||||||
target.timezone = timezone
|
target.timezone = timezone
|
||||||
except TypeError:
|
except TypeError:
|
||||||
turbogears.flash(_('Your account details could not be saved: %s' % e))
|
turbogears.flash(_('Your account details could not be saved: %s' % e))
|
||||||
|
@ -245,7 +244,7 @@ class User(controllers.Controller):
|
||||||
if people.count() < 0:
|
if people.count() < 0:
|
||||||
turbogears.flash(_("No users found matching '%s'") % search)
|
turbogears.flash(_("No users found matching '%s'") % search)
|
||||||
return dict(people=people, search=search)
|
return dict(people=people, search=search)
|
||||||
|
|
||||||
@expose(template='fas.templates.user.new')
|
@expose(template='fas.templates.user.new')
|
||||||
def new(self):
|
def new(self):
|
||||||
if turbogears.identity.not_anonymous():
|
if turbogears.identity.not_anonymous():
|
||||||
|
@ -257,7 +256,7 @@ class User(controllers.Controller):
|
||||||
@error_handler(error)
|
@error_handler(error)
|
||||||
@expose(template='fas.templates.new')
|
@expose(template='fas.templates.new')
|
||||||
def create(self, username, human_name, email, telephone, postal_address):
|
def create(self, username, human_name, email, telephone, postal_address):
|
||||||
# TODO: Ensure that e-mails are unique- this should probably be done in the LDAP schema.
|
# TODO: Ensure that e-mails are unique?
|
||||||
# Also, perhaps implement a timeout- delete account
|
# Also, perhaps implement a timeout- delete account
|
||||||
# if the e-mail is not verified (i.e. the person changes
|
# if the e-mail is not verified (i.e. the person changes
|
||||||
# their password) withing X days.
|
# their password) withing X days.
|
||||||
|
@ -271,45 +270,44 @@ class User(controllers.Controller):
|
||||||
person.emails['primary'] = PersonEmails(email=email, purpose='primary')
|
person.emails['primary'] = PersonEmails(email=email, purpose='primary')
|
||||||
newpass = generate_password()
|
newpass = generate_password()
|
||||||
message = turbomail.Message(config.get('accounts_mail'), person.emails['primary'].email, _('Welcome to the Fedora Project!'))
|
message = turbomail.Message(config.get('accounts_mail'), person.emails['primary'].email, _('Welcome to the Fedora Project!'))
|
||||||
message.plain = _(dedent('''
|
message.plain = _('''
|
||||||
You have created a new Fedora account!
|
You have created a new Fedora account!
|
||||||
Your new password is: %s
|
Your new password is: %s
|
||||||
|
|
||||||
Please go to https://admin.fedoraproject.org/fas/ to change it.
|
Please go to https://admin.fedoraproject.org/fas/ to change it.
|
||||||
|
|
||||||
Welcome to the Fedora Project. Now that you've signed up for an
|
Welcome to the Fedora Project. Now that you've signed up for an
|
||||||
account you're probably desperate to start contributing, and with that
|
account you're probably desperate to start contributing, and with that
|
||||||
in mind we hope this e-mail might guide you in the right direction to
|
in mind we hope this e-mail might guide you in the right direction to
|
||||||
make this process as easy as possible.
|
make this process as easy as possible.
|
||||||
|
|
||||||
Fedora is an exciting project with lots going on, and you can
|
|
||||||
contribute in a huge number of ways, using all sorts of different
|
|
||||||
skill sets. To find out about the different ways you can contribute to
|
|
||||||
Fedora, you can visit our join page which provides more information
|
|
||||||
about all the different roles we have available.
|
|
||||||
|
|
||||||
http://fedoraproject.org/en/join-fedora
|
|
||||||
|
|
||||||
If you already know how you want to contribute to Fedora, and have
|
|
||||||
found the group already working in the area you're interested in, then
|
|
||||||
there are a few more steps for you to get going.
|
|
||||||
|
|
||||||
Foremost amongst these is to sign up for the team or project's mailing
|
|
||||||
list that you're interested in - and if you're interested in more than
|
|
||||||
one group's work, feel free to sign up for as many mailing lists as
|
|
||||||
you like! This is because mailing lists are where the majority of work
|
|
||||||
gets organised and tasks assigned, so to stay in the loop be sure to
|
|
||||||
keep up with the messages.
|
|
||||||
|
|
||||||
Once this is done, it's probably wise to send a short introduction to
|
|
||||||
the list letting them know what experience you have and how you'd like
|
|
||||||
to help. From here, existing members of the team will help you to find
|
|
||||||
your feet as a Fedora contributor.
|
|
||||||
|
|
||||||
And finally, from all of us here at the Fedora Project, we're looking
|
|
||||||
forward to working with you!
|
|
||||||
|
|
||||||
''') % newpass['pass'])
|
Fedora is an exciting project with lots going on, and you can
|
||||||
|
contribute in a huge number of ways, using all sorts of different
|
||||||
|
skill sets. To find out about the different ways you can contribute to
|
||||||
|
Fedora, you can visit our join page which provides more information
|
||||||
|
about all the different roles we have available.
|
||||||
|
|
||||||
|
http://fedoraproject.org/en/join-fedora
|
||||||
|
|
||||||
|
If you already know how you want to contribute to Fedora, and have
|
||||||
|
found the group already working in the area you're interested in, then
|
||||||
|
there are a few more steps for you to get going.
|
||||||
|
|
||||||
|
Foremost amongst these is to sign up for the team or project's mailing
|
||||||
|
list that you're interested in - and if you're interested in more than
|
||||||
|
one group's work, feel free to sign up for as many mailing lists as
|
||||||
|
you like! This is because mailing lists are where the majority of work
|
||||||
|
gets organised and tasks assigned, so to stay in the loop be sure to
|
||||||
|
keep up with the messages.
|
||||||
|
|
||||||
|
Once this is done, it's probably wise to send a short introduction to
|
||||||
|
the list letting them know what experience you have and how you'd like
|
||||||
|
to help. From here, existing members of the team will help you to find
|
||||||
|
your feet as a Fedora contributor.
|
||||||
|
|
||||||
|
And finally, from all of us here at the Fedora Project, we're looking
|
||||||
|
forward to working with you!
|
||||||
|
''') % newpass['pass']
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
person.password = newpass['pass']
|
person.password = newpass['pass']
|
||||||
turbogears.flash(_('Your password has been emailed to you. Please log in with it and change your password'))
|
turbogears.flash(_('Your password has been emailed to you. Please log in with it and change your password'))
|
||||||
|
@ -352,7 +350,7 @@ class User(controllers.Controller):
|
||||||
turbogears.flash(_('You are already logged in!'))
|
turbogears.flash(_('You are already logged in!'))
|
||||||
turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name)
|
turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name)
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
@expose(template="fas.templates.user.resetpass")
|
@expose(template="fas.templates.user.resetpass")
|
||||||
def sendpass(self, username, email, encrypted=False):
|
def sendpass(self, username, email, encrypted=False):
|
||||||
import turbomail
|
import turbomail
|
||||||
|
@ -368,13 +366,17 @@ class User(controllers.Controller):
|
||||||
return dict()
|
return dict()
|
||||||
newpass = generate_password()
|
newpass = generate_password()
|
||||||
message = turbomail.Message(config.get('accounts_mail'), email, _('Fedora Project Password Reset'))
|
message = turbomail.Message(config.get('accounts_mail'), email, _('Fedora Project Password Reset'))
|
||||||
mail = _(dedent('''
|
mail = _('''
|
||||||
You have requested a password reset!
|
You have requested a password reset!
|
||||||
Your new password is: %s
|
Your new password is: %s
|
||||||
|
|
||||||
Please go to https://admin.fedoraproject.org/fas/ to change it.
|
Please go to https://admin.fedoraproject.org/fas/ to change it.
|
||||||
''')) % newpass['pass']
|
''') % newpass['pass']
|
||||||
if encrypted:
|
if encrypted:
|
||||||
|
# TODO: Move this out to a single function (same as
|
||||||
|
# CLA one), think of how to make sure this doesn't get
|
||||||
|
# full of random keys (keep a clean Fedora keyring)
|
||||||
|
# TODO: MIME stuff?
|
||||||
try:
|
try:
|
||||||
subprocess.check_call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', person.gpg_keyid])
|
subprocess.check_call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', person.gpg_keyid])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
|
|
24
fas/fas2.sql
24
fas/fas2.sql
|
@ -51,13 +51,13 @@ CREATE TABLE people (
|
||||||
affiliation TEXT,
|
affiliation TEXT,
|
||||||
certificate_serial INTEGER DEFAULT 1,
|
certificate_serial INTEGER DEFAULT 1,
|
||||||
-- tg_user::created
|
-- tg_user::created
|
||||||
creation TIMESTAMP DEFAULT NOW(),
|
creation TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
--approval_status TEXT DEFAULT 'unapproved',
|
--approval_status TEXT DEFAULT 'unapproved',
|
||||||
internal_comments TEXT,
|
internal_comments TEXT,
|
||||||
ircnick TEXT,
|
ircnick TEXT,
|
||||||
last_seen TIMESTAMP DEFAULT NOW(),
|
last_seen TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
status TEXT,
|
status TEXT,
|
||||||
status_change TIMESTAMP DEFAULT NOW(),
|
status_change TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
locale TEXT not null DEFAULT 'C',
|
locale TEXT not null DEFAULT 'C',
|
||||||
timezone TEXT null DEFAULT 'UTC',
|
timezone TEXT null DEFAULT 'UTC',
|
||||||
latitude numeric,
|
latitude numeric,
|
||||||
|
@ -123,7 +123,7 @@ CREATE TABLE groups (
|
||||||
prerequisite_id INTEGER REFERENCES groups(id),
|
prerequisite_id INTEGER REFERENCES groups(id),
|
||||||
joinmsg TEXT NULL DEFAULT '',
|
joinmsg TEXT NULL DEFAULT '',
|
||||||
-- tg_group::created
|
-- tg_group::created
|
||||||
creation TIMESTAMP DEFAULT NOW(),
|
creation TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
check (group_type in ('bugzilla','cvs', 'bzr', 'git', 'hg', 'mtn',
|
check (group_type in ('bugzilla','cvs', 'bzr', 'git', 'hg', 'mtn',
|
||||||
'svn', 'shell', 'torrent', 'tracker', 'tracking', 'user'))
|
'svn', 'shell', 'torrent', 'tracker', 'tracking', 'user'))
|
||||||
);
|
);
|
||||||
|
@ -159,8 +159,8 @@ CREATE TABLE person_roles (
|
||||||
role_status text DEFAULT 'unapproved',
|
role_status text DEFAULT 'unapproved',
|
||||||
internal_comments text,
|
internal_comments text,
|
||||||
sponsor_id INTEGER REFERENCES people(id),
|
sponsor_id INTEGER REFERENCES people(id),
|
||||||
creation TIMESTAMP DEFAULT NOW(),
|
creation TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
approval TIMESTAMP DEFAULT NULL,
|
approval TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||||
primary key (person_id, group_id),
|
primary key (person_id, group_id),
|
||||||
check (role_status in ('approved', 'unapproved')),
|
check (role_status in ('approved', 'unapproved')),
|
||||||
check (role_type in ('user', 'administrator', 'sponsor'))
|
check (role_type in ('user', 'administrator', 'sponsor'))
|
||||||
|
@ -180,8 +180,8 @@ CREATE TABLE group_roles (
|
||||||
role_status text DEFAULT 'unapproved',
|
role_status text DEFAULT 'unapproved',
|
||||||
internal_comments text,
|
internal_comments text,
|
||||||
sponsor_id INTEGER REFERENCES people(id),
|
sponsor_id INTEGER REFERENCES people(id),
|
||||||
creation TIMESTAMP DEFAULT NOW(),
|
creation TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
approval TIMESTAMP DEFAULT NOW(),
|
approval TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
primary key (member_id, group_id),
|
primary key (member_id, group_id),
|
||||||
check (role_status in ('approved', 'unapproved')),
|
check (role_status in ('approved', 'unapproved')),
|
||||||
check (role_type in ('user', 'administrator', 'sponsor'))
|
check (role_type in ('user', 'administrator', 'sponsor'))
|
||||||
|
@ -209,7 +209,7 @@ create table bugzilla_queue (
|
||||||
create table log (
|
create table log (
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
author_id INTEGER references people(id) not null,
|
author_id INTEGER references people(id) not null,
|
||||||
changetime TIMESTAMP default NOW(),
|
changetime TIMESTAMP WITH TIME ZONE default NOW(),
|
||||||
description TEXT
|
description TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ create table requests (
|
||||||
hostname TEXT not null,
|
hostname TEXT not null,
|
||||||
ip TEXT not null,
|
ip TEXT not null,
|
||||||
action TEXT not null default 'trust_all',
|
action TEXT not null default 'trust_all',
|
||||||
last_request TIMESTAMP default now() not null,
|
last_request TIMESTAMP WITH TIME ZONE default now() not null,
|
||||||
approved boolean,
|
approved boolean,
|
||||||
unique (person_id, hostname, ip, action)
|
unique (person_id, hostname, ip, action)
|
||||||
);
|
);
|
||||||
|
@ -249,8 +249,8 @@ cluster requests_last_request_idx on requests;
|
||||||
--
|
--
|
||||||
create table visit (
|
create table visit (
|
||||||
visit_key CHAR(40) primary key,
|
visit_key CHAR(40) primary key,
|
||||||
created TIMESTAMP not null default now(),
|
created TIMESTAMP WITH TIME ZONE not null default now(),
|
||||||
expiry TIMESTAMP
|
expiry TIMESTAMP WITH TIME ZONE
|
||||||
);
|
);
|
||||||
|
|
||||||
create index visit_expiry_idx on visit(expiry);
|
create index visit_expiry_idx on visit(expiry);
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
#this is the fedoraPerson shema file for use with the Account system
|
|
||||||
#it is based on the inetOrgPerson shema, but has some spicific
|
|
||||||
#attribues added onto it for use by the Account system
|
|
||||||
#for now this is the contents
|
|
||||||
#sshkey bugzillaemail ircNick approvalStatus creationDate
|
|
||||||
dn: cn=schema
|
|
||||||
attributeTypes: ( 2.5.444.8 NAME 'fedoraPersonSshKey' DESC 'ssh key for this member' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} SINGLE-VALUE)
|
|
||||||
attributeTypes: ( 2.5.444.9 NAME 'fedoraPersonBugzillaMail' DESC 'members preferred bugzilla email address' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
|
|
||||||
attributeTypes: ( 2.5.444.16 NAME 'fedoraPersonIrcNick' DESC 'irc nick of the user on freenode' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{100} )
|
|
||||||
attributetypes: ( 2.5.444.17 NAME 'fedoraPersonCreationDate' DESC 'date entry was created' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
|
||||||
attributeTypes: ( 2.5.444.18 NAME 'fedoraPersonApprovalStatus' DESC 'users approval status' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
attributeTypes: ( 2.5.444.19 NAME 'fedoraPersonKeyId' DESC 'users GPG key ID' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
attributeTypes: ( 2.5.444.22 NAME 'fedoraPersonCertSerial' DESC 'users SSL cert serial' EQUALITY IntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
|
||||||
attributeTypes: ( 2.5.444.23 NAME 'fedoraPersonTimeZone' DESC 'time zone of the user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
attributeTypes: ( 2.5.444.24 NAME 'fedoraPersonEmailConfirm' DESC 'user email confirmation' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
attributeTypes: ( 2.5.444.25 NAME 'fedoraPersonEmailCode' DESC 'user email code' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
|
|
||||||
# fedoraPerson
|
|
||||||
# The fedoraPerson represents people who are a member of the fedora project
|
|
||||||
# in some way. It is a structural class and inherits
|
|
||||||
# from the inetOrgPerson class
|
|
||||||
objectClasses: ( 2.5.555.1 NAME 'fedoraPerson' DESC 'A member of the fedoraproject group' SUP inetOrgPerson STRUCTURAL MUST ( fedoraPersonSshKey $ mail $ fedoraPersonCreationDate $ fedoraPersonTimeZone ) MAY (fedoraPersonIrcNick $ fedoraPersonApprovalStatus $ fedoraPersonBugzillaMail $ fedoraPersonKeyId $ fedoraPersonCertSerial ) )
|
|
|
@ -1,28 +0,0 @@
|
||||||
#this is the fedoraMembership shema file for use with the Account system
|
|
||||||
#check out http://www.openldap.org/doc/admin23/schema.html#Extending%20Schema
|
|
||||||
#for more information
|
|
||||||
#for now this is the contents
|
|
||||||
#role_type
|
|
||||||
#role_domain
|
|
||||||
#role_status
|
|
||||||
#internal_comments
|
|
||||||
#sponsor (points to the sponsor's DN)
|
|
||||||
#creation (date)
|
|
||||||
#approval (date)
|
|
||||||
#don't have a name use cn instead
|
|
||||||
#attributeType ( 2.5.444.1 NAME 'name'
|
|
||||||
# DESC 'group name'
|
|
||||||
# EQUALITY caseIgnoreMatch
|
|
||||||
# SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
dn: cn=schema
|
|
||||||
attributeTypes: ( 2.5.444.2 NAME 'fedoraRoleType' DESC 'the type of role' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{25} )
|
|
||||||
attributeTypes: ( 2.5.444.15 NAME 'fedoraRoleDomain' DESC 'the domain of this role' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{15} )
|
|
||||||
attributeTypes: ( 2.5.444.3 NAME 'fedoraRoleStatus' DESC 'the approval status of this role' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{15} )
|
|
||||||
#attributeTypes: ( 2.5.444.4 NAME 'internalComments'
|
|
||||||
# DESC 'group membership comments'
|
|
||||||
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1000} )
|
|
||||||
attributeTypes: ( 2.5.444.5 NAME 'fedoraRoleSponsor' DESC 'role sponsor' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{25} )
|
|
||||||
attributeTypes: ( 2.5.444.6 NAME 'fedoraRoleCreationDate' DESC 'membership creation date' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
|
||||||
attributeTypes: ( 2.5.444.7 NAME 'fedoraRoleApprovalDate' DESC 'membership approval date' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
|
||||||
objectClasses: ( 2.5.555.2 NAME 'fedoraRole' DESC 'An object describing a persons roles with the fedora project' STRUCTURAL MUST ( cn ) MAY ( fedoraRoleApprovalDate $ fedoraRoleCreationDate $ fedoraRoleType $ fedoraRoleStatus $ fedoraRoleDomain $ fedoraRoleSponsor ) )
|
|
|
@ -1,17 +0,0 @@
|
||||||
#this is the fedora group schema file for use with the accounts system2
|
|
||||||
#it currently contains the following:
|
|
||||||
#owner (the owner's DN)
|
|
||||||
#group_type
|
|
||||||
#needs_sponsor
|
|
||||||
#user_can_remove (will be handled by ACLs, but we need to clue the interface about it)
|
|
||||||
#prerequisite_id (no idea what that is, so maybe not) -- not included yet
|
|
||||||
#joinmsg
|
|
||||||
dn: cn=schema
|
|
||||||
attributeTypes: ( 2.5.444.10 NAME 'fedoraGroupOwner' DESC 'group owner' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
attributeTypes: ( 2.5.444.11 NAME 'fedoraGroupType' DESC 'the type of group' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
attributeTypes: ( 2.5.444.12 NAME 'fedoraGroupNeedsSponsor' DESC 'boolean indicating whether or not the group needs a sponsor' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )
|
|
||||||
attributeTypes: ( 2.5.444.13 NAME 'fedoraGroupUserCanRemove' DESC 'boolean indicating whether or not the user can remove the group' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )
|
|
||||||
attributeTypes: ( 2.5.444.14 NAME 'fedoraGroupJoinMsg' DESC 'message received upon joining the group' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1000} )
|
|
||||||
attributeTypes: ( 2.5.444.21 NAME 'fedoraGroupDesc' DESC 'group description' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{100} )
|
|
||||||
attributeTypes: ( 2.5.444.20 NAME 'fedoraGroupRequires' DESC 'Requisites of this Group' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
objectClasses: ( 2.5.555.3 NAME 'fedoraGroup' DESC 'A object describing a group entry' STRUCTURAL MUST ( cn $ fedoraGroupDesc $ fedoraGroupOwner ) MAY ( fedoraGroupJoinMsg $ fedoraGroupUsercanRemove $ fedoraGroupType $ fedoraGroupNeedsSponsor $ fedoraGroupRequires ) )
|
|
|
@ -1,434 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
"""
|
|
||||||
PgToLDAP is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
PgToLDAP is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with PgToLDAP; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Id: $Id: PgToLDAP.py,v 1.5 2006/12/07 01:40:06 lyz Exp $
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys, time
|
|
||||||
import ldap, ldif, pgdb, ldap.modlist
|
|
||||||
from optparse import OptionParser
|
|
||||||
import sha
|
|
||||||
import base64
|
|
||||||
from random import randrange
|
|
||||||
|
|
||||||
|
|
||||||
version = "0.112"
|
|
||||||
|
|
||||||
def encode_SSHA_password ( password ):
|
|
||||||
p_ssha = sha.new( password )
|
|
||||||
salt = ''
|
|
||||||
|
|
||||||
for n in range(7):
|
|
||||||
salt += chr(randrange(256))
|
|
||||||
|
|
||||||
|
|
||||||
p_ssha.update( salt )
|
|
||||||
p_ssha_base64 = base64.encodestring(p_ssha.digest() + salt + '' )
|
|
||||||
return '%s%s' %( '{SSHA}', p_ssha_base64 )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parseArgs():
|
|
||||||
parser = OptionParser(version="%prog " + version)
|
|
||||||
parser.add_option ("-v", "--verbose", dest="verbose", action="store_true", default=False,
|
|
||||||
help="Verbose output")
|
|
||||||
|
|
||||||
parser.add_option ("--pgUser", dest="pgUser", default="postgres",
|
|
||||||
help="PostgreSQL User [default: %default]", metavar="USER")
|
|
||||||
parser.add_option ("--pgPassword", dest="pgPassword",
|
|
||||||
help="PostgreSQL Password", metavar="PASSWORD")
|
|
||||||
parser.add_option ("--pgHost", dest="pgHost", default="localhost",
|
|
||||||
help="PostgreSQL Host [default: %default]", metavar="HOST")
|
|
||||||
parser.add_option ("--pgPort", dest="pgPort", default="5432",
|
|
||||||
help="PostgreSQL Port [default: %default]", metavar="PORT")
|
|
||||||
parser.add_option ("--pgDb", dest="pgDB",
|
|
||||||
help="PostgreSQL Database", metavar="DATABASE")
|
|
||||||
|
|
||||||
parser.add_option ("-o", "--output", dest="outType", default="file",
|
|
||||||
help="Output Type [file|ldap] [default: %default]")
|
|
||||||
parser.add_option ("-f", "--file", dest="outFile", default="out.ldif",
|
|
||||||
help="Output file [default: %default]", metavar="FILE")
|
|
||||||
|
|
||||||
parser.add_option ("--ldapUser", dest="ldapUser", default="cn=Directory Manager",
|
|
||||||
help="LDAP User [default: %default]", metavar="USER")
|
|
||||||
parser.add_option ("--ldapPassword", dest="ldapPassword",
|
|
||||||
help="LDAP Password", metavar="PASSWORD")
|
|
||||||
parser.add_option ("--ldapHost", dest="ldapHost", default="localhost",
|
|
||||||
help="LDAP Host [default: %default]", metavar="HOST")
|
|
||||||
parser.add_option ("--ldapPort", dest="ldapPort", default="389",
|
|
||||||
help="LDAP Port [default: %default]", metavar="PORT")
|
|
||||||
parser.add_option ("--ldapOU", dest="ldapBaseOU", default="dc=fedoraproject, dc=org",
|
|
||||||
help="LDAP Base OU [default: %default]", )
|
|
||||||
(options, args) = parser.parse_args()
|
|
||||||
if options.outType != "file" and options.outType != "ldap":
|
|
||||||
parser.error("Output type must be file or ldap")
|
|
||||||
return (options, args)
|
|
||||||
|
|
||||||
def connPostgres(user, password, db, host, port):
|
|
||||||
"""Tries to connect to the Postgres db server.
|
|
||||||
Will exit with exit code 1 it it fails."""
|
|
||||||
global verbose
|
|
||||||
if verbose:
|
|
||||||
print "Connecting to postgres://%s@%s:%s" % (user, host, port)
|
|
||||||
try:
|
|
||||||
dbConn = pgdb.connect(user=user,
|
|
||||||
password=password,
|
|
||||||
database=db,
|
|
||||||
host='%s:%s' %(host, port))
|
|
||||||
return dbConn
|
|
||||||
except:
|
|
||||||
print "Error connecting to Postgres server"
|
|
||||||
# TODO: Remove exit comment
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def connLDAP(user, password, host, port):
|
|
||||||
"""Tries to bind to the LDAP server.
|
|
||||||
Will exit with exit code 1 it it fails."""
|
|
||||||
global verbose
|
|
||||||
if verbose:
|
|
||||||
print "Connecting to ldap://%s@%s:%s" % (user, host, port)
|
|
||||||
try:
|
|
||||||
ldapConn = ldap.open(host)
|
|
||||||
ldapConn.protocol_version = ldap.VERSION3
|
|
||||||
ldapConn.simple_bind_s(user, password)
|
|
||||||
return ldapConn
|
|
||||||
except ldap.LDAPError, error_message:
|
|
||||||
print 'Error connecting to LDAP Server'
|
|
||||||
print error_message
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def openLdifFile(filename):
|
|
||||||
"""Tries to open the output file for writing.
|
|
||||||
Will exit with exit code 1 it it fails."""
|
|
||||||
global verbose
|
|
||||||
if verbose:
|
|
||||||
print "Opening output file %s" % filename
|
|
||||||
try:
|
|
||||||
#ldifWriter = ldif.LDIFWriter(ldap.initialize('ldap://localhost:1390'),filename)
|
|
||||||
fileHandel = open (filename,'w')
|
|
||||||
|
|
||||||
# | __init__(self, output_file, base64_attrs=None, cols=76, line_sep='\n')
|
|
||||||
# | output_file
|
|
||||||
# | file object for output
|
|
||||||
# | base64_attrs
|
|
||||||
# | list of attribute types to be base64-encoded in any case
|
|
||||||
# | cols
|
|
||||||
# | Specifies how many columns a line may have before it's
|
|
||||||
# | folded into many lines.
|
|
||||||
# | line_sep
|
|
||||||
# | String used as line separator
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ldifWriter = ldif.LDIFWriter(fileHandel,"None")
|
|
||||||
return ldifWriter
|
|
||||||
except ldap.LDAPError, error_message:
|
|
||||||
print "Error opening output file: %s" % (filename)
|
|
||||||
print error_message
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def cleanLDAP(ldapConn, ldapBaseOU):
|
|
||||||
"""Removes all existing entries under ou=People and ou=Groups for
|
|
||||||
the defined base OU.
|
|
||||||
Will exit with exit code 1 if an LDAP error is encountered."""
|
|
||||||
global verbose
|
|
||||||
if verbose:
|
|
||||||
print "Deleting existing users from LDAP"
|
|
||||||
try:
|
|
||||||
timeout = 0
|
|
||||||
result_id = ldapConn.search("ou=People, " + ldapBaseOU,
|
|
||||||
ldap.SCOPE_ONELEVEL,
|
|
||||||
"cn=*",
|
|
||||||
None)
|
|
||||||
while 1:
|
|
||||||
result_type, result_data = ldapConn.result(result_id, timeout)
|
|
||||||
if (result_data == []):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if result_type == ldap.RES_SEARCH_ENTRY:
|
|
||||||
if verbose:
|
|
||||||
print "Deleting LDAP user: " + result_data[0][1]['cn'][0]
|
|
||||||
ldapConn.delete_s(result_data[0][0])
|
|
||||||
except ldap.LDAPError, error_message:
|
|
||||||
print "Error deleting existing users from LDAP"
|
|
||||||
print error_message
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
print "Deleting existing groups from LDAP"
|
|
||||||
try:
|
|
||||||
timeout = 0
|
|
||||||
result_id = ldapConn.search("ou=Groups, " + ldapBaseOU,
|
|
||||||
ldap.SCOPE_ONELEVEL,
|
|
||||||
"cn=*",
|
|
||||||
None)
|
|
||||||
while 1:
|
|
||||||
result_type, result_data = ldapConn.result(result_id, timeout)
|
|
||||||
if (result_data == []):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if result_type == ldap.RES_SEARCH_ENTRY:
|
|
||||||
if verbose:
|
|
||||||
print "Deleting LDAP group: " + result_data[0][1]['cn'][0]
|
|
||||||
ldapConn.delete_s(result_data[0][0])
|
|
||||||
except ldap.LDAPError, error_message:
|
|
||||||
print "Error deleting existing groups from LDAP"
|
|
||||||
print error_message
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
global verbose
|
|
||||||
(options, cruft) = parseArgs()
|
|
||||||
verbose = options.verbose
|
|
||||||
|
|
||||||
dbConn = connPostgres(options.pgUser, options.pgPassword,
|
|
||||||
options.pgDB, options.pgHost, options.pgPort)
|
|
||||||
|
|
||||||
# Cleanup LDAP (if necessary)
|
|
||||||
if options.outType == "ldap":
|
|
||||||
ldapConn = connLDAP(options.ldapUser, options.ldapPassword,
|
|
||||||
options.ldapHost, options.ldapPort)
|
|
||||||
#cleanLDAP(ldapConn, options.ldapBaseOU)
|
|
||||||
else:
|
|
||||||
ldifWriter = openLdifFile(options.outFile)
|
|
||||||
|
|
||||||
# Copy all users from db to ldap/ldif
|
|
||||||
# this will to queries and mappings
|
|
||||||
|
|
||||||
try:
|
|
||||||
if verbose:
|
|
||||||
print "Selecting all users from Postgres Database"
|
|
||||||
userCursor = dbConn.cursor()
|
|
||||||
userCursor.execute ("SELECT * FROM person")
|
|
||||||
|
|
||||||
#id, username, email 2, human_name 3, gpg_keyid 4, ssh_key 5, password 6, comments 7, postal_address 8, telephone 9, facsimile 10, affiliation 11, creation 12, approval_status 13, internal_comments 14, wiki_prefs 15, ircnick 16
|
|
||||||
except:
|
|
||||||
print "Error selecting users from db"
|
|
||||||
raise
|
|
||||||
sys.exit(1)
|
|
||||||
while 1:
|
|
||||||
user = userCursor.fetchone()
|
|
||||||
if user == None:
|
|
||||||
break
|
|
||||||
|
|
||||||
date = str(user[12]).split('.')[0]
|
|
||||||
timestamp = time.strftime('%s', time.strptime(date, "%Y-%m-%d %H:%M:%S"))
|
|
||||||
|
|
||||||
# TODO: Create method createLdapUserEntry(user)
|
|
||||||
#(dn, entry) = createLdapUserEntry(user)
|
|
||||||
if options.outType == "ldif":
|
|
||||||
ldifWriter.unparse(dn, entry)
|
|
||||||
else:
|
|
||||||
|
|
||||||
|
|
||||||
print "Adding ldif info for " + user[3] + "."
|
|
||||||
|
|
||||||
#userLdif = [["objectClass",["fedoraPerson","organizationalUnit"]] , [ "displayName",[ user[1] ] ] ]
|
|
||||||
userLdif = [["objectClass",["fedoraPerson"]] , [ "displayName",[ user[1] ] ] ]
|
|
||||||
userLdif.append(["mail",[str(user[2])]])
|
|
||||||
userLdif.append(["sn",[str(user[1])]])
|
|
||||||
userLdif.append(["fedoraPersonBugzillaMail",[str(user[2])]])
|
|
||||||
userLdif.append(["cn",[str(user[1])]])
|
|
||||||
userLdif.append(["givenName",[str(user[3])]])
|
|
||||||
userLdif.append(["fedoraPersonKeyId",[str(user[4])]])
|
|
||||||
userLdif.append(["fedoraPersonCertSerial",['-1']])
|
|
||||||
userLdif.append(["fedoraPersonSshKey",[str(user[5])]])
|
|
||||||
userLdif.append(["userPassword",[encode_SSHA_password(str(user[6]))]])
|
|
||||||
userLdif.append(["postalAddress",[str(user[8])]])
|
|
||||||
userLdif.append(["telephoneNumber",[str(user[9])]])
|
|
||||||
userLdif.append(["fax",[str(user[10]) or "None"]])
|
|
||||||
userLdif.append(["o",[str(user[11]) or "None" ]]) # affiliation is set to the o -- another stretch ??
|
|
||||||
userLdif.append(["fedoraPersonCreationDate",[str(timestamp)]])
|
|
||||||
userLdif.append(["fedoraPersonApprovalStatus",[str(user[13])]])
|
|
||||||
userLdif.append(["description",[str(user[14])]]) #this one may be a streach -- original field was internal comments
|
|
||||||
userLdif.append(["fedoraPersonTimeZone",["UTC"]])
|
|
||||||
userLdif.append(["fedoraPersonIrcNick",[str(user[16])]])
|
|
||||||
#userLdif.append(["ou",["Roles"]]) Adding an OU instead
|
|
||||||
|
|
||||||
print userLdif
|
|
||||||
#for userKey in userLdif.keys():
|
|
||||||
#print "Key Name -> " + userKey
|
|
||||||
#print ":::Key Value::: "
|
|
||||||
#print userLdif[userKey]
|
|
||||||
#ldifWriter.unparse("dc=fedoraproject,dc=org cn=" + user[3] , { userKey : [str(userLdif[userKey])] } )
|
|
||||||
|
|
||||||
#print userLdif.keys()
|
|
||||||
#print userLdif.values()
|
|
||||||
ldifWriter.unparse("cn=" + str(user[1]) +",ou=People,dc=fedoraproject,dc=org" , userLdif )
|
|
||||||
|
|
||||||
roleOuLdif = [["objectClass",["organizationalUnit"]] , [ "ou",[ "Roles" ] ] ]
|
|
||||||
ldifWriter.unparse("ou=Roles,cn=" + str(user[1]) +",ou=People,dc=fedoraproject,dc=org" , roleOuLdif )
|
|
||||||
|
|
||||||
#ldifWriter.unparse("dc=fedoraproject,dc=org, cn=" + user[3] , [ ['ano',['domini']],['uances',['od']] ])
|
|
||||||
|
|
||||||
#time.sleep (2)
|
|
||||||
|
|
||||||
|
|
||||||
#ldapConn.add_s(dn, entry)
|
|
||||||
|
|
||||||
userCursor.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Select all groups from the DB
|
|
||||||
|
|
||||||
try:
|
|
||||||
if verbose:
|
|
||||||
print "Selecting all groups from Postgres Database"
|
|
||||||
groupCursor = dbConn.cursor()
|
|
||||||
groupCursor.execute ("SELECT * FROM project_group")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
except:
|
|
||||||
print "Error selecting groups from db"
|
|
||||||
raise
|
|
||||||
sys.exit(1)
|
|
||||||
while 1:
|
|
||||||
group = groupCursor.fetchone()
|
|
||||||
if group == None:
|
|
||||||
break
|
|
||||||
# TODO: Create method createLdapGroupEntry(group)
|
|
||||||
#(dn, entry) = createLdapGroupEntry(group)
|
|
||||||
if options.outType == "ldif":
|
|
||||||
ldifWriter.unparse(dn, entry)
|
|
||||||
else:
|
|
||||||
#ldapConn.add_s(dn, entry)
|
|
||||||
|
|
||||||
print "Adding group info for %s." % group[7]
|
|
||||||
#id0, owner_id1, group_type2, needs_sponsor3, user_can_remove4, prerequisite_id5, joinmsg6, name7
|
|
||||||
|
|
||||||
uidLookupCursor = dbConn.cursor()
|
|
||||||
uidLookupCursor.execute ("SELECT username FROM person where id =" + str(group[1]) )
|
|
||||||
owner = uidLookupCursor.fetchone()
|
|
||||||
if str(group[5]) != "None" :
|
|
||||||
uidLookupCursor.execute ("SELECT name FROM project_group where id =" + str(group[5]) )
|
|
||||||
prereq = uidLookupCursor.fetchone()
|
|
||||||
print prereq
|
|
||||||
else:
|
|
||||||
prereq=["None"]
|
|
||||||
|
|
||||||
print owner
|
|
||||||
|
|
||||||
#id0, name1, owner_id2, group_type3, needs_sponsor4, user_can_remove5, prerequisite_id6, joinmsg7
|
|
||||||
userLdif = [["objectClass",["fedoraGroup"]] ]
|
|
||||||
userLdif.append(["cn",[str(group[7])]])
|
|
||||||
userLdif.append(["fedoraGroupOwner",owner]) # need to get a cn for this not just the id
|
|
||||||
#userLdif.append(["groupOwner",[str(group[2])]]) # need to get a cn for this not just the id
|
|
||||||
userLdif.append(["fedoraGroupType",[str(group[3]) or "None" ]])
|
|
||||||
|
|
||||||
#we're using the boolean type for these. This means they need to be converted to the TRUE and FALSE strings
|
|
||||||
|
|
||||||
if str(group[3]) == "0" :
|
|
||||||
group[3]="FALSE"
|
|
||||||
else:
|
|
||||||
group[3]="TRUE"
|
|
||||||
|
|
||||||
if str(group[4]) == "0" :
|
|
||||||
group[4]="FALSE"
|
|
||||||
else:
|
|
||||||
group[4]="TRUE"
|
|
||||||
|
|
||||||
if group[5] == None:
|
|
||||||
group[5] = ""
|
|
||||||
|
|
||||||
userLdif.append(["fedoraGroupNeedsSponsor",[str(group[3])]]) #need to convert to bool
|
|
||||||
userLdif.append(["fedoraGroupUserCanRemove",[str(group[4])]]) #need to convert to bool
|
|
||||||
userLdif.append(["fedoraGroupDesc",[str('Please fill out a Group Description')]]) #need to convert to bool
|
|
||||||
#userLdif.append(["groupPrerequisite",[str(group[5])]])
|
|
||||||
userLdif.append(["fedoraGroupRequires",[str(group[5])]]) # <- Hope this is added properly - Ricky
|
|
||||||
#userLdif.append(["groupPrerequisite",prereq]) not currently in the schema
|
|
||||||
userLdif.append(["fedoraGroupJoinMsg",[str(group[6]) or "None" ]])
|
|
||||||
ldifWriter.unparse("cn=" + str(group[7]) +",ou=FedoraGroups,dc=fedoraproject,dc=org" , userLdif )
|
|
||||||
|
|
||||||
|
|
||||||
groupCursor.close()
|
|
||||||
|
|
||||||
# Select all roles from the DB
|
|
||||||
|
|
||||||
try:
|
|
||||||
if verbose:
|
|
||||||
print "Selecting all roles from Postgres Database"
|
|
||||||
roleCursor = dbConn.cursor()
|
|
||||||
roleCursor.execute ("SELECT * FROM role")
|
|
||||||
#person_id, project_group_id, role_type, role_domain, role_status, internal_comments, sponsor_id (Points to a person), creation (TIMESTAMP), approval (TIMESTAMP)
|
|
||||||
except:
|
|
||||||
print "Error selecting roles from db"
|
|
||||||
raise
|
|
||||||
sys.exit(1)
|
|
||||||
while 1:
|
|
||||||
role = roleCursor.fetchone()
|
|
||||||
if role == None:
|
|
||||||
break
|
|
||||||
date1 = str(role[7]).split('.')[0]
|
|
||||||
date2 = str(role[8]).split('.')[0]
|
|
||||||
try:
|
|
||||||
timestamp1 = time.strftime('%s', time.strptime(date1, "%Y-%m-%d %H:%M:%S"))
|
|
||||||
except:
|
|
||||||
timestamp1 = "None"
|
|
||||||
try:
|
|
||||||
timestamp2 = time.strftime('%s', time.strptime(date2, "%Y-%m-%d %H:%M:%S"))
|
|
||||||
except:
|
|
||||||
timestamp2 = "None"
|
|
||||||
# TODO: Create method createLdapRoleEntry(group)
|
|
||||||
#(dn, entry) = createLdapGroupRole(group)
|
|
||||||
if options.outType == "ldif":
|
|
||||||
ldifWriter.unparse(dn, entry)
|
|
||||||
else:
|
|
||||||
#ldapConn.add_s(dn, entry)
|
|
||||||
#person_id0, group_project_id1, role_type2, role_domain3, role_status4, internal_comments5, sponsor_id6, creation7, approval8
|
|
||||||
|
|
||||||
|
|
||||||
uidRoleCursor = dbConn.cursor()
|
|
||||||
uidRoleCursor.execute ("SELECT username FROM person where id =" + str(role[0]) )
|
|
||||||
username = uidRoleCursor.fetchone()
|
|
||||||
uidRoleCursor.execute ("SELECT name FROM project_group where id =" + str(role[1]) )
|
|
||||||
group = uidRoleCursor.fetchone()
|
|
||||||
if str(role[6]) != "None" :
|
|
||||||
uidRoleCursor.execute ("SELECT username FROM person where id =" + str(role[6]) )
|
|
||||||
sponsor = uidRoleCursor.fetchone()
|
|
||||||
else:
|
|
||||||
sponsor = ["None"]
|
|
||||||
|
|
||||||
print "Adding " + str(role[4]) + " role info for " + group[0] + " for user " + username[0] + "."
|
|
||||||
#if str(group[6]) != "None" :
|
|
||||||
# uidLookupCursor.execute ("SELECT name FROM project_group where id =" + str(group[6]) )
|
|
||||||
# prereq = uidLookupCursor.fetchone()
|
|
||||||
# print prereq
|
|
||||||
#else:
|
|
||||||
# prereq=["None"]
|
|
||||||
#print owner
|
|
||||||
|
|
||||||
#person_id0, group_project_id1, role_type2, role_domain3, role_status4, internal_comments5, sponsor_id6, creation7, approval8
|
|
||||||
|
|
||||||
roleLdif = [["objectClass",["fedoraRole"]] ]
|
|
||||||
#roleLdif.append(["cn",[str(group[0]) + str(role[2])]]) #Fix me
|
|
||||||
roleLdif.append(["cn",[str(group[0])]]) #Fix me
|
|
||||||
roleLdif.append(["fedoraRoleType",[str(role[2])]])
|
|
||||||
roleLdif.append(["fedoraRoleDomain",[str(role[3]) or "None" ]])
|
|
||||||
roleLdif.append(["fedoraRoleStatus",[str(role[4])]])
|
|
||||||
roleLdif.append(["fedoraRoleSponsor",sponsor])
|
|
||||||
roleLdif.append(["fedoraRoleCreationDate",[str(timestamp1)]])
|
|
||||||
roleLdif.append(["fedoraRoleApprovalDate",[str(timestamp2)]])
|
|
||||||
|
|
||||||
ldifWriter.unparse("cn=" + group[0] + ",ou=Roles,cn=" + username[0] + ",ou=People,dc=fedoraproject,dc=org" , roleLdif )
|
|
||||||
|
|
||||||
roleCursor.close()
|
|
||||||
|
|
||||||
sys.exit(1)
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -1,45 +0,0 @@
|
||||||
#this is the fedora group schema file for use with the accounts system2
|
|
||||||
#it currently contains the following:
|
|
||||||
#owner (the owner's DN)
|
|
||||||
#group_type
|
|
||||||
#needs_sponsor
|
|
||||||
#user_can_remove (will be handled by ACLs, but we need to clue the interface about it)
|
|
||||||
#prerequisite_id (no idea what that is, so maybe not) -- not included yet
|
|
||||||
#joinmsg
|
|
||||||
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.10 NAME 'fedoraGroupOwner'
|
|
||||||
DESC 'group owner'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.11 NAME 'fedoraGroupType'
|
|
||||||
DESC 'the type of group'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.12 NAME 'fedoraGroupNeedsSponsor'
|
|
||||||
DESC 'boolean indicating whether or not the group needs a sponsor'
|
|
||||||
EQUALITY booleanMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.13 NAME 'fedoraGroupUserCanRemove'
|
|
||||||
DESC 'boolean indicating whether or not the user can remove the group'
|
|
||||||
EQUALITY booleanMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.14 NAME 'fedoraGroupJoinMsg'
|
|
||||||
DESC 'message received upon joining the group'
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1000} )
|
|
||||||
|
|
||||||
|
|
||||||
objectclass ( 2.5.555.3
|
|
||||||
NAME 'fedoraGroup'
|
|
||||||
DESC 'A object describing a group entry'
|
|
||||||
STRUCTURAL
|
|
||||||
MAY ( fedoraGroupJoinMsg $ fedoraGroupUsercanRemove $ fedoraGroupType $ fedoraGroupNeedsSponsor $ fedoraGroupUserCanRemove )
|
|
||||||
MUST ( cn $ fedoraGroupOwner )
|
|
||||||
)
|
|
|
@ -1,57 +0,0 @@
|
||||||
#this is the fedoraPerson shema file for use with the Account system
|
|
||||||
#it is based on the inetOrgPerson shema, but has some spicific
|
|
||||||
#attribues added onto it for use by the Account system
|
|
||||||
#for now this is the contents
|
|
||||||
#sshkey bugzillaemail ircNick approvalStatus creationDate
|
|
||||||
attributeType ( 2.5.444.8 NAME 'fedoraPersonSshKey'
|
|
||||||
DESC 'ssh key for this member'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096}
|
|
||||||
SINGLE-VALUE)
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.9 NAME 'fedoraPersonBugzillaMail'
|
|
||||||
DESC 'members preferred bugzilla email address'
|
|
||||||
EQUALITY caseIgnoreIA5Match
|
|
||||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.16 NAME 'fedoraPersonIrcNick'
|
|
||||||
DESC 'irc nick of the user on freenode'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{100} )
|
|
||||||
|
|
||||||
attributetype ( 2.5.444.17 NAME 'fedoraPersonCreationDate'
|
|
||||||
DESC 'date entry was created'
|
|
||||||
EQUALITY caseIgnoreIA5Match
|
|
||||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
|
||||||
SINGLE-VALUE )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.18 NAME 'fedoraPersonApprovalStatus'
|
|
||||||
DESC 'users approval status'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.19 NAME 'fedoraPersonKeyId'
|
|
||||||
DESC 'users GPG key ID'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
|
|
||||||
|
|
||||||
# fedoraPerson
|
|
||||||
# The fedoraPerson represents people who are a member of the fedora project
|
|
||||||
# in some way. It is a structural class and inherits
|
|
||||||
# from the inetOrgPerson class
|
|
||||||
objectclass ( 2.5.555.1
|
|
||||||
NAME 'fedoraPerson'
|
|
||||||
DESC 'A member of the fedoraproject group'
|
|
||||||
SUP inetOrgPerson
|
|
||||||
STRUCTURAL
|
|
||||||
MUST ( fedoraPersonSshKey $ mail $ fedoraPersonCreationDate )
|
|
||||||
MAY (fedoraPersonIrcNick $ fedoraPersonApprovalStatus $ fedoraPersonBugzillaMail $ fedoraPersonKeyId )
|
|
||||||
)
|
|
|
@ -1,66 +0,0 @@
|
||||||
#this is the fedoraMembership shema file for use with the Account system
|
|
||||||
#check out http://www.openldap.org/doc/admin23/schema.html#Extending%20Schema
|
|
||||||
#for more information
|
|
||||||
#for now this is the contents
|
|
||||||
#role_type
|
|
||||||
#role_domain
|
|
||||||
#role_status
|
|
||||||
#internal_comments
|
|
||||||
#sponsor (points to the sponsor's DN)
|
|
||||||
#creation (date)
|
|
||||||
#approval (date)
|
|
||||||
#don't have a name use cn instead
|
|
||||||
#attributeType ( 2.5.444.1 NAME 'name'
|
|
||||||
# DESC 'group name'
|
|
||||||
# EQUALITY caseIgnoreMatch
|
|
||||||
# SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.2 NAME 'fedoraRoleType'
|
|
||||||
DESC 'the type of role'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{25} )
|
|
||||||
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.15 NAME 'fedoraRoleDomain'
|
|
||||||
DESC 'the domain of this role'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{15} )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.3 NAME 'fedoraRoleStatus'
|
|
||||||
DESC 'the approval status of this role'
|
|
||||||
EQUALITY caseIgnoreMatch
|
|
||||||
SUBSTR caseIgnoreSubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{15} )
|
|
||||||
|
|
||||||
|
|
||||||
#attributeType ( 2.5.444.4 NAME 'internalComments'
|
|
||||||
# DESC 'group membership comments'
|
|
||||||
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1000} )
|
|
||||||
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.5 NAME 'fedoraRoleSponsor'
|
|
||||||
DESC 'role sponsor'
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{25} )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.6 NAME 'fedoraRoleCreationDate'
|
|
||||||
DESC 'membership creation date'
|
|
||||||
EQUALITY caseIgnoreIA5Match
|
|
||||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
|
||||||
|
|
||||||
attributeType ( 2.5.444.7 NAME 'fedoraRoleApprovalDate'
|
|
||||||
DESC 'membership approval date'
|
|
||||||
EQUALITY caseIgnoreIA5Match
|
|
||||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
|
||||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
|
||||||
|
|
||||||
objectclass ( 2.5.555.2
|
|
||||||
NAME 'fedoraRole'
|
|
||||||
DESC 'An object describing a persons roles with the fedora project'
|
|
||||||
STRUCTURAL
|
|
||||||
MAY ( fedoraRoleApprovalDate $ fedoraRoleCreationDate $ fedoraRoleType $ fedoraRoleStatus $ fedoraRoleDomain $ fedoraRoleSponsor )
|
|
||||||
MUST ( cn )
|
|
||||||
)
|
|
1240
fas/po/fas.pot
Normal file
1240
fas/po/fas.pot
Normal file
File diff suppressed because it is too large
Load diff
1304
fas/po/messages.pot
1304
fas/po/messages.pot
File diff suppressed because it is too large
Load diff
1240
fas/po/test/LC_MESSAGES/fas.po
Normal file
1240
fas/po/test/LC_MESSAGES/fas.po
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,10 +5,12 @@
|
||||||
# Extraction from Genshi HTML and text templates
|
# Extraction from Genshi HTML and text templates
|
||||||
|
|
||||||
[genshi: **/templates/**.html]
|
[genshi: **/templates/**.html]
|
||||||
ignore_tags = script,style
|
extract_text = False
|
||||||
include_attrs = alt title summary
|
#ignore_tags = script,style
|
||||||
|
#include_attrs = alt title summary
|
||||||
|
|
||||||
[genshi: **/templates/**.txt]
|
#[genshi: **/templates/**.txt]
|
||||||
template_class = genshi.template:TextTemplate
|
#template_class = genshi.template:TextTemplate
|
||||||
encoding = UTF-8
|
#extract_text = False
|
||||||
|
#encoding = UTF-8
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue