# Form Based Authentication erweitern? Custom JDBCRealm!?!



## quadro (25. Jan 2008)

Hi Leute, 
ich nutze die Tomcateigenen Mechanismen für Authentication.  Funktioniert alles prima nur möchte ich diese erweitern. Hat jeman erfahrungen wie man das machen könnte?!? 

Und zwar werden ja 2 Parameter abgefragt, die die  "Authentication" am Server sichern. Das sind das Passwort und der Nutzername. Ich benötige aber noch einen weiteren. In meiner DB gibts noch nen Eintrag, ob die User Ihren Account aktiviert haben oder nicht. (true/false) Diesen muss ich noch abfragen, damit nur die User zugriff auf geschützte Inhalte haben, die auch Ihren Account aktiviert haben. 

Die Anmeldung für diesen Dienst habe ich fertig, die User bekommen vom System ne Mail mit nem Aktivierungslink, der vom Server genriert wird, in der DB eingetragen wird und dann das Flag "active" geändert wird. Diesen Eintrag möchte ich jetzt gerne beim Login mit abfragen... 

Besteht die Möglichkeit, das man die authenticate() Methode überschreibt und seinen eigenen Mechanismus implemntiert oder gibts dafür schon fertige Ansätze...?!?


Wäre froh wenn mir da jemand ein paar Tips geben kann....vielleicht hat ja jemand damit schon Erfahrungen...!!!

Tomcat 5.5.xxxxxxx + JSF/JSP

Danke!

*****


----------



## maki (25. Jan 2008)

> ich nutze die Tomcateigenen Mechanismen für Authentication.


Welchen den genau?
Da gibt es einige (MemoryRealm, JDBCRealm, JNDIRealm über LDAP...)


----------



## quadro (25. Jan 2008)

JDBCRealm nutze ich...! Vielleicht gibts ja auch nen anderen Ansatz, aber dieser war sehr einfach...


----------



## quadro (25. Jan 2008)

Mir ist gerade ein anderer Ansatz eingefallen. Und zwar gibt es in der DB die Tabelle mit der "Verknüpfung" Username-Rollenname. Ich könnte nach dem erfolgreichen Anmelden und der Authentifizierung auch dann erst die Rolle eintragen zu dem speziellen user. Damit würde ich den Kram ein wenig umgehen.... So könnte ich als Flag die Rollen nutzen...

Was haltet Ihr davon? Irgendwelche Bedenken? Risiken? Nebenwirkungen?!?


----------



## ms (25. Jan 2008)

Ich habe es so gelöst, dass ich dem SQL-Statement einfach eine zusätzliche WHERE-Bedingung mit dem Flag für die Aktivierung angefügt habe. Die Idee mit der Rolle ist aber auch ein brauchbarer Ansatz.

ms


----------



## quadro (29. Jan 2008)

ms hat gesagt.:
			
		

> Ich habe es so gelöst, dass ich dem SQL-Statement einfach eine zusätzliche WHERE-Bedingung mit dem Flag für die Aktivierung angefügt habe. Die Idee mit der Rolle ist aber auch ein brauchbarer Ansatz.
> ms



Ok, aber hast Du die Anmeldung komplett selber geschrieben, ich nutze die eigenen Mechanismen von Tomcat, da kümmer ich mich ja um keine Statements. Lege halt nur die nötigen Tabellen an und los gehts...

Oder hast Du in einer eigenen Klasse die Anmeldung gemanaged?!? Wäre nett wenn Du Deinen Ansatz noch ein wenig ausfühlicher beschreibts, mein Ansatz mit den Rollen ist dann doch hackeliger als ich dachte... Muss dann die dafault Fehlermeldungen etc. ändern, die Stimmen ja dann nicht miehr so richtig...  

Dann jedes mal die Session killen....

Bin also immer noch auf der Suche!

THX!


----------



## ms (29. Jan 2008)

Sorry, ich habe voreilig von einem DatabaseLoginModule des JBoss auf den JDBCRealm von Tomcat geschlossen.
Beim DatabaseLoginModule/Jboss gibt man zwei SQL-Statements (User und Rollen) an, beim JDBCRealm/Tomcat nur die Tabellen- und Spaltennamen. Von daher ist das was ich geschrieben habe falsch.

