Security mit Glassfish 3 - JSF2 - jdbcRealm über MySQL5.5 Authentication

Cicero M

Grünschnabel
Hallo,

mein jdbcRealm scheint nicht zu funktionieren und ich hoffe ihr könnt mir helfen.

Nach 2 Wochen Internetrecherche und probieren, wage ich es überhaupt einen neuen Eintrag zu erstellen. Ich versuche erstmalig JEE definierte Security einzurichten, ohne groß selbst etwas zu entwickeln. Über normale user-password Kombination, soll man auf geschützte Webseiten zugreifen können. Es soll die Gruppen admin und member geben. Ich glaub, damit dürfte ich erstmal klarkommen.

Folgende gute Tutorial-Seite konnte ich bisher ausmachen:
http://blog.triona.de/ (Java-EE-Webapplikation absichern)

Folgende Punkte müssen demnach gemacht werden:
1. MYSQL: Mysql-Tabellen einrichten
2. GLASSFISH: Datenbankverbindung Glassfish bekanntgeben
3. GLASSFISH: JNDI mit der Verbindung einrichten
4. GLASSFISH: jdbcRealm einrichten
5. APPLIKATION: Sicherheitseinstellungen in web.xml und glassfish-web.xml
6. APPLIKATION: JSF-Login-Seite erstellen

Die Punkte 5. und 6. konnte ich schon prüfen. Sie sind korrekt, da ich schon erfolgreich ein fileRealm ('file') testen konnte. Auch Punkt 2. ist durch den erfolgreichen Ping bereits als korrekt bestätigt?! Aber wie teste ich die anderen Punkte?

aus der web.xml nur den realm-name geändert, sieht der snipped nun so aus:
Code:
	<login-config>
		<auth-method>FORM</auth-method>
		<realm-name>loginRealm</realm-name>
		<form-login-config>
			<form-login-page>/login.xhtml</form-login-page>
			<form-error-page>/loginFailed.xhtml</form-error-page>
		</form-login-config>
	</login-config>
aus dem server.log:
Code:
Information: SEC1115: Realm [file] of classtype [com.sun.enterprise.security.auth.realm.file.FileRealm] successfully created.
Information: SEC1115: Realm [loginRealm] of classtype [com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm] successfully created.
Allerdings weiß ich hier ja nicht, was er sich beim jdbc eingelesen hat.

So hab ich den Punkt "1. MYSQL: Mysql-Tabellen einrichten" umgesetzt.
Meine Datenbank sieht so aus:
Code:
CREATE TABLE USER(
        username VARCHAR(128) NOT NULL PRIMARY KEY ,
        password VARCHAR(128) NOT NULL,
        INDEX (username)
);

create table USERGROUP(
        username varchar(128) NOT NULL,
        groupid  varchar(128) NOT NULL,
        PRIMARY KEY (username, groupid),
        INDEX (username),
        FOREIGN KEY (username)
          REFERENCES USER(username)
          ON UPDATE CASCADE ON DELETE RESTRICT
);
und hiermit sehr billig gefüllt:
Code:
INSERT INTO USER ( username , password)VALUES  ('admin', 'admin');
INSERT INTO USERGROUP ( username , groupid) VALUES  ('admin', 'admin');

2. GLASSFISH: Datenbankverbindung Glassfish bekanntgeben
Meine ausgeführten Schritte:
C:\Program Files\MySQL\MySQL Connector J\mysql-connector-java-5.1.15-bin.jar kopieren nach Glassfish\lib.
- Admin Konsole von Glassfish öffnen: Glassfish starten, http://localhost:4848/ (admin, changeit)
- "Ressourcen" -> "JDBC" -> "JDBC Verbindungspools" -> "Neu"
Seite 1:
Poolname: Mysql
Ressourcentyp: javax.sql.ConnectionPoolDataSource
Datenbanktreiber-Hersteller: MySql
Wenn der Glassfish Server den Treiber gefunden hat, ergänzt er automatisch den Klassennamen der Datenquelle mit "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource".

Seite 2:
DatabaseName: <dbname>
User: root
Password: admin
URL: jdbc:mysql://localhost:3306/<dbname>
Url: jdbc:mysql://localhost:3306/<dbname>
ServerName: MySQLServer
- PING muss erfolgreich sein. Ist es auch :)

3. GLASSFISH: JNDI mit der Verbindung einrichten
"JDBC"->"JDBC Ressourcen"
JNDI-Name: jdbc/mysql
Poolname: MySQL (Dropdown: hatte er fein erkannt und übernommen aus dem gerade erstellten Verbindungspool)
Kann ich davon ausgehen, dass das jetzt einfach funktioniert? War ja nicht viel einzustellen. Wie könnte man JNDI testen?

