Tomcat Login Mechanismus

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Hier mal ein kleines Beispiel für ein simples Login-Formalar, welches die Tomcat eigenen
Security-Mechanismen verwendet.

wir legen im Verzeichnis %TOMCAT_HOME%/webapps
ein neues Verzeichnis namens "a" an.

In diesem Verzeichnis "a" legen wir ein weiteres Verzeichnis namens "web-inf" an.
In Verzeichnis "a" legen wir nun die folgenden Dateien an:

login.jsp:
Code:
<html>
    <head>
        <title>Login</title>
    </head>
    <body>
        <form action='<%= response.encodeURL("j_security_check") %>' method="POST">
            Username:<input type="text" name="j_username"/><br>
            Password:<input type="text" name="j_password"/><br>
            <input type="submit" value="login"/>
        </form>
    </body>
</html>

error.jsp:
Code:
error!

index.html:
Code:
Hallo!

Im Verzeichnis web-inf legen wir eine Datei namens web.xml an:

Code:
<?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>

Nun wechseln wir ins Verzeichnis %TOMCAT_HOME%/conf
und editieren die Datei tomcat-users.xml
und ergänzen diese um folgende Einträge:
Code:
  <role rolename="authUser"/>
  <user username="testuser" password="test" roles="authUser"/>

Nun startet ihr den Tomcat über
%TOMCAT_HOME%/bin/startup.bat

und ruft die URL http://localhost:8080/a/
auf.
Standardmäßig würde Tomcat nun die index.html zeigen, da wir jedoch einen Security-Constraint
außen herum gelegt haben bekommen wir ein login-Formular zu sehen.

Wenn wir uns dort mit
user: testuser
password: test

Einloggen bekommen wir die index.html zu sehen. Geben wir andere Login Daten ein sehen wir die
error Seite.

HTH,
Gruß Tom
 
Hallo Tom,