Man könnte jetzt auf die schnelle JDBCRealm ableiten und die entsprechende Methode, die das SQL-Statement zusammensetzt erweitern aber damit sind wahrscheinlich noch nicht alle deine Anforderungen abgedeckt.

Zu der Sache mit der Fehlermeldung: ich nehme an du möchtest eine eigene Fehlermeldung für einen noch nicht aktivierten Account anzeigen?
Und warum die Session killen?

ms


----------



## quadro (29. Jan 2008)

ms hat gesagt.:
			
		

> Man könnte jetzt auf die schnelle JDBCRealm ableiten und die entsprechende Methode, die das SQL-Statement zusammensetzt erweitern aber damit sind wahrscheinlich noch nicht alle deine Anforderungen abgedeckt.
> 
> Zu der Sache mit der Fehlermeldung: ich nehme an du möchtest eine eigene Fehlermeldung für einen noch nicht aktivierten Account anzeigen?
> Und warum die Session killen?
> ...



Meine Anfrage müsste aus 

- Passwort
- Username
- Account aktiv(ja/nein)

bestehen. Passwort und Username werden ja schon genutzt. Müsste also nur um die eine Abfrage ergänzt werden und zwar ob der Account schon aktiv ist oder nicht.  

Und zu Deiner 2. Frage. Ja wenn leite ich auf eine Fehlerseite um, die genau das gleiche Loginformular zeigt, sowie den Hinweis, das entweder die Daten Falsch sind oder der Account noch nicht aktiv ist.

Ich habe es probiert, erst die Rolle dem Nutzer zuzuweisen, nachdem der Account aktiviert wurde, das bürgt aber andere Hindernisse... Ich muss dann den Fehler 403 umgehen, bzw. hatte ich dann auf die loginseite mit der Fehlermeldung verlinkt, das funktioniert, wenn man dann aber nen aktivierten nutzer anmelden will, wird der j_security_check nicht gefunden... Das wurde mir dann zu "bastelmässig" und das habe ich dann verworfen... 

Daher wäre es cooler, wenn man das sofort beim einfachen Login mit abfragen kann...


----------



## ms (29. Jan 2008)

Ich fürchte du wirst mit einfachen Mitteln nicht unterscheiden können ob der Benutzer ein falsches Passwort angegeben hat oder einen inaktiven Account hat weil beim Authentifizieren letztendlich nur ein Objekt vom Typ Principal mit seinen Rollen abgefragt wird. Daher wirst du auch keine separate Fehlermeldung anzeigen können. 
Aber eine gemeinsame Fehlermeldung so wie du es möchtest (entweder falscher Benutzernamen, falsches Passwort oder inaktiver Account) ist damit machbar.

Lade dir mal die Tomcat-Sourcen runter und schau dir die Klasse JDBCRealm an.

Für die Variante mit den Rollen: die erste Rolle, die ein neuer Benutzer haben sollte wäre wohl INACTIVE oder so ähnlich.
In einem Filter könntest du dann auf diese Rolle abfragen und auf die Login-Seite mit der entsprechenden Meldung umleiten.

ms


----------



## quadro (29. Jan 2008)

Genau so in die richtung müsste das gehen... Ich werde mir das morgen mal ansehen und meine Ergebnisse dann hier posten.  Vielen Dank schonmal und wir lesen dann voneinader...


----------



## quadro (30. Jan 2008)

Nochmal ne Frage zu der Klasse JDBCRealm. Und zwar habe ich die Sourcen, die Klasse ist ja relativ easy. Ich könnte jetzt einfach noch die Abfrage meiner Tabellenspalte implementieren und dann diese mit in den Authenifizierungsvorgang mit einbeziehen. Das nicht so das Problem. Wie aber binde ich dann mein Custom JDBCRealm ein?!? Das muss ja in den Tomcat "reinkompiliert" werden oder gibts da ne andere Möglichkeit?!? Im Netz findet man leider nicht so die Erläuterungen.

Andererseits, wenn ich jetzt den Tomcat modifiziere, dann ist das Problem, das die Application ja nur auf meinem Custom Tomcat läuft, das ja auch nicht so cool, vor allem wenn es nur um so eine schnöde Abfrage geht. 

Gibts da ne andere Methode, mein Custom JDBCRealm dem Tomcat aufzudrängen, ausser mir den Tomcat selber zu kompilieren?!?

Spannend ist das aber alle male... 

THX!


----------



## maki (30. Jan 2008)

Vielleicht hilft dir ja das etwas, da geht es auch um die TC Konfig für selbstgeschriebene Realms:
http://www.christianschenk.org/blog/setup-your-own-tomcat-security-realm/


----------



## quadro (31. Jan 2008)

Hi Leute,
ich habe nach stundenlangem Suchen dann doch noch was gefunden, was dem entspricht was ich suche. Leider bekomme ich das aber nicht ans laufen, obwohl das ganz easy zu implemntieren ist. Vielleicht hat ja jemand lust sich das mal anzuschauen und kann mir meinen Fehler nennen. 

Es handelt sich um das Jaffa Framework


jaffa.sourceforge.net/documentation/security/web/

Bei diesem Realm handelt es sich um genau das was ich suche, kann damit eine Spalte in meiner User Tabelle abfragen um zu schauen, ob der Account aktiv ist oder nicht. 

Die Schritte um das zu implementieren sind denkbar einfach.

1.) jaffa-tomcat.jar in %CATALINA_HOME%/server/lib kopieren...  Habe ich gemacht!

2.) Server.xml um folgenden Eintrag ergänzen...  Habe ich gemacht!

Auszug aus meiner server.xml

```
<Realm
        className          = "org.jaffa.tomcat.realm.JDBCEncryptionRealm"
        debug              = "0"
        driverName         = "com.mysql.jdbc.Driver"
        connectionURL      = "jdbc:mysql://localhost/mydb"
        connectionName     = "root"
        connectionPassword = ""
        userTable          = "users"
        userNameCol        = "username"
        userCredCol        = "password"
        userClause         = "status!='INACTIVE'"
        userRoleTable      = "user_roles"
        roleNameCol        = "rolename"
	encryptionClass    = "nmf.realm.Encrypt"
        encryptionMethod   = "encrypt"
        />
```


3.) encryption Klasse schreiben



> You can use any className and method name, just make sure you deploy your encryption routine as a '.class' file under %CATALINA_HOME%/server/classes or in a JAR file under %CATALINA_HOME%/server/lib
> 
> The only pre-requisite for the encryption method is that is must have a signature that matches either
> public String xxx(String password)
> ...



Das habe ich gemacht. Habe eine Klasse geschrieben, die nichts macht ausser das Passwort im Klartext zurückzuliefern. MD5 kommt dann später oder was auch immer...!

Auszug meiner Klasse.


```
package realm;

public class Encrypt {
	
	
	public String encrypt(String password){
		return password;
	}

}
```


Diese Klasse ist in dem jar, welches in der server.xml angegeben ist 

```
encryptionClass    = "nmf.realm.Encrypt"
```
 und liegt genau wie das jaffa-tomcat.jar in
%CATALINA_HOME%/server/lib





Als Fehlermeldung bekomme ich vom Tomcat beim starten nun folgendes. Das liegt auch an den Einträgen in der Server.xml (encryptionClass    = "nmf.realm.Encrypt") weiss aber nicht was ich da falsch gemacht haben soll... ?!?


```
INFO: Starting Servlet Engine: Apache Tomcat/5.5.25
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:295)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:433)
Caused by: java.lang.NoSuchFieldError: debug
	at org.jaffa.tomcat.realm.JDBCEncryptionRealm.start(JDBCEncryptionRealm.java:870)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1006)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
	at org.apache.catalina.core.StandardService.start(StandardService.java:448)
	at org.apache.catalina.core.StandardServer.start(StandardServer.java:700)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:552)
	... 6 more
```



Meine Frage. Hat jemand ne idee, warum der meine Klasse nicht findet und warum diese Fehlermeldung entsteht?!?


Ich danke schon mal für Tips![/code]


----------



## eSK (25. Feb 2008)

Mal ganz anders - kann deine drunterliegende DB vielleicht sowas wie Views?

Ich benutze hauptsächlich Oracle. MSSQL-Server hat glaube ich auch Views, MySQL ist schon zu lange her.

Wenn ja, mach dir doch einfach eine View, wo nur die aktivierten User enthalten sind, dann brauchst du nichts ableiten, vererben, etc.


----------



## thajek (25. Feb 2008)

Moin

hm kann es sein das ein feld bei der configuration in der server.xml nicht vorhanden, also zu viel angegebenist,die felder  müssten als setter in der realm vorhanden sein


----------

