Individuelle, geschützte und dynamisch erstellte SVN-Repositories

facesDas Problem: Es sollen individuelle SVN Verzeichnisse erstellt werden. Ein Bereich also, in dem eine Person beliebig viele Repositories erstellen kann, die nur von ihr selbst angesehen und bearbeitet werden können. Mann könnte jetzt meinen – vorallem mit viel jugendlichem Leichtsinn – das sei ein einfaches, allgemein bekanntes Problem. Pustekuchen! Das muss ein ganz fremder wohl ganz abstruser Wunsch sein.

Verschiedene Dinge schränken die Chance ein, eine einigermassen vernünftige und allgemeine Lösung zu finden 🙁 .Doch der Reihe nach. Was ist gegeben:

  • Ein wunderbarer Server, mit SSL und allem.
  • Das Einrichten eines neuen Users sollte ungefähr 0,01 Sekunden menschlicher Arbeitskraft bedürfen.
  • Die Benutzer sind in einem Active Directory gespeichert.
  • Apache2, PHP, und alles was man will ist installiert.

Einschränkende Dinge

Die grösste Peinlichkeit ist die Direktive SVNParentPath (von mod_dav_svn). An sich sollte die Direktive ein Basisverzeichnis für die SVN-Repositories angeben aber:

  • Der Parameter (das Verzeichnis) ist absolut undynamisch. Er nimmt keine Umgebungsvariable, Regexp oder sonst was, sondern ganz stur nur einen festen Pfad.
  • Kann nicht in einer .htaccess Datei gesetzt werden

Gna! Das ist echt 2002! So wird das nichts mit dynamisch erstellten SVN-Verzeichnissen. Aus reinem Masochismus hane ich verschiedene Lösungen wie mod_rewrite, symbolischen Links, LocationMatch und alles was sonst noch so Zeit kostet ausprobiert. Keine Chance…
Erschwerend hinzu kommt, dass sich SVN überhaupt nicht mit der Alias Direktive anfreunden kann und konsistent stur auf eine jungfräuliche Location beharrt: Der Versuch wird mit einem Repository moved permanently, please relocate belohnt.

Die Krönung: mod_authz_path

mod_authz_path klingt vielversprechend. An Hand des Pfades sollte der User und das Realm festgelegt werden können. Jaaa, aber nicht als Location, sondern nur als Pfad (<Directory> im Apache), wie man mit dem Debuggen feststellen kann:

AuthNamePathMatch (.+) "Persoenliches SVN $1"
AuthzUserPathMatch (.+) $1

Mit dem Pfad findet sich aber – wie schon weiter oben geflucht – das SVN nicht zurecht.

Ganz nebenbei hat mich dieses Modul etwa viertausend Stunden gekostet. Wenn es geladen wird, funktioniert authnz_ldap nicht mehr richtig. Nicht überhaupt nicht, sondern einfach das require Statement spielt verrückt und verhält sich unberechenbar. Nach langer Zeit habe ich dann das auch gemerkt :irre: . Aber erst nachdem ich unter viel Wehklagen in einer Panik die anderen Server getestet habe, ob die Authentifizierung dort auch nur scheinbar funktioniert.

Die Lösung

Nach ein paar Jahren die Lösung: Gutes, altes PHP.

Auf dem SSL-Port des Servers ist eine Website, auf der sich die User mal als erstes über Apache am Active Directory authentifizieren müssen. Dadurch habe ich Zugriff auf den Benutzername mittels $_SERVER['AUTHENTICATE_SAMACCOUNTNAME']. Loggt sich jemand ein den wir noch nicht kennen, dann:

  1. Wird der svn-Grundpfad erstellt, wenn er noch nicht existiert.
  2. Wird eine Apache-Konfiguration für diesen neuen Grundpfad erstellt, die das ParentPath und den entsprechenden User beinhaltet.
  3. Wird Apache neu gestartet → und der Benutzer währenddessen zum Warten gebracht. Das ist leider notwendig zum Einlesen der Konfigurationserweiterung.

