25
35
# - Rebuild svn auth file
26
36
# - Rebuild passwd + push to nodes.
29
38
def create_user(props):
30
39
"""Create the database record for the given user.
31
40
Expected properties:
32
username - used as a unix login name and svn repository name.
41
login - used as a unix login name and svn repository name.
34
uid - the unix uid under which execution will take place
43
unixid - the unix uid under which execution will take place
35
44
on the behalf of the user. Don't use 0! If not specified
36
45
or None, one will be allocated from the configured
56
65
Return Value: the uid associated with the user. INT
59
# FIXME: the IVLE server must check that an admin is doing this!
61
if 'uid' not in props or props['uid'] is None:
62
raise NotImplementedError, "No algorithm for creating uids yet!"
66
username = props['username']
69
password = props['password']
73
email = props['email']
77
fullname = props['fullname']
78
rolenm = props['rolenm']
80
studentid = props['studentid']
83
common.makeuser.make_user_db(username, uid, password, email, nick,
84
fullname, rolenm, studentid)
68
common.makeuser.make_user_db(**props)
69
user = common.db.get_user(props["login"])
72
def update_user(props):
73
"""Create the database record for the given user.
75
login - user who is making the change (not necessarily the one
77
update - dict of fields to be updated. The fields are all those
78
in the login table of the db.
80
Omitted fields will not be set.
82
update = props['update']
83
# Note: "login" is special - it is not part of the kwargs to
84
# db.update_user, but the first arg - used to find the user to update.
85
# However it doesn't need any special treatment here.
88
db.update_user(**update)
91
def get_login(login, passwd, realm, existing_login, _may_save):
92
"""Callback function used by pysvn for authentication.
93
login, passwd: Credentials of the user attempting to log in.
94
passwd in clear (this should be the user's svn_pass, a
95
randomly-generated permanent password for this user, not their main
97
realm, existing_login, _may_save: The 3 arguments passed by pysvn to
99
The following has been determined empirically, not from docs:
100
existing_login will be the name of the user who owns the process on
101
the first attempt, "" on subsequent attempts. We use this fact.
103
logging.debug("Getting password for %s (realm %s)" % (login, realm))
104
# Only provide credentials on the _first_ attempt.
105
# If we're being asked again, then it means the credentials failed for
106
# some reason and we should just fail. (This is not desirable, but it's
107
# better than being asked an infinite number of times).
108
if existing_login == "":
109
logging.warning("Could not authenticate SVN for %s" % login)
110
return (False, login, passwd, False)
112
return (True, login, passwd, False)
88
114
def activate_user(props):
89
115
"""Create the on-disk stuff for the given user.
105
133
details = db.get_user(login)
107
# FIXME: make svn config/auth
111
common.makeuser.make_jail(login, details['unixid'])
135
# make svn config/auth
137
logging.debug("Creating repo")
138
common.makeuser.make_svn_repo(login, throw_on_error=False)
139
logging.debug("Creating svn config")
140
common.makeuser.make_svn_config(login, throw_on_error=False)
141
logging.debug("Creating svn auth")
142
passwd = common.makeuser.make_svn_auth(login, throw_on_error=False)
143
logging.debug("passwd: %s" % passwd)
146
svn.callback_get_login = partial(get_login, login, passwd)
148
if conf.svn_addr[-1] != '/':
149
conf.svn_addr = conf.svn_addr + "/"
151
# FIXME: This should be a loop over enrolements.
152
# We're not going to fix this now because it requires
153
# a large amount of admin console work to manage subject
155
# Instead, we're just going to use a single offering with
156
# a "short" name of "info1".
157
logging.debug("Creating /info1")
159
svn.mkdir(conf.svn_addr + login + "/info1",
160
"Initial creation of work directory for Informatics 1")
161
except Exception, exc:
162
logging.warning("While mkdiring info1: %s" % str(exc))
164
logging.debug("Creating /stuff")
166
svn.mkdir(conf.svn_addr + login + "/stuff",
167
"Initial creation of directory for miscellania")
168
except Exception, exc:
169
logging.warning("While mkdiring stuff: %s" % str(exc))
172
logging.debug("Creating jail")
173
common.makeuser.make_jail(login, details.unixid, svn_pass=passwd)
175
common.makeuser.mount_jail(login)
177
do_checkout(props, svn_pass=passwd)
179
# FIXME: should this be nicer?
180
os.system("chown -R %d:%d %s" \
181
% (details.unixid, details.unixid,
182
common.studpath.url_to_local(login)[1]))
184
logging.info("Enabling user")
113
185
db.update_user(login, state='enabled')
115
187
return {"response": "okay"}
192
def do_checkout(props, svn_pass=None):
193
"""Create the default contents of a user's jail by checking out from the
195
If any directory already exists, just fail silently (so this is not a
196
"wipe-and-checkout", merely a checkout if it failed or something).
198
login - the user name for the jail
202
login = props['login']
205
user = db.get_user(login)
206
# If svn_pass isn't supplied, grab it from the DB
208
svn_pass = user.svn_pass
212
svn.callback_get_login = partial(get_login, login, svn_pass)
214
if conf.svn_addr[-1] != os.sep:
215
conf.svn_addr += os.sep
219
logging.debug("Checking out directories in the jail")
221
svn.checkout(conf.svn_addr + login + "/stuff",
222
common.studpath.url_to_local(login + "/stuff")[1])
223
os.system("chown -R %d:%d %s" \
224
% (user.unixid, user.unixid,
225
common.studpath.url_to_local(login + "/stuff")[1]))
226
except Exception, exc:
227
logging.warning("While mkdiring stuff: %s" % str(exc))
230
svn.checkout(conf.svn_addr + login + "/info1",
231
common.studpath.url_to_local(login + "/info1")[1])
232
os.system("chown -R %d:%d %s" \
233
% (user.unixid, user.unixid,
234
common.studpath.url_to_local(login + "/info1")[1]))
235
except Exception, exc:
236
logging.warning("While mkdiring info1: %s" % str(exc))
241
return {"response": "okay"}
121
244
'create_user':create_user,
122
'activate_user':activate_user
245
'update_user':update_user,
246
'activate_user':activate_user,
247
'do_checkout':do_checkout,
252
pidfile = open('/var/run/usrmgt-server.pid', 'w')
253
pidfile.write('%d\n' % os.getpid())
255
except IOError, (errno, strerror):
256
print "Couldn't write PID file. IO error(%s): %s" % (errno, strerror)
125
259
def dispatch(props):
260
logging.debug(repr(props))
126
261
action = props.keys()[0]
127
262
return actions[action](props[action])
129
264
if __name__ == "__main__":
266
print >>sys.stderr, "Usage: usrmgt-server <port> <magic>"
130
268
port = int(sys.argv[1])
131
269
magic = sys.argv[2]
133
common.chat.start_server(port, magic, False, dispatch)
273
logging.basicConfig(filename="/var/log/usrmgt.log", level=logging.INFO)
274
logging.info("Starting usrmgt server on port %d (pid = %d)" % (port, pid))
276
common.chat.start_server(port, magic, True, dispatch, initializer)