Ändern einer IP-Route als User (Mac OS X) // sudoers [Update]

Im Zuge einer Überarbeitung meiner VPN-Firewall-Gateway-VM stolperte ich wieder über den Routing-Activator. Dieses kleine Script macht nichts anderes, als das externe VPN-Netzwerk über eine Gateway-VM zu routen. Da jedoch route zwingend root-Rechte benötigt, musste ich bei jedem VPN-Aufbau (sprich: Starten der VPN-Gateway-VM) oder einem Netzwerk-Neustart ein sudo /path/to/your/script via Terminal abfeuern — inklusive lästiger Passworteingabe.

Okay. Gehen wir das Problem an!

Das eigentliche Problem ist, das route nur als superuser ausgeführt werden darf. Für solche Fälle gibt es die sudoers-Datei, welche in Kurzform beschreibt, welche User welche Befehle als superuser ausführen dürfen. In der Regel landen dort manchmal Services (wenn ein Service bspw. zwar als Superuser gestartet werden muss, aber eigentlich im Kontext eines normalen Benutzers läuft und gesteuert wird) oder bestimmte Systembefehle.

Nun könnte man natürlich route für den eigenen Benutzer komplett freischießen, aber dann gelte dieser Freibrief für alle Prozesse. Nein, das will man auch nicht. Eigentlich soll ja nur die eine Route erlaubt werden. Und da praktischerweise diese Konfiguration bereits als ein Script — /path/to/your/script — vorliegt, wird einfach dieses dort eingetragen. Dabei sind jedoch einige Vorsichtsmaßnahmen zu treffen.

  1. Mit dem Befehl sudo visudo öffnet man eine spezielle Instanz von vi zum Editieren der sudoers.
  2. Ganz am Ende trägt man eine weitere Zeile an (man kann sich an den Beispielen orientieren):

    Damit erlaubt man dem Benutzer USER das Ausführen des definierten Commands ohne Passwortabfrage.
    Sollte das Script natürlich woanders liegen, so muss das angepasst werden (irgendwie klar, oder?) Man kann auch andere Muster (beispielsweise ganze Gruppen) oder andere Modi wählen (siehe dazu man sudoers).
  3. Wichtig: Um jegliches Sicherheitsrisiko zu vermeiden, sollte man unbedingt das Script danach abschotten. Dazu werden die Rechte auf das mindeste entfernt.
    1. sudo chmod -w /path/to/your/script entfernt für alle Benutzer das Schreibrecht (muss man es dennoch editieren, geht es mit sudo vi und einem abschließenden :wq! natürlich dennoch).
    2. sudo chown root /path/to/your/script übertragt das Script dem Root-Benutzer, um eine nachträgliche Rechte-Änderung ohne Passwort zu verhindern.
  4. Fertig. Das Script kann nun mit sudo /path/to/your/script nun mit Rechten des superuser gestartet werden (ohne Passwort) und ist gleichzeitig ohne administrative Rechte nicht mehr änderbar.

Featurities meets Fallstrick: Die Spring Security 3.0 Konfigurationsodyssey

Mit dem Majorrelease 3.0 wurde dem Modul Spring Security eine Menge von neuen Features angeignet. Spring Security ist die Modulkomposition, welches für das Java Framework Spring quasi die gesamte Authentifizierung, Autorisierung, Legitimierung jedwegiger Art ermöglicht.

Leider wurden mit dem Release 2.x auf 3.0 eine Reihe von API-Changes vollzogen. Zugegeben, die waren auch sicher alle sinnvoll, weil Komponenten wie die Authentifizierung weiter geteilt wurden und man somit wesentlich flexibler ist, neue Anforderungen zu ermöglichen (Baukastenprinzip). Aber die Dokumentation ist – gesamtheitlich betrachtet – irgendwie immer noch mies und oft nicht aktualisiert. Oder man findet im Internet einfach nur (alte) Beispiele.

Die http-Direktive