das oben von dir beschriebene habe ich ausprobiert und das klappt auch ganz gut. Ich habe das für eine Anwendung als tmporären Zugang benutzt. Jetzt stehe ich allerdings vor dem Problem, dass sich die Benutzer über LDAP authentifizieren sollen.
Dazu habe ich ein Servlet geschrieben, dass sich mit dem LDAP-Server verbindet und prüft, ob der User existiert. In meiner Login-JSP rufe ich dementsprechend auch nicht mehr "j_security_check" sondern mein Servlet auf. Allerdings glaube ich, dass ich da in einer Sackgasse stecke, denn das Servlet ruft die richtige Seite nach erfolgreichem Login zwar auf, Tomcat jedoch weiß natürlich nicht, dass der Benutzer authentifiziert ist und bei einem weiteren Klick greift wieder die web.xml Einstellung und die Login-Seite wird aufgerufen. Sprich: Login -> Suchvormular -> Klick auf "Suchen" -> Loginseite und nicht das Suchergebnis, da ich nicht weiß, wie ich dem Server mitteilen kann, dass der Benutzer gültig ist bzw. aus dem Servlet heraus die j_security_check ansprechen kann. Oder denke ich da insgesamt viel zu umständlich und das geht alles viel einfacher? Evtl. irgendwie über die server.xml und Realms, nur davon habe ich noch weniger Ahnung :(
Hast du oder hat sonst jemand eine Idee und kann mir helfen?

EDIT: ach ja, ist der Tomcat 4.1.31
 
Zuletzt bearbeitet:
Hallo scuffy
über LDAP geht das auch mit den Realms allerdings hab ich den Tomcat 5.02 deshalb wird sich meine Lösung ein wenig von deiner Unterscheiden.
Ich hab in dem Verzeichnis TomcatHome/conf/Catalina/Localhost die Datei ldap-demo.xml mit dem Inhalt:

<Context
cookies="true"
crossContext="false"
docBase="ldap-demo"
override="false"
privileged="false"
path="/ldap-demo"
displayName="ldap-demo 1.0"
reloadable="true"
cachingAllowed="true"
charsetMapperClass="org.apache.catalina.util.CharsetMapper"
debug="0"
swallowOutput="false"
useNaming="true"
allowLinking="true">

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99"
resourceName="UserDatabase"
connectionName="cn=Name,ou=Gruppe,o=Firma"
connectionPassword="pass"
connectionURL="ldap://192.168.1.1"
userBase="ou=Gruppe,,o=Firma"
userSubtree="true"
userSearch="(cn={0})"
roleBase="ou=Gruppe,o=Firma"
roleSubtree="true"
roleName="cn"
roleSearch="(uniqueMember={0})"
/>
</Context>

Du musst natürlich die Ip von deinem LDAP-Server und deinen Context eintragen. Ich denke bei Tomcat 4.x musst du alles was ich in der Datei ldap-test.xml habe in die server.xml reinschreiben.

Die web.xml sieht bei mir so aus

<web-app>
<display-name>ldap-demo 1.0</display-name>

<!-- Session Configuration -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>

<!-- The Usual Welcome File List -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>protected</web-resource-name>
<url-pattern>/pages/protected/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>


<login-config>
<auth-method>BASIC</auth-method>
<realm-name>TEST-TREE</realm-name>
</login-config>

</web-app>
unterscheidet sich also nicht groß von Toms Beispiel. Ansonsten immer interessant das Realm How-To auf der Tomcat Seite http://jakarta.apache.org/tomcat/tomcat-4.1-doc/realm-howto.html
 
Hallo buiters,

vielen Dank für die Antwort. Dass das wohl am elegantesten über Realms funktioniert hatte ich befürchtet und mich jetzt noch mal ausgiebig damit beschäftigt. Auf die Seite, deren Link du mir gepostet hast, bin ich auch schon gestoßen, aber ich "schwimme" hier wirklich in vielen Themen, mit denen ich bis vor wenigen Wochen noch nix zu tun hatte. Kein JSP, keine Servlets, Tomcat (was ist das) und LDAP sagten mir nichts und ich habe noch immer ein Problem mit den ganzen LDAP Parametern wie "cn" und was es da so alles gibt.

Ich habe mir deinen Vorschlag mal angesehen und versucht, das alles anzuwenden - es klappt!
Jedenfalls klappt es teilweise. Ich habe den Realm in der server.xml eingerichtet und die web.xml fast komplett übernommen. Ich kann mich mit dem LDAP-Server verbinden und er versucht auch, den user zu finden. Dabei kommt es aber zu unterschiedlichen Problemen. Er findet den Benutzer und versucht dann die "Rollen" zu ermitteln - nach dem <auth-constraint> in der web.xml sucht er dann natürlich nach role=tomcat und role=admin und kann diese natürlich nicht finden:

Code:
JNDIRealm[Standalone]: Username scuffy does NOT have role tomcat
JNDIRealm[Standalone]: Username scuffy does NOT have role admin

Jetzt will ich aber eigentlich nicht mit diesen roles zu tun haben :rolleyes:
Ich möchte erst mal nur wissen, ob der Benutzer existiert und eben Benutzername und Passwort - Kombination richtig waren (Authentifikation).
Wenn das (irgend wann mal) klappt, dann möchte ich einen Schritt weiter gehen und benötige zusätzlich Informationen vom LDAP über den User. Nennen wir diese Parameter einfach x, y und z - diese enthalten Länderkennungen. Wenn alle Attribute in etwa so aussehen: x=DE,y=DE,z=DE - DANN ist der Benutzer erst berechtigt die Applikation zu benutzen (Authorisierung).

Bisher sieht mein Code so aus (Variablen geändert) server.xml:
Code:
<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99"
	connectionURL=ldaps://qwertz.com:636
	connectionName="uid=scuffy,o=Firma,c=DE,o=Konzern"
	connectionPassword="xxx"
	 userBase="o=Konzern"
	userSubtree="true"
	userSearch="(uid={0})"
/>

Für die Attribute, die ich vom LDAP-Server erhalten möchte, muss ich angeblich der Zeile:
Code:
	userSearch="(uid={0})"
diese Attribute hinzufügen, jetzt stehe ich natürlich vor dem Rätsel wie genau das aussieht und wie ich diese Rückgabe auswerten kann...

Meine web.xml:
Code:
<web-app>
<display-name>Anwendung</display-name>
<!-- Session Configuration -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>
<!-- The Usual Welcome File List -->
<welcome-file-list> 
<welcome-file>index.jsp</welcome-file> 
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>protected</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name> 
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Anwendung</realm-name>
</login-config> 
</web-app>
.... nur der Vollständigkeit halber :)

