Beispiel zum Thema Websecurity mit JBoss 4.0.2

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Wir wollen eine Webanwendung die innerhalb von JBoss läuft mit den gegebenen Mitteln schützen. Als Server Konfiguration wählen wir "default". Die Authentifizierung und Authorisierung stützt sich auf Daten die aus einer MySQL Datenbank stammen.

Hierzu erzeugen wir in mysql eine neue Datenbank namens "security_example", legen die notwendigen Tabellen an und bevölkern diese mit Test-Daten.

Code:
drop database security_example;
create database security_example;
use security_example;
create table user (id int not null, username varchar(32) not null unique, password varchar(32) not null, primary key(id));
create table role (id int not null, rolename varchar(32) not null, primary key(id));
create table user_role_map(id int not null auto_increment, user_id int not null, role_id int not null,primary key(id));

insert into user values (1,'tom','test');
insert into role values (1,'admin');
insert into role values (2,'member');

insert into user_role_map (user_id,role_id) values (1,1);
insert into user_role_map (user_id,role_id) values (1,2);

commit;

Nun definieren wir uns eine MySQL Datenquelle im JBoss:
Dazu kopieren wir zuerst den MySQL JDBC Treiber (z:bsp.: mysql-connector-java-3.1.8-bin.jar) ins lib Verzeichnis der default Server Konfiguration (z:bsp.:E:\jboss\4.0.2\jboss-4.0.2\server\default\lib)

Anschließend nehmen wir uns aus dem Verzeichnis examples/jca eine Beispiel Konfiguration für eine MySQL Datenquelle und passen diese unseren Bedüfrnissen an: z:bsp.:E:\jboss\4.0.2\jboss-4.0.2\docs\examples\jca -> mysql-ds.xml)

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: mysql-ds.xml,v 1.3.2.1 2004/12/01 11:46:00 schrouf Exp $ -->
<!--  Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->
<datasources>
  <local-tx-datasource>
    <jndi-name>MySqlDS</jndi-name>
    <connection-url>jdbc:mysql://localhost:3306/security_example</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password></password>
   <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
    <!-- sql to call when connection is created
    <new-connection-sql>some arbitrary sql</new-connection-sql>
      -->
    <!-- sql to call on an existing pooled connection when it is obtained from pool 
    <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
      -->
    <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

Anschließend kopieren wir diese angepasste xml Datei ins Deploy Verzeichnis unserer default Server-Konfiguration, damit diese beim nächsten start (JBoss ist auch hot-deployfähig sprich neue Dienste/Connectoren können auch zur Laufzeit hinzugefügt werden) erkannt wird.

Anschließend bearbeiten wir die login-config.xml (z.Bsp: E:\jboss\4.0.2\jboss-4.0.2\server\default\conf )
und fügen am Ende:
Code:
<application-policy name="security_example">
   	<authentication>
		<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
			<module-option name="dsJndiName">java:/MySqlDS</module-option>
			<module-option name="unauthenticatedIdentity">nobody</module-option>
			<module-option name="principalsQuery">SELECT password FROM user WHERE username=?</module-option>
			<module-option name="rolesQuery">SELECT rolename Roles, 'Roles' FROM (user u inner join user_role_map urm on u.id = urm.user_id) inner join role r on urm.role_id = r.id WHERE u.username=?</module-option>
		</login-module>
	</authentication>
</application-policy>
vor </policy> hinzu

Damit haben wir einen neuen Authentifizierungs Apparat installiert der auf den Namen "security_example" und im lokalen JNDI über java:/jaas/security_example gefunden werden kann.