Die neue Konfigurationsdatei wird „lokal“ erstellt und in der Grundkonfiguration /etc/apache2/sites-available/isvn.myhost.ch eingebunden:

        Include /data/www/isvn.myhost.ch/config/svn.conf

PHP Code für die neuen Benutzer:

  $svn_user=strtolower($_SERVER['AUTHENTICATE_SAMACCOUNTNAME']);
  if(!$svn_user) { echo "Hacker, you will be disintegrated!"; exit(1); }
  $svn_root=SVNROOT."/".$svn_user;
  if(!is_dir($svn_root)) { // NEW USER
        // Make svn Parent Path
        mkdir($svn_root);
        // Write Config
        $fh = fopen(SVNCONF, 'a') or die("can't open file");
        $svnDirective =<<<EOD

<Location /svn/lp/$svn_user>
        DAV svn
        SVNParentPath /data/svn/lp/$svn_user
        AuthName "Persoenliches SVN von $svn_user"
        AuthType Basic
        AuthBasicProvider ldap
        AuthLDAPBindDN ldapanonymous@myhost.local
        AuthLDAPBindPassword g3h31M3Sp+
        AuthLDAPUrl ldap://adc1.myhost.local/ou=Accounts,dc=myhost,dc=local?sAMAccountName?sub
        require ldap-user $svn_user
</Location>

EOD
;
        fwrite($fh, $svnDirective);
        fclose($fh);

        // Make th User wait
        echo "<html><head><title>SVN wird eingerichtet</title>\n";
        echo '<meta http-equiv="refresh" content="5; URL=https://isvn.myhost.ch">'."\n";
        echo "</head><body>".implode(" ", explode(".",$_SERVER['AUTHENTICATE_SAMACCOUNTNAME'])).": Ihr SVN Grundverzeichnis wird erstellt. Bitte warten Sie.</body></html>";

        // Restart Apache
        exec('echo "/usr/bin/sudo /etc/init.d/apache2 restart" | /usr/bin/at now');
        exit();
  }

Damit der User www-data den Apache restarten darf, muss ihm das per /etc/sudoers erlaubt werden:

www-data ALL=NOPASSWD: /etc/init.d/apache2

Dass die Berechtigungen auch für alle benötigten Zusatzdateien reichen, machen wir den Trick mit dem at.

Somit haben wir also eine hochindividuelle Konfigurationsdatei für alle User und Ihr SVN Grundverzeichnis. Die PHP-Seite ermöglicht es, SVN-Repositories anzulegen und zeigt auch gerade den annektierten Platz an:

Die SVN-Steuerkonsole

Die SVN-Steuerkonsole

Die Quellen

Hier sind die PHP-Quellen. Für weitere Details stehe ich gerne zur Verfügung.

Suchmaschine für Websites: mnoGoSearch und das Umwandeln von Dateien in Text

searchLeider wurde die Entwicklung von htdig scheinbar eingestellt, und so wurde ich gezwungen nach Alternativen zu suchen. Aber alles der Reihe nach: was will ich denn, ausser 12 Stunden Schlaf? Also; An unserer Schule werden alle Unterrichtsunterlagen in SVN-Repositories abgelegt, Um das Zusammenarbeiten der Lehrpersonen zu fördern soll es eine Suche über alle Unterrichtsmaterialien geben. So besteht die Chance, dass einiges an Doppelspurigkeiten vermieden werden könnte. Eine Recherche hat einiges an Kandidaten aufgezeigt: Sphinx schien ein wenig SQL-Lastig zu sein, Swish-e kannte ich schon und somit habe ich mich mal auf mnoGoSearch gestürzt. Für Unix ist mnoGoSearch gratis, open Source und sogar in Debian verfügbar.

Suchmaschinen Theorie

