# Benutzerauthorisierung, User-Login, Anmeldeseite - wie am besten?



## Andron (12. Februar 2007)

*Benutzerauthorisierung, User-Login, Anmeldeseite - wie am besten? BITTE UM HILFE*

Hallo,
ich möchte eine Anmelde-Seite einrichten. Habe auch einiges gelesen und wie es aussieht, gibt es mehrere Möglichkeiten:

 - Einstellungen in der Tomcat-konfiguration
 - Einfache DB-Vergleiche
 - Servlet-Filter
... und noch einiges mehr.


Welche Vorgehensweise würdet ihr mir empfehlen?
Welche ist einfacher und gleichzeitig auch sicher?
Danke


----------



## Thomas Darimont (12. Februar 2007)

Hallo,

erstmal muss man bei diesem Thema zwischen Authentisierung (Wer bist du?) und Authorisierung
(Was darfst du?) unterscheiden.

Für Authentisierung über eine zentrale Login-Komponente bietet sich in der JEE WebApp-Welt
beispielsweise ein einfacher (Tomcat)Realm an. Diesen Konfigurierst du zum einen über deinen
Servlet Container und zum anderen über die web.xml. Im Grunde genommen erledigt dann der Realm für dich die Arbeit des Abgleichs der eingegebenen Benutzerdaten mit denen in der Datenbank. Den Realm kannst du so konfigurieren, dass bestimmte URL-Muster von diesem geschützt werden. Ruft nun ein noch nicht authentisierter Benutzer (keine Userinformationen in der Session, keine Cookies) eine geschützte Seite des Realms auf, so wird dieser sofort 
auf die Loginseite umgeleitet. (Das passiert intern über einen ServletFilter) Nach der Eingabe von gültigen Benutzerdaten wird der Benutzer nach dem klick auf "login" wieder zur ursprünglich angefragten Resource weitergeleitet.

Hier ein kleines Beispiel für Tomcat:
http://www.tutorials.de/forum/j2ee/189049-tomcat-login-mechanismus.html

Hier ein kleines Beispiel für JBoss 4.x
http://www.tutorials.de/forum/j2ee/208655-beispiel-thema-websecurity-jboss-4-0-2-a.html


Für Authorisierung würde sich ein ServletFilter bzw. ein Interceptor-basierter Ansatz lohnen, welcher die reine Überprüfungslogik (darf der Benutzer diese Funktion verwenden?) kapselt.
Damit lassen sich dann beispielse Authorisierungen deklarativ konfigurieren ( für jede Methode, Klasse, etc.). AOP (Spring AOP, AspectJ) sind auch zwei beliebte Frameworks um deklarative Authorisierung zu implementieren.

