Arndt Schönbergs Weblog

Freitag Okt 14, 2016

Tipps zu JSF Composite Componentes

Umgebung

  • EE7
  • JSF 2.2
Mit diesem Post möchte ich einige Hinweise zu den Composite Componentes von JSF geben, die immer wieder gefragt werden.

Zugriff auf Attribute des Interfaces

Auf Attribute des Interfaces wird über #{cc.attrs.<Name aus dem Interface>} zugegriffen.

Rendered und id verhalten sich seltsam

Composite Componentes leiten sich aus UINamingContainer und UIComponentBase ab. Daher dürfen und sollen einige Attribute wie rendered oder id nicht überschrieben werden. Diese stehen bereits durch die Ableitung zur Verfügung und können direkt übergeben werden.

Parameter an action oder actionListener binden

Sollen Methoden für action oder actionListener übergeben werden, müssen im Interface die Signaturen angegeben werden z.B.
<cc:attribute name="action" required="true" method-signature="java.lang.String action()" />
<cc:attribute name="actionListener" required="true" method-signature="void actionListener(javax.faces.event.ActionEvent)" />
Werden diese Attribute in der Komponente an action oder actionListener von entsprechenden Komponenten (z.B. h:actionButton) gebunden, dürfen sie nicht leer sein. Es sollte also required="true" verwendet werden. Alternativ müssen in der Komponente verschiedene Varianten umgesetzt und über z.B. rendered=“not empty cc.attrs.action“ ein- und ausgeblendet werden.

Einbinden von Kindernkomponenten

Kindelemente aus den HTML-Seiten werden über <cc:insertChildren /> eingefügt.

Donnerstag Okt 13, 2016

SSL Remote Zugriff auf Wildfly - Teil 2

Umgebung

  • Wildfly 10
  • EE7
Nachdem im letzten Post der Server und das SSL Zertifikat vorbereitet wurden, folgt in diesem Post der Zugriff vom Fat-Client.

Client Keystore erstellen

Es wird für den Zugriff der Client-Keystore erstellt und das im letzten Post erstellte Server Zertifikat importiert.
keytool -import -file server.crt -keystore client.keystore -storepass wildflyClientPass
Diese Datei wird zur Validierung des Zugriffs auf dem Client benötigt und sollte daher im Pfad des Clients (z.B. im src Verzeichnis) abgelegt werden. Im nächsten Schritt muss sichergestellt werden, dass dem Zertifikat auch vertraut wird, wenn es nicht von einer offiziellen CA erstellt wurde.

Trustmanager

Einem Server Zertifikat wird vertraut, wenn es im eignen, verwendeten Keystore liegt. Daher wird hier ein Trustmanager implementiert, der auf den Truststore von oben im Pfad zugreift und diesen mit dem zuvor angegebenen Passwort öffnet.
package de.schoeso.testRemoteCalculatorEJBClient;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class TrustManagerClassPath implements X509TrustManager {

    private final X509TrustManager trustManager;

    public TrustManagerClassPath() throws Exception {
        this.trustManager = loadTrustManager();
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        this. trustManager.checkClientTrusted(chain, authType);
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        this.trustManager.checkServerTrusted(chain, authType);
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return this.trustManager.getAcceptedIssuers();
    }

    private X509TrustManager loadTrustManager() throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream trustStoreInputStream = getClass().getResourceAsStream("/client.keystore");
        if (null == trustStoreInputStream) {
            throw new RuntimeException("Error loading the client truststore. Check if the classpath entry '/client.keystore' exists");
        }
        // Passwort, das bei der Erzeugung des Keystores verwendet wurde
        ks.load(trustStoreInputStream, "wildflyClientPass".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);

        for (TrustManager tm : tmf.getTrustManagers()) {
            if (tm instanceof X509TrustManager) {
                return (X509TrustManager) tm;
            }
        }
        throw new NoSuchAlgorithmException("No X509TrustManager in TrustManagerFactory");
    }
}
Für den Zugriff müssen die Properties festgelegt werden. Im folgenden Beispiel erfolgt dies im Java-Code.
    /** @return Properties mit den notwendigen Werten für die Core-Api ohne weitere Property Dateien */
    private static Properties getJndiPropertiesCoreApiPropertiesNoFileSSL() {
        final Properties jndiProperties = new Properties ();
        // Core-Api aktivieren - java.naming.factory.url.pkgs
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

        // remote.connections=0 -- und dann statt default 0 verwenden, um mehrerer Verbindungen zu verwalten

        jndiProperties.put("endpoint.name", "backOfficeEndPoint");
        jndiProperties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "true");
        jndiProperties.put("remote.connections", "default");
        jndiProperties.put("remote.connection.default.host", "192.168.1.31");
        jndiProperties.put("remote.connection.default.port", "8443");
        jndiProperties.put("remote.connection.default.protocol", "https-remoting");

        jndiProperties.put("remote.connection.default.username", "MyLogin");
        jndiProperties.put("remote.connection.default.password", "MyPassord");

        jndiProperties.put("remote.connection.default.connect.timeout", "60000");
        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS", "JBOSS-LOCAL-USER");
        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SSL_STARTTLS", "true");
        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SSL_PROTOCOL", "TLSv1.2");
        // TRUST_MANAGER_CLASS is required only in case of self-signed certificate
        jndiProperties.put("remote.connection.default.connect.options.org.xnio.Options.SSL_JSSE_TRUST_MANAGER_CLASSES", "de.schoeso.testRemoteCalculatorEJBClient.TrustManagerClassPath");
        // Vereinfachte Anbindung
        jndiProperties.put("org.jboss.ejb.client.scoped.context", "true");
        return jndiProperties;
    }