Das mit den Lokalen Suchmaschinen läuft immer ziemlich ähnlich und wurde auch schon an verschiedenen Stellen in diesem Blog besprochen (Beagle (neu) und xFriend (alt)). Ein Indexer liest alle Dateien und erstellt einen – ja was denn wohl? – Index. Damit er das kann, müssen alle Dateien in eine für ihn lesbare Form umgewandelt werden. Normalerweise ist „Lesbar“ Text oder HTML. Einige Suchmaschinen – wie beispielsweise Lucene oder Swish-e – erlauben auch XML um gewisse Felder zu bezeichnen, aber das ist eine andere Geschichte. Eine Suchoberfläche interagiert nun mit dem Index und versucht möglichst viele Seiten zu Finden und diese nach Relevanz geordnet dem Benutzer zu präsentieren.
Weiterlesen

Ausschliessen von Repositories bei WebSVN

hiddenWie schon ein paar mal erwähnt: Websvn ist ein geniales Tool! Es ermöglicht das Browsen von verschiedenen Repositories übers Web mit dem Browser. Manchmal möchte man aber nicht alle Verzeichnisse freigeben und anzeigen.

Ich habe einen Patch erstellt, der eine neue Option in /etc/websvn/config.inc erlaubt: $config->excludeRepository("name");. Diese Option kann mehrfach angegeben werden und alle excludeten Repositories werden nicht mehr dargestellt…

Beispiel:

// Select Repositories to exclude
$config->excludeRepository("Geheime-Codes");
$config->excludeRepository("Jokes");

Und hier der Patch: Websvn exclude Repositories Patch.

Viel Spass… Eine Rückmeldung bei Anwendung würde mich freuen…

Websvn mit Repositories in verschiedenen Verzeichnissen

Websvn in AktionWebsvn kann mehrere Repositories in verschiedenen Unterverzeichnissen darstellen, allerdings muss man sich entscheiden: Alle Repositories aller Unterverzeichnisse aufs mal oder nur Repositories eines einzelnen Unterverzeichnisses.
Bei uns im Betrieb hat jede Abteilung (Informatik, Physik, …) ihre Repositories in eigenen Verzeichnissen auf dem Server. Websvn unterstützt zwar mehrere parentPath und stellt alle SVN-Repositories in diesen Verzeichnissen dar, will man aber auch noch einzelne Ansichten für die Abteilungen machen wird es schwer. Lösung: Der parentPath wird an Hand der URL gesetzt.

Unter Debian kann die Datei /etc/websvn/svn_deb_conf.inc direkt missbraucht werden. In anderen Distributionen muss eventuell am Schluss der Datei config.inc folgendes Codesnippet eingefügt und danach für die Änderungen gebraucht werden:

<?php
if ( file_exists("/etc/websvn/svn_sup_conf.inc") ) {
  include("/etc/websvn/svn_sup_conf.inc");
}
?>

Nun soll an Hand des Pfades der /etc/websvn/svn_deb_conf.inc parentPath gesetzt werden:

/websvn
Alle Repositories
/websvn/informatik
Alle Repositories der Abteilung Informatik
/websvn/physik
Alle Repositories der Abteilung Physik

Dafür muss man in der oben konfigurierten Datei folgendes zum Besten geben (bei mehr Abteilungen einfach intelligent erweitern):