Neben eigenen Lösungen gibt es für das Problem (wie immer in der Java Welt  natürlich zahlreiche open source Lösungen:
http://www.acegisecurity.org/
http://www.ja-sig.org/products/cas/index.html
http://www.josso.org/

... um die interessantesten mal zu nennen.

Gruß Tom


----------



## Andron (13. Februar 2007)

Danke für die detailierte Antwort.
Ich habe hier ein Buch vor mir liegen: Tomcat5 Einsatz in Unternehmensanwendungen mit JSP und Servlets von Lajos Moczar. 
Dort ist die formularbasierte Authentifizierung beschrieben, die folgendermaßen aussieht:

Es gibt eine Login-Seite für die FORM-Authentifizierung, also ein Formular mit Eingabefeldern, die heißt login.jsp.
Dann gibt es eine Fehlerseite, error.jsp.

Auszug aus der web.xml:

```
<security-constaint>
    <display-name>Scheduler Authentication</display-name>
    <web-resource-collection>
        <web-resource-name>SchedulerServlet</web-resource-name>
        <url-pattern>/main/*</url-pattern
    </web-resource-collection>
    <auth-constraint>
        ...
    </auth-constraint>
</security-constaint>

<login-config>
 ...
</login-config>

<security-role>
 ...
</security-role>
```

Als role-name werden zwei Rolen festgelegt und in der Datei unleashed-users.xml samt Passwörtern abgelegt.
Im Buch ist also Beschieben, wie man Rollen anlegt und Passwörter definiert.
Und der Datenabgleich findet mit den Daten in der Datei unleashed-users.xml statt.

Wie kann ich das auf mein Problem umstellen?
In welchem Teil soll ich die Daten mit der DB abgleichen, da ich keine unleashed-users.xml haben möchte?

Im <web-resource-name>SchedulerServlet</web-resource-name> wird ein Servlet angegeben, ich nehme an, der ist für die Anfragen zuständig.
Könnte ich dort die Daten vergleichen? 
Oder gibt es andere bessere Möglichkeit?

Ich werde mir mal die beiden Links ansehen, vielleicht finde ich dort was.


----------



## Andron (13. Februar 2007)

Ok, habe mir den Link http://www.tutorials.de/forum/j2ee/189049-tomcat-login-mechanismus.html angesehen.
Ist dasselbe, was ich auch habe.
Mein Problem bleibt aber immer noch.
Hier:

```
<role rolename="authUser"/>
 <user username="testuser" password="test" roles="authUser"/>
```
werden die User schon festgelegt. 
Ich möchte aber die Daten mit der DB vergleichen.
Nur wo soll das geschehen, weiß ich noch nicht.

EDIT: Habe mir nun den zweiten Link angesehen, der erklärt mir schon einiges, scheint aber komplizierter zu sein.
Ich habe an folgendes Szenario gedacht:

User ruft eine Seite auf.
Es wird eine login-Seite angezeigt.
Wenn User sich vorher nicht registriert hat, kann er auf "Registrieren" klicken und seine Daten eintragen, die werden dann in die DB gespeichert.
Wenn der User seine Daten nun angibt auf der login.jsp, werden diese zum Servlet "CheckerServlet" per POST übertragen. 
Der Servlet hat nun die Daten und kann diese mit der Datenbank abgleichen.
Es wird also eine Verbinung zur DB aufgebaut und die Daten werden geprüft.
Wenn alles stimmt, wird der benutzer auf die vorher angegebene oder eine Standard-Seite geforwardet.
Gleichzeit wird dem Benutzer eine Session-ID zugeweisen und diese auch in der DB abgelegt. Die Session-ID wird nach 30 min. ungültig. Wenn der Benutzer die Seite verlässt und wieder aufruft, so hat er ja eine andere Session-ID, somit wird die alte ungültig und der User muss sich dann wieder einloggen.

Ich bin für alle Kommentare und Tipps dankbar.


----------



## Thomas Darimont (13. Februar 2007)

Hallo,

du musst einfach anstatt eines MemoryRealms (Arbeitet mit dieser XML Datei) einen JDBCRealm (Arbeitet mit der Datenbank) verwenden.
http://tomcat.apache.org/tomcat-5.5-doc/realm-howto.html#JDBCRealm
http://www.linux-sxs.org/internet_serving/c619.html

Gruß Tom


----------



## Andron (13. Februar 2007)

Danke, das ist es, was ich gesucht habe,denke ich.

Ich werde das bis Ende der Woche testen und melde mich wieder.

Danke nochmals.


----------



## Andron (17. Februar 2007)

So, nun poste ich hier meine Fortschritte, wenn es die überhaupt gibt.

Zuerst habe ich die Datei web.xml angelegt:


```
<?xml version="1.0" encoding="ISO-8859-1"?>
 
 <!DOCTYPE web-app
 	PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 	"http://java.sun.com/dtd/web-app_2_3.dtd">
 
 <web-app>
   <display-name>A</display-name>
   <description>
 	A Simple test
   </description>
 
  <security-constraint>
    <display-name>A Configuration Security Constraint</display-name>
    <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <!-- Define the context-relative URL(s) to be protected 
      In dem Fall wollen wir einfach unsere index.html schützen.
      -->
      <url-pattern>*.html</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>authUser</role-name>
    </auth-constraint>
  </security-constraint>
	
 <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>A Server Configuration Form-Based Authentication Area</realm-name>
    <form-login-config>
      <form-login-page>/login.jsp</form-login-page>
      <form-error-page>/error.jsp</form-error-page>
    </form-login-config>
  </login-config>

  <security-role>
    <description>
      The role that is required to log in to the A Application
    </description>
    <role-name>authUser</role-name>
  </security-role>
 </web-app>
```


Danach die server.xml geändert, folgende Zeilen waren auskommentiert, ich habe die ein wenig angepasst :


```
<Realm  className="org.apache.catalina.realm.JDBCRealm"
             driverName="com.mysql.jdbc.Driver"
          connectionURL="jdbc:mysql://localhost:3306/meinedb"
         connectionName="root" connectionPassword="meinpass"
              userTable="users" userNameCol="user_name" userCredCol="user_pass" />
```

Danach folgende Tabelle erzeugt:


```
mysql> describe users;
+----------------+-----------------+-------+-------+----------+-----------------------+
| Field          | Type          | Null  | Key | Default | Extra               |
+----------------+-----------------+-------+-------+----------+-----------------------+
| id              | int(11)        | NO   | PRI | NULL    | auto_increment |
| user_name | varchar(15) | NO   |       |             |                        |
| user_pass  | varchar(15) | NO   |       |             |                        |
+----------------+-----------------+-------+------+-----------+-----------------------+
```

In der Tabelle wurde ein User mit user_name und user_pass erzeugt.

Das funktioniert aber nicht.
Ich bekomme die login.jsp angezeigt, nach der Eingabe meiner Daten, bekomme ich folgendes:


```
HTTP Status 403 - Access to the requested resource has been denied

--------------------------------------------------------------------------------

type Status report

message Access to the requested resource has been denied

description Access to the specified resource (Access to the requested resource has been denied) has been forbidden.
```

Außerdem kommt folgende Fehlermeldung:

```
17.02.2007 17:47:25 org.apache.catalina.realm.JDBCRealm getRoles
SCHWERWIEGEND: Exception performing authentication
com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your S
QL syntax; check the manual that corresponds to your MySQL server version for th
e right syntax to use near 'null WHERE user_name = 'usr'' at line 1
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)
        at com.mysql.jdbc.Connection.execSQL(Connection.java:3176)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.ja
va:1153)
        at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:
1266)
        at org.apache.catalina.realm.JDBCRealm.getRoles(JDBCRealm.java:629)
        at org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:421)
        at org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:347)
        at org.apache.catalina.authenticator.FormAuthenticator.authenticate(Form
Authenticator.java:257)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Authentica
torBase.java:416)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.j
ava:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.j
ava:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineVal
ve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.jav
a:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java
:869)
        at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.p
rocessConnection(Http11BaseProtocol.java:664)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpo
int.java:527)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFol
lowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadP
ool.java:684)
        at java.lang.Thread.run(Thread.java:619)
```




Was habe ich falsch gemacht? 
Bitte um Hilfe.


----------



## Andron (17. Februar 2007)

Ich glaube, das Problem wurde gelöst.
Es fehlte Tabelle user_roles und entsprechende Einträge in der server.xml.
Muss ich den user_role vergeben?
Ich dachte, es geht auch ohne. 
Na ja, falls wieder was ist, melde ich mich.


----------



## Thomas Darimont (17. Februar 2007)

Hallo,

du solltest dir mal die Doku zum JDBCRealm durchlesen...
http://tomcat.apache.org/tomcat-5.5-doc/realm-howto.html#JDBCRealm
Dort steht drin welche Tabellen und Spalten du für den Standard Login-Mechanismus brauchst (... ja du brauchst die user_role mapping Tabelle).

Wie du sicherlich schon bemerkt hast ist der Standard JDBCRealm sehr unflexibel was das Datenbankschema angeht... wie schon gesagt würde ich dir empfehlen auf ACEGI Security oder Josso zu wechseln.

Gruß Tom


----------



## Andron (5. März 2007)

Es klappt, aber nicht so, wie ich es möchte.
Habe mir die Seiten mit josso und jaas angeschaut, ziemlich kompliziert würde ich sagen.
Ich habe hier ein Ablaufdiagramm erstellt, wie es ungefähr aussehe soll:





Erklärung:
Die User rufen meine Seite auf und werden immer auf eine Instanz weitergeleitet, die zuerst überprüft, ob der User bereits eingeloggt ist oder nicht (Hier habe ich schon Schwierigkeiten Filter oder Mapping?).
Falls der User schon eingeloggt war, kommt er in den security-Bereich. Der Aufruf wird von einem Servlet empfangen, der dann entscheidet, welche jsp - Seite aufgerufen werden soll.
Wenn nich, wird er auf die login.jsp verwiesen, wo er seine Daten eingeben muss. Danach findet Datenbagleich mit der Datenbank statt. Wenn die Daten stimmen, kommt er, wie oben, zu einem Servlet.

Wie programmiere ich das am besten?
Wie kann ich unterscheiden, ob der User schon eingeloggt war oder nicht?
Muss ich dafür immer seine Session-ID überprüfen, ob die in der Datenbank vorhanden ist oder nicht? 
Bitte um Hilfe.


----------



## Andron (6. März 2007)

Kann mir denn niemand helfen)