Nun machen wir uns endlich an unsere Webanwendung.
Im Verzeichnis WEB-INF legen wir folgende Dateien an:
web.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
	xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<security-constraint>
		<web-resource-collection>
			<web-resource-name>restricted</web-resource-name>
			<url-pattern>/protected/*</url-pattern>
			<http-method>GET</http-method>
			<http-method>POST</http-method>
		</web-resource-collection>
		<auth-constraint>
			<role-name>admin</role-name>
		</auth-constraint>
	</security-constraint>
	
	<login-config>
		<auth-method>FORM</auth-method>
		<realm-name>security_example</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 admin role is required...
		</description>
		<role-name>admin</role-name>
	</security-role>
</web-app>

Damit sagen wir dem Webcontainer, dass wir den Bereich /protected/* durch eine FORMular-Basierte Authentifikationseinheit schützen möchten. Das ganze konfigurieren wir so, dass login.jsp als Loginseite und error.jsp als Fehlerseite (bei falschen / Unbenkannten Login Daten) angezeigt wird. Darüber hinaus sagen wir auch, dass nur Benutzer mit der Rolle 'admin' den geschützten Bereich betreten dürfen.

Anschließend erstellen wir wieder in WEB-INF die Datei jboss-web.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" 
	"http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">
<jboss-web>
	<security-domain>java:/jaas/security_example</security-domain>
</jboss-web>
Damit sagen wir dem Webcontainer, dass wir diese Webanwendung von der zuvor festgelegten Sicherheitseinrichtung "beschützen" lassen wollen.

Nun folgen nich im root die Dateien login.jsp, error.jsp und index.jsp:
Login.jsp:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="text/html" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
	<head>
		<title>Login</title>
	</head>
	<body bgcolor="#FFFFFF">
		<table border="0">
			<form method="post" action="j_security_check">
				<tr>
					<td>Benutzername: </>
					<td><input type="text" maxlength="32" name="j_username"/></td>
				</tr>
				<tr>
					<td>Passwort: </>
					<td><input type="password" maxlength="32" name="j_password"/></td>
				</tr>
				<tr>
					<td>
						<input type="submit" value="Anmelden"/>
					</td>
					<td>
					</td>
				</tr>
			</form>
		</table>
	</body>
</html>

Error.jsp
Code:
<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="text/html" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
	<head>
		<title>JSP Page</title>
	</head>
	<body bgcolor="#FFFFFF">
		Unbekannter Benutzer!
	</body>
</html>

index.jsp
Code:
<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="text/html" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>

<head>
	<title>JSP Page</title>
</head>

<body bgcolor="#FFFFFF">
<a href="protected/secret.html">Wanna see the Secret?</a>
</body>

</html>

Anschließend legen wir innerhalb des roots noch ein Verzeichnis namens protected für unseren geschützten Bereich an. Darin legen wir eine Datei namens secrent.html
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    
<head>
		<title>HTML Page</title>
</head>

<body bgcolor="#FFFFFF">
YOU FOUND THE KEY :)
</body>
    
</html>

Der Anhang enthält dein Beispielprojekt mit einem fertigen war-archive im Verzeichnis deploy.
Will man das ganze ausprobieren, so muss man nur das war archiv ins deploy Verzeichnis der jeweiligen Server konfiguration kopieren.

Danach kann man die Anwendung z.Bsp. über die URL http://localhost:8080/security_example/ aufrufen.

Gruß Tom
 

Anhänge

  • de.tutorials.jboss.security.exam
    7,4 KB · Aufrufe: 262
Super!

Vielen Dank für die Mühe Thomas, das werde ich mir heute nacht gleichmal zu gemüte führen !

Danke schön

Mfg
Martin
 
Hi,

danke für das sehr gute Beispiel, gibt es die Möglichkeit das irgendwie mit Struts zu kombinieren? Das kann eigentlich nicht so schwer sein, nur bekomme ich das irgendwie nicht hin :(

Danke und Gruß

Bonkers
 
jo, Super-Tutorial, läuft bestens
Auch die Portierung auf Oracle lief problemlos.

Nun will ich aber wie Bonkers das ganze mit Struts kombinieren habe da aber mehrere Probleme:

  • In der jboss-eb.xml wird schon gleich der Eintrag <security-domain>java:/jaas/security_example</security-domain> als Fehlerhaft angemeckert
  • Beim Aufruf der Anwendung bekomme ich IMMER die error.jsp ausgegeben, auch wenn User/Passwort richtig sind
  • Wenn denn dieses Phänomen endlich mal richtig laufen sollte (help needed), dann ist hier die Frage, wie ich die Login- und Error-JSP-Seiten in der web.xml denn nun struts-konform deklariere
  • Hat außerdem jemand einen Tipp, wie ich es realisiere, dass nach erfolgreicher Anmeldung ein Benutzer der Rolle x auf die Seite x.jsp verwiesen wird, ein Benutzer der Rolle y auf y.jsp und Benutzer, deren Name oder Passwort unbekannt sind wieder auf der Login.JSP, wo allerdings der Hinweis erscheint, dass Benutzername oder Passwort unbekannt sind

Grüße
DerAlbers
 
Moin.

Ich habe ungefähr so etwas wie das, was hier beschrieben wurde, aufgesetzt.
Bei mir wird jedoch immer gesagt, dass zu dem Benutzernamen kein Passwort gefunden werden konnte.
Nun habe ich mal den Datenverkehr mit ethereal überwacht und siehe da was ich hier seltsames habe:
SELECT PASSWORT_USER FROM USER WHERE NAME_USER=?

Wieso steht da ein Fragezeichen?
Also der Query stimmt schon. Wenn ich nun am Ende meinen Benutzernamen angebe funktioniert der wunderbar.
So ein Query mit einem Fragezeichen an die MySQL DB macht natürlich keinen Sinn.
Hat jemand eine Idee woran das liegen kann?
Ob da evtl. ein Fehler in der Implementierung vorliegt.
Ich verwende übrigens JBoss 4.0.3 SP1

Beste Grüße,
Marcel
 
Zurück