April 16, 2008

JSF & Security

This article introduces a Java module which utilizes phase listeners for securing JSF applications.

Feature list:
  • user, password and role based
  • interfaces throughout for independence of concrete implementations
  • easy to integrate into a Spring framework environment
  • supports password and cookie encoding
  • login data can be placed in cookies for automatic user logins
  • a special navigation handler ensures that invalid navigation rules do not open security holes
  • users may be allowed to login to multiple sessions or not

Introduction

The security core is independent of JSF. Thus, it could be used for other view technologies as well as for any view-independent access control. This affects all classes for authentication, authorization, access rules and cryptography.

How does it work ?

We have identities, usually representing application users. Identities are grouped by assigning roles. Access rules define which roles
are required to path through to certain views.
The authenticator is responsible for identifying users, whereas guards process authorization requests and either approve or refuse them.

Guards do not know whether access requests represent web sites or anything else. They just follow their given rules to make decisions.
Thus, other implementations of Guard and Rule are possible, for example to secure single UI components.

The following two classes allow the integration of the security core into JSF:
  • SecurityListener is a phase listener working in the RESTORE_VIEW phase
  • the LoginService is responsible for logins, cookies and creating identities respectively user objects

For denied requests two cases must be distinguished:
  1. The user is not logged in. If so, the loginRequiredNavigation of LoginService returns the new navigation.
  2. The user was logged in or can be logged in automatically. Then,
    • the Guard delivered the violated rule, its errorView is taken as navigation target
    • property defaultErrorNavigation of LoginService represents the fallback for rules without error view

In either case, if no valid target can be obtained or any exception raises, a 403-HTTP error is sent.


Configuration

Sample Spring configuration:




The default navigation handler of JSF is ignorant of invalid navigation rules. Non-existing rule outcomes result in no navigation at all, meaning that view requests which have just been denied, would pass through nevertheless.
The AssertingNavigationHandler takes care of this problem: an InvalidNavigationRuleException is thrown in case of an unknown or maybe just misspelled navigation directive.
<navigation-handler>
   de.voodoosoft.jroots.ui.jsf.core.AssertingNavigationHandler
</navigation-handler>   
(faces-config.xml)

To be able to configure the SecurityListener as Spring bean, the following listener delegate must be installed:
<lifecycle>
   <phase-listener>
      de.voodoosoft.jroots.ui.jsf.core.DelegatingPhaseListenerMulticaster
   </phase-listener>
</lifecycle>
(faces-config.xml)

The DelegatingPhaseListenerMulticaster automatically searches Spring's application context for registered phase listeners like this:
<bean id="securityListener"
   class="de.voodoosoft.jroots.ui.jsf.security.SecurityListener">
   <property name="loginService" ref ="loginService"></property>
   <property name="guard" ref="guard"/>  
   <property name="defaultErrorNavigation" value="login"></property>
</bean>

Download and Example

The complete package jroots-jsf-security.zip with a full working example (folder /examples/example4) and sample Spring configurations can be downloaded here: JRoots Application Bricks

April 4, 2008

Dynamic JSF tables

Here, I like to present a small open source library allowing to dynamically create JSF tables with Java code instead of using JSP tags.
JSP pages tend to get clumsy and not very easy to get at first sight, so we benefit from smaller files, more dynamic views as well as from the decouplement of pages and underlying bean properties.

Features

The required table structure (shown columns) can be put together by manual coding or automatically from processing properties of a given Java bean.
Column labels can be retrieved from assigned resource files.
The concrete component classes used are externally configured, for example with Spring, thus leaving the table factory independent of various JSF libraries and making it possible to switch the UI without complex engagement.
Numeric columns get right aligned by default.

At present there are the following column types:
  • Standard-Text
  • Link
  • Checkbox
  • Drop-Down (<select>-Tag)
  • Image

If these column types are not sufficient, additional individually built columns can be integrated as well.

Packages:
  • de.voodoosoft.jroots.ui.jsf.factory.table
  • de.voodoosoft.jroots.ui.jsf.factory.table.impl
Dependencies:
  • de.voodoosoft.jroots.ui.jsf.core
  • de.voodoosoft.jroots.core.annotations