----------



## Thomas Darimont (6. März 2007)

Hallo,



> Erklärung:
> Die User rufen meine Seite auf und werden immer auf eine Instanz weitergeleitet, die zuerst überprüft, ob der User bereits eingeloggt ist oder nicht (Hier habe ich schon Schwierigkeiten Filter oder Mapping?).
> Falls der User schon eingeloggt war, kommt er in den security-Bereich. Der Aufruf wird von einem Servlet empfangen, der dann entscheidet, welche jsp - Seite aufgerufen werden soll.
> Wenn nich, wird er auf die login.jsp verwiesen, wo er seine Daten eingeben muss. Danach findet Datenbagleich mit der Datenbank statt. Wenn die Daten stimmen, kommt er, wie oben, zu einem Servlet.


... genau das passiert doch beim oben beschriebenen Standard Mechanismus...
Darüber hinaus würde ich die tatsächlich zu verbergenden Seiten in einem separtem Verzeichnis innerhalb des Web-Inf verzeichnisses ablegen und dann nur noch explizit darauf forwarden. Resourcen die im Web-Inf liegen sind nicht direkt über den Browser zu erreichen (das geht aber bespielsweise über einen internen forward der nur authentifizierte User mit den entsprechenden Berechtigungen durch lässt).

Gruß Tom