Zugriff auf Remote Beans

Der Zugriff erfolgt immer über die vergebenen JNDI-Namen. Eine gute Stelle für die Einsicht in die von Wildfly verwendeten JNDI-Namen ist das server.log. In diesem werden beim Boot-Vorgang alle Namen eingetragen. Mit den entsprechenden JNDI-Namen des Remote-Interfaces erfolgt als letzter Schritt Zugriff aus dem fat-Client.
this.context = new InitialContext(properties);
this.context.lookup(...)

Dienstag Okt 11, 2016

SSL Remote Zugriff auf Wildfly - Teil 1

Umgebung

  • Wildfly 10
  • EE7
Wenn Remote-Zugriffe auf einen Wildfly Server erfolgen, sollten diese auch innerhalb eines Unternehmens verschlüsselt werden. Für einen externen Zugriff ist dies eine Selbstverständlichkeit. In der Standardkonfiguration erfolgen die Remote-Zugriffe auf dem ungesicherten Port 8080. Im Folgenden wird beschrieben, wie eine SSL / TLS verschlüsselte Kommunikation eingerichtet wird. In den früheren Einträgen z.B. Post 1 und Post 2 habe ich bereits über den SSL Zugriff auf die Management-Konsole und den ungesicherten Remote-Zugriff geschrieben.

Einen Realm für SSL / TLS einrichten

Nach der Grundinstallation von Wildfly 10 finden sich zwei security-realms in der Konfiguration eines Wildfly (Datei standalone.xml). In diesem Bereich werden wir einen neuen security-realms für die SSL / TLS Kommunikation einrichten. Es wäre auch denkbar einen existierenden auch für den Remote-Zugriff zu verwenden, ich halte aber eine saubere Trennung für besser.
<management>
    <security-realms>
        ...
        <security-realm name="SSLRealm">
            <server-identities>
                <ssl>
                    <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="wildflyKeystorePassword" alias="wildflyKey" key-password="wildflyKeyPassword"/>
                </ssl>
            </server-identities>
            <authentication>
                 <properties path="sslrealm-users.properties" relative-to="jboss.server.config.dir"/>
            </authentication>
        </security-realm>
...
Die Passwörter für den Keystore und den Key werden bei deren Erzeugung vergeben (s.u.).

Erzeugung eines Keystores

Für die Absicherung des Wildfly erzeugen wir ein selbstsigniertes Zertifikat mit dem „keytool“, das mit dem JDK ausgeliefert wird. Der Schlüssel sollte mindestens eine Größe von 2048 besitzen. Die erzeugten Dateien müssen zur Absicherung des Wildfly im Konfigurationsverzeichnis (i.A. standelone/configuration) abgelegt werden. Der folgende Befehl legt die Datei
server.keystore
an, die ein Zertifikat mit der Gültigkeit von 20 Jahren enthält.
keytool -genkey -alias wildflyKey -keyalg RSA -keysize 2048 -keystore server.keystore -validity 7300 -storepass wildflyKeystorePassword -dname "CN=srv01, OU=, O=, L=, ST=, C=" -keypass wildflyKeyPassword
Es wird der Common Name srv01 für den in diesem Beispiel verwendeten internen Server verwendet. Wenn dieses Zertifikat auch für den Web-Zugriff verendet wird, sollte statt dessen die Domain hier eingetragen werden, um Inkompatibilitäten zu vermeiden. Andernfalls müssen entsprechende Ausnahmen in den Browsern definiert werden.

