
commit
5987d349aa
5 changed files with 854 additions and 0 deletions
@ -0,0 +1,104 @@ |
|||||||
|
SVN USER MANAGEMENT README |
||||||
|
========================== |
||||||
|
|
||||||
|
First of all, we talk about the following files and folders: |
||||||
|
|
||||||
|
.htpasswd |
||||||
|
.svn-dir-creator |
||||||
|
README |
||||||
|
authz |
||||||
|
cpi |
||||||
|
elab-users.py |
||||||
|
old-scripts-backup |
||||||
|
|
||||||
|
** WARNING: ** |
||||||
|
In this list, there are two hidden files: `.htpasswd` and |
||||||
|
`.svn-dir-creator`. This two are hidden on purpose, so |
||||||
|
** don't mess with these files **. |
||||||
|
|
||||||
|
|
||||||
|
quick file overview |
||||||
|
------------------- |
||||||
|
|
||||||
|
`.htpasswd`: stores the passwords for the users (classical apache htpaswd-file) |
||||||
|
|
||||||
|
`.svn-dir-creator`: creates empty svn directories for new users |
||||||
|
|
||||||
|
`README`: this file |
||||||
|
|
||||||
|
`authz`: defines the access controll list, so who has access to what |
||||||
|
|
||||||
|
`cpi`: folder that holds the svn repository itself |
||||||
|
|
||||||
|
`elab-users.py`: usermanagement script |
||||||
|
|
||||||
|
`old-scripts-backup`: contains the old scripts to add a user for backup reasons |
||||||
|
|
||||||
|
|
||||||
|
Usermanagement with `elab-users.py` |
||||||
|
----------------------------------- |
||||||
|
|
||||||
|
** HINT: ** To run this scipt first change to the directory with `cd /var/www/svn` and prepend every command with `./` (e.g. `./elab-users.py --help`). |
||||||
|
|
||||||
|
The script `elab-users.py` provides some options to add and delete users, |
||||||
|
show access information from users and their elab journals. If the scprit |
||||||
|
is called with the `--help` option, the folowing help message is displayed: |
||||||
|
|
||||||
|
Usage: elab-users.py [option] name |
||||||
|
|
||||||
|
shows and manipulates svn access rights |
||||||
|
|
||||||
|
Options: |
||||||
|
-h, --help show this help message and exit |
||||||
|
-g, --groupinfo display users in a group |
||||||
|
-a, --add add a regular user |
||||||
|
-r, --restricted add a restricted user |
||||||
|
-m, --move move a user to alumni |
||||||
|
-p, --password reset a user password |
||||||
|
|
||||||
|
to grant a restricted user access to another folder, you have to carefully |
||||||
|
edit the authz file |
||||||
|
|
||||||
|
the following combinations are possible: |
||||||
|
|
||||||
|
* `elab-users.py`: will show a list of all groups and their users |
||||||
|
* `elab-users.py UserName`: shows the access rights of the user and their labjournal |
||||||
|
* `elab-users.py -g GroupName`: shows a list of all group members |
||||||
|
* `elab-users.py -a UserName`: adds a regular user, creates svn folders and sets a random password |
||||||
|
* `elab-users.py -a UserName`: adds a restricted user, creates svn folders and sets a random password |
||||||
|
* `elab-users.py -m UserName`: moves an existing user to the alumni group, removes his password |
||||||
|
* `elab-users.py -p UserName`: resets the password for an existing user to a new random one |
||||||
|
|
||||||
|
|
||||||
|
Grant read writes to restricted users |
||||||
|
------------------------------------- |
||||||
|
|
||||||
|
As noted in the help message of `elab-users.py`, if a restriced user should have |
||||||
|
read access to another labjournal, the `authz` file has to be edited manually. |
||||||
|
Here are two examples that grant the user 'UrmilShah' read access to |
||||||
|
two different lab journals: |
||||||
|
|
||||||
|
... snip ... |
||||||
|
|
||||||
|
[cpi:/AndreasEvers] |
||||||
|
@restricted = |
||||||
|
UrmilShah = r |
||||||
|
|
||||||
|
... snip ... |
||||||
|
|
||||||
|
[cpi:/HolgerFrey] |
||||||
|
@restricted = |
||||||
|
UrmilShah = r |
||||||
|
HolgerFrey = rw |
||||||
|
|
||||||
|
... snip ... |
||||||
|
|
||||||
|
This does not apply to regular users, since these have read access to all folders. |
||||||
|
|
||||||
|
|
||||||
|
Hint |
||||||
|
---- |
||||||
|
|
||||||
|
This readme is written in Markdown. |
||||||
|
So if you want a nice printout, use a markdown converter first. |
||||||
|
Something like <http://www.markdownviewer.com> |
@ -0,0 +1,428 @@ |
|||||||
|
[groups] |
||||||
|
administrators = OswaldPrucker |
||||||
|
restricted = AndreasEver, ArthurMartens, BeniPrasser, JuliaSaar, SimonZunker, SirasaYodmongkol, UrmilShah, YongZhou |
||||||
|
alumni = AlexeyKopyshev, AndreasBoenisch, AnkeWoerz, AnneLoesche, ArulGeetha, ChristianSchuh, ChristineBunte, CkPandiyarajan, FanWu, GinoRodriguez, GuillermoBenites, HeikeHaller, IrenaEipert, JacobBelardi, JenniferPfau, JoachimLauterwasser, JohannesBaader, KatrinMoosmann, KerstinSchuh, KimberlySimancas, MarcelHoffmann, MarcoArmbruster, MariaVoehringer, MariaVohringer, MartinaAuerswald, MartinVellinger, MatthiasLischka, MessRechner, MichaelaFrase, MiriamScheckenbach, MonicaPerez, MonikaKurowska, NinoLomadze, Nongluck, OliverDornfeld, PeterZahn, PhilippDiefenthaler, PhilippWollermann, RodrigoNavarro, SaraFuchs, SebastianBoehmer, SebastianSebald, SimonBodendorfer, SimonSchuster, ThidaratWangkam, TobiasKoenig, TristanBourrel, UlrikeRiehle, ViVek, WolfgangEhm, YnSekhar, ZouStaarter |
||||||
|
users = AlexanderDietz, AliciaMalekLuz, AndreasMader, AnnaSchuler, AnneBuderer, CanerKaganaslan, ChristophScheibelein, DanielaMoessner, DavidBoschert, DavidSchwaerzle, FrankScherag, FranziskaDorner, GerhardBaaken, GregorOsterwinter, HolgerFrey, JanNiklasSchoenberg, JonGreen, KarenLienkamp, KeLi, MalwinaPajestka, MaraFlorea, MarcelRothfelder, MarcZinggeler, MarcelHoffmann, MartinKoerner, MartinRendl, MartinSchoenstein, MatthiasMenzel, MelanieEichhorn, MichaelHenze, MostafaMahmoud, NataliaSchatz, NicoleBirsner, NilsKorf, PetraHettich, PhilipKotrade, RaduCristianMutihac, RebeccaBlell, RomanErath, SamarKazan, SaschaEngel, ShararehSahneh, SureshReddyBanda, ThomasBrandstetter, TianyangZheng, TobiasHeitzler, VinicioCarias, VitaliyKondrashov, WibkeHartleb, XiaoqiangHou |
||||||
|
|
||||||
|
[cpi:/] |
||||||
|
@admins = rw |
||||||
|
@users = r |
||||||
|
@restricted = r |
||||||
|
@alumni = |
||||||
|
|
||||||
|
[cpi:/AlexanderDietz] |
||||||
|
@restricted = |
||||||
|
AlexanderDietz = rw |
||||||
|
|
||||||
|
[cpi:/AlexeyKopyshev] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/AliciaMalekLuz] |
||||||
|
@restricted = |
||||||
|
AliciaMalekLuz = rw |
||||||
|
|
||||||
|
[cpi:/AndreasBoenisch] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/AndreasEver] |
||||||
|
@restricted = |
||||||
|
AndreasEver = rw |
||||||
|
|
||||||
|
[cpi:/AndreasEvers] |
||||||
|
@restricted = |
||||||
|
UrmilShah = r |
||||||
|
|
||||||
|
[cpi:/AndreasMader] |
||||||
|
@restricted = |
||||||
|
AndreasMader = rw |
||||||
|
SirasaYodmongkol = r |
||||||
|
|
||||||
|
[cpi:/AnkeWoerz] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/AnnaSchuler] |
||||||
|
@restricted = |
||||||
|
AnnaSchuler = rw |
||||||
|
|
||||||
|
[cpi:/AnneBuderer] |
||||||
|
@restricted = |
||||||
|
AnneBuderer = rw |
||||||
|
|
||||||
|
[cpi:/AnneLoesche] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/AnselmHoppmann] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/ArthurMartens] |
||||||
|
@restricted = |
||||||
|
ArthurMartens = rw |
||||||
|
|
||||||
|
[cpi:/ArulGeetha] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/BeniPrasser] |
||||||
|
@restricted = |
||||||
|
BeniPrasser = rw |
||||||
|
|
||||||
|
[cpi:/CanerKaganaslan] |
||||||
|
@restricted = |
||||||
|
CanerKaganaslan = rw |
||||||
|
|
||||||
|
[cpi:/ChristianSchuh] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/ChristineBunte] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/ChristophScheibelein] |
||||||
|
@restricted = |
||||||
|
ChristophScheibelein = rw |
||||||
|
|
||||||
|
[cpi:/CkPandiyarajan] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/DanielaMoessner] |
||||||
|
@restricted = |
||||||
|
DanielaMoessner = rw |
||||||
|
|
||||||
|
[cpi:/DavidBoschert] |
||||||
|
@restricted = |
||||||
|
DavidBoschert = rw |
||||||
|
|
||||||
|
[cpi:/DavidSchwaerzle] |
||||||
|
@restricted = |
||||||
|
DavidSchwaerzle = rw |
||||||
|
|
||||||
|
[cpi:/DennisTrenkle] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/DingdingHe] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/FanWu] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/FrankScherag] |
||||||
|
@restricted = |
||||||
|
FrankScherag = rw |
||||||
|
|
||||||
|
[cpi:/FranziskaDorner] |
||||||
|
@restricted = |
||||||
|
FranziskaDorner = rw |
||||||
|
|
||||||
|
[cpi:/GerhardBaaken] |
||||||
|
@restricted = |
||||||
|
GerhardBaaken = rw |
||||||
|
|
||||||
|
[cpi:/GinoRodriguez] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/GregorOsterwinter] |
||||||
|
@restricted = |
||||||
|
GregorOsterwinter = rw |
||||||
|
|
||||||
|
[cpi:/GuillermoBenites] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/HeikeHaller] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/HolgerFrey] |
||||||
|
@restricted = |
||||||
|
HolgerFrey = rw |
||||||
|
UrmilShah = r |
||||||
|
|
||||||
|
[cpi:/IrenaEipert] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/JacobBelardi] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/JanNiklasSchoenberg] |
||||||
|
@restricted = |
||||||
|
JanNiklasSchoenberg = rw |
||||||
|
|
||||||
|
[cpi:/JenniferPfau] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/JoachimLauterwasser] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/JohannesBaader] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/JonGreen] |
||||||
|
@restricted = |
||||||
|
JonGreen = rw |
||||||
|
|
||||||
|
[cpi:/JonasGroten] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/JuliaSaar] |
||||||
|
@restricted = |
||||||
|
JuliaSaar = rw |
||||||
|
|
||||||
|
[cpi:/KarenLienkamp] |
||||||
|
@restricted = |
||||||
|
KarenLienkamp = rw |
||||||
|
|
||||||
|
[cpi:/KatrinMoosmann] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/KeLi] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/KerstinSchuh] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/KimberlySimancas] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MalwinaPajestka] |
||||||
|
@restricted = |
||||||
|
MalwinaPajestka = rw |
||||||
|
|
||||||
|
[cpi:/MaraFlorea] |
||||||
|
@restricted = |
||||||
|
MaraFlorea = rw |
||||||
|
|
||||||
|
[cpi:/MarcelRothfelder] |
||||||
|
@restricted = |
||||||
|
MarcelRothfelder = rw |
||||||
|
|
||||||
|
[cpi:/MarcZinggeler] |
||||||
|
@restricted = |
||||||
|
MarcZinggeler = rw |
||||||
|
|
||||||
|
[cpi:/MarcelHoffmann] |
||||||
|
@restricted = |
||||||
|
MarcelHoffmann = rw |
||||||
|
|
||||||
|
[cpi:/MarcoArmbruster] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MariaVoehringer] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MartinaAuerswald] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MartinKoerner] |
||||||
|
@restricted = |
||||||
|
MartinKoerner = rw |
||||||
|
|
||||||
|
[cpi:/MartinMarazita] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MartinRendl] |
||||||
|
@restricted = |
||||||
|
MartinRendl = rw |
||||||
|
ArthurMartens = r |
||||||
|
|
||||||
|
[cpi:/MartinSchoenstein] |
||||||
|
@restricted = |
||||||
|
MartinSchoenstein = rw |
||||||
|
|
||||||
|
[cpi:/MartinVellinger] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MatthiasLischka] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MatthiasMenzel] |
||||||
|
@restricted = |
||||||
|
MatthiasMenzel = rw |
||||||
|
|
||||||
|
[cpi:/MaxMustermann] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MelanieEichhorn] |
||||||
|
@restricted = |
||||||
|
MelanieEichhorn = rw |
||||||
|
|
||||||
|
[cpi:/MessRechner] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MichaelHenze] |
||||||
|
@restricted = |
||||||
|
MichaelHenze = rw |
||||||
|
|
||||||
|
[cpi:/MichaelaFrase] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MiriamScheckenbach] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MonicaPerez] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MonikaKurowska] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/MostafaMahmoud] |
||||||
|
@restricted = |
||||||
|
MostafaMahmoud = rw |
||||||
|
|
||||||
|
[cpi:/NataliaSchatz] |
||||||
|
@restricted = |
||||||
|
NataliaSchatz = rw |
||||||
|
|
||||||
|
[cpi:/NicolasSchorr] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/NicoleBirsner] |
||||||
|
@restricted = |
||||||
|
NicoleBirsner = rw |
||||||
|
|
||||||
|
[cpi:/NilsKorf] |
||||||
|
@restricted = |
||||||
|
NilsKorf = rw |
||||||
|
|
||||||
|
[cpi:/NinoLomadze] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/Nongluck] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/OliverDornfeld] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/OswaldPrucker] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/PengZou] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/PeterZahn] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/PetraHettich] |
||||||
|
@restricted = |
||||||
|
PetraHettich = rw |
||||||
|
|
||||||
|
[cpi:/PhilippDiefenthaler] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/PhilipKotrade] |
||||||
|
@restricted = |
||||||
|
PhilipKotrade = rw |
||||||
|
|
||||||
|
[cpi:/RaduCristianMutihac] |
||||||
|
@restricted = |
||||||
|
RaduCristianMutihac = rw |
||||||
|
|
||||||
|
[cpi:/RebeccaBlell] |
||||||
|
@restricted = |
||||||
|
RebeccaBlell = rw |
||||||
|
|
||||||
|
[cpi:/RodrigoNavarro] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/RomanErath] |
||||||
|
@restricted = |
||||||
|
RomanErath = rw |
||||||
|
|
||||||
|
[cpi:/SamarKazan] |
||||||
|
@restricted = |
||||||
|
SamarKazan = rw |
||||||
|
|
||||||
|
[cpi:/SaraFuchs] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/SaschaEngel] |
||||||
|
@restricted = |
||||||
|
SaschaEngel = rw |
||||||
|
|
||||||
|
[cpi:/SebastianBoehmer] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/ShararehSahneh] |
||||||
|
@restricted = |
||||||
|
ShararehSahneh = rw |
||||||
|
|
||||||
|
[cpi:/SimonBodendorfer] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/SimonEbner] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/SimonSchuster] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/SimonZunker] |
||||||
|
@restricted = |
||||||
|
SimonZunker = rw |
||||||
|
|
||||||
|
[cpi:/SirasaYodmongkol] |
||||||
|
@restricted = |
||||||
|
SirasaYodmongkol = rw |
||||||
|
|
||||||
|
[cpi:/SureshReddyBanda] |
||||||
|
@restricted = |
||||||
|
SureshReddyBanda = rw |
||||||
|
|
||||||
|
[cpi:/ThidaratWangkam] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/ThomasBrandstetter] |
||||||
|
@restricted = |
||||||
|
ThomasBrandstetter = rw |
||||||
|
|
||||||
|
[cpi:/TianyangZheng] |
||||||
|
@restricted = |
||||||
|
TianyangZheng = rw |
||||||
|
|
||||||
|
[cpi:/TobiasHeitzler] |
||||||
|
@restricted = |
||||||
|
TobiasHeitzler = rw |
||||||
|
|
||||||
|
[cpi:/TobiasKoenig] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/TristanBourrel] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/UlrikeRiehle] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/UrmilShah] |
||||||
|
@restricted = |
||||||
|
UrmilShah = rw |
||||||
|
|
||||||
|
[cpi:/ViVek] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/VinicioCarias] |
||||||
|
@restricted = |
||||||
|
VinicioCarias = rw |
||||||
|
|
||||||
|
[cpi:/VitaliyKondrashov] |
||||||
|
@restricted = |
||||||
|
VitaliyKondrashov = rw |
||||||
|
SimonZunker = r |
||||||
|
|
||||||
|
[cpi:/WibkeHartleb] |
||||||
|
@restricted = |
||||||
|
WibkeHartleb = rw |
||||||
|
|
||||||
|
[cpi:/WolfgangEhm] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/XiaoqiangHou] |
||||||
|
@restricted = |
||||||
|
XiaoqiangHou = rw |
||||||
|
|
||||||
|
[cpi:/YnSekhar] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/YongZhou] |
||||||
|
@restricted = |
||||||
|
YongZhou = rw |
||||||
|
|
||||||
|
[cpi:/ZhuolingDeng] |
||||||
|
@restricted = |
||||||
|
|
||||||
|
[cpi:/ZouStaarter] |
||||||
|
@restricted = |
||||||
|
|
@ -0,0 +1,6 @@ |
|||||||
|
foo:$apr1$SzJRyvJU$U3luHwCA6xHfKowizE.Gl. |
||||||
|
FOO:$apr1$LSPDdLqg$tiGbDGgNEXcRA/oyadYSw1 |
||||||
|
AndreasEvers:$apr1$n0Oaok6e$wyHcUg6Upm9sE2AoYlVMO/ |
||||||
|
FOOBar:$apr1$pZCbClF5$smEDwhMJIVmPsNmMEkRPd1 |
||||||
|
FooBar:$apr1$24r9zF2e$9q30fNOqSlvn6itdhZMpc1 |
||||||
|
UrmilShh:$apr1$WxMGE8Wb$H0xWao6KZGqBJoXj7fJ420 |
@ -0,0 +1,288 @@ |
|||||||
|
#/usr/bin/python |
||||||
|
|
||||||
|
# imports of modules |
||||||
|
import ConfigParser |
||||||
|
import optparse |
||||||
|
import os |
||||||
|
import re |
||||||
|
import random |
||||||
|
import string |
||||||
|
import subprocess |
||||||
|
import sys |
||||||
|
|
||||||
|
# defining some constants |
||||||
|
AUTHZ_PATH = "authz" |
||||||
|
HTPWD_PATH = "htpasswd" |
||||||
|
SVN_DIR_CREATOR = "svn-dir-creator" |
||||||
|
SVN_BASE = "cpi:/" |
||||||
|
|
||||||
|
ADMINS = "administrators" |
||||||
|
REGULAR = "users" |
||||||
|
RESTRICTED = "restricted" |
||||||
|
ALUMNI = "alumni" |
||||||
|
|
||||||
|
READ_ACL = "r" |
||||||
|
WRITE_ACL = "rw" |
||||||
|
|
||||||
|
re_separators = re.compile("[\t ,;]+") |
||||||
|
|
||||||
|
# helper functions |
||||||
|
def group_users(users): |
||||||
|
""" uses the list of users to group them by their group name """ |
||||||
|
groups = dict() |
||||||
|
for user in users.values(): |
||||||
|
if user.group not in groups: |
||||||
|
groups[user.group] = [] |
||||||
|
groups[user.group].append(user.name) |
||||||
|
return groups |
||||||
|
|
||||||
|
def set_new_password(name, length=10): |
||||||
|
""" sets a new password for a username """ |
||||||
|
characters = string.ascii_letters + string.digits |
||||||
|
password = "".join(random.choice(characters) for i in range(length)) |
||||||
|
subprocess.check_call(["htpasswd", "-b", HTPWD_PATH, name, password]) |
||||||
|
return password |
||||||
|
|
||||||
|
def delete_password(name, length=10): |
||||||
|
""" deletes a password for a username """ |
||||||
|
# if the user was not added to the password db, the removal will show |
||||||
|
# an error message that is confusing to the user - at least it confused me |
||||||
|
# so redirect this to /dev/null |
||||||
|
with open(os.devnull, 'wb') as devnull: |
||||||
|
subprocess.check_call(["htpasswd", "-D", HTPWD_PATH, name], stderr=devnull) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# class definitions |
||||||
|
class User(object): |
||||||
|
""" Collect the username, group and access control lists """ |
||||||
|
|
||||||
|
def __init__(self, name, group): |
||||||
|
""" initialization of the class """ |
||||||
|
self.name = name |
||||||
|
self.group = group |
||||||
|
self.write_acl = [] |
||||||
|
self.read_acl = [] |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
""" return a string representation """ |
||||||
|
return self.name |
||||||
|
|
||||||
|
def __repr__(self): |
||||||
|
""" return a string representation of the object """ |
||||||
|
return "<User '%s@%s'>" % (self.name, self.group) |
||||||
|
|
||||||
|
|
||||||
|
class AuthzConfigParser(ConfigParser.ConfigParser, object): |
||||||
|
""" custom functions for parsing the "authz" file as used at cpi """ |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
""" initialization of the class """ |
||||||
|
self.users = None |
||||||
|
super(AuthzConfigParser, self).__init__() |
||||||
|
|
||||||
|
def optionxform(self, value): |
||||||
|
""" reset the method to use cases ensitive names """ |
||||||
|
return str(value) |
||||||
|
|
||||||
|
def extract_users(self): |
||||||
|
""" extract user information from config """ |
||||||
|
users = dict() |
||||||
|
# first we go through the groups, as found in the groups section of the |
||||||
|
# authz file |
||||||
|
for group, userlist in self.items("groups"): |
||||||
|
for username in re_separators.split(userlist): |
||||||
|
if username in users: |
||||||
|
raise Exception("Found duplicate entry for user " + username) |
||||||
|
user = User(username, group) |
||||||
|
users[username] = user |
||||||
|
# second we scan each section that is related to an svn folder (it |
||||||
|
# starts with the svn base) for read and write access user entries |
||||||
|
for section in self.sections(): |
||||||
|
if section.startswith(SVN_BASE): |
||||||
|
belongs_to = section.lstrip(SVN_BASE) |
||||||
|
for (option, value) in self.items(section): |
||||||
|
if option in users: |
||||||
|
if value.lower() == WRITE_ACL: |
||||||
|
users[option].write_acl.append(belongs_to) |
||||||
|
elif value.lower() == READ_ACL: |
||||||
|
users[option].read_acl.append(belongs_to) |
||||||
|
# return the userlist |
||||||
|
return users |
||||||
|
|
||||||
|
def get_folder_info(self, name): |
||||||
|
""" returns read and write access info of an svn folder """ |
||||||
|
if not name.startswith(SVN_BASE): |
||||||
|
name = SVN_BASE + name |
||||||
|
if not self.has_section(name): |
||||||
|
return None |
||||||
|
info = { WRITE_ACL: [], READ_ACL: [] } |
||||||
|
for (option, value) in self.items(name): |
||||||
|
if value in (WRITE_ACL, READ_ACL): |
||||||
|
info[value].append(option) |
||||||
|
return info |
||||||
|
|
||||||
|
def move_user_to_alumni(self, user): |
||||||
|
""" moves a user to the alumni group and removes every access rights """ |
||||||
|
for access_to in user.write_acl: |
||||||
|
folder = SVN_BASE + access_to |
||||||
|
self.remove_option(folder, user.name) |
||||||
|
for access_to in user.read_acl: |
||||||
|
folder = SVN_BASE + access_to |
||||||
|
self.remove_option(folder, user.name) |
||||||
|
user.write_acl = [] |
||||||
|
user.read_acl = [] |
||||||
|
user.group = ALUMNI |
||||||
|
delete_password(user.name) |
||||||
|
|
||||||
|
def update_user_groups(self, users): |
||||||
|
""" updates the config settings of the groups section """ |
||||||
|
groups = group_users(users) |
||||||
|
for group, userlist in groups.items(): |
||||||
|
self.set("groups", group, ", ".join(sorted(userlist))) |
||||||
|
|
||||||
|
def write_to_file(self): |
||||||
|
with open(AUTHZ_PATH, "w") as filehandle: |
||||||
|
self.write(filehandle) |
||||||
|
|
||||||
|
def write(self, fp): |
||||||
|
"""Write an .ini-format representation of the configuration state. |
||||||
|
|
||||||
|
this is adapted from the original library file. changes: |
||||||
|
- no default section |
||||||
|
- group-section at top |
||||||
|
- rest of section sorted by name |
||||||
|
""" |
||||||
|
sorted_keys = sorted(self._sections.keys()) |
||||||
|
sorting = ["groups"] |
||||||
|
sorting.extend([k for k in sorted_keys if k <> "groups"]) |
||||||
|
for section in sorting: |
||||||
|
fp.write("[%s]\n" % section) |
||||||
|
for (key, value) in self._sections[section].items(): |
||||||
|
if key == "__name__": |
||||||
|
continue |
||||||
|
if (value is not None) or (self._optcre == self.OPTCRE): |
||||||
|
key = " = ".join((key, str(value).replace('\n', '\n\t'))) |
||||||
|
fp.write("%s\n" % (key)) |
||||||
|
fp.write("\n") |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
# create configparser instance |
||||||
|
config = AuthzConfigParser() |
||||||
|
# change option name transformation to case sensitive |
||||||
|
config.optionxform = str |
||||||
|
# read config file |
||||||
|
config.read(AUTHZ_PATH) |
||||||
|
users = config.extract_users() |
||||||
|
|
||||||
|
# command line interface: |
||||||
|
# no option: display info |
||||||
|
# -g display users in a group |
||||||
|
# -a add regular user |
||||||
|
# -r add restricted user |
||||||
|
# -m move to alumni |
||||||
|
# -p reset user password |
||||||
|
parser = optparse.OptionParser( |
||||||
|
usage="usage: %prog [option] name", |
||||||
|
description="shows and manipulates svn access rights", |
||||||
|
epilog="to grant a restricted user access to another folder, you have to carefully edit the authz file") |
||||||
|
parser.add_option("-g", "--groupinfo", action="store_const", dest="what", |
||||||
|
const="g", help="display users in a group") |
||||||
|
parser.add_option("-a", "--add", action="store_const", dest="what", |
||||||
|
const="a", help="add a regular user") |
||||||
|
parser.add_option("-r", "--restricted", action="store_const", dest="what", |
||||||
|
const="r", help="add a restricted user") |
||||||
|
parser.add_option("-m", "--move", action="store_const", dest="what", |
||||||
|
const="m", help="move a user to alumni") |
||||||
|
parser.add_option("-p", "--password", action="store_const", dest="what", |
||||||
|
const="p", help="reset a user password") |
||||||
|
options, args = parser.parse_args() |
||||||
|
|
||||||
|
if len(args)==0: |
||||||
|
# no arguments? then display all the users! |
||||||
|
groups = group_users(users) |
||||||
|
for name, usernames in groups.items(): |
||||||
|
print "Users in group '%s':" % name |
||||||
|
for name in sorted(usernames): |
||||||
|
print " " + name |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
if len(args)>1: |
||||||
|
# more than one usename? not here, john boy |
||||||
|
sys.exit("please provide only one name") |
||||||
|
name = args[0] |
||||||
|
|
||||||
|
if options.what == "g": |
||||||
|
# show group information |
||||||
|
groups = group_users(users) |
||||||
|
if name not in groups: |
||||||
|
sys.exit("Group not found") |
||||||
|
print "Users in group '%s':" % name |
||||||
|
for usernamename in sorted(groups[name]): |
||||||
|
print " " + usernamename |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
if options.what in ("a", "r"): |
||||||
|
# add a user, restricted or regular |
||||||
|
if name in users: |
||||||
|
sys.exit("Username '%s' already in use" % name) |
||||||
|
group = RESTRICTED if options.what == "r" else REGULAR |
||||||
|
users[name] = User(name, group) |
||||||
|
config.update_user_groups(users) |
||||||
|
folder = SVN_BASE + name |
||||||
|
config.add_section(folder) |
||||||
|
config.set(folder, "@"+RESTRICTED, "") |
||||||
|
config.set(folder, name, WRITE_ACL) |
||||||
|
#subprocess.check_call(SVN_DIR_CREATOR + " " + name, shell=True) |
||||||
|
password = set_new_password(name) |
||||||
|
print "New password for user '%s': '%s'" % (name, password) |
||||||
|
config.write_to_file() |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
# from here downwards we need already existent usernames |
||||||
|
if name not in users: |
||||||
|
sys.exit("User '%s' not found, use this without a name to get a list of users." % name) |
||||||
|
user = users[name] |
||||||
|
|
||||||
|
if options.what == "m": |
||||||
|
# move user to alumni |
||||||
|
groups = group_users(users) |
||||||
|
if user.group == ALUMNI: |
||||||
|
sys.exit("User '%s' is already in group '%s'" % (name, ALUMNI)) |
||||||
|
if user.group == ADMINS: |
||||||
|
sys.exit("User '%s' is in group '%s', will not moved to '%s'" % (name, ADMINS, ALUMNI)) |
||||||
|
config.move_user_to_alumni(user) |
||||||
|
config.update_user_groups(users) |
||||||
|
config.write_to_file() |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
if options.what == "p": |
||||||
|
# reset a password |
||||||
|
password = set_new_password(name) |
||||||
|
print "New password for user '%s': '%s'" % (name, password) |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
# no option, just a name: |
||||||
|
# print all the infos connected to a name |
||||||
|
print "User %s is in group '%s':" % (name, user.group) |
||||||
|
if user.group == ADMINS: |
||||||
|
print " Write access is granted to all folders." |
||||||
|
elif user.write_acl: |
||||||
|
write_acl = [ SVN_BASE + username for username in user.write_acl ] |
||||||
|
print " Write access is granted to folders '%s'. " % "', '".join(write_acl) |
||||||
|
else: |
||||||
|
print " Write access is NOT granted to any folder" |
||||||
|
if user.group in (ADMINS, REGULAR): |
||||||
|
print " Read access is granted to all folders." |
||||||
|
elif user.read_acl: |
||||||
|
read_acl = [ SVN_BASE + username for username in user.read_acl ] |
||||||
|
print " Read access is granted to folders '%s'. " % "', '".join(read_acl) |
||||||
|
else: |
||||||
|
print " Read access is NOT granted to any folder" |
||||||
|
info = config.get_folder_info(name) |
||||||
|
print "Labjornal %s%s:" % (SVN_BASE, name) |
||||||
|
write_acl = [ "@" + ADMINS ] + info[WRITE_ACL] |
||||||
|
print " Write access granted to " + ", ".join(write_acl) |
||||||
|
read_acl = [ "@" + ADMINS, "@" + REGULAR ] + info[READ_ACL] |
||||||
|
print " Read access granted to: " + ", ".join(read_acl) |
@ -0,0 +1,28 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
# This script will add a new user directory to the svn repository |
||||||
|
# it will only checkout the top level directory and should therefore |
||||||
|
# be faster then the original script |
||||||
|
# HF |
||||||
|
|
||||||
|
set -e |
||||||
|
set -u |
||||||
|
|
||||||
|
username=$1 |
||||||
|
year=`date +"%Y"` |
||||||
|
|
||||||
|
# checkout only the top level directory into a new folder |
||||||
|
cd /var/www |
||||||
|
svn checkout file:///var/www/svn/cpi svn-dirs-empty --depth immediates |
||||||
|
|
||||||
|
# create the user folder and commit it |
||||||
|
cd /var/www/svn-dirs-empty |
||||||
|
mkdir -p $username |
||||||
|
mkdir -p $username/$year/$year-{01,02,03,04,05,06,07,08,09,10,11,12} |
||||||
|
for i in $username/$year/*; do touch $i/.empty; done |
||||||
|
svn add $username |
||||||
|
svn commit -m"New user: $username" |
||||||
|
|
||||||
|
# remove the temporary directory |
||||||
|
cd /var/www |
||||||
|
rm -r svn-dirs-empty/ |
Loading…
Reference in new issue