----------



## Andron (6. März 2007)

Thomas Darimont hat gesagt.:


> Hallo,
> 
> 
> ... genau das passiert doch beim oben beschriebenen Standard Mechanismus...
> ...




Ich habe das auf verschiedebeb Weiseb ausprobiert. Irgendwie klappte das nicht so richtig.
Bei der Formularbasierten Authentifiziereung vom Tomcat wird der User nach dem Einloggen auf die Seite verwiesen, die er vorher eingegeben hat. So möchte ich das nicht.
Ich möchte, dass der User immer zum Servlet kommt, der dann entscheidet, welche JSP dann weiter macht.
Z.B. lautet meine Seite (lokal): localhost:8080/MyApplikation
Wenn der User diese Seite aufruft, wird er immer auf die login.jsp verwiesen.
Wird dagegen irgendeine JSP-Seite aufgerufen (z.B.: localhost:8080/MyApplikation/city.jsp), wird zuerst geprüft ob er bereits eingeloggt ist oder nicht, wenn ja, wird er trotzdem zum Servlet geschickt, wenn nicht zur loggin.jsp.
Außerdem hatte ich das Problem, dass Tomcat wohl nicht immer unterscheiden kann, ob der User eine Seite aufgerufen hat, oder wurde der User auf diese Seite von einer anderen JSP oder einem Servlet verweisen. Denn wenn der User selbst die Seite aufruft, wird ihm der Zugang verweisen, wenn er aber von meiner Appl. weitergeleitet wurde, ist das ok.

Ich werde mich morgen mit der Lösung des Problem intensiver beschäftigen (habe frei) und werde dann hier den Code und die Ergebnisse posten.
Danke für die Hilfe.
Bis morgen.

PS: vielleicht hatte schon jemand etwas ähnliches entwickelt, ein Paar Beispiele wäre nicht schlecht.


----------



## puschel0815 (19. August 2008)

Andron hat gesagt.:


> Ich werde mich morgen mit der Lösung des Problem intensiver beschäftigen (habe frei) und werde dann hier den Code und die Ergebnisse posten.



... also die Lösung dafür würde mich auch brennend interessieren. Scheint aber nicht so trivial zu sein, da du den Code offensichtlich nicht gepostet hast :-(

Grüße...


----------



## Andron (20. August 2008)

Hallo,
mein Beitrag ist schon etwas älter.
Ich habe das Problem mit einem Filter gelöst.


----------