Erzeugen des Public-Key Zertifikates

Es wird das Zertifikat zum signieren der Clients erzeugt.
keytool -export -alias wildflyKey -keystore server.keystore -storepass wildflyKeystorePassword -keypass wildflyKeyPassword -file server.crt

Erzeugen eines Nutzers im Realm

Da mir kein Tool bekannt ist, das in einen selbsterstellten Realm schreibt, verwenden wir ein Java-Programm, das den Hash erzeugt
package schoeso.testRemoteCalculatorEJBClient;
import org.jboss.crypto.CryptoUtil;
/**
 * Erzeugt das PW für
 * username=HEX( MD5( username ':' realm ':' password))
 * @author schönberg-solutions GmbH
 */
public class WildflyPasswd {

    public WildflyPasswd() {
        // TODO Auto-generated constructor stub
    }

    public static void main(String[] args) {
        /*
        You will need the following JAFRs in your classpath in order to compile & run this program
        export CLASSPATH=$JBOSS_HOME/modules\system\layers\base\org\picketbox:$JBOSS_HOME/bin/client/jboss-client.jar:$CLASSPATH:.:
        */

        String userName = null; //args[0];
        String realmName = null; //args[1];
        String password = null; //args[2];

        userName="meinUser";
        realmName="SSLRealm";  // aus der stanalone.xml
        password="xxx!!121";

        String clearTextPassword=userName+":"+realmName+":"+password;

        String hashString=CryptoUtil.createPasswordHash("MD5", "hex", null, null, clearTextPassword);
        System.out.println("In der Datei des Realms " + realmName + " muss die Zeile " + userName + "=" + hashString + " eingetragen werden");

    }
}
Die ausgegebene Zeile muss in die Datei sslrealm-users.properties übernommen werden, die einen Aufbau wie im Folgenden hat (entsprechend mit dem gewählten user und dem Hash).
#
# The format of this realm is as follows: -
# username=HEX( MD5( username ':SSLRealm:' password))
#
meinUser=c46f3b79ab15t7480b1cb417d3e1eb63
Die Berechnung kann auch im Web unter https://schoenberg-solutions.de/schoeso/example/wildlfyHashKey.xhtml erfolgen.

Das Undertow-System

In dem Undertow-System des Wildfly in der standalone.xml muss ein neuer Listener für https registriert werden.
<subsystem xmlns="urn:jboss:domain:undertow:1.2">
  ...
  <server name="default-server">
    ...
    <https-listener name="default-https" socket-binding="https" security-realm="SSLRealm"  enabled-protocols="TLSv1.2" />
    ...
  </server>
</subsystem>

Das Remoting-System

Im zweiten Schritt wird der http-connector des Wildfly in der standalone.xml mit dem Realm verknüpft.
<subsystem xmlns="urn:jboss:domain:remoting:2.0">
  ...
  <http-connector name="https-remoting-connector" connector-ref="default-https" security-realm="SSLRealm"/>
  ...
</subsystem>
Nun ist die Serverkonfiguration abgeschlossen, so dass wir uns dem Client im nächsten Post zuwenden können.

Donnerstag Okt 06, 2016

JSF Execute vs. PrimeFaces Process

Umgebung

  • Wildfly 10
  • EE7
  • PrimeFaces 6.1 Snapshot