Vielen Dank noch mal für die bisherige Hilfe, ich bin wirklich ganz schön verzweifelt gewesen, da ich da schon ziemlich lange dran sitze und jetzt endlich das Gefühl habe "das Richtige" zu tun - jedenfalls scheint das ein recht eleganter Lösungsweg zu sein und nicht so etwas umständliches über das Servlet und dann wieder zurück ...

Wäre schön, wenn ich noch ein paar Tipps zu den roles und den Attributen bekommen könnte - vielen Dank

Grüße
Scuffy
 
Zuletzt bearbeitet:
Hallo scuffy
eine Warnung vorweg ich beschäftige mich mit dem LDAP-Thema auch erst seit Januar diesen Jahres.
Hier mal ein link zu einer LDAP Erklärung ist halt sehr Novell spezifiesch ich fands aber ganz gut (liegt vielleicht auch daran das wir Novell einsetzten)
http://www.novell.com/documentation/edir87/index.html
vor allem die Abschnitte Understanding LDAP Services und Configuring LDAP Services könnten Interessant sein.
Um die Rollen wirst du nicht herumkommen da so wie ich das Realm-How-To verstehe diese immer mit den Rollen arbeiten. Du kannst höchstens jedem User die Rolle "Mitglied" oder so geben und auf diese Rolle dann überprüfen.
Auch das mit den verschiedenen Daten funktioniert so meiner Meinung nach nicht. Du müsstest wenn dann aufgrund dieser Daten Rollen vergeben und auf diese Rollen dann abprüfen direkt über die Realms diese Daten abzufragen halt ich für unmöglich höchstens du programmierst deine eigene Realm was möglich aber wahrscheinlich nicht in deinem Interesse ist.

userSearch="(uid={0})"

uid = {0} bedeutet das der bei der Abfrage eingegebene Username verwendet wird wenn du uid{1} machst wird der User den du unter connectionName="cn=Name,ou=Gruppe,o=Firma" angegeben hast verwendet in diesem Fall Name. Ich sehe im Moment keine Möglichkeit dort nach anderen Attributen zu suchen.
Ich hoffe ich konnte dir helfen
Gruß buiters
 
Hallo buiters,
auch erst seit Januar - naja das sind immerhin ein paar Tage länger als ich ^^ ;-)
Was die roles angeht habe ich das jetzt so gelöst, dass ich im auth-constraint jede role zulasse:
Code:
  <auth-constraint>
   <role-name>*</role-name> 
  </auth-constraint>
... beinahe schon zu einfach, wenn man sich ein paar Zeilen darüber das Element "url-pattern" ansieht :-(
Naja, aber das muss man eben wissen, dass das da auch so funktionieren könnte. Was meine Attribute angeht muss ich mal schauen, wie ich das mache.
Vielen Dank noch mal :)

Gruß
Scuffy
 
Hallo!

UPDATE:
- Logout-Möglichkeit eingefügt
- Verzeichnisschutz
- Anzeige des aktuellen Benutzers