Example
jroots-example1
(configured with Spring's dependency injection):

What is left inside the JSP is the raw table without columns but with bindings for both the table component and the presented data.
<h:dataTable id="customerList"
   binding="#{customerController.dataTable}"
   value="#{customerController.beanData}"
   var="rowBean">
</h:dataTable>

In order to resolve Spring beans placed in JSP pages, the following configuration is required:

web.xml:
<listener>
   <listener-class>
      com.sun.faces.config.ConfigureListener
   </listener-class>
</listener>

<listener>
   <listener-class>
      org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>

faces-config.xml:
<variable-resolver>
   org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>

The UI-controller is defined inside Spring'S application context:
<bean id="customerController"
   class="de.voodoosoft.jroots.examples.example2.ui.jsf.customer.CustomerController"
   scope="request">
   <property name="tableFactory" ref="tableFactory"/>
</bean>

Dependency injection is used to assign the used TableFactory to the controller:
public class CustomerController {
    public void setTableFactory(TableFactory factory) {
        this.factory = factory;
    }

    private TableFactory factory;

When JSF asks for the table component, it gets built by the TableFactory:
public class CustomerController {
   public UIData getDataTable() {
      if (dataTable == null) {
         TableDefinition tableDef = factory.buildDefinition(CustomerBean.class);
         dataTable = factory.buildTable(tableDef);
      }

      return dataTable;
   }

The table structure follows the properties of the given bean, in this example name and address:
public class CustomerBean {
   public CustomerBean(String name, String address) {
      this.name = name;
      this.address = address;
   }

   private String name, address;

The second example jroots-example2 demonstrates the usage of RichFaces components instead of the reference implementation. All that has to be done is to modify the application context: properties of tableFactory and columnBuilder get component classes of RichFaces:
<bean id="tableFactory"
   class="de.voodoosoft.jroots.ui.jsf.factory.table.impl.DefaultTableFactory">
   <property name="resourceTag" value="res"/>
   <property name="rowBeanTag" value="rowBean"/>
   <property name="uiDataClass" value="org.richfaces.component.html.HtmlDataTable"/>
   <property name="columnBuilder">
      <map>
         <entry key="de.voodoosoft.jroots.ui.jsf.factory.table.ColumnDefinition" value-ref="defaultColumnBuilder"/>
      </map>
   </property>
</bean>


Finally, the third example jroots-example3 shows generation of link and drop-down columns. There are annotations for both column types. However, there is no need to use those, you can define any column by manual coding as well:
public class Guitar {

   @Link
   private String name;

   @DropDown(targetEntity = Wood.class)
   private Long bodyWood;

   @DropDown(targetEntity = Wood.class)
   private Long neckWood;

Links can either be mapped to controller methods (formSubmit = true) or point to external targets. Link targets are set inside the controller:

Internal Link:
LinkColumnDefinition linkCol = tableDef.getColumn("name");
linkCol.setTarget("#{guitarController.onGuitarClicked}");

External Link:
linkCol = new LinkColumnDefinition("google");
linkCol.setOutput("google");
linkCol.setFormSubmit(false);
linkCol.setTarget("http://www.google.de/search?q=#{guitarController.dataTable.rowData.name}");
tableDef.addColumn(linkCol);
Here we have the characteristic that controller properties are evaluated and passed as URL parameters. To access the current row bean, getRowData() of UIData is invoked in this example.

Spring configuration:



Download:
All the involved jar files
  • jroots-core.jar
  • jroots-jsf-core.jar
  • jroots-jsf-factory.jar
and the presented examples are available for download: voodoosoft

March 27, 2008

Frühlingsgesichter - JSF und Spring

Spring-Beans lassen sich leicht in JSF-Seiten verwenden.

Im folgenden Beispiel soll der customerController nicht als normale Managed Bean sondern als Spring-Bean definiert werden:
<h:inputText value="#{customerController.name}"/>
1. spring.jar

Kopieren in den Ordner WEB-INF/lib

2. web.xml

In der web.xml den Pfad zur Spring-Konfiguration festlegen, beispielsweise:
<web-app>
   <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath:config/applicationContext.xml</param-value>
   </context-param>

  <listener>
     <listener-class>
        org.springframework.web.context.ContextLoaderListener
     </listener-class>
  </listener>

  (...)

</web-app>

3. faces-config.xml

Der DelegatingVariableResolver dient zur Auflösung der in den JSF-Seiten benutzten Beans:
<faces-config>
  <application>
     <variable-resolver>
        org.springframework.web.jsf.DelegatingVariableResolver
     </variable-resolver>
  </application>

  (...)

</faces-config>

4. Beans für den Application Context

Die JSF-eigene Definition als Managed Bean entfällt - stattdessen wird eine Spring-Bean konfiguriert:
<beans (...) >

 (...)

 <bean id="customerController"
      class="whatever.package.CustomerController"
      scope="request">
  </bean>

</beans>

March 22, 2008

JSF und die Keksfabrik

Eine kurze Übersicht über die Behandlung von Cookies unter Java und JSF:

Erzeugen:
public void bakeCookie(FacesContext ctx) {
  Cookie cookie = new Cookie("tastyCookie", "mySecretCookieData");
  cookie.setMaxAge(604800); // Haltbarkeit in Sekunden

  HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
  response.addCookie(cookie);             
}
Die eigentlichen Daten sollten selbstverständlich verschlüsselt sein. Weiterhin sollte man in der Verwendung von Sonderzeichen Vorsicht walten lassen - diese könnten je nach Browser zu eigentümlichen Verhalten führen (richtig, genau der Browser).

Auslesen:
public boolean tasteCookie(FacesContext ctx) {
  Map cookieMap = ctx.getExternalContext().getRequestCookieMap();
  Cookie cookie = (Cookie)cookieMap.get("tastyCookie");
  if (cookie != null && cookie.getValue().length() > 0) {
     // enjoy cookie
     String val = cookie.getValue();
  }
}
Entsorgen:
public void eatCookie(FacesContext ctx) {
  Cookie cookie = new Cookie("tastyCookie");
  cookie.setMaxAge(0);

  HttpServletResponse response = (HttpServletResponse)ctx.getExternalContext().getResponse();
  response.addCookie(cookie);      
}

JSF und die wesentlichen Bestandteile einer Bohne

Benötigt man für jedes Feld einer JSF-Seite wirklich ein weitgehend sinnfreies Getter/Setter-Paar in der zugehörigen Managed-Bean ?
Nein - denn JSF ist konfigurierbar und Java bietet das Reflection-Package...

In der faces.config.xml kann der zu verwendende ELResolver geändert werden:

<application>  
  <el-resolver>
     com.whatever.package.FieldResolver
  </el-resolver>     
</application>
Die Methoden des EL-Resolvers werden dann analog dem folgenden Beispiel für getValue implementiert.
Zuerst wird weiterhin versucht, einen passenden Getter zu finden. Das ist wichtig, um Sonderfälle, die ohne Getter nicht auskommen, behandeln zu können. Wurde keine Methode gefunden, wird nach einem entsprechenden Class-Field gesucht. Nur bei letztendlichem Erfolg wird die Anfrage als bearbeitet markiert (context.setPropertyResolved(true)) - andernfalls werden implizit die übrigen EL-Resolver aufgerufen.
Da dies alles nur Sinn macht, wenn es überhaupt um Objekt-Properties geht, werden nur Ausdrücke mit einem Basis-Objekt bearbeitet (base != null).
public class FieldResolver extends ELResolver {
    private static final Object[] sNoArgs = new Object[0];
    private static final Class[] sNoClassArgs = new Class[0];

    public Object getValue(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException {
        String name = property.toString();

        if (base != null) {
            // 1. try getter
            try {
                String getterName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
                Method getter = base.getClass().getMethod(getterName, sNoClassArgs);
                context.setPropertyResolved(true);
                return getter.invoke(base, sNoArgs);
            }
            catch (NoSuchMethodException ne) {
                // no error so far           
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);
            }

            // 2. direct field access
            try {
                Field field = getField(base, property);
                if (field != null) {
                    context.setPropertyResolved(true);
                    return field.get(base);
                }
            }
            catch (Exception e) {
                String message = "Error accessing property '" + name + "' in bean of type " + base.getClass().getName();
                throw new PropertyNotFoundException(message, e);
            }
        }

        return null;
    }
...
}

JSF und die Frage wie es losgeht

Wer sich erstmals mit den Java Server Faces befasst und/oder von Struts umsteigt, steht wahrscheinlich vor der Frage, wie und wann man am besten einen UI-Controller bzw. die zugrundeliegende(n) Managed Beans initialisiert, sprich, die benötigten Daten lädt. Denn alle darzustellenden Felder werden nur lose an beliebige Beans gebunden. Abgesehen von weiterführenden Themen wie Servlet Filtern oder Phase Listenern gibt es keine vordefinierten Einsprungmethoden.
Eine simple Lösung macht sich die Möglichkeit der Expression Language (EL) zunutze, komplexere und hierarchische Property-Ausdrücke aufzulösen.

Anstatt beispielsweise den Kundennamen wie folgt zu binden,
<h:inputText
    id="name" value="#{customerController.name}">
</h:inputText>

setzt man ein Formbean-Object davor:
<h:inputText
    id="name" value="#{customerController.formBean.name}">
</h:inputText>

Die Formbean wird als normale Java-Bean implementiert:
public class CustomerBean {
   private String name;
   public void setName(String name) {
      this.name = name; 
   }
   public String getName() {
      return name;
   }
}

Der Übersichtlichkeit kommt dies natürlich auch zugute, da der UI-Controller nicht mehr mit Gettern und Settern für alle Felder überschwemmt wird.

Im Controller gibt es nun eine zentrale Stelle für die Initialisierung:
public class CustomerController {
   public Object getFormBean() {
      if (formBean == null) {
         formBean = new CustomerBean();    
      
       // load form data, set form properties, etc.
       ... 
      }
   
      return formBean; 
   }  
   
   private CustomerBean formBean; 
}


Sobald erstmalig der Wert eines Feldes angefordert wird, wird die Formbean erzeugt - bei allen folgenden Property-Zugriffen wird die Initialisierung dann übersprungen.

March 20, 2008

JavaDB in 5 Schritten

Für einen ersten Test mit der JavaDB (früher Apache Derby, davor IBM sowie Cloudscape) habe ich ein bestehendes Oracle/Postgres-Schema mit etwa 60 Tabellen übertragen.
Das ging erfreulich unkompliziert. Ebenso der anschließende Zugriff über Hibernate.
Angepasst werden mussten lediglich:
  • die ID-Vergabe aus Hibernate (statt Sequenzen nun Identity-Felder, durch Ableiten der SQL-Dialekte kann weiterhin mit bestehenden Entity-Annotations gearbeitet werden).
  • die JavaDB mag in Scripten keine NULL-Keywords hinter den Columns (NOT NULL fkt. selbstverständlich)

1. Der Server kann durch die mitgelieferten Batchdateien gestartet werden. Das Setzen der Umgebungsvariablen DERBY_HOME ist gar nicht nötig.
Im Falle von Windows:
startNetworkServer.bat im Verzeichnis javadb\bin

2. Anlegen einer Datenbank mit dem Kommandozeilentool "ij":
connect 'jdbc:derby://localhost:1527/c:/JavaDB/db/myDB;create=true';

3. Beispiel zum Ausführen eines Scripts über ij:
run 'c:\JavaDB\createDatabase.sql';

4. JDBC-Connections
Der Treiber für den Client/Server-Betrieb ist org.apache.derby.jdbc.ClientDriver, für den Embedded-Mode org.apache.derby.jdbc.EmbeddedDriver.
Für User + Passwort interessiert sich die JavaDB offenbar erst nach entsprechender Konfiguration.

5. Shutdown
Im Embedded-Mode erfolgt ein ordnungsgemäßes Herunterfahren durch Anfordern einer Connection:
DriverManager.getConnection("jdbc:derby:;shutdown=true");
Eigentümlicherweise bedankt sich die JavaDB dabei standardmäßig mit einer Exception (Error-Code 50000).

Weiteres:
  • Für den Embedded-Mode ist die Datenbank sofort nach Anfordern einer Connection über den DriverManager betriebsbereit.
  • Ohne weitere Änderungen werden nur lokale Verbindungen akzeptiert. Dies kann durch Ergänzen der Batchdatei mit folgendem Startparameter geändert werden:
  • (... ) org.apache.derby.drda.NetworkServerControl start -h 0.0.0.0
  • In URLs für den Embedded-Treiber entfällt die Host-Angabe (z.B.: jdbc:derby:c:/JavaDB/db/myDB)
  • Hilfestellung gibt ij durch das help-Kommando

Schließlich zur interessanten Frage: was ist mit der Performance ?
Nun, der Mythos von der Langsamkeit von Java wird mit einer in Java geschriebenen Datenbank sicherlich auch nicht aussterben.
Wie auch immer, der erste Eindruck ist gut (einige Suchanfragen über 10000 Artikelsätze mit Joins und Subselects).
Besonders interessant ist auf jeden Fall der Embedded-Mode für unkomplizierte Auslieferungen als Teil von Datenbank-Anwendungen oder für einen autarken JUnit-Testbetrieb.