4. GLASSFISH: jdbcRealm einrichten
Admin Konsole von Glassfish öffnen
"Konfiguration" -> "server-config" -> "Sicherheit" -> "Bereiche" --> Neu
Name: loginRealm
Klassenname: com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm
JAAS-Kontext: loginRealm
JNDI: jdbc/mysql
Benutzertabelle: USER
Benutzernamenspalte: username
Passwortspalte: password
Gruppentabelle: USERGROUP
Gruppennamenspalte: groupid
Digest-Algorithmus: none

Wie kann man nun prüfen, ob nun mein "admin" korrekt aus der Datenbank in dieses Realm eingeflossen ist?

Aus dem oberen server.log wurde scheinbar das Realm als loginRealm "korrekt" eingerichtet.

Dennoch kommt bei login "admin"/"admin" der Fehler
Code:
Warnung: WEB9102: Web Login Failed: com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Für loginRealm sind keine LoginModules konfiguriert
Warnung: Exception
com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Für loginRealm sind keine LoginModules konfiguriert
	at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:394)
	at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:240)
	at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:153)
	at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:512)
	at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:453)
	at org.apache.catalina.connector.Request.login(Request.java:1932)
	at org.apache.catalina.connector.Request.login(Request.java:1895)
	at org.apache.catalina.connector.RequestFacade.login(RequestFacade.java:1146)
	at de.familienschaetze.LoginBean.login(LoginBean.java:23)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at com.sun.el.parser.AstValue.invoke(AstValue.java:234)
	at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
	at javax.faces.component.UICommand.broadcast(UICommand.java:315)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:722)
Caused by: javax.security.auth.login.LoginException: Für loginRealm sind keine LoginModules konfiguriert
	at javax.security.auth.login.LoginContext.init(LoginContext.java:273)
	at javax.security.auth.login.LoginContext.<init>(LoginContext.java:382)
	at javax.security.auth.login.LoginContext.<init>(LoginContext.java:459)
	at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:381)
	... 49 more

Schwerwiegend: javax.servlet.ServletException: Exception thrown while attempting to authenticate for user: admin
	at org.apache.catalina.connector.Request.login(Request.java:1964)
	at org.apache.catalina.connector.Request.login(Request.java:1895)
	at org.apache.catalina.connector.RequestFacade.login(RequestFacade.java:1146)
	at de.familienschaetze.LoginBean.login(LoginBean.java:23)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at com.sun.el.parser.AstValue.invoke(AstValue.java:234)
	at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
	at javax.faces.component.UICommand.broadcast(UICommand.java:315)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:722)
Caused by: javax.servlet.ServletException: Failed login while attempting to authenticate user: admin
	at org.apache.catalina.connector.Request.login(Request.java:1935)
	... 44 more

Die Exception wird genau bei login() geworfen
Code:
		final FacesContext fc = FacesContext.getCurrentInstance();
		final HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
		request.login(username, password);

Dass LoginModules nicht konfiguriert sind, habe ich gerade beim erstellen des Threads gesehen. Was ich da tun muss und warum das nicht im Tutorial beschrieben war, überprüfe ich jetzt. Über Hilfe würde ich mich freuen, da ich bald am Ende meiner Nerven bin.

Gruß
Marco

edit:
ich hab nun unter<domain-dir>/config/login.conf die LoginModule zu den vorhanden Realms gefunden.
Code:
fileRealm {
	com.sun.enterprise.security.auth.login.FileLoginModule required;
};

...

jdbcRealm {
	com.sun.enterprise.security.auth.login.JDBCLoginModule required;
};

Im Gegensatz zum FileLoginModule finde ich das JDBCLoginModule nicht im Applications-Classpath.

Ich muss mal sehen welche Bibliothek mir das zur Verfügung stellt. Bin ich auf dem richtigen Weg?

Ich habe gerade gesehen, dass ich das FileLoginModule über com.sun.jmx.remote.security gefunden hab.
Ist aber nonsense.
Weil: auth über fileRealm hatte funktioniert --> demnach wurde auch com.sun.enterprise.security.auth.login.FileLoginModule gefunden.
Warum sollte nun com.sun.enterprise.security.auth.login.JDBCLoginModule nicht existieren ****** Liegt im gleichen Paket und wird von Glassfish standardmäßig bereitgestellt.

Tschuldigt, dass ich so laut denke. Aber irgendwie hilft das.

edit2:
Einen Fehler hab ich nun gefunden. In der Realmdefinition muss
Code:
JAAS-Kontext: loginRealm
muss durch
Code:
JAAS-Kontext: jdbcRealm
ersetzt werden.

Wie schön, wenn man seine eigenen Probleme löst :p
 
Zuletzt bearbeitet von einem Moderator:
Ich weiss, dass dieser Thread 8 Jahre alt ist, aber dieser hat mir bei meinem Glassfish 5 Problem geholfen! :-D
Danke dafür!
 
Zurück