Hier mal ein kleines Beispiel für ein simples Login-Formalar, welches die Tomcat eigenen
Security-Mechanismen verwendet.

wir legen im Verzeichnis %TOMCAT_HOME%/webapps
ein neues Verzeichnis namens "a" an.

In diesem Verzeichnis "a" legen wir ein weiteres Verzeichnis namens "WEB-INF" an.
In diesem Verzeichnis "a" legen wir ein weiteres Verzeichnis namens "secure" an, dies soll
unser zu schützender Bereich sein.
In Verzeichnis "a" legen wir nun die folgenden Dateien an:

login.jsp:
Code:
 <html>
 	<head>
 		<title>Login</title>
 	</head>
 	<body>
 		<form action='<%= response.encodeURL("j_security_check") %>' method="POST">
 			Username:<input type="text" name="j_username"/><br>
 			Password:<input type="password" name="j_password"/><br>
 			<input type="submit" value="login"/>
 		</form>
 	</body>
 </html>

error.jsp:
Code:
 error!

index.jsp:
Code:
 <html>
    <head>
 	  <title>Öffentlicher Bereich</title>
    </head>
    <body>
 	  <a href="secure/secret.jsp">geschützter Bereich</a></br>
 	  <a href="logout.jsp">logout</a>
    </body>
 </html>

logout.jsp
Code:
 <% 
 session.invalidate();
 request.getRequestDispatcher("index.jsp").forward(request,response);
 %>

Im Verzeichnis secret erstellen wir nun die Datei secret.jsp
Code:
 <html>
    <head>
 	  <title>secure_area</title>
    </head>
    <body>
 	  Hallo <%=request.getUserPrincipal().getName() %>!</br>
 	  <a href="../index.jsp">index</a></br>
 	  <a href="../logout.jsp">logout</a>
    </body>
 </html>


Im Verzeichnis web-inf legen wir eine Datei namens web.xml an:

