httpd, der Apache HTTP-Server

Der Apache HTTP-Server ist ein Hochleistungs-Netzwerk-Server, den Subversion zu seinem Vorteil nutzen kann. Über ein angepasstes Modul macht httpd Subversion-Projektarchive für Clients über das WebDAV/DeltaV-Protokoll verfügbar, welches eine Erweiterung von HTTP 1.1 ist (siehe http://www.webdav.org/ für weitere Informationen). Dieses Protokoll nimmt das allgegenwärtige HTTP-Protokoll, das der Kern des World Wide Web ist, und fügt Schreibfähigkeiten – im Besonderen, versioniertes Schreiben – hinzu. Das Ergebnis ist ein standardisiertes, robustes System, das auf geeignete Weise als Teil der Software Apache 2.0 verteilt wird, die von zahlreichen Betriebssystemen und Drittanbieter-Produkten unterstützt wird und keine Netzwerk-Administratoren benötigt, um einen weiteren speziellen Port zu öffnen. [42] Während ein Apache-Subversion-Server mehr Möglichkeiten bietet als svnserve, ist er allerdings auch etwas schwieriger einzurichten. Flexibilität geht oft mit Komplexität einher.

Viele der folgenden Erläuterungen beziehen sich auf Konfigurationsdirektiven von Apache. Obwohl ein paar Beispiele zur Verwendung dieser Direktiven gegeben werden, würde deren erschöpfende Behandlung dieses Kapitel sprengen. Das Apache-Team verfügt über hervorragende Dokumentation, die auf deren Web-Seite http://httpd.apache.org frei verfügbar ist. So befindet sich beispielsweise eine allgemeine Referenz der Konfigurationsdirektiven unter http://httpd.apache.org/docs-2.0/mod/directives.html.

Falls Sie Änderungen an den Einstellungen von Apache vornehmen, ist es wahrscheinlich, dass sich irgendwo ein Fehler einschleicht. Wenn Sie noch nicht mit der Protokollierung von Apache vertraut sind, sollten sie sich damit vertraut machen. In der Datei httpd.conf befinden sich Direktiven, die angeben, wo auf der Platte sich die von Apache erzeugten Zugriffs- und Fehlerprotokollierungsdateien befinden (die Direktiven CustomLog bzw. ErrorLog). Auch mod_dav_svn von Subversion verwendet die Protokollierungsschnittstelle von Apache. Sie können jederzeit den Inhalt dieser Dateien nach Informationen durchforsten, die eine Problemquelle aufdecken könnten, die sonst nicht offensichtlich wäre.

Voraussetzungen

Um Ihr Projektarchiv im Netz über HTTP zur Verfügung zu stellen, brauchen Sie grundsätzlich vier Komponenten, die in zwei Paketen verfügbar sind. Sie benötigen Apache httpd 2.0, das dazugelieferte DAV-Modul mod_dav, Subversion und das mitgelieferte Dateisystemmodul mod_dav_svn. Sobald Sie über all diese Komponenten verfügen, ist die Bereitstellung Ihres Projektarchivs über das Netz ganz einfach:

  • Inbetriebnahme von httpd 2.0 mit dem Modul mod_dav

  • Installation des mod_dav_svn-Backends zu mod_dav, das die Bibliotheken von Subversions für den Zugriff auf das Projektarchiv verwendet

  • Konfiguration Ihrer Datei httpd.conf, um das Projektarchiv zu exportieren (oder sichtbar zu machen)

Sie können die ersten beiden Punkte bewerkstelligen, indem Sie entweder httpd und Subversion aus den Quellen übersetzen oder als vorgefertigte Binärpakete auf Ihrem System installieren. Die aktuellsten Informationen zur Übersetzung von Subversion in Verbindung mit dem Apache HTTP-Server sowie die Übersetzung und Konfigurierung von Apache zu diesem Zweck finden Sie in der Datei INSTALL in der obersten Verzeichisebene des Quelltextes von Subversion.

Grundlegende Konfiguration von Apache

Sobald alle notwendigen Komponenten auf Ihrem System installiert sind, bleibt nur noch die Konfiguration von Apache über seine Datei httpd.conf. Weisen Sie Apache mit der Direktive LoadModule an, das Modul mod_dav_svn zu laden. Diese Direktive muss vor allen Konfigurationseinträgen in Verbindung mit Subversion stehen. Falls Ihr Apache mit dem vorgegebenen Aufbau installiert wurde, sollte sich das Modul mod_dav_svn im Unterverzeichnis modules des Apache-Installationsverzeichnisses befinden (oft /usr/local/apache2). Die Direktive LoadModule hat eine einfache Syntax, wobei ein benanntes Modul auf den Ort einer Shared-Library auf der Platte abgebildet wird:

LoadModule dav_svn_module     modules/mod_dav_svn.so

Falls mod_dav als Shared-Objekt übersetzt wurde (statt statisch direkt in die httpd-Binärdatei gelinkt worden zu sein), benötigen Sie hierfür ebenfalls einen ähnlichen LoadModule-Eintrag. Stellen Sie sicher, dass er vor der mod_dav_svn-Zeile steht:

LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so

Weiter unten in der Konfigurationsdatei sollten Sie Apache nun mitteilen, wo Sie Ihr Subversion-Projektarchiv (oder Ihre Projektarchive) aufbewahren. Die Direktive Location besitzt eine XML-ähnliche Notation, beginnend mit einem öffneneden Tag, endend mit einem schliessenden Tag und verschiedener anderer Konfigurationsdirektiven dazwischen. Der Zweck der Direktive Location besteht darin, Apache anzuweisen, etwas Besonderes zu tun, falls Anfragen bearbeitet werden, die an einen bestimmten URL oder dessen Kinder gerichtet sind. Im Fall von Subversion möchten Sie, dass Apache die Unterstützung für URLs, die auf versionierte Ressourcen zeigen, einfach an die DAV-Schicht weiterleitet. Sie können Apache anweisen, die Bearbeitung aller URLs, deren Pfadteile (der Teil des URL, der nach dem Servernamen und der optionalen Portnummer steht) mit /repos/ beginnen, an einen DAV-Provider zu delegieren, dessen Projektarchiv unter /var/svn/repository liegt, indem Sie die folgende httpd.conf-Syntax verwenden:

<Location /repos>
  DAV svn
  SVNPath /var/svn/repository
</Location>

Falls Sie planen, mehrere Subversion-Projektarchive zu unterstützen, die sich unterhalb eines gemeinsamen Elternverzeichnisses auf Ihrer lokalen Platte befinden, können Sie eine alternative Direktive, SVNParentPath, verwenden, um auf das gemeinsame Elternverzeichnis hinzuweisen. Wenn Sie beispielsweise wissen, dass Sie mehrere Subversion-Projektarchive in einem Verzeichnis /var/svn anlegen möchten, auf die über URLs wie http://my.server.com/svn/repos1, http://my.server.com/svn/repos2 usw. zugegriffen werden soll, könnten Sie die Konfigurationssyntax von httpd.conf aus dem folgenden Beispiel verwenden:

<Location /svn>
  DAV svn

  # any "/svn/foo" URL will map to a repository /var/svn/foo
  SVNParentPath /var/svn
</Location>

Die Verwendung der vorangegangenen Syntax veranlasst Apache, die Bearbeitung aller URLs, deren Pfadteil mit /svn/ beginnt, an den Subversion-DAV-Provider weiterzuleiten, der dann davon ausgeht, dass alle Objekte in dem durch die SVNParentPath-Direktive spezifizierten Verzeichnis tatsächlich Subversion-Projektarchive sind. Dies ist insofern eine besonders bequeme Syntax, da Sie im Gegensatz zur Direktive SVNPath Apache nicht neu starten müssen, wenn Sie neue Projektarchive erstellen und über das Netz verfügbar machen.

Achten Sie beim Definieren Ihrer neuen Location darauf, dass sie sich nicht mit anderen bereits exportierten überschneidet. Wenn beispielsweise Ihre Haupt-DocumentRoot nach /www exportiert wird, sollten Sie ein Subversion-Projektarchiv nicht in <Location /www/repos> exportieren. Falls eine Anfrage für den URI /www/repos/foo.c hereinkommt, weiß Apache nicht, ob die Datei repos/foo.c in DocumentRoot gesucht wird oder ob es die Herausgabe von foo.c aus dem Projektarchiv an mod_dav_svn delegieren soll. Das Ergebnis ist oftmals ein Fehler vom Server der Form 301 Moved Permanently.

An dieser Stelle sollten Sie ernsthaft über Berechtigungen nachdenken. Falls Sie Apache schon eine Zeit lang als Ihren regulären Web-Server in Betrieb haben, werden Sie wahrscheinlich bereits eine Ansammlung von Inhalt haben, etwa Webseiten, Skripte usw. Diese Dinge sind bereits mit einer Menge an Berechtigungen versehen, die es ihnen erlauben, mit Apache zusammen zu arbeiten, oder passender, die es Apache erlauben, mit diesen Dateien zu arbeiten. Wenn Apache als Subversion-Server eingesetzt wird, braucht er ebenfalls die richtigen Berechtigungen zum Lesen und Schreiben Ihres Subversion-Projektarchivs.

Sie werden ein Berechtigungssystem festlegen müssen, das die Anforderungen von Subversion erfüllt, ohne dabei bestehende Webseiten oder Skriptinstallationen zu beeinträchtigen. Das kann bedeuten, dass die Berechtigungen für Ihr Projektarchiv an die anderen Dinge angepasst werden müssen, die Apache für Sie zur Verfügung stellt, oder dass Sie die Direktiven User und Group in httpd.conf verwenden, um Apache mit denjenigen Benutzer- und Gruppenkennungen laufen zu lassen, die auch das Subversion-Projektarchiv besitzt. Es gibt keine einzig richtige Methode, um die Berechtigungen zu vergeben, und jeder Administrator wird bestimmte Gründe haben, um es auf eine bestimmte Art zu tun. Seien Sie sich lediglich bewusst, dass Probleme im Zusammenhang mit den Berechtigungen am häufigsten übersehen werden, wenn ein Subversion-Projektarchiv für die Verwendung mit Apache eingerichtet wird.

Authentifizierungsoptionen

Falls Sie httpd.conf dergestalt konfiguriert haben, so dass sie etwa den folgenden Eintrag enthält:

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
</Location>

kann die Welt anonym auf Ihr Projektarchiv zugreifen. Bis Sie Authentifizierungs- und Autorisierungsrichtlinien konfiguriert haben, sind die über die Direktive Location zur Verfügung gestellten Projektarchive allgemein für jedermann zugreifbar. Mit anderen Worten:

  • Jeder kann mit einem Subversion-Client eine Arbeitskopie eines Projektarchiv-URLs (oder irgendeins der Unterverzeichnisse) auschecken.

  • Jeder kann interaktiv die letzte Revision des Projektarchivs durchstöbern, indem der Projektarchiv-URL einfach mit einem Web-Browser geöffnet wird.

  • Jeder kann an das Projektarchiv übergeben.

Natürlich kann es sein, dass Sie schon längst ein pre-commit Hook-Skript bereitgestellt haben, um Übergaben zu verhindern (siehe „Erstellen von Projektarchiv-Hooks“). Sie werden jedoch beim Weiterlesen feststellen, dass es möglich ist, die eingebauten Methoden von Apache zu verwenden, um den Zugriff auf bestimmte Art und Weise einzuschränken.

HTTP Authentifizierung aufsetzen

Die einfachste Methode, einen Client zu authentifizieren geht über den HTTP-Basic-Authentifizierungsmechanismus, der einfach einen Benutzernamen und ein Passwort verwendet, um sicherzustellen, das ein Benutzer auch derjenige ist, für den er sich ausgibt. Apache stellt ein Dienstprogramm zur Verwaltung der Liste zulässiger Benutzernanen und Passwörter namens htpasswd zur Verfügung. Lassen Sie uns Sally und Harry die Berechtigung zur Übergabe erteilen. Zunächst müssen wir sie der Passwortdatei hinzufügen:

$ ### Beim 1. Mal: -c verwenden, um die Datei anzulegen
$ ### -m für die sicherere MD5-Verschlüsselung des Passworts verwenden
$ htpasswd -cm /etc/svn-auth-file harry
New password: *****
Re-type new password: *****
Adding password for user harry
$ htpasswd -m /etc/svn-auth-file sally
New password: *******
Re-type new password: *******
Adding password for user sally
$

Als nächstes müssen Sie innerhalb Ihres Location-Blocks ein paar weitere httpd.conf-Directiven hizufügen, um Apache zu sagen, was mit Ihrer neuen Passwortdatei zu tun ist. Die Direktive AuthType spezifiziert den Typ des zu verwendenden Authentifizierungssystems. In diesem Fall möchten wir das Basic-Authentifizierungssystem spezifizieren. AuthName ist ein beliebiger Name, den Sie Ihrer Authentifizierungsdomäne geben. Die meisten Browser zeigen diesen Namen in einem Dialog an, wenn der Browser den Benutzer nach seinem Namen und dem Passwort fragt. Verwenden Sie schließlich die Direktive AuthUserFile, um den Ort der Passwortdatei zu spezifizieren, die sie mit htpasswd erstellt haben.

Nachdem Sie diese Direktiven hinzugefügt haben, sollte Ihr <Location>-Block etwa so aussehen:

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /etc/svn-auth-file
</Location>

Dieser <Location>-Block ist noch unvollständig und bewirkt noch nichts sinnvolles. Er teilt Apache lediglich mit, dass es sich den Benutzernamen und das Passwort vom Subversion-Client besorgen soll, falls eine Autorisierung benötigt wird. Was hier jedoch noch fehlt, sind Direktiven, die Apache sagen, welche Arten von Client-Anfragen eine Autorisierung erfordern. Überall dort wo eine Autorisierung verlangt wird, erwartet Apache auch eine Authentifizierung. Das Einfachste ist es, alle Anfragen zu schützen. Durch Hinzufügen von Require valid-user wird Apache mitgeteilt, dass alle Anfragen einen authentifizierten Benutzer erfordern:

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /etc/svn-auth-file
  Require valid-user
</Location>

Stellen Sie sicher, dass Sie für weitere Details zur Require-Directive und anderen Wegen, Autorisierungsrichtlinien festzulegen, den nächsten Abschnitt („Autorisierungsoptionen“) lesen.

Ein Wort zur Warnung: HTTP-Basic-Auth-Passwörter werden nahezu im Klartext durch das Netz geschickt und sind deshalb in höchstem Maße unsicher.

Eine weitere Option besteht darin, statt der Basic-Authentifizierung die Digest-Authentifizierung zu verwenden. Digest-Authentifizierung erlaubt es dem Server, die Identität des Clients zu bestätigen, ohne das Passwort als Klartext durch das Netz zu schicken. Unter der Voraussetzung, dass sowohl dem Client als auch dem Server das Passwort des Benutzers bekannt ist, können sie verifizieren, dass das Passwort dasselbe ist, indem sie eine Hashfunktion auf ein Einweg-Informationshäppchen anwenden. Der Server sendet eine kleine zufällige Zeichenkette an den Client. Der Client verwendet das Passwort des Benutzers, um die Zeichenkette zu hashen, und der Server prüft dann, ob der gehashte Wert dem erwarteten Ergebnis entspricht.

Es ist auch ziemlich einfach, Apache für die Digest-Authentifizierung zu konfigurieren und lediglich eine kleine Abweichung des vorangegangenen Beispiels. Für weitere Einzelheiten wird die Dokumentation zu Apache empfohlen.

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
  AuthType Digest
  AuthName "Subversion repository"
  AuthDigestDomain /svn/
  AuthUserFile /etc/svn-auth-file
  Require valid-user
</Location>

Falls Sie maximale Sicherheit anstreben, ist ein asymmetrisches Kryptosystem das Mittel der Wahl. Am besten solte eine Art der SSL-Verschlüsselung eingesetzt werden, so dass Clients sich über https:// statt http:// authentifizieren; als Minimallösung können Sie Apache so einstellen, dass ein selbstsigniertes Server-Zertifikat verwendet wird. [43] Wie das bewerkstelligt wird, ist der Dokumentation von Apache (und OpenSSL) zu entnehmen.

SSL-Zertifikatsverwaltung

Unternehmen, die ihre Projektarchive für den Zugriff von außerhalb der Firewall freigeben müssen, sollten sich bewusst sein, dass Unbefugte den Netzverkehr abhören könnten. SSL lässt diese Art unerwünschte Aufmerksamkeit weniger anfällig für heikle Datenlecks werden.

Ist ein Subversion-Client für die Verwendung von OpenSSL übersetzt worden, ist er in der Lage, mit einem Apache-Server über https://-URLs zu kommunizieren. Die vom Subversion-Client verwendete Neon-Bibliothek kann nicht nur Server-Zertifikate zertifizieren, sondern nach Aufforderung auch Client-Zertifikate liefern. Wenn der Client und der Server SSL-Zertifikate ausgetauscht und sich gegenseitig erfolgreich authentifiziert haben, wird jede weitere Kommunikation durch einen Sitzungsschlüssel verschlüsselt.

Es würde den Rahmen dieses Buches sprengen, wenn beschrieben würde, wie Client- und Server-Zertifikate erzeugt werden und wie Apache für ihre Verwendung konfiguriert wird. Viele andere Bücher, darunter Apaches eigene Dokumentation, erläutern diese Aufgabe. Was wir an dieser Stelle jedoch behandeln können, ist die Verwaltung der Client- und Server-Zertifikate durch einen gewöhnlichen Subversion-Client.

Wenn über https:// mit Apache gesprochen wird, kann ein Subversion-Client zwei unterschiedliche Arten von Informationen empfangen:

  • Ein Server-Zertifikat

  • Eine Anfrage nach einem Client-Zertifikat

Wenn der Client ein Server-Zertifikat empfängt, muss er sicherstellen, dass er dem Zertifikat vertrauen kann: handelt es sich bei dem Server wirklich um denjenigen, fűr den er sich ausgibt? Die OpenSSL-Bibliothek macht das, indem der Unterzeichner des Server-Zertifikats, die sogenannte Certificate Authority (CA), oder Zertifizierungsstelle, untersucht wird. Falls OpenSSL der CA nicht automatisch vertrauen kann, oder falls ein anderes Problem auftaucht (etwa ein abgelaufenes Zertifikat oder ein nicht übereinstimmender Rechnername), fragt Sie der Subversion-Kommandozeilenclient, ob Sie dem Server-Zertifikat dennoch vertrauen möchten:

$ svn list https://host.example.com/repos/project

Fehler bei der Validierung des Serverzertifikats für »https://host.example.com:443«:
 - Das Zertifikat ist nicht von einer vertrauenswürdigen Instanz ausgestellt
   Überprüfen Sie den Fingerabdruck, um das Zertifikat zu validieren!
Zertifikats-Informationen:
 - Hostname: host.example.com
 - Gültig: von Jan 30 19:23:56 2004 GMT bis Jan 30 19:23:56 2006 GMT
 - Aussteller: CA, example.com, Sometown, California, US
 - Fingerabdruck: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b

Ve(r)werfen, (t)emporär akzeptieren oder (p)ermanent akzeptieren?

Dieser Dialog sollte Ihnen bekannt vorkommen; im Wesentlichen ist es dieselbe Frage, die Sie wahrscheinlich bei Ihrem Web-Browser gesehen haben (der auch bloß ein weiterer HTTP-Client ist, so wie Subversion). Falls Sie die Option (p)ermanent auswählen, wird das Server-Zertifikat in Ihrem privaten Laufzeit-auth/-Bereich zwischengespeichert, ebenso wie Ihr Benutzername und Passwort (siehe „Zwischenspeicherung der Client-Zugangsdaten“). Falls es zwischengespeichert ist, wird Subversion diesem Zertifikat bei künftigen Protokollverhandlungen vertrauen.

Ihre Laufzeit-Datei servers ermöglicht es Ihrem Client auch, automatisch bestimmten CAs zu vertrauen, entweder global oder pro Host. Setzen Sie die Variable ssl-authority-files auf eine durch Semikolons getrennte Liste PEM-kodierter CA-Zertifikate:

[global]
ssl-authority-files = /path/to/CAcert1.pem;/path/to/CAcert2.pem

Viele OpenSSL-Installationen besitzen auch eine vordefinierte Menge von Standard-CAs, denen nahezu allgemein vertraut wird. Damit der Subversion-Client diesen Standard-Zertifizierungsstellen automatisch vertraut, setzen Sie die Variable ssl-trust-default-ca auf true.

Bei der Kommunikation mit Apache kann ein Subversion-Client die Aufforderung erhalten, ein Client-Zertifikat vorzulegen. Apache ersucht den Client, sich zu identifizieren; ist der Client wirklich derjenige, als der er sich ausgibt? Wenn alles richtig funktioniert, schickt der Client ein privates Zertifikat zurück, das von einer CA signiert wurde, der Apache vertraut. Für gewöhnlich wird ein Client-Zertifikat, durch ein lokales Passwort geschützt, verschlüsselt auf Platte gespeichert. Wenn Subversion diese Aufforderung erhält, fragt es Sie nach dem Pfad zum Zertifikat und dem Passwort:

$ svn list https://host.example.com/repos/project

Anmeldebereich: https://host.example.com:443
Client Zertifikatsdatei: /path/to/my/cert.p12
Passphrase für »/path/to/my/cert.p12«:  ********
…

Beachten Sie, dass das Client-Zertifikat eine p12-Datei ist. Um ein Client-Zertifikat mit Subversion verwenden zu können, muss es im PKCS#12-Format sein, was einem portablen Standard entspricht. Die meisten Web-Browser können bereits Zertifikate in diesem Format im- und exportieren. Eine weitere Option ist es, die OpenSSL-Kommandozeilenwerkzeuge zu verwenden, um bestehende Zertifikate in PKCS#12 zu überführen.

Auch hier erlaubt Ihnen die Laufzeitdatei servers, diese Aufforderung pro Host zu automatisieren. Diese Informationen lassen sich für sich oder gemeinsam in Laufzeitvariablen beschreiben:

[groups]
examplehost = host.example.com

[examplehost]
ssl-client-cert-file = /path/to/my/cert.p12
ssl-client-cert-password = somepassword

Sobald die Variablen ssl-client-cert-file und ssl-client-cert-password gesetzt sind, kann der Subversion-Client automatisch auf eine Anforderung eines Client-Zertifikats antworten, ohne eine Eingabe von Ihnen zu verlangen. [44]

Autorisierungsoptionen

An diesem Punkt haben Sie die Authentifizierung eingerichtet, nicht jedoch die Autorisierung. Apache kann Clients auffordern und Identitäten bestätigen, aber es wurde ihm noch nicht gesagt, wie er den Zugriff von Clients mit diesen Identitäten erlauben oder einschränken soll. Dieser Abschnitt beschreibt zwei Strategien, um den Zugriff auf Ihre Projektarchive zu kontrollieren.

Pauschale Zugriffskontrolle

Die einfachste Form der Zugriffskontrolle besteht darin, bestimmten Nutzern entweder nur Lesezugriff oder Lese- und Schreibzugriff auf ein Projektarchiv zu gewähren.

Sie lönnen den Zugriff auf alle Operationen im Projektarchiv einschränken, indem Sie die Direktive Require valid-user Ihrem <Location>-Block hinzufügen. Für unser vorheriges Beispiel würde das bedeuten, dass es nur Clients, die sich entweder als harry oder sally ausgeben und das korrekte Passwort für den entsprechenden Nutzernamen liefern, erlaubt wird, irgendetwas mit dem Subversion-Projektarchiv zu machen:

<Location /svn>
  DAV svn
  SVNParentPath /var/svn

  # wie ein Nutzer authentifiziert wird
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file

  # nur authentifizierte Nutzer dürfen an das Projektarchiv
  Require valid-user
</Location>

Manchmal müssen Sie gar nicht so ein strenges Regiment führen. So erlaubt beispielsweise das eigene Projektarchiv von Subversion unter http://svn.collab.net/repos/svn allen auf der Welt lesende Operationen (wie etwa das Auschecken von Arbeitskopien und das Stöbern mit einem Web-Browser), beschränkt jedoch Schreiboperationen auf authentifiziere Nutzer. Um diese abgestufte Einschränkung einzurichten, können Sie die Konfigurationsdirektiven Limit und LimitExcept verwenden. Ähnlich der Direktive Location haben diese Blöcke Start- und End-Tags, die Sie innerhalb Ihres <Location>-Blocks unterbringen.

Die für die Ditrektiven Limit und LimitExcept verfügbaren Parameter sind HTTP-Anfrage-Typen, die durch diesen Block berührt werden. Falls Sie beispielsweise alle Zugriffe auf Ihr Projektarchiv unterbinden möchten, außer die momentan unterstützten Leseoperationen, so würden Sie die Direktive LimitExcept mit den Anfrage-Parametern GET, PROPFIND, OPTIONS und REPORT verwenden. Dann wird die eben erwähnte Direktive Require valid-user im <LimitExcept>-Block statt innerhalb des <Location>-Blocks eingefügt.

<Location /svn>
  DAV svn
  SVNParentPath /var/svn

  # wie ein Nutzer authentifiziert wird
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file

  # nur authentifizierte Nutzer dürfen mehr als die angegebenen Operationen
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
</Location>

Dies sind nur ein paar einfache Beispiele. Für tiefer gehende Informationen über Apaches Zugriffskontrolle und die Direktive Require sollten Sie im Abschnitt Security der Apache Lehrbuchsammlung unter http://httpd.apache.org/docs-2.0/misc/tutorials.html nachlesen.

Verzeichnisweise Zugangskontrolle

Es ist möglich, mithilfe eines zweiten Apache http-Moduls – mod_authz_svn – detailliertere Zugriffsrechte einzurichten. Dieses Modul schnappt sich die verschiedenen undurchsichtigen URLs, die vom Client zum Server gereicht werden, fordert mod_dav_svn auf, sie zu dekodieren, und unterbindet dann möglicherweise Anforderungen entsprechend in einer Konfigurationsdatei definierter Zugriffsregeln.

Falls Sie Subversion aus Quellcode gebaut haben, ist mod_authz_svn automatisch neben mod_dav_svn gebaut und installiert worden. Viele binäre Distributionen installieren es ebenfalls automatisch. Um die korrekte Installation zu überprüfen, müssen Sie sicherstellen, dass es direkt hinter der LoadModule-Directive von mod_dav_svn in httpd.conf auftaucht:

LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so
LoadModule authz_svn_module   modules/mod_authz_svn.so

Zur Aktivierung dieses Moduls müssen Sie Ihren Location-Block mit der Direktive AuthzSVNAccessFile konfigurieren, die eine Datei mit Zugriffsrichtlinien für Pfade in Ihren Projektarchiven bezeichnet. (Gleich werden wir auf das Format dieser Datei eingehen.)

Da Apache flexibel ist, haben Sie die Wahl, Ihren Block auf eine von drei Arten zu konfigurieren. Fangen Sie mit der Auswahl eines dieser grundlegenden Konfigurationsmuster an. (Die folgenden Beispiele sind sehr einfach gehalten; sehen Sie sich die mitgelieferte Apache-Dokumentation an, um wesentlich mehr Einzelheiten zu den Authentifizierungs- und Autorisierungsoptionen von Apache zu erfahren.)

Der einfachste Block besteht aus einem völlig offenen Zugang. In diesem Szenario schickt Apache niemals Aufforderungen zur Authentifizierung, so dass alle Benutzer als anonymous behandelt werden. (Siehe Beispiel 6.1, „Eine Beispielkonfiguration für anonymen Zugang“.)

Beispiel 6.1. Eine Beispielkonfiguration für anonymen Zugang

<Location /repos>
  DAV svn
  SVNParentPath /var/svn

  # unsere Zugangsrichtlinie
  AuthzSVNAccessFile /path/to/access/file
</Location>
          

Am anderen Ende der Paranoia-Skala können Sie Ihren Block so konfigurieren, dass sich jedermann authentifizieren muss. Alle Clients müssen sich ausweisen. Ihr Block verlangt eine unbedingte Authentifizierung mit der Direktive Require valid-user; diese Direktive definiert auch, wie die Authentifizierung erfolgen soll. (Siehe Beispiel 6.2, „Eine Beispielkonfiguration für authentifizierten Zugang“.)

Beispiel 6.2. Eine Beispielkonfiguration für authentifizierten Zugang

<Location /repos>
  DAV svn
  SVNParentPath /var/svn

  # unsere Zugangsrichtlinie
  AuthzSVNAccessFile /path/to/access/file

  # nur authentifizierte Benutzer haben Zugriff auf das Projektarchiv
  Require valid-user

  # wie ein Benutzer zu authentifizieren ist
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file
</Location>
          

Ein drittes sehr verbreitetes Muster ist es, eine Kombination aus authentifizierten und anonymen Zugriff zu erlauben. So möchten beispielsweise viele Administratoren den Lesezugriff auf bestimmte Verzeichnisse des Projektarchivs für anonyme Benutzer freigeben, während in heiklen Bereichen nur authentifizierte Benutzer lesen (oder schreiben) dürfen. Bei dieser Einstellung greifen alle Benutzer zunächst anonym auf das Projektarchiv zu. Falls Ihre Zugangsrichtlinien an einer Stelle einen echten Benutzernamen erfordern sollte, fordert Apache den Client auf, sich zu authentifizieren. Eingestellt wird dieses Verhalten mit den gemeinsam verwendeten Direktiven Satisfy Any sowie Require valid-user. (Siehe Beispiel 6.3, „Eine Beispielkonfiguration für gemischten authentifizierten/anonymen Zugang“.)

Beispiel 6.3. Eine Beispielkonfiguration für gemischten authentifizierten/anonymen Zugang

<Location /repos>
  DAV svn
  SVNParentPath /var/svn

  # unsere Zugangsrichtlinie
  AuthzSVNAccessFile /path/to/access/file

  # erst anonymen Zugang, nach Bedarf
  # echte Authentifizierung
  Satisfy Any
  Require valid-user

  # wie ein Benutzer zu authentifizieren ist
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file
</Location>
          

Sobald Sie sich für eine dieser drei grundsätzlichen httpd.conf-Vorlagen entschieden haben, müssen Sie Ihre Datei mit den Zugangsregeln für bestimmte Pfade innerhalb des Projektarchivs erstellen. Wir beschreiben später in „Path-Based Authorization“ wie das funktioniert.

Abstellen pfadbasierter Prüfungen

Das Modul mod_dav_svn unternimmt einen hohen Arbeitsaufwand, um sicherzustellen, dass Daten, die Sie als nicht lesbar markiert haben, nicht versehentlich nach draußen geraten. Das bedeutet, dass es aufmerksam alle Pfade überwachen muss, die von Befehlen wie svn checkout und svn update zurückgegeben werden. Begegnen diese Befehle einem Pfad, der aufgrund einer Autorisierungsrichtlinie nicht lesbar ist, wird dieser Pfad üblicherweise vollständig unterdrückt. Im Fall der Historien- oder Umbenennungsverfolgung, z.B. mit einem Befehl wie svn cat -r OLD foo.c auf einer Datei, die vor langer Zeit umbenannt wurde, bleibt die Umbenennungsverfolgung einfach stehen, wenn einer der früheren Namen des Objektes als lesebeschränkt erkannt wird.

All diese Pfadüberprüfungen können manchmal sehr teuer werden, besonders mit svn log. Wenn eine Liste mit Revisionen erstellt wird, sieht der Server bei jedem geänderten Pfad in jeder Revision nach, ob er lesbar ist. Falls ein nicht lesbarer Pfad entdeckt wird, taucht er in der Liste der geänderten Pfade dieser Revision nicht auf (normalerweise sichtbar mit der Option --verbose), und die gesamte Protokollnachricht wird unterdrückt. Es bedarf wohl keiner Erwähnung, dass dies bei Revisionen, die eine große Anzahl an Pfaden betreffen, sehr zeitaufwändig sein kann. Das ist der Preis für Sicherheit: selbst wenn Sie überhaupt kein Modul wie mod_authz_svn konfiguriert haben, fordert das Modul mod_dav_svn Apache httpd auf, Autorisierungsüberprüfungen für jeden Pfad vorzunehmen. Das Modul mod_dav_svn weiß nicht, welche Autorisierungsmodule installiert wurden, also kann es lediglich Apache auffordern, all das aufzurufen, was vorhanden sein könnte.

Auf der anderen Seite gibt es auch eine Art Notausgang, der es Ihnen erlaubt, Sicherheitsmerkmale gegen Geschwindigkeit zu tauschen. Falls Sie nicht irgendeine Art verzeichnisbasierter Auorisierung durchsetzen möchten (d.h., mod_authz_svn oder ähnliche Module nicht verwenden), können Sie die gesamte Pfadüberprüfung abstellen. Verwenden Sie die Direktive SVNPathAuthz in Ihrer Datei httpd.conf wie in Beispiel 6.4, „Abstellen aller Pfadüberprüfungen“ gezeigt.

Beispiel 6.4. Abstellen aller Pfadüberprüfungen

<Location /repos>
  DAV svn
  SVNParentPath /var/svn

  SVNPathAuthz off
</Location>
          

Standardmäßig steht die Direktive SVNPathAuthz auf on. Auf off gesetzt, wird die gesamte pfadbasierte Autorisierungsüberprüfung abgestellt. mod_dav_svn beendet den Aufruf von Autorisierungsüberprüfungen für jeden entdeckten Pfad.

Extra Goodies

We've covered most of the authentication and authorization options for Apache and mod_dav_svn. But there are a few other nice features that Apache provides.

Repository browsing

One of the most useful benefits of an Apache/WebDAV configuration for your Subversion repository is that the youngest revisions of your versioned files and directories are immediately available for viewing via a regular web browser. Since Subversion uses URLs to identify versioned resources, those URLs used for HTTP-based repository access can be typed directly into a web browser. Your browser will issue an HTTP GET request for that URL; based on whether that URL represents a versioned directory or file, mod_dav_svn will respond with a directory listing or with file contents.

Since the URLs do not contain any information about which version of the resource you wish to see, mod_dav_svn will always answer with the youngest version. This functionality has the wonderful side effect that you can pass around Subversion URLs to your peers as references to documents, and those URLs will always point at the latest manifestation of that document. Of course, you can even use the URLs as hyperlinks from other web sites, too.

Proper MIME type

When browsing a Subversion repository, the web browser gets a clue about how to render a file's contents by looking at the Content-Type: header returned in Apache's response to the HTTP GET request. The value of this header is some sort of MIME type. By default, Apache will tell the web browsers that all repository files are of the default MIME type, typically text/plain. This can be frustrating, however, if a user wishes repository files to render as something more meaningful—for example, it might be nice to have a foo.html file in the repository actually render as HTML when browsing.

To make this happen, you need only to make sure that your files have the proper svn:mime-type set. We discuss this in more detail in „Datei-Inhalts-Typ“, and you can even configure your client to automatically attach proper svn:mime-type properties to files entering the repository for the first time; see „Automatisches Setzen von Eigenschaften“.

So in our example, if one were to set the svn:mime-type property to text/html on file foo.html, Apache would properly tell your web browser to render the file as HTML. One could also attach proper image/* MIME-type properties to image files and ultimately get an entire web site to be viewable directly from a repository! There's generally no problem with this, as long as the web site doesn't contain any dynamically generated content.

Customizing the look

You generally will get more use out of URLs to versioned files—after all, that's where the interesting content tends to lie. But you might have occasion to browse a Subversion directory listing, where you'll quickly note that the generated HTML used to display that listing is very basic, and certainly not intended to be aesthetically pleasing (or even interesting). To enable customization of these directory displays, Subversion provides an XML index feature. A single SVNIndexXSLT directive in your repository's Location block of httpd.conf will instruct mod_dav_svn to generate XML output when displaying a directory listing, and to reference the XSLT stylesheet of your choice:

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
  SVNIndexXSLT "/svnindex.xsl"
  …
</Location>

Using the SVNIndexXSLT directive and a creative XSLT stylesheet, you can make your directory listings match the color schemes and imagery used in other parts of your web site. Or, if you'd prefer, you can use the sample stylesheets provided in the Subversion source distribution's tools/xslt/ directory. Keep in mind that the path provided to the SVNIndexXSLT directory is actually a URL path—browsers need to be able to read your stylesheets to make use of them!

Listing repositories

If you're serving a collection of repositories from a single URL via the SVNParentPath directive, then it's also possible to have Apache display all available repositories to a web browser. Just activate the SVNListParentPath directive:

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
  SVNListParentPath on
  …
</Location>

If a user now points her web browser to the URL http://host.example.com/svn/, she'll see a list of all Subversion repositories sitting in /var/svn. Obviously, this can be a security problem, so this feature is turned off by default.

Apache logging

Because Apache is an HTTP server at heart, it contains fantastically flexible logging features. It's beyond the scope of this book to discuss all of the ways logging can be configured, but we should point out that even the most generic httpd.conf file will cause Apache to produce two logs: error_log and access_log. These logs may appear in different places, but are typically created in the logging area of your Apache installation. (On Unix, they often live in /usr/local/apache2/logs/.)

The error_log describes any internal errors that Apache runs into as it works. The access_log file records every incoming HTTP request received by Apache. This makes it easy to see, for example, which IP addresses Subversion clients are coming from, how often particular clients use the server, which users are authenticating properly, and which requests succeed or fail.

Unfortunately, because HTTP is a stateless protocol, even the simplest Subversion client operation generates multiple network requests. It's very difficult to look at the access_log and deduce what the client was doing—most operations look like a series of cryptic PROPPATCH, GET, PUT, and REPORT requests. To make things worse, many client operations send nearly identical series of requests, so it's even harder to tell them apart.

mod_dav_svn, however, can come to your aid. By activating an operational logging feature, you can ask mod_dav_svn to create a separate log file describing what sort of high-level operations your clients are performing.

To do this, you need to make use of Apache's CustomLog directive (which is explained in more detail in Apache's own documentation). Be sure to invoke this directive outside your Subversion Location block:

<Location /svn>
  DAV svn
  …
</Location>

CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION

In this example, we're asking Apache to create a special logfile, svn_logfile, in the standard Apache logs directory. The %t and %u variables are replaced by the time and username of the request, respectively. The really important parts are the two instances of SVN-ACTION. When Apache sees that variable, it substitutes the value of the SVN-ACTION environment variable, which is automatically set by mod_dav_svn whenever it detects a high-level client action.

So, instead of having to interpret a traditional access_log like this:

[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/vcc/default HTTP/1.1" 207 398
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/bln/59 HTTP/1.1" 207 449
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc HTTP/1.1" 207 647
[26/Jan/2007:22:25:29 -0600] "REPORT /svn/calc/!svn/vcc/default HTTP/1.1" 200 607
[26/Jan/2007:22:25:31 -0600] "OPTIONS /svn/calc HTTP/1.1" 200 188
[26/Jan/2007:22:25:31 -0600] "MKACTIVITY /svn/calc/!svn/act/e6035ef7-5df0-4ac0-b811-4be7c823f998 HTTP/1.1" 201 227
…

you can peruse a much more intelligible svn_logfile like this:

[26/Jan/2007:22:24:20 -0600] - get-dir /tags r1729 props
[26/Jan/2007:22:24:27 -0600] - update /trunk r1729 depth=infinity send-copyfrom-args
[26/Jan/2007:22:25:29 -0600] - status /trunk/foo r1729 depth=infinity
[26/Jan/2007:22:25:31 -0600] sally commit r1730

For an exhaustive list of all actions logged, see „Protokollierung auf hoher Ebene“.

Write-through proxying

One of the nice advantages of using Apache as a Subversion server is that it can be set up for simple replication. For example, suppose that your team is distributed across four offices around the globe. The Subversion repository can exist only in one of those offices, which means the other three offices will not enjoy accessing it—they're likely to experience significantly slower traffic and response times when updating and committing code. A powerful solution is to set up a system consisting of one master Apache server and several slave Apache servers. If you place a slave server in each office, users can check out a working copy from whichever slave is closest to them. All read requests go to their local slave. Write requests get automatically routed to the single master server. When the commit completes, the master then automatically pushes the new revision to each slave server using the svnsync replication tool.

This configuration creates a huge perceptual speed increase for your users, because Subversion client traffic is typically 80–90% read requests. And if those requests are coming from a local server, it's a huge win.

In this section, we'll walk you through a standard setup of this single-master/multiple-slave system. However, keep in mind that your servers must be running at least Apache 2.2.0 (with mod_proxy loaded) and Subversion 1.5 (mod_dav_svn).

Configure the servers

First, configure your master server's httpd.conf file in the usual way. Make the repository available at a certain URI location, and configure authentication and authorization however you'd like. After that's done, configure each of your slave servers in the exact same way, but add the special SVNMasterURI directive to the block:

<Location /svn>
  DAV svn
  SVNPath /var/svn/repos
  SVNMasterURI http://master.example.com/svn
  …
</Location>

This new directive tells a slave server to redirect all write requests to the master. (This is done automatically via Apache's mod_proxy module.) Ordinary read requests, however, are still serviced by the slaves. Be sure that your master and slave servers all have matching authentication and authorization configurations; if they fall out of sync, it can lead to big headaches.

Next, we need to deal with the problem of infinite recursion. With the current configuration, imagine what will happen when a Subversion client performs a commit to the master server. After the commit completes, the server uses svnsync to replicate the new revision to each slave. But because svnsync appears to be just another Subversion client performing a commit, the slave will immediately attempt to proxy the incoming write request back to the master! Hilarity ensues.

The solution to this problem is to have the master push revisions to a different <Location> on the slaves. This location is configured to not proxy write requests at all, but to accept normal commits from (and only from) the master's IP address:

<Location /svn-proxy-sync>
  DAV svn
  SVNPath /var/svn/repos
  Order deny,allow
  Deny from all
  # Only let the server's IP address access this Location:
  Allow from 10.20.30.40
  …
</Location>
Set up replication

Now that you've configured your Location blocks on master and slaves, you need to configure the master to replicate to the slaves. This is done the usual way— using svnsync. If you're not familiar with this tool, see „Projektarchiv Replikation“ for details.

First, make sure that each slave repository has a pre-revprop-change hook script which allows remote revision property changes. (This is standard procedure for being on the receiving end of svnsync.) Then log into the master server and configure each of the slave repository URIs to receive data from the master repository on the local disk:

$ svnsync init http://slave1.example.com/svn-proxy-sync file://var/svn/repos
Copied properties for revision 0.
$ svnsync init http://slave2.example.com/svn-proxy-sync file://var/svn/repos
Copied properties for revision 0.
$ svnsync init http://slave3.example.com/svn-proxy-sync file://var/svn/repos
Copied properties for revision 0.

# Perform the initial replication

$ svnsync sync http://slave1.example.com/svn-proxy-sync
Transmitting file data ....
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .......
Committed revision 2.
Copied properties for revision 2.
…

$ svnsync sync http://slave2.example.com/svn-proxy-sync
Transmitting file data ....
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .......
Committed revision 2.
Copied properties for revision 2.
…

$ svnsync sync http://slave3.example.com/svn-proxy-sync
Transmitting file data ....
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .......
Committed revision 2.
Copied properties for revision 2.
…

After this is done, we configure the master server's post-commit hook script to invoke svnsync on each slave server:

#!/bin/sh
# Post-commit script to replicate newly committed revision to slaves

svnsync sync http://slave1.example.com/svn-proxy-sync > /dev/null 2>&1
svnsync sync http://slave2.example.com/svn-proxy-sync > /dev/null 2>&1
svnsync sync http://slave3.example.com/svn-proxy-sync > /dev/null 2>&1

The extra bits on the end of each line aren't necessary, but they're a sneaky way to allow the sync commands to run in the background so that the Subversion client isn't left waiting forever for the commit to finish. In addition to this post-commit hook, you'll need a post-revprop-change hook as well so that when a user, say, modifies a log message, the slave servers get that change also:

#!/bin/sh
# Post-revprop-change script to replicate revprop-changes to slaves

REV=${2}
svnsync copy-revprops http://slave1.example.com/svn-proxy-sync ${REV} > /dev/null 2>&1
svnsync copy-revprops http://slave2.example.com/svn-proxy-sync ${REV} > /dev/null 2>&1
svnsync copy-revprops http://slave3.example.com/svn-proxy-sync ${REV} > /dev/null 2>&1

The only thing we've left out here is what to do about locks. Because locks are strictly enforced by the master server (the only place where commits happen), we don't technically need to do anything. Many teams don't use Subversion's locking features at all, so it may be a nonissue for you. However, if lock changes aren't replicated from master to slaves, it means that clients won't be able to query the status of locks (e.g., svn status -u will show no information about repository locks). If this bothers you, you can write post-lock and post-unlock hook scripts that run svn lock and svn unlock on each slave machine, presumably through a remote shell method such as SSH. That's left as an exercise for the reader!

Caveats

Your master/slave replication system should now be ready to use. A couple of words of warning are in order, however. Remember that this replication isn't entirely robust in the face of computer or network crashes. For example, if one of the automated svnsync commands fails to complete for some reason, the slaves will begin to fall behind. For example, your remote users will see that they've committed revision 100, but then when they run svn update, their local server will tell them that revision 100 doesn't yet exist! Of course, the problem will be automatically fixed the next time another commit happens and the subsequent svnsync is successful—the sync will replicate all waiting revisions. But still, you may want to set up some sort of out-of-band monitoring to notice synchronization failures and force svnsync to run when things go wrong.

Other Apache features

Several of the features already provided by Apache in its role as a robust web server can be leveraged for increased functionality or security in Subversion as well. The Subversion client is able to use SSL (the Secure Sockets Layer, discussed earlier). If your Subversion client is built to support SSL, it can access your Apache server using https:// and enjoy a high-quality encrypted network session.

Equally useful are other features of the Apache and Subversion relationship, such as the ability to specify a custom port (instead of the default HTTP port 80) or a virtual domain name by which the Subversion repository should be accessed, or the ability to access the repository through an HTTP proxy.

Finally, because mod_dav_svn is speaking a subset of the WebDAV/DeltaV protocol, it's possible to access the repository via third-party DAV clients. Most modern operating systems (Win32, OS X, and Linux) have the built-in ability to mount a DAV server as a standard network shared folder. This is a complicated topic, but also wondrous when implemented. For details, read Anhang C, WebDAV und Autoversionierung.

Note that there are a number of other small tweaks one can make to mod_dav_svn that are too obscure to mention in this chapter. For a complete list of all httpd.conf directives that mod_dav_svn responds to, see „Anweisungen“.



[42] Die hassen sowas echt.

[43] Obwohl selbstsignierte Server-Zertifikate immer noch verwundbar für einen Man-in-the-middle-Angriff sind, ist solch ein Angriff für einen gelegentlichen beobachter ungleich schwieriger durchzuführen als ungeschützte Passwörter abzugreifen.

[44] Sicherheitsbewusstere Leute verzichten möglicherweise darauf, das Passwort des Client-Zertifikats in der servers-Laufzeitdatei abzulegen.

[45] Back then, it was called ViewCVS.