Da wir gerade in einem Projekt eine Fehlersuche hinter uns haben, hier ein kleiner Post zu den Attributen execute der JSF Standardkomponenten und process der PrimeFaces Komponenten. Der Standardwert von execute ist laut Dokumentation @this (vergl. http://docs.oracle.com/javaee/6/tutorial/doc/gkace.html). Es wird also nur der Inhalt der aktuellen Komponente übermittelt.

Zu den Standardwert des process Attributs der PrimeFaces Komponenten gibt es unterschiedliche Aussagen. Im von uns verwendeten Snapshot war die Defaulteinstellung des Attributs in einer p:remoteCommand Komponente der Wert @form und sorgte für einige Verwirrung, da deutlich mehr Werte übertragen wurden, als bei dem erwarteten Wert @this.

Lesson to be learned

Die Vorbelegung von ähnlichen Attributen sind in verschiedenen Komponentenbibliotheken sind nicht einheitlich. Hier sollte die Programming Guidelines dafür sorgen, dass die Attribute immer angegeben werden, um Wartbarkeit und den einfachen Neueinstieg von Kollegen zu gewährleisten.

Freitag Sep 23, 2016

JEE7: JSF Gui Komponenten auslagern

Umgebung

  • Wildfly 10
  • EE7

Neben den Java Klassen werden in einer Web-Anwendung auch die JSF-Darstellungskomponenten verwaltet. Dies sind ganze HTML-Seiten, Includes in XHTML-Seiten, Templates, Grafiken und andere Darstellungsbeschreibungen. Auch diese können in externe jar-Dateien ausgelagert werden. Bei der Bereitstellung gibt es Einschränkungen (vergl. Ende dieses Abschnitts), die aber keine Einschränkungen für die Entwicklung und die Auslagerung in separate Projekte für die Wiederverwendung darstellen.

Das Auslagern von EJB Bestandteilen ist in diesem Post und das Auslagern von Java Komponenten aus JSF ist in diesem Post besprochen worden.

Ablage in jar-Archiven

Bei Start des Anwendungs-Servers werden folgende Ordner nach Ressourcen durchsucht
  • Im Wurzelverzeichnis der Webanwendung oder des Web-Moduls das Verzeichnis /resources
  • Das Verzeichnis /META-INF/resources in allen Jar-Dateien des Classpaths
In diese Ressourcen-Verzeichnisse können alle oben genannten Ressourcen ausgelagert werden.

Pfad zu den Ressourcen im Web-Projekt ändern

Web-Projekte suchen die Ressourcen in der Grundeinstellung im Verzeichnis /resources des Web-Root. Dieser (öffentliche) Pfad kann seit JSF 2.2 über einen Parameter in der web.xml verändert werden.
<context-param>
  <?param-name>
    javax.faces.WEBAPP_RESOURCES_DIRECTORY
  </param-name>
  <param-value>/WEB-INF/resources</param-value>
</context-param>
Das obige Beispiel verschiebt den Ressourcen-Pfad in das nicht öffentliche Verzeichnis WEB-INF.

Zugriff auf CSS

CSS-Dateien können seit JSF 2.2 auf zwei Arten in die JSF Seiten eingebunden werden. Entweder über oder wie bisher im Kopf der Datei, wobei die Ressource über #{resource angesprochen wird.
<link rel="stylesheet" type="text/css" href="#{resource['/resBase/css/common/ecrBase.css']}" ></link>
(alte Notation mit festem Pfad z.B. für ein Image: #{facesContext.externalContext.requestContextPath}/resources/image/favicon.png)

Das Attribut library schafft eine weitere Strukturierungsebne auf die ich hier nicht weiter eingehe. Es kann im einfachen Fall auch weggelassen werden.

Nutzung von JSF Ressourcen innerhalb von CSS-Dateien

Innerhalb der CSS Dateien werden die Ressourcen ebenfalls über die EL angesprochen.
background-image: url("#{resource['img/glyphicons-halflings.png']}");

Zugriff auf Javascript

Im h:head Tag eines Faclets kann wie bisher allerdings mit neuer Notation auf die Dateien zugegriffen werden.
<script type="text/javascript" src="#{resource['/resBase/jscript/common/timeOutTimer.js']}" ></script>
Alternativ kann das folgende JSF-Tag verwendet werden.
<h:outputScript name="resBase/jscript/common/timeOutTimer.js" target="head" />

JSF-Templates

Der Pfad für Templates kann relativ zu oben bestimmten Ressourcen angegeben werden und damit in allen eingelesenen Dateien liegen. Zumindest in Wildfly 10 muss allerdings ein jar-Archiv, das solche Ressourcen hält, im lib Verzeichnis des Web-Moduls liegen, damit der Zugriff funktioniert.
<ui:composition template="/common/sometemplate.xhtml" />
In der aktuellen MyEclipse Version werden ausgelagerte Dateien nicht erkannt und führen zu einer Warnung im xhtml-Editor. Zur Laufzeit gibt es keine Probleme.

JSF-Includes

Für JSF-Includes gilt das Gleiche wie für JSF-Templates.
<ui:include src="/common/someinclude.xhtml" />

JSF-Composits

Für JSF-Composits gilt das Gleiche wie für JSF-Templates.

Grafiken

Um auf Grafiken aus Ressourcen zuzugreifen kann statt src das Attribut name verwendet werden
<h:graphicImage name="/resBase/image/helper/1x1-trans.gif" width="5" height="1" />

Calendar

Feeds

Search

Links

Navigation