Code:
 <?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>/secure/*</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>

Nun wechseln wir ins Verzeichnis %TOMCAT_HOME%/conf
und editieren die Datei tomcat-users.xml
und ergänzen diese um folgende Einträge:
Code:
 <role rolename="authUser"/>
 <user username="testuser" password="test" roles="authUser"/>

Nun startet ihr den Tomcat über
%TOMCAT_HOME%/bin/startup.bat

und ruft die URL http://localhost:8080/a/
auf.

Wir sehen nun die Seite index.jsp. Klicken wir auf "geschützter Bereich",
so müssen wir uns zuerst Authentifizieren. Dazu wird ein login-Formular angezeigt.

Wenn wir uns dort mit
user: testuser
password: test

einloggen bekommen wir die secret.jsp zu sehen. Geben wir "ungültige" Benutzerdaten ein
gelangen wir auf error.jsp. Sind wir auf secret.jsp können wir über einen klick auf
logout die aktuelle Session für ungültig erklären und kehren wieder auf die index.jsp Seite zurück.
Klicken wir innerhalb von secret.jsp auf den Link "index" gelangen wir wieder zurück zu index.jsp.
Klicken wir dort nun erneut auf "geschützter Bereich" gelangen wir sofort dorthin, ohne unsere
Benutzerdaten wieder eingeben zu müssen, da unsere Authentifizierungsdaten in der Session gespeichert
sind.

HTH,
Gruß Tom
 

Anhänge

@ Thomas Danke für das plausieble Beispiel.

Ich habe das "Form" Realm mit jdbc:mysql realiesiert. Es funtioniert auch so weit.

Nun ist auf meiner Startseite ein Loginformular. Leider komme ich nicht dahinter wie ich
den user der sich auf der ersten Seite anmeldet der vorher KEINEN link innerhalb
geschützen angecklickt hat. Es ist also nicht bekannt wohin er will.
Das System soll ihn auf eine bestimmte Seite schicken
die im Formular oder der web.xml festgelegt ist.


Zürück zum Beispiel vieleicht ist es dann verstänlicher.

Es verhält sich so als ob es keine index.jsp gibt sondern nur die login.jsp.

In einem Standartformular ist innerhalb der Form Action eine Zielseite angegeben
hier geht das nicht weil. <%= response.encodeURL("j_security_check") %> als Ziel festgesetz ist.

Wie bekomme in das form action eine Zielseite und den j_security_check?

<form action='<%= response.encodeURL("j_security_check") %>' method="POST">

Das funktioniert logischer weise nicht.
<form action="/geschützterBereich.jsp?"'<%= response.encodeURL("j_security_check") %>' method="POST">

Ich habe auch innerhalb der Tomcat docu kein tag gefunden in dem
eine default Seite angeben werden kann.

Ich danke für die Aufmerksamkeit
esion


.
 
Hi,

ich bin gerade dabei, eine Authentifizierung via LDAP in meine WebApp einzubauen. Das ganze funktioniert auch schon ganz gut: Melde ich mich mit den falschen Daten (user/pass) an, so bekomme ich nach 3 Versuchen einen Error 401 (Unauthorized) - genau so soll es ja sein. Melde ich mich hingegen mit den richtigen Daten an, so bekomme ich einen Error 403 (Forbidden), was mir auch klar ist, da ich in LDAP keinerlei Rollen zugeteilt bin (also genau das gleiche wie weiter oben im Thread von scuffy geschildert).

Mein Problem: Ich kann in LDAP keine Rollen einpflegen (ca. 100.000 User => hier darf nicht jeder "rumpfuschen"). Deshalb möchte ich gerne nur die Authentifizierung (user/pass) via LDAP machen. Die Rollenzuweisung würde ich hingegen gerne in der web.xml machen.

Konkret stelle ich mir das in etwa so vor (willkürliche Syntax):
<user ldapmatch="(cn=hansi)||(cn=alfons)" role="admin" />
<user ldapmatch="ou=it,dc=de,dc=example,dc=com" role="readonly" />

Kann mir jemand sagen, ob dies möglich ist, oder müssen die Rollen unbedingt in LDAP definiert werden? (was meiner Meinung nach unsinnig wäre, da sich die Rollen ja von Webapp zu Webapp unterscheiden können)

Vielen Dank schonmal für eure Hilfe!

Viele Grüße
Markus
 
@ Thomas Danke für das plausieble Beispiel.

Ich habe das "Form" Realm mit jdbc:mysql realiesiert. Es funtioniert auch so weit.

Nun ist auf meiner Startseite ein Loginformular. Leider komme ich nicht dahinter wie ich
den user der sich auf der ersten Seite anmeldet der vorher KEINEN link innerhalb
geschützen angecklickt hat. Es ist also nicht bekannt wohin er will.
Das System soll ihn auf eine bestimmte Seite schicken
die im Formular oder der web.xml festgelegt ist.


Zürück zum Beispiel vieleicht ist es dann verstänlicher.

Es verhält sich so als ob es keine index.jsp gibt sondern nur die login.jsp.

In einem Standartformular ist innerhalb der Form Action eine Zielseite angegeben
hier geht das nicht weil. <%= response.encodeURL("j_security_check") %> als Ziel festgesetz ist.

Wie bekomme in das form action eine Zielseite und den j_security_check?

<form action='<%= response.encodeURL("j_security_check") %>' method="POST">

Das funktioniert logischer weise nicht.
<form action="/geschützterBereich.jsp?"'<%= response.encodeURL("j_security_check") %>' method="POST">

Ich habe auch innerhalb der Tomcat docu kein tag gefunden in dem
eine default Seite angeben werden kann.

Ich danke für die Aufmerksamkeit
esion


.


Genau dasselbe Problem habe ich auch und konnte es bisjetzt noch nicht lösen.
Wäre für ein Paar Tipps sehr dankbar.
 
Zurück