Skip to content
This repository was archived by the owner on Sep 18, 2020. It is now read-only.

Backend LoginFilter

Jonas Stegmaier edited this page Jan 26, 2015 · 3 revisions

← zurück zur Backend-Ablauf Übersicht

Autor: Maren

Folgende Pfade dürfen nur durch einen Administrator aufgerufen werden:

  • HTTP-GET: /bars/reports: Gemeldete Bars anzeigen
  • HTTP-DELETE: /report/:reportID: Bestimmte Fehlermeldung löschen
  • HTTP-DELETE: /bars/:barID/report: Alle Fehlermeldungen einer Bar löschen
  • HTTP-POST: /bars/:barID/hour: Neue HappyHour speichern
  • HTTP-DELETE: /delHour/:hourID: Happy Hour löschen

Aus diesem Grund muss jede Anfrage an die Datenbank vorab gefiltert werden, ob derjenige, der drauf zu greifen möchte auch berechtigt dazu ist.

Administratoren anlegen

Es wurde in der Gruppe entschieden, dass die Administratoren manuell in die Datenbank eingegeben werden. Jeder vom Team erhält einen Eintrag in der Datenbank mit Name und Passwort. Die Datenbanktabelle ist wie unter diesem Link zu sehen ist, angelegt wurden. Folglich gibt es keine Registrierungsseite.
Das Passwort wird als MD5 Hash in der Datenbank abgelegt. Die Datenklasse User.java hält lediglich die Getter und Setter für den Namen bereit, da das Passwort nicht zwischengespeichert werden darf.

Entscheidung wie die Login-Daten überprüft werden

Zunächst wurde überlegt, ob beim Login des Administrator eine Session gestartet werden soll oder ein Cookie gesetzt werden soll. Eine Session ist für REST-Schnittstellen nicht üblich. Folglich wurde versucht für die Pfade /login und /logout ein Cookie zu erzeugen.
Die Idee war zwei Filter einzuführen:

  • Einer der überprüft, ob ein Cookie vorhanden ist und ob das Cookie manipuliert wurde. Um eine Manipulation aufzuspüren, wird beim erfolgreichen Login der Cookie protectet zurückgegeben und bei einer Anfrage wieder unprotectet und überprüft.
  • Der zweite Filter überprüft, ob der Anfragensteller berechtigt ist auf die Pfade zuzugreifen.

Diese Funktionalität konnte soweit implementiert werden. Es gab nur ein Problem: Das verwendete Spark-Framework, auf das sich zu Beginn des Projekts geeinigt wurde, verhindert, dass ein Cookie abgefragt, verändert und dann weitergegeben wird. Aus diesem Grund war es nicht möglich die Cookies zu protecten und bei einer erneuten Anfrage wieder zu unprotecten. Da aber sichergestellt werden muss, dass keine manipulierten Cookies eintreffen und somit unberechtigte Personen sich Zugriff verschaffen können, war dieser Weg nicht möglich. Es wurde überlegt, ob die Spark Methode direkt erweitert werden soll, doch der Aufwand hierfür wurde als zu groß abgetan, da man sich dann in die komplette Funktionalität von Spark einarbeiten muss und der zur Verfügung stehende Zeitraum hierfür nicht ausreicht.
Aus den hier aufgeführten Gründen, wurde entschieden, dass das Frontend bei jeder Anfrage auf ein Pfad, der nur von Administratoren aufgerufen werden darf, die Login-Daten mitübergeben muss. Folglich ist auf Seiten des Backends nur noch eine Überprüfung erforderlich, die bei Anfrage auf einen solchen Pfad filtert, ob der Anfragensteller als Administartor eingeloggt ist oder nicht.

Erstellen der Funktionalität

Erstellen des Login Filters

Für den Login Filter wird in den de.dhbw.hh.rest-Ordner eine LoginFILTER-Klasse angelegt und in Spark.java vor den ganzen REST-Modulen eingebunden, damit dieser zurerst durchlaufen wird.
Das Spark Framework stellt für einen solche Funktion einen Filter bereit, der durch den Befehl before bei jeder Anfrage durchlaufen wird:

before((request, response) -> {
   ...
   }
});

Durch eine if-Abfrage innerhalb der Funktion kann nun die Anfrage auf bestimmte Pfade abgefangen werden. Ist der angefragt einer der oben aufgelisteten Pfade, so wird der Code-Block innerhalb der if-Schleife durchlaufen. Ist er es nicht, passiert nichts und der Server leitet die Anfrage an die anderen REST-Module weiter.
Handelt es sich bei dem Pfad, um einen Pfad für den Administartorrechte benötigt werden, so wird der Name und das Passwort des Anfragensteller aus den übergebenen Parametern ausgelesen und anschließend überprüft, ob der Name und das Passwort auch mit denen aus der Datenbank übereinstimmen. Hierfür wird über das UserDAO.java-Interface auf die checkLogin-Funktion der H2UserDAO.java-Klasse zugegriffen und der Name und das Passwort aus der Anfrage übergeben:

boolean successful = daoFactory.getUserDAO().checkLogin(name, password);

In der H2UserDAO-Klasse wird das übergebene Passwort zunächst in einen MD5-Hash umgewandelt, damit dieser mit dem aus der Datenbank abgeglichen werden kann. Hierfür wurde eine extra Hilfsklasse HashConverter in de.dhbw.hh.utils angelegt. Diese Hilfsklasse enthält ein Java Framework, dass mit einem Algorithmus einen übergebenen String in einen Hash umwandelt und zurückgibt.
Nun kann mit einer SQL-Abfrage überprüft werden, ob das Passwort und der Name übereinstimmen, indem folgende Where-Bedingung gesetzt wird:

"SELECT name FROM user WHERE name=? and hashPw=?"

Der Name und der Hash des Passworts werden in die Abfrage übergeben und die zurückgegebenen Daten in eine Collection gespeichert. Durch eine if-Abfrage wird überprüft, ob die Rückgabe der SQL-Abfrage leer ist oder nicht. Wurde ein Name zurückgegeben, so war das Passwort und der eingegebene Name korrekt und es kann true zurückgegeben werden. War dies nicht der Fall so erofolgt false als Rückgabe.

Im Login Filter wird nun noch in einer if-Abfrage abgefangen, ob die Rückgabe false oder true war. Bei true wird ein Log-Eintrag erstellt mit dem Namen des Anfragestellers und mit welcher Methode auf welchen Pfad zugegriffen wurde. Bei false wird die Anfrage abgebrochen durch die halt-Funktion, die Spark hierfür bereitstellt:

if (successful){
					// Log-Eintrag bei erfolgreichen Zugriff auf Pfade, die eine Adminberechtigung benötigen
					log.debug("Admin: " + name + " - " + request.requestMethod() + ":" + request.pathInfo());
				} 
				else {
					// Stimmt das eingegebene Passwort nicht überein, wird die Anfrage abgebrochen
					halt(401, "Du bist nicht berechtigt auf diese Funktion zuzugreifen");
				}

Clone this wiki locally