Im Namespace von Spring Security existiert das Tagelement http, mit welchem man kurze, knappe und verständliche Konfigurationen anlegen kann. Der Vorteil liegt klar auf der Hand: Man muss nicht alle Beans, Listener und Provider anlegen, denn das geschieht automatisch. Tja, wären da nicht ein paar Einschränkungen in der Funktionsvielfalt.

Konkretes Beispiel: Remember Me

Just wurde das Minor-Release 3.0.1 veröffentlicht, und nur wenige Tage später zu erfahren, dass Remember Me kaputt sei. Egal, fahren wir erstmal weiter mit 3.0.0.

Laut Dokumentation ist es am einfachsten, wenn man die Direktive remember-me (Security Namespace) innerhalb der http-Direktive (Security Namespace) verwendet. Ohne irgendeine Angabe wird ein stinknormales, Cookie basiertes Tokenverfahren ohne (echten) privaten Schlüssel verwendet. Reicht für den ersten Einsatz erstmal auf, soll ja erstmal funktionieren.

Fehlermöglichkeit 1a: Man loggt sich ein, und es passiert nichts (kein „RememberMe“-Cookie).
Lösung: Wenn man einen eigenen Auth-Filter einsetzt, muss man diesem auch den RememberMe-Service „setten“. Außerdem muss der SecurityChainFilter (web.xml!) auch auf die login-Seite verweisen. Es dürfen auch keine Filter bei der Konfigurierung von intercepted Urls (speziell hier: login, logout) gemacht werden.

Fehlermöglichkeit 1b: Es passiert noch immer nichts?
Lösung: Vielleicht wurde vergessen, einen Parameternamen für den Request zu setzen. Der Standardname ist ein typischer Springname, der natürlich unschön ist. Und den kann man nicht über die RememberMe-Direktive setzen, also muss man eh einen eigenen Service definieren. Bäm. Referenzierung geht dann zwar noch, aber für mehr ist die RememberMe-Direktive dann nicht mehr zu gebrauchen.

Fehlermöglichkeit 2a: Man besucht die Seite ohne Login, aber mit Cookie – und die Loginseite kommt (Log sagt kein gültiger Auth).
Lösung: Man kann der Log trauen, wenn sie zwar beim Einloggen nun einen Token ablegt (kann man zum Beispiel sehr einfach mit diesem Firefox-Addon inkl. Editor(!) verifizieren), dieses aber beim erneuten Besuchen der Seite (bzw. ohne JSPSESSION-Cookie) nicht verwendet bzw. wird nicht erkannt. Schlussendlich half u.a. das Umbenennen der Userservices-Bean in „userService“. Außerdem sollte die Loginseite keinen Filter/Access haben (s.o.) Lieber 2x prüfen!

Fehlermöglichkeit 2b: Es erscheint eine Ausnahme, dass der Key falsch sei.
Lösung: Dazu muss man wissen: Sobald man eine individualisierte RememberMe-Konfiguration nutzt, wird auch der Key nicht mehr vernünftig auf alle Komponenten (Provider, Filter, Manager) gesetzt. Beim Anlegen wird also der eigene Key verwendet, beim Auslesen der Standardkey. Yes! (s.o.)

Fehlermöglichkeit 3: Man besucht die Seite ohne Login, aber mit Cookie – aber wie in 2 nur die Loginseite.
Lösung: Im Logger/Debugger kann man nun feststellen, dass zwar das Cookie gefunden wurde, das Token gefunden und validiert wurde aber dann keine Rechte existieren – aha? Wahrscheinlich fehlt im Provider noch ein zusätzliches Setting der Komponenten. Am besten von RememberMe Service/Filter/Provider jeweils alle möglichen Properties durchgehen. Jaja, wie gesagt.. 😉

Fehlermöglichkeit 4: Das Ausloggen (beispielsweise logout.html) hat nach Aktivierung von Rememberme plötzlich keine Auswirkungen mehr.
Lösung: Zwar wird die Seite gefunden, aber es wird kein „Logout“ gemacht. Auch hier sollte man prüfen, ob ein SecurityChainFilter (web.xml) auch für die logout-Seite greift.

Fehlermöglichkeit 5: Das Besuchen der Seite wirft einen Fehler (ggf. „mit weißer Seite“), dass keine neue Session erstellt werden kann.
Lösung: Richtig, nach einem Request ist ja dann auch zu spät. Das Attribut create-session in der Direktive http sollte daher auf „ifRequeried“ gestellt sein.

Fazit:

  • SecurityChainFilter immer prüfen
  • Intercepted Urls prüfen
  • RememberMe-Direktive innerhalb der http-Direktive ist quasi abgesehen von der services-ref unbrauchbar.

Anmerkung:

Natürlich kann man sich das Problem mit den SecurityChains vom Hals schaffen, indem man stupide ein /* filtert. Das hat jedoch zur Auswirkung, das Spring Security auch jeden verdammten Request anguckt; bei zusätzlichen (statischen) Inhalten wie Javascript, Stylesheets, Bildern, Flash u.ä. ist das ein Overhead, der unnötig ist.

Howto: trac auf Mac OS X 10.6

Für den privaten Gebrauch – und für unterwegs, auf dem mobilen – kann sowohl ein Subversion als auch trac sicherlich eine Offline-Alternative sein.

Tatsächlich suchte ich nun eine Möglichkeit, „mal eben“ eine trac-Instanz aufzusetzen: Auf dem Webserver erschien mir zu komplex und kompliziert, eine neue VM auf dem Macbook etwas ineffizient, oder? 🙂 Also warum nicht direkt unter OS X, bzw. technisch gesehen BSD?

Die initiale Suche nach der Thematik bringt einen schnell zu einer Fink-Lösung – also mal ehrlich, schon etwas aufwendig?

Tatsächlich gibt es auch einfachere Varianten, etwa hier. Aber auch hier wird noch einiges runtergeladen, kompiliert.. ach, Informatiker sind von Grund her faul. Nein, das ist es auch nicht.

# python2.6 ist bereits installiert.
python -version
> Python 2.6.1

Die abgespeckte, und funktionstüchtige Methode lautet daher – kurz und knapp:

sudo easy_install Pygments
sudo easy_install Genshi
sudo easy_install Trac

Das war es, trac ist installiert.

Für diejenigen, die nun auch eine Schnelleinweisung in eine erste Konfiguration brauchen, ein Schnelldurchlauf. Bemerk: Natürlich können auch andere Pfade für die Repositories verwendet werden, wichtig ist nur: Der eigene Benutzer muss später Lese- und Schreibrechte besitzen. Das heißt im Klartext: Entweder nachher „umgranten“ mit chown, oder woanders hinpacken. Auf /usr/local hat in der Regel nur der Superuser Zugriff, d.h. hier muss mit sudo gearbeitet werden.

# ein neues Subversion Repository anlegen
svnadmin create /usr/local/svn
# ein neues trac Repository anlegen - man kann alle Standardwerte nutzen, evtl. Pfad ändern
trac-admin /usr/local/trac initenv

Trac liefert einen kleinen Miniserver mit, der für diesen Zweck erst einmal reicht.

tracd --port 8000 /usr/local/trac/

Voilá.

Selbstverständlich brauchen wir noch einen User, zum Einloggen. Beispiel für den Benutzer user.

htpasswd -c /usr/local/trac/trac.htpasswd admin
> New password:
> New password:
> Re-type new password:
> Adding password for user admin
htpasswd /usr/local/trac/trac.htpasswd knalli
> New password:
> New password:
> Re-type new password:
> Adding password for user knalli

Jetzt den Server mit erweiterteten Parametern starten, also beispielsweise:

tracd --port 8000 --basic-auth=trac,/usr/local/trac/trac.htpasswd,trac /usr/local/trac

Eine Konfiguration über Apache2 ist dauerhaft eventuell zu empfehlen, aber für’s erste reicht es auch so. Ebenfalls empfiehlt die Dokumenation den Einsatz des Parameters –auth (Digest), dazu bitte jene konsultieren.