<?php
  $repository=dirname($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']);
  // echo "::: $repository :::";
  switch($repository) {
    case "/websvn/informatik":
    case "/websvn/physik":
          $reppath="/data/svn/repositories/".substr(dirname($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']),8)."/"; // "/websvn/" entfernen
          //print "::: $reppath :::"; exit(1);
          $config->parentPath($reppath);
    break;
    default:
        $config->parentPath("/data/svn/repositories/informatik");
        $config->parentPath("/data/svn/repositories/physik");
    break;
  }
?>

Der Apache muss dies natürlich auch noch mitkriegen. Die /websvn/ URL-Teile müssen dort konfiguriert werden (site-available oder .htaccess) und das wärs dann:

# Websvn is installed in /usr/share/websvn
Alias /websvn /usr/share/websvn

Alias /websvn/informatik /usr/share/websvn
Alias /websvn/physik /usr/share/websvn

<Location /websvn>
  # DO FUNKY (AUTHENTICATION) STUFF HERE
  <IfModule mod_php4.c>
    php_flag magic_quotes_gpc Off
    php_flag track_vars On
  </IfModule>
</Location>

Mit Apache 2.2 an einem Windows ADC authentifizieren

Zentrale Accountverwaltung (oder in Managerdeutsch: Single Signon) ist etwas schönes! Der IT-Support kann sich darum kümmern, spontan Änderungen vornehmen und die Websiteverantwortlichen müssen nicht mehr rennen und vergessene Passworte zurücksetzen. Viele Zentrale Verzeichnisse laufen unter Windows mittels ADCs (Active Directory Connector). Der ist so nett und stellt seine Dienste auch als LDAP (Lightweight Directory Access Protocol) zur Verfügung. Der Apache kann darüber (auch unter Linux) authentifizieren mit Basic Authentication, also mit dem Passwortfenster aber ohne PHP und PERL und so…

Benötigt wird das Modul authnz-ldap. Unter Debian kann das eingeschaltet werden mittels:

a2enmod

In einer .htaccess Datei oder in der Site-Konfiguration kann man nun sehr gezielt für Verzeichnisse oder URLs die Authentifizierung einschalten. Hier ein Beispiel:

<location /admin>
                AuthName "LDAP-Authentifizierter Bereich"
                AuthType Basic
                AuthBasicProvider ldap
                AuthLDAPBindDN ldapreader@aden.local
                AuthLDAPBindPassword secretpassword
                AuthLDAPUrl ldap://adc1.aden.local/ou=Accounts,dc=aden,dc=local?sAMAccountName?sub
                AuthzLDAPAuthoritative on
                require ldap-group CN=Angestellte,OU=Berechtigungsgruppen,OU=Gruppen,DC=domain,DC=local
</location>
ldapreader@aden.local:
Ist ein Benutzer mit Leserechten aus der Domäne domain.local
secretpassword:
Ist das Passwort dieses Benutzers.
require:
Gibt an, wer Zugriff hat. ldap-group authentifiziert ganze Gruppen. Es gibt aber auch noch andere Direktiven.

Das Ganze funktioniert natürlich auch für SVN und Websvn Zugriffe über das Web!

Zertifikat erstellen und http-Anfragen auf https umleiten

Um zu einem SSL- Zertifikat zu kommen, kann unter Debian folgendes Kommando verwendet werden:

apache2-ssl-certificate

Dieses könnte man nun signieren lassen oder wenn man nur die Verschlüsselungseigenschaften braucht einfach so belassen. Wenn Apache das Modul mod_ssl geladen hat, kann man nun noch die Datei ans richtige Ort bewegen (Siehe SSLCertificateFile Parameter weiter unten).

Port 443 ist der Port auf dem der Apache auf https Verbindungen hört. Dass er dort ein Ohr platziert muss /vserver/webv2/etc/apache2/ports.conf angepasst werden;

Listen 80
Listen 443

Man hat ein schönes Zertifikat mit ganz vielen Bitlein und nun sollen die Benutzer dies auch gefälligst nutzen. Auf gut Deutsch: man zwingt alle http-Anfragen auf https (http://sicher.oncode.info soll zu https://sicher.oncode.info werden). mod_rewrite für Apache kann das gut, sehr gut sogar und erst noch automatisch. Dafür muss Apache folgendermassen konfiguriert werden:

Datei /vserver/webv2/etc/apache2/sites-available/default

NameVirtualHost *:443
NameVirtualHost *:80

<virtualhost *:80>
        RewriteEngine On
        RewriteCond %{HTTPS} !=on
        RewriteRule ^/(.*) https://%{SERVER_NAME}%{REQUEST_URI} [R]
</virtualhost>

<virtualhost *:443>
        ServerName sicher.oncode.info
        ServerAdmin apache.admin@onc0de.info
        SSLEngine On
        SSLCertificateFile /etc/apache2/ssl/apache.pem
[...]
</virtualhost>

Ein nettes Tutorial gibt es auch auf Tim Bormans Blog.

SVN und Moodleintegration: Einen Schritt weiter

In einem älteren Posting habe ich schon beschrieben, dass wir das LMS Moodle mit SVN integrieren. Um die Integration voranzutreiben habe ich einen Block gecoded, von welchem aus man direkt die Dateien aktualisieren kann:

Moodle SVN Block

Den Code zu posten macht nicht viel Sinn, da es sehr installationsabhängig ist. Auf Anfrage hin rücke ich aber gerne was raus 🙂 ….

Changelogs mit SVN

Aufgabe

Und die Aufgabe sei: Es werde ein Tool geschaffen, das jeden Tag prüft, wer an den Repositories gefrickelt hat und daraus ein Changelog generieret. Fürtherhin sei eine Liste als Index erstellt, die alle diese Repositories mit den Committern anzeiget und mit Links versehet, die zum detailierten Changelog geleiten. Auch ein RSS sei geschaffen, der abonniert werden kann.

So sei es. svn2log kann Text-Changelogs generieren. source-highlight kann daraus html-Seiten basteln. Damit svn2log auch Commits ohne Kommentar berücksichtigt, wird es gepatcht.

So sei Dir ein BASH-Script geschrieben, das durch unsere 2 Stufige Repositoryhierarchie hindurchloopt, und 4 Dinge erzeuge:

  • Text Changelog generell
  • Text Changelog der letzten 7 Tage
  • Html Changelog generell
  • Html Changelog der letzten 7 Tage

Und danach ein PHP fürwahr ein Index erstelle der eine Übersicht zeige und der auch via RSS in ein jede heimische Stube kommen kann!

Beispiel: Changelog Index

Bemerkungen

Nachtrag: Eine weitere Möglichkeit ist svn2rss. Ein etwas mächtigeres Paket, geschrieben in Ruby.

Code

Den Code gibts bei oncode.info.

SVN mit Moodle integrieren

Moodle eignet sich sehr gut um Dokumente für Lernende bereitzuhalten und zu publizieren. SVN eignet sich, um Dokumente abzulegen wenn mehrere Leute zusammenarbeiten. Was liegt also näher als die beiden Dinge zu kombinieren?

Vorteile:

  • Es sind immer aktuelle Dokumente auf dem Moodle
  • Das lästige Hochladen entfällt
  • Es ist mächtig 1337!

Soweit die Theorie, doch wie läuft das in der Praxis?

Grundsätzlich werden auf dem Moodleserver die SVN-Verzeichnisse ausgecheckt. Jede Nacht läuft ein Cronjob, der diese Arbeitsverzeichnisse aktualisiert und noch nicht vorhandene an diesen Ort auscheckt. Im Moodle „data“ Verzeichnis werden in den Kursen symbolische Links auf diese Arbeitsverzeichnisse gesetzt, die dann in Moodle selber wie normale Verzeichnisse behandelt werden können.

Um diese Arbeitsverzeichnisse auszuchecken habe ich ein Bash-Script geschrieben, für das Setzen der Links gibt es ein ganz hässliches Webinterface. Beide Quellcodes stelle ich gerne zur Verfügung, hierhin passense nicht….

Probleme:

  • Die Berechtigungen der Arbeitsverzeichnisse müssen so gesetzt werden, dass normale Benutzer über Moodle keine Dateien verändern oder löschen können.
  • Da es ein Link ist und kein echtes Verzeichnis, lässt Moodle keine „Verzeichnis Ressourcentypen“ zu. Korrigiert werden kann dies in lib/moodlelib.php, Funktion get_directory_list:
    if (!is_dir($rootdir)  && !is_link($rootdir)) {          // Must be a directory

    und:

    if (filetype($fullfile) == 'dir'  || filetype($fullfile) == "link") {
  • Die SVN-Arbeitsverzeichnisse sollen ja nicht migebackupt werden, da man gescheiter die Repositories sichert. Darum in backup/backuplib.php, Funktion backup_copy_course_files anpassen:
    if ($dir !== $name_moddata and $dir !== $name_backupdata and !is_link($rootdir."/".$dir)) {