Showing posts with label JSF. Show all posts
Showing posts with label JSF. Show all posts

Thursday, December 08, 2011

JSF 1.2 (myFaces) + RichFaces 3.3.x + IE 9 = troubles

Note: below description uses Eclipse Indigo, Tomcat 7.0.28, MyFaces 1.2.12, RichFaces 3.3.3 (Final).

Requirements:
  • working JSF 1.2 sample application from here
  • RichFaces 3.3.x added to the project
You will learn:
  • how to fix problems with RichFaces 3.3.x for IE 9
Let's assume that You develop JSF 1.2 web application. It does not matter if Your application uses .jsp pages or Facelets with .xhtml pages. I assume that .jsp pages are in use. Then You decided to add some Ajax capabilities, new components and so on. So You simply take RichFaces and add them to the project. This is simple thing:
a) download latest RichFaces 3.3.3 (final), take those jars: richfaces-api-3.3.3.Final.jar, richfaces-impl-3.3.3.Final.jar, richfaces-ui-3.3.3.Final.jar and place them in WEB-INF\lib folder of Your web application. 
b) modify your web.xml file by adding there:
 <filter>
  <display-name>RichFaces Filter</display-name>
  <filter-name>richfaces</filter-name>
  <filter-class>org.ajax4jsf.Filter</filter-class>
 </filter>

 <filter-mapping>
  <filter-name>richfaces</filter-name>
  <servlet-name>Faces Servlet</servlet-name>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>INCLUDE</dispatcher>
 </filter-mapping>
c) add proper taglib directives to each Your jsp page (note that for .xhtml pages syntax is different):
<%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
<%@ taglib uri="http://richfaces.org/rich" prefix="rich"%>
Now You can use RichFaces components. Let's try to modify our sample JSF 1.2 application by creating new web project named "JSFRichFaces". Then let's add ajax button (<a4j:commanButton>) and expandable toggle panel (<rich:simpleTogglePanel>). All modifications are shown below:




Everything works OK under Firefox, Chrome, IE 7, IE 8 - unless You use Internet Explorer 9. You can observe two problems: with RichFaces ajax components and RichFaces components layout.

RichFaces 3.3.x does not fully support IE 9. RichFaces developers encourage everyone to migrate into RichFaces 4.x which are IE 9 compatible. The main problem is that RichFaces 4.x works only with JSF 2.x application, and this is not so easy to migrate If You have many clients where You already delivered Your application...

Problem 1: ajax components do not work (some JavaScript errors).


When You try to press ajax button named "Go (RichFaces) " under IE 9, You can observe following error (open IE Developer's Toolbar Java Script console before):





Solution: You have to force IE 9 to act as IE 8, where RichFaces 3.3.x works OK. In order to do it You have to define X-UA-Compatible header for each page. You can do it in two ways:
a) add a special <meta> element for each page or
b) write a special filter which adds this header to the HTTP response

In our simple case it is sufficient to add a <meta> into the page <head> section:

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />
Remember that this <meta> must be placed as first element in <head> section!

Problem 2: RichFaces components have broken layout (problems with CSS).


When You open our sample application under IE 9, toggle panel has no CSS styles set at all. Under Chrome or Firefox everything looks OK. Checking HTTP request/response headers shows that for IE 9 proper CSS for RichFaces component (CSS located in the .jar file) is not loaded and server returns error:





Console under Eclipse shows that exception is thrown:



Under Firefox everything looks OK:






Why it happens? Accroding to that article, there was a change in IE 9 for MIME type handling. IE 9 ignores CSS styles if they are not delivered with a text/css MIME type.

Why it works for previous IE 7 and IE 8? Because also HTTP Request Accept header sent by IE 9 is different than sent from IE 7 or 8. IE 7/8 sent text/css, */* as Accept, where IE 9 sends only text/css as Accept.
Knowing that it is time to look inside myFaces source, to find the code which produces mentioned exception. Everything is located in HtmlRendererUtils.java (located in myfaces-impl-1.2.11.jar) in the selectContentType() method. It works for IE 7/8 because */* sent in Accept by IE 7/8 is on supported content type list, where text/css is not recognized at all.

Solution: add text/css support, then recompile HtmlRendererUtils.java and replace it in myfaces-impl-1.2.11.jar (or build complete myfaces-impl-1.2.11.jar). In order to avoid this mumbo-jumbo with Maven to build whole .jar, just create simple Java Project, create a HtmlRendererUtils.java in certain package, change it and compile, then replace compiled class in myfaces-impl-1.2.11.jar ;-)





Or download recompiled myfaces-impl-1.2.11.jar from here.


That's all. IE 9 works again without need to add Your web page to its compatibility view list or something. And You have time to migrate to JSF 2.x and RichFaces 4.x before IE 10 comes to market...

Wednesday, September 21, 2011

Tomcat - using Realm to protect access to JSF application (part 2 of 2)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28, MyFaces 2.1.7
 
Requirements:
  • understanding basics of Tomcat's Realm
You will learn:
  • how to define users and roles in own web applications (JSF 2.0 as example)
  • how to use encrypted passwords for realm users instead od plain text
In the previous post I described how to configure access to Tomcat's server administration application using Tomcat's Realm elements. The whole thing boiled down to write a few lines of text in server.xml file. But how does it look like when we have to do it from scratch in our application?

Step 1. Let's create very simple JSF application which has only 3 pages:
  • /index.html - main page with two buttons navigating into two pages:
  • /unrestrictedPage.xhtml - page always accessible and visible to anyone
  • /restricted/restrictedPage.xhtml - page and directory available only for valid users
The complete application structure will look like:



Step 2: we have to add a privilleged user named admin with password adminpass who belongs to role privillegedUsers (You can choose any user login, password and role name). Just simply add this line:
<user username="admin" password="adminpass" roles="privillegedUsers" />
into [tomcat directory]\conf\tomcat-users.xml file.

Step 3: configuring application. We have to modify web.xml of our sample application by adding following text:
<web-app>
...
    <security-role>
        <description>
              All persons belong to that role have access to restricted application area.
        </description>
        <role-name>privillegedUsers</role-name>
    </security-role>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Restricted</web-resource-name>
            <url-pattern>/faces/restricted/*</url-pattern>
            <url-pattern>/restricted/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>privillegedUsers</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Restricted access</realm-name>
    </login-config>
...
</web-app>
First we defined a role named privillegedUsers - the same we put in tomcat-users.xml file above. Second we have to defined prottected parts of our application, by providing proper URL pattern. Please note that we have two entries here: /restricted/* - everything in this directory is protected in case someone typed this part manually in browser's address bar,  /faces/restricted/* - JSF adds "faces" prefix when navigating between pages, so the URL is a little bit different and we have to watch for this also. After that we have to define a role which is allowed to access to the protected parts. This is privillegedUsers role defined earlier. At the end we have to define the way how the authentication is done - the simplest way is BASIC, which displays predefined form with credentials.

Now we are ready to deploy our application on Tomcat and run it. It should look like this:


when we try to access to restricted area. In order to do this we have to put credentials for user defined in step 2 (admin, adminpass).

Note: there is a little trick here, for the button "Restricted area" - see index.xhtml page source code:
<h:commandButton value="Resricted area" action="/restricted/restrictedPage.xhtml?faces-redirect=true" />
<h:commandButton value="Unrestricted area" action="/unrestrictedPage.xhtml" />
Because JSF internally by default makes forward to other page, browser is unaware what has happened and display URL from one step back. In such case our URL security patterns will not match anything, and restrictedPage.xhtml will be displayed without asking for login and password! In order to make protection work we have to perform full redirection for that action in order to force browser to fetch target URL and display it. For JSF applications it is better to use filters or Spring Security in order to avoid such dirty tricks.

Encrypted passwords.

As You probably have seen, passwords vor valid users are stored inside tomcat-users.xml file as a plain text. There is a possibility to store them in encrypted form, using MD5. Here is what needs to be done:

Step 1: using Eclipse modify Tomcat server.xml and its <Realm> atrribute into:
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" digest="MD5"/>
Step 2: in web.xml change <auth-method> from BASIC to DIGEST

Step 3: for user admin and his previous password adminpass we have to generate its md5 equivalent using Tomcat's digest.bat file (located in [tomcat directory]\bin folder) :

digest.bat -a md5 admin:"Restricted access":adminpass

"Restricted access" is a realm name taken from <auth-method> tag from web.xml. Those names must match, if name contains spaces, it must be surrounded with "".


Step 4: using Eclipse modify Tomcat's tomcat-users.xml file:
<user username="admin" password="db7bc05adcf611fc779f32a4e680cc01" roles="privillegedUsers" /> 
where password was taken as a result of executing command from step 3.

-------------------------------------------
Download source files:

Note: make sure that Java, Eclipse and Tomcat are properly installed and configured for running the project (additional configuration may be required if different directories are used).

Eclipse complete sample project is here (with all required libraries).

Tuesday, September 13, 2011

Tomcat - change default application, protecting access to web applications using Realm (part 1 of 2)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28,

Requirements:
  • installed Java (description here)
  • installed and configured Eclipse (description here)
  • installed and confiured Tomcat for the Eclipse (description here)
You will learn:
  • how to change default Tomcat application
  • how to allow users access to Tomcat's server administration application using Tomcat's Realm

Let's assume that You have Tomcat which is configured to work in Eclipse. When You start Tomcat (using Eclipse or standard scripts from Tomcat's distribution) and type in the browser URL http://localhost:8080, You will see Tomcat's default application:


This application is located in the [tomcat directory]\webapps\ROOT folder. If You want to change this page, just edit content of file index.jsp and index.html. If You want to completely remove this application, just remove complete ROOT folder.
Removing is not the best choice, because Tomcat is shipped with a special applications for server administration. You can access those applications using links in red square. Try to click on any link - You should see screen with login and password prompt:


Those parts are protected using Tomcat Realm. What is Realm? Realm is a set of valid users (defined by user name and password) and roles where those users belong. The idea is to configure access to web application only for valid users from certain roles. But where are those users and roles stored? It depends on a implementation of a realm - they can be stored in database, in LDAP, or in xml file. Tomcat's server administration application uses xml file to define users' access. Let's try to set up some users able to start that application.

Step 1: using Eclipse open server.xml from the Servers, and make sure that entry <Realm classname="org.apache.catalina.realm.UserDatabaseRealm" resourcename="UserDatabase"></Realm> exsits between <Engine> tags, outside <Host&gt tags - it means that this realm will be used for all hosts and all applications on that  hosts:


Step 2: using Eclipse open tomcat-users.xml from the Servers and add an entry for the user who will be able to access Tomcat's server administration application:


By default UserDatabaseRealm uses [tomcat directory]\conf\tomcat-users.xml file to load users and their roles into memory on server startup. In order to allow defined users to access administration application, they need to belong to roles named manager-status, manager-gui and admin-gui. After changes made, restart Tomcat server and try to access Tomcat's administration application giving username and password from tomcat-users.xml file. If everything was set up OK, You should see mentioned applications.

You may wonder why we used here roles named manager-status or manager-gui or admin-gui. Those role names come from Tomcat's server administration application specific settings, stored in the web.xml file. In the next post I will show how to protect own application (JSF2 application will be used as an example) and how to define own roles.

Tuesday, April 26, 2011

JSF 2, Spring 3, JPA (Hibernate 3), PostgreSQL, c3p0 - everything together (part 2 of 2)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28, MyFaces 2.1.7, Spring Framework 3.1.1, Spring Security 3.1.0, Hibernate 3.6.10 (Final), PostgreSQL 9.1.

Requirements:
  • running database and complete project with all required libraries integrated, described in previous post (can be found here)

Step 4 (continued): configuration files - faces-config.xml.

Comparing to a JSF 2.0 project with Spring integrated, only applicationContext.xml file will be changed - web.xml and faces-config.xml files will be the same. We need to add below code into applicationContext.xml:
<bean id="pooledDataSource" 
 class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
 <property name="driverClass" value="org.postgresql.Driver" />
 <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/bikes"/>  
    <property name="user" value="postgres"/>  
    <property name="password" value="pgpass"/> 
    <property name="maxPoolSize" value="10" />
 <property name="maxStatements" value="0" />
 <property name="minPoolSize" value="5" />  
</bean>
 
<bean id="JDBCDataSource" 
 class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
 <property name="driverClassName" value="org.postgresql.Driver"/>
 <property name="url" value="jdbc:postgresql://localhost:5432/bikes"/>
 <property name="username" value="postgres"/>
 <property name="password" value="pgpass"/>
</bean>
 
<bean id="entityManagerFactory"
 class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="jpaVendorAdapter">
  <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
   <!-- 
   Specific properties for Hibernate are in persistence.xml file, 
   but also can be placed here and removed from persistence.xml file.  
   -->
  </bean>
 </property>
 <property name="dataSource" ref="pooledDataSource" />
 <property name="persistenceUnitName" value="persistenceUnit"/> 
</bean>

<bean 
 class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean name="transactionManager" 
 class="org.springframework.orm.jpa.JpaTransactionManager">
 <property name="entityManagerFactory" ref="entityManagerFactory" />  
</bean>

<tx:annotation-driven />
Note that this approach is similar to situation when plain Hibernate API is used with Spring: JPA's EntityManagerFactory is like Hibernate's SessionFactory, JPA's EntityManager (obtained from EntityManagerFactory) is like Hibernate's Session (obtained from SessionFactory). JPA's EntityManager is injected into Repositories (with the help of Spring's PersistenceAnnotationBeanPostProcessor class), while Hibernate's Session was injected into DAO's (with the help of Spring's HibernateDaoSupport class exteneded by each DAO). JPA's TransactionManager (built on EntityManagerFactory) is like Hibernate's HibernateTransactionManager (built on SessionFactory).
JPA's Repositories and Services are similar to oldschool DAOs and Facades. Repositories are injected into Services, while DAOs are injected into Facades.

Please note that I defined here two datasources: a basic one without connection pool (JDBCDataSource) and second one using c3p0 as a connection pool (pooledDataSource).


Step 5: configuration files - persistence.xml

In addition JPA uses a special configuration file named persistence.xml. This file contains additional settings for JPA vendor. The location of this file is described in this article. In order to have this file inside WEB-INF/classes/META-INF/persistence.xml under Eclipse, I created a directory "config" where I put META-INF subdirectory with persistence.xml file inside. Then I select the directory "config" to be used as a source directory. This means that content of "config" directory will be on classpath, and for a web application during a build time it will be moved into WEB-INF/classes. Note that I also added there log4j config file:




Persistence.xml file contains some specific settings for Hibernate (as JPA vendor):
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
 version="1.0">

 <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
  <properties>   
     <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
     <property name="hibernate.show_sql" value="true" />
    </properties> 
 </persistence-unit>
</persistence>


Step 6: configuration files - log4j.properties


As I wrote before we will use Log4j instead of Hibernate's default SLF4j. Lets's log everything we can (we can see how Hibernate opens/closes connections, how connections are taken from the pool, how Spring manages transactions and so on):
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n
log4j.rootLogger=info,A1

log4j.logger.com.mchange.v2=DEBUG 
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.springframework=DEBUG

Step 7: database entities.

As shown at the beginning of previous post, we had only one entity represented by the class Bike.java. Instances of Bike.java where created inside Spring service named bikeDataProvider (BikeDataProviderImp.java). Now we have a database with tables Bike, Bike_Category, Account and Role. For each table we should create one class (note: this is the simplest mapping one table to one class - there are other way to map tables to classes).


Bike entity:
package com.jsfsample.model;

@Entity
@Table(name="bike")
public class Bike implements Serializable {

 private Integer id;
 private BikeCategory category; 
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)     
 @Column(name="bike_id")
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 
 @ManyToOne
 @JoinColumn(name="bike_category_id") 
 public BikeCategory getCategory() {
  return category;
 }
 public void setCategory(BikeCategory category) {
  this.category = category;
 }
 
 // rest of columns
}
Bike_category entity:
package com.jsfsample.model;

@Entity
@Table(name="bike_category")
public class BikeCategory {
 
 private Integer categoryId;
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="bike_category_id")
 public Integer getCategoryId() {
  return categoryId;
 }
 public void setCategoryId(Integer categoryId) {
  this.categoryId = categoryId;
 }
 // rest of columns
}
Account entity:
package com.jsfsample.model;

@Entity
@Table(name="account")
public class Person {
 
 private Integer accountId;
 private Role currentRole;
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="account_id")
 public Integer getAccountId() {
  return accountId;
 }
 public void setAccountId(Integer accountId) {
  this.accountId = accountId;
 }
 
 @ManyToOne
 @JoinColumn(name="role_id") 
 public Role getCurrentRole() {
  return currentRole;
 }
 public void setCurrentRole(Role currentRole) {
  this.currentRole = currentRole;
 }
 // rest of columns 
}
Role entity:
package com.jsfsample.model;

@Entity
@Table(name="role")
public class Role {

 private Integer roleId;
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="role_id")
 public Integer getRoleId() {
  return roleId;
 }
 public void setRoleId(Integer roleId) {
  this.roleId = roleId;
 }
 // rest of columns
}
Note how classes are mapped to tables (using @Table(name="...")) and how fields are mapped to columns (using @Column(name="...")). We also mapped many-to-one relations between tables using @ManyToOne annotation with proper joim column name. Note also how primary keys are generated - we do not use PostgreSQL sequence (GenerationType.SEQUENCE) - PostgreSQL supports SERIAL data type for primary keys, which actually hides sequences (see this link).

Step 8: repositories and services.

Spring repositories are similar to DAO. All database interactions is done insde them. As an example, let's look inside repository resposnible for loading and saving bikes - BikesDAOImpl.java:


package com.jsfsample.repositories.impl;

@Repository("BikesRepository")
public class BikesDAOImpl implements BikesDAO {
 
 private EntityManager em = null;
 
 @PersistenceContext
 public void setEntityManager(EntityManager em) {
  this.em = em;
 }
 
 @Override
 public Bike loadSelectedBike(Integer bikeId) {
  return em.find(Bike.class, bikeId);
 }
 // other methods for saving bike and loading bike for given category

}

This repository is used in Spring's service named bikeDataProvider (BikeDataProviderImpl.java):


package com.jsfsample.services.impl;
...
@Service("bikeDataProvider")
public class BikeDataProviderImpl implements BikeDataProvider {

 @Resource(name="BikesRepository")
 private BikesDAO bikesRepository;
 
 @Resource(name="DictionaryRepository")
 private DictionariesDAO dictionaryRepository;

 public Bike getBikeById(Integer id){
  return bikesRepository.loadSelectedBike(id);
 }
 
 @Transactional
 public void add(Bike newBike, Integer categoryId) {
  BikeCategory categorySelected = dictionaryRepository.loadBikeCategroryById(categoryId);
  newBike.setCategory(categorySelected);
  bikesRepository.saveBike(newBike);
 } 
 
 // other methods using repositories
}
Similar solution is used for account (person) repository which is then used in Spring's Security service named userDetailsService (UserDetailsServiceImpl.java). Note how easy is to execute a method within database transaction - just use @Transactional annotation and voila.

That's all about adding JPA into Spring-based JSF2 sample application.

The rest of application code (web pages, JSF managed beans) are the same as in pure Spring example project - we only modified services by providing repositories.

How to test it? After deploying application on the server and starting the server, we have to open a browser and type in URL:

http://localhost:8080/JSF2FeaturesSpringJPA



-------------------------------------------
Download source files:
Note: make sure that Java, Eclipse and Tomcat are properly installed and configured for running the project (additional configuration may be required if different directories are used).

Eclipse complete sample project is here (with all required libraries). The sample project is a ready to run application which contains JPA (Hibernate), Spring (with Spring Security). You can also download a war file located here (just copy it inside webapps folder in Your Tomcat and start Tomcat with the script startup.bat). Make sure that before doing this You created required database and PostgreSQL server is up and running (You can check access using pgAdmin III).

Wednesday, March 09, 2011

JSF 2, Spring 3, JPA (Hibernate 3), PostgreSQL, c3p0 - everything together (part 1 of 2)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28, MyFaces 2.1.7, Spring Framework 3.1.1, Spring Security 3.1.0, Hibernate 3.6.10 (Final), PostgreSQL 9.1.

Requirements:
  • a working example of JSF 2.0 application with Spring Framework and Spring Security integrated (can be found here)
  • installed PostgreSQL database (simple installation variant described here)
You will learn:
  • how to use database for loading and storing the data in the sample JSF 2.0  application
  • how to access the database from the application using JPA (Hibernate) and Spring
  • how to optimize database access by using connection pool (c3p0)
It is a high time to create a real working example with a database. Sample application used in previous posts use no database. We had Spring's managed service named bikeDataProvider acting as a database - all bikes data were created in that service during startup, all bikes data were retrieved from that service, even new bike data were stored internally in the service:
package com.jsfsample.services.impl;
...
@Service("bikeDataProvider")
public class BikeDataProviderImpl implements BikeDataProvider {

 private List<Bike> bikes;

 @PostConstruct
 private void prepareData(){
  bikes = new ArrayList<Bike>();
  
  // MTB
  Bike mtb1 = new Bike();
  mtb1.setId(1);
  mtb1.setName("Kellys Mobster");
  mtb1.setDescription("Kellys Mobster, lorem ipsut...");
  mtb1.setPrice(6500);
  mtb1.setCategory(1);
  
  // ... rest of mock bikes created here
 }
 
 public List<Bike> getBikesByCategory(Integer categoryId, boolean onlyWithDiscount) {
  // returns bikes by given category
 }
 
 public Bike getBikeById(Integer id){
  // returns certain bike for its details
 }

 @Override
 public void add(Bike newBike) {
  // add new bike 
  bikes.add(newBike);
 }
}
The same method of creating mock data was used in Spring's managed service named userDetailsService - users and their authorities were created directly inside the service:
package com.jsfsample.application.impl;
...
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

 private HashMap<String, org.springframework.security.core.userdetails.User> users = new HashMap<String, org.springframework.security.core.userdetails.User>();
 
 @Override
 public UserDetails loadUserByUsername(String username) {
  // returns user
 }

 @PostConstruct
 public void init() {
  
  // mocked roles  
  Collection<GrantedAuthority> adminAuthorities = new ArrayList<GrantedAuthority>();
  adminAuthorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
  
  Collection<GrantedAuthority> userAuthorities = new ArrayList<GrantedAuthority>();
  userAuthorities.add(new GrantedAuthorityImpl("ROLE_REGISTERED"));
  
  boolean enabled = true;
  boolean accountNonExpired = true;
  boolean credentialsNonExpired = true;
  boolean accountNonLocked = true;
  
  // mocked users with roles
  users.put("admin", new org.springframework.security.core.userdetails.User("admin", "admin", enabled, accountNonExpired,
    credentialsNonExpired, accountNonLocked, adminAuthorities));
  
  users.put("user", new org.springframework.security.core.userdetails.User("user", "user", enabled, accountNonExpired,
    credentialsNonExpired, accountNonLocked, userAuthorities));
 }
}
In both cases all data are created in the method annotated with @PostConstruct. That annotation means, that method will be invoked first after creating an instance of a class (in this case Spring creates instances of those service classes).

Our objective is to remove that mocked data created explicite in the services classes and replace them with data coming from real database.

Step 1: we need database structure:
CREATE TABLE "role" (
 role_id SERIAL NOT NULL,
 name VARCHAR(32),  
 CONSTRAINT role_pk PRIMARY KEY (role_id)
);

CREATE TABLE "account" (
 account_id SERIAL NOT NULL,
 role_id INTEGER NOT NULL,
 login VARCHAR(32),
 password VARCHAR(32),
 CONSTRAINT account_pk PRIMARY KEY (account_id),
 CONSTRAINT role_id_fk FOREIGN KEY (role_id) REFERENCES role(role_id)
);

CREATE TABLE "bike_category" (
 bike_category_id SERIAL NOT NULL,
 name VARCHAR(32),  
 CONSTRAINT bike_category_pk PRIMARY KEY (bike_category_id)
);

CREATE TABLE "bike" (
 bike_id SERIAL NOT NULL,
 bike_category_id INTEGER NOT NULL,
 name VARCHAR(32),
 description TEXT,
 price numeric(10,2),
 discount_price numeric(10,2),    
 CONSTRAINT bike_pk PRIMARY KEY (bike_id),
 CONSTRAINT bike_category_fk FOREIGN KEY (bike_category_id) REFERENCES bike_category(bike_category_id)
);
This is very simple database with two many-to-one relations: many users belongs to (have) one role and many bikes belongs to (have) one category. Of course in real world user would have many roles, so we would use many-to-many relation, but I decided to use many-to-one to simplify it.
Tables account and role will be used by Spring Security - they store users and their authorities (roles). Tables bike and bike_category are the "heart" of bike store.

Step 2: when structure is ready, it is time to insert some sample data:
INSERT INTO role (name) values ('ROLE_ADMIN'); -- id 1
INSERT INTO role (name) values ('ROLE_REGISTERED'); -- id 2

INSERT INTO account (role_id, login, password) values (1, 'admin', 'admin'); -- ROLE_ADMIN
INSERT INTO account (role_id, login, password) values (2, 'user', 'user'); -- ROLE_REGISTERED

INSERT INTO bike_category (name) values ('Mountain'); -- id 1
INSERT INTO bike_category (name) values ('Trekking'); -- id 2
INSERT INTO bike_category (name) values ('Cross'); -- id 3

INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (1, 'Kellys Mobster', 'Kellys Mobster, lorem ipsut...', 6500, null); -- Mountain
INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (1, 'Scott Scale', 'Scott Scale, lorem ipsut...', 18900, null); -- Mountain
INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (1, 'Author Magnum', 'Author Magnum, lorem ipsut...', 17200, 15500); -- Mountain

INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (2, 'Giant Accend', 'Giant Accend, lorem ipsut...', 5000, 4600); -- Trekking
INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (2, 'Merida Freeway', 'Merida Freeway, lorem ipsut...', 2400, 2100); -- Trekking
INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (2, 'Mbike Massive', 'Mbike Massive, lorem ipsut...', 1900, null); -- Trekking

INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (3, 'Giant Roam XR 1', 'Giant Roam XR 1, lorem ipsut...', 3900, null); -- Cross
INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (3, 'Cannondale Quick Cx', 'Cannondale Quick Cx, lorem ipsut...', 4999, null); -- Cross
INSERT INTO bike (bike_category_id, name, description, price, discount_price) values (3, 'Cube Cross', 'Cube Cross, lorem ipsut...', 4500, 4200); -- Cross

Step 3: adding required libraries into project.


Comparing those libraries with libraries from clean JSF 2.0 project (look here) or libraries from JSF 2.0 project with Spring (look here) we have extra libraries here: Hibernate libraries marked green, Spring JPA libraries marked red and some third party libraries marked blue. Those blue libraries are:
  • c3p0 libraries for connection pool
  • log4j library and bridge library from sl4j to log4j - Hibernate by default uses sl4j, but we would like to use log4j
  • JDBC driver for PostgreSQL
Step 4: configuration files - will be continued in next post.

-------------------------------------------
Download source files:
The complete working example of mentioned application which will contain all described issues, will be available in the last (second) article of this serie.

Friday, January 28, 2011

JSF 2 with Spring 3 - protection with Spring Security (part 2 of 2)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28, MyFaces 2.1.7, Spring Framework 3.1, Spring Security 3.1.0.


Requirements:
  • a working example of JSF 2.0 application with Spring Framework integrated (can be found here)
You will learn:
  • how to use Spring Security Framework in order to protect web application
From the previous post we know what Spring Framework is, and what advantages it gives us when used in web application. Business logic managed by Spring is not the only one advantage coming from Spring - we can use Spring's embedded mechanisms to secure our web application. This post will show the basic usage of Spring Security for securing our sample JSF 2.0 webapp. 
What parts of our application will be protected? Consider those scenarios:
1. Only registered user (or page administrator) can see details of a selected bike.
2. Only page administrator can add a new bike to the shop offer.

We need two user roles which will determine the privilleges which user has: registered users role and admin users role. Moreover, for the scenario 2, we have to add a new function: adding new bike. For this function we will create a page addBike.xhtml and a JSF managed bean for that page, named addBike.java.

addBike.xhtml source code is shown below:
<?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 xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
  <ui:composition template="../shopTemplate.xhtml">
       
        <ui:define name="content">
        <h:form>
         <h:outputText value="#{msg['bikes.list.name']}: "/><h:inputText value="#{addBike.name}" /><br/>
         <h:outputText value="#{msg['bikes.list.price']}: "/><h:inputText value="#{addBike.price}" /><br/>
         <h:outputText value="#{msg['bikes.list.discountprice']}: "/><h:inputText value="#{addBike.discountPrice}" /><br/>         
         <h:outputText value="#{msg['bikes.list.description']}: "/><h:inputText value="#{addBike.description}" /><br/>
         <h:commandButton action="#{addBike.addNewBike}" value="#{msg['bikes.add.button']}" />
        </h:form>
        </ui:define>

  </ui:composition>
</html>
Nothing special - standard form for entering the data.
addBike.java source code is also simple:
package com.jsfsample.managedbeans;
...
@ManagedBean(name="addBike")
@SessionScoped
public class AddBike implements Serializable {

 private static final long serialVersionUID = -2155913853431899821L;
 
 
 @ManagedProperty("#{bikeDataProvider}")
 private BikeDataProvider bikeDataProvider; // injected Spring defined service for bikes
 
 private String name;
 private String description;
 private String price;
 private String discountPrice;
 private Integer categoryId;
 
 public String addNewBike(){

  Bike newBike = new Bike();
  newBike.setName(getName());
  newBike.setDescription(getDescription());
  newBike.setPrice(Integer.parseInt(getPrice()));
  newBike.setDiscountPrice(Integer.parseInt(getDiscountPrice()));
  newBike.setCategory(categoryId);
  
  // save new bike and return to the shop
  bikeDataProvider.add(newBike);  
  return "/bikesShop.xhtml";
 }; 
 ...
}
Please note that we use here BikeDataProvider.java class, which is Spring managed service, the same we used for loading bikes list and loading a certain bike details in previous post.

Now it is time for protected parts of application. I will show two ways of protecting webapp: protecting resources (like access to certain page) and protecting business logic methods execution. Scenario 1 will be an example of protecting business logic and scenario 2 will be an example of protecting resources.
When user tries to access the protected area (resource or invoke protected method), application will check user roles and based on them will decide if let the user go further or force him to log in. Log in - that's right - a login page will be displayed where user will enter his credentials. Based on them Spring Security will decide what roles user has and depends on assigned roles further action will be continued or not. Let's modify our application to use Spring Security:

Step 1. Modify configuration files:
applicationContext.xml source:
...
 <!-- 
 resource security  
 -->
 <sec:http auto-config="true" access-denied-page="/faces/accessDenied.xhtml">
  <sec:form-login login-page="/faces/login.xhtml" />
  <sec:intercept-url pattern="/faces/admin/**" access="ROLE_ADMIN" />     
 </sec:http>
 <!-- 
 business logic (method) security 
 -->
 <sec:global-method-security
  secured-annotations="enabled" jsr250-annotations="enabled" >  
 </sec:global-method-security>
 <!-- 
 manager responsible for loading user account with assigned roles 
 -->
 <sec:authentication-manager alias="authenticationManager">
  <sec:authentication-provider
   user-service-ref="userDetailsService" />
 </sec:authentication-manager>
 ...
Access-denied-page is invoked when user is authenticated but is not authorized to access protected resources. When user is not authenticated, he is moved into form-login instead of access-denied-page.
web.xml source:
...
 <filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 ...
Step 2. Additional pages: login.xhtml and accessDenied.xhtml.
accessDenied.xhtml is simple page displaying only a message saying that the user is authenticated but still is not authorized to go further.
login.xhtml is a simple page with login form where user enters his credentials (login and password). The more interesting part is corresponding managed bean LoginBean.java which uses a Spring service for authenticating users:
package com.jsfsample.managedbeans;
...
@ManagedBean(name = "loginBean")
@SessionScoped
public class LoginBean implements Serializable {
 private static final long serialVersionUID = 1L;

 private String login;
 private String password;

 @ManagedProperty(value = "#{authenticationService}")
 private AuthenticationService authenticationService; // injected Spring defined service for bikes


 public String login() {

  boolean success = authenticationService.login(login, password);
  
  if (success){
   return "bikesShop.xhtml"; // return to application but being logged now 
  }
  else{
   FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Login or password incorrect."));   
   return "login.xhtml";
  }
 }
 ...
}
When login was successful and user is authenticated, he is moved to the shop. If not a proper message is displayed and user can re-enter his credentials or go back to the shop without login. Let's look inside AuthenticationService.java class which is a service deciding if user is authenticated or not.

Step 3. AuthenticationService implementation:
package com.jsfsample.application.impl;
...
@Service("authenticationService")
public class AuthenticationServiceImpl implements com.jsfsample.application.AuthenticationService {


 @Resource(name = "authenticationManager")
 private AuthenticationManager authenticationManager; // specific for Spring Security

 @Override
 public boolean login(String username, String password) {
  try {
   Authentication authenticate = authenticationManager
     .authenticate(new UsernamePasswordAuthenticationToken(
       username, password));
   if (authenticate.isAuthenticated()) {
    SecurityContextHolder.getContext().setAuthentication(
      authenticate);    
    return true;
   }
  } catch (AuthenticationException e) {   
  }
  return false;
 }
 ...
}
This Spring managed service uses internally a class AuthenticationManager, which comes from Spring Security and was defined as a manager in applicationContext.xml file:
...
 <!-- 
 manager responsible for loading user account with assigned roles 
 -->
 <sec:authentication-manager alias="authenticationManager">
  <sec:authentication-provider
   user-service-ref="userDetailsService" />
 </sec:authentication-manager>
 ...
Note that we do not explicit define AuthenticationManager! It is a ready to use object. But AuthenticationManager has helper service named userDetailService defined in applicationContext.xml file - this service must be written by our own.

Step 4. Implementation of userDetailService
userDetailsService source code is shown below:
package com.jsfsample.application.impl;
...
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

 private HashMap users = new HashMap();
 
 @Override
 public UserDetails loadUserByUsername(String username)
   throws UsernameNotFoundException{
  
  org.springframework.security.core.userdetails.User user = users.get(username);
  
  if (user == null) {
   throw new UsernameNotFoundException("UserAccount for name \""
     + username + "\" not found.");
  }
  
  return user;
 }

 @PostConstruct
 public void init() {
  
  // sample roles  
  Collection adminAuthorities = new ArrayList();
  adminAuthorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
  
  Collection userAuthorities = new ArrayList();
  userAuthorities.add(new GrantedAuthorityImpl("ROLE_REGISTERED"));
  
  boolean enabled = true;
  boolean accountNonExpired = true;
  boolean credentialsNonExpired = true;
  boolean accountNonLocked = true;
  
  // sample users with roles set
  users.put("admin", new org.springframework.security.core.userdetails.User("admin", "admin", enabled, accountNonExpired,
    credentialsNonExpired, accountNonLocked, adminAuthorities));
  
  users.put("user", new org.springframework.security.core.userdetails.User("user", "user", enabled, accountNonExpired,
    credentialsNonExpired, accountNonLocked, userAuthorities));
 }
}
We have here a Spring Security specific objects representing users and roles. In the init() method I created some mocked data two roles representing page administrators and registered users - ROLE_ADMIN and ROLE_REGISTERED. For each role I created a single account: admin (password: admin) for the ROLE_ADMIN and user (password: user) for the ROLE_REGISTERED. That's all - it is time to protect applicartion.

Step 5. Protecting application.
5 a) Scenario 1: protecting business logic. We have to protect invoking a method which allows to see bike details. This method is placed inside BikeDataProvider.java service class. In order to protect the method we have to add an annotation defining roles allowed to execute this method:
package com.jsfsample.services;
...
public interface BikeDataProvider {
 ...
 
 @RolesAllowed({"ROLE_ADMIN","ROLE_REGISTERED"}) 
 public abstract Bike getBikeById(Integer id);
 
 public abstract void add(Bike newBike);
}
This simply means that only registered users or admin users can see bike details. 
Why we do not protect the add(...) method? Because we protect the whole page access where this method is executed - of course in addition we can also protect this method by annotating it with @RolesAllowed({"ROLE_ADMIN"}).
5 b) Scenario 2: protecting resource. According to rules of protecting resources defined in applicationContext.xml, we protect all resources which are located inside /admin directory. So we have to create a directory /admin under /WebContent directory and move addBike.xhtml page there. It should look like this:




Note: there is a little trick in the protecting resources like pages in JSF. Spring Security tries to match exact URL address to apply the rule. But in JSF there is a "old URL" issue - after navigtation from page A to page B, URL address in browser still points to page A. In order to make the rule working we have to force the browser to show the current URL instead of old one. It is done by adding a special command into the navigation string returning a page for adding a bike:
public String showForm(){  
 ...  
 return "/admin/addBike.xhtml?faces-redirect=true";
}


That's all about Spring Security in our sample application. 
How to test it? After deploying application on the server and starting the server, we have to open a browser and type in URL:

http://localhost:8080/JSF2FeaturesSpring

Then try to display some bike details. When promped for login, enter credentials: user, user and try again. Then try to add a new bike - You should see access denied page. The close the application and clean the browser cache and try the same with the user admin, admin.

-------------------------------------------
Download source files:

Note: make sure that Java, Eclipse and Tomcat are properly installed and configured for running the project (additional configuration may be required if different directories are used).

Eclipse complete sample project is here (with all required libraries). The sample project is a ready to run application which contains all described Spring Security issues in this post. You can also download a war file located here (just copy it inside webapps folder in Your Tomcat and start Tomcat with the script startup.bat)

Tuesday, December 14, 2010

JSF 2 with Spring 3 - basics (part 1 of 2)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28, MyFaces 2.1.7, Spring Framework 3.1.1, Spring Security 3.1.0.

Requirements:
  • a working example from the last article of a serie introducing new JSF 2.0 features.
You will learn:
  • how to integrate Spring Framework into JSF 2.0 application
In the previous three posts I described some interesting JSF 2.0 features and I put them together in the sample application. Those parts were mostly focused on web content, a GUI and its behaviour.
What about the server side? What about the business logic executed underneath? Do we had a business logic in the sample application mentioned above? Of course we had. Presenting bikes list or a certain bike under some condition -  this is business logic resposniblity. Filtering bikes and presenting only those with the discount - this is also business logic. Don't think of it as a naive filtering of presented data - the business logic decides what does it mean that the certain bike has discount - it can be lower price but it can be also more complicated. In the previous example we had a class named BikeDataProvider.java which represented business logic. It was a singleton invoked with the help of static method getInstance() anywhere where needed.
When the application starts to grow up, we have more business logic accomplishing some business cases. We need something that will help us to manage the whole business logic in an elegant way - this is where Spring comes to play.
We will change the BikeDataProvider class into object created and managed by Spring. This object will be called service. A service which serves business logic. Then the service will be used by JSF managed beans. Let's add Spring to our sample web apllication. 

Step 1: adding required Spring libraries into the project. 


Step 2: creating Spring's configuration file named applicationContext.xml. The file has to be located inside /WEB-INF directory. This is full content of that file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:faces="http://www.springframework.org/schema/faces"
 xmlns:int-security="http://www.springframework.org/schema/integration/security"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sec="http://www.springframework.org/schema/security"
 xsi:schemaLocation="http://www.springframework.org/schema/integration/security http://www.springframework.org/schema/integration/security/spring-integration-security-3.1.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
  http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces-3.1.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

 <context:component-scan base-package="com.jsfsample" />

</beans>

Step 3: modifying web.xml by registering listener resposnible for loading Spring in web application.
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext.xml</param-value>
 </context-param>
Step 4: modifying faces-config.xml file for allow JSF components use Spring components.
<application>
... <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
...
 </application>
Step 5: modifying BikeDataProvider.java toward Spring managed service.

First of all we will add a new functionality to the application - possibility to add a new bike to the selected category. We need to create an .xhtml page with the form, then managed bean for that page and at the end a business logic method in class BikeDataProvider.java responsible for adding new bike to bikes' list. That's easy part - it will be visible in the attached complete example. 
Assuming that we have this new funcitonality, we can modify .java files for Spring integration. First we create an interface: 
package com.jsfsample.services;
//imports
public interface BikeDataProvider {

 public List<Bike> getBikesByCategory(Integer categoryId,
   boolean onlyWithDiscount);

 public Bike getBikeById(Integer id);

 public void add(Bike newBike); // new function

} 
Then we have to create an implementation named BikeDataProviderImpl.java (yes, I know that this naming convention is bad) which will have the source code from previous BikeDataProvider.java class. This implementation will have Spring specific annotation defining the service:
package com.jsfsample.services.impl;
//imports
@Service("bikeDataProvider")
public class BikeDataProviderImpl implements BikeDataProvider {

 private List<Bike> bikes;
 private Integer currentBikeId;
 
 @PostConstruct
 private void prepareData(){
  bikes = new ArrayList<Bike>();
  
  // MTB
  Bike mtb1 = new Bike();
  mtb1.setId(1);
  mtb1.setName("Kellys Mobster");
  mtb1.setDescription("Kellys Mobster, lorem ipsut...");
  mtb1.setPrice(6500);
  mtb1.setCategory(1); 
  bikes.add(mtb1);
  // other bikes are mocked up the same way
  
 }
 
 public List<Bike> getBikesByCategory(Integer categoryId, boolean onlyWithDiscount) {
  // implementation 
 }
 public Bike getBikeById(Integer id){
  // implementation 
 }

 public void add(Bike newBike) {
  bikes.add(newBike);
 }
} 
The annotation @Service("bikeDataProvider") means that this is Spring managed object (created by Spring) and is visible in the Spring context under the name "bikeDataProvider". @PostConstruct is a little trick here - when object of this class is instantiated by Spring, the method is invoked right after the object is created. I used this for preparing demo data of bikes. The whole BikeDataProviderImpl.java class acts as a simple data source for the application - in the future we will use a real database instead.

Step 6: modifying JSF managed beans to use Spring service inside.

We will use registered Spring service inside JSF managed-beans. For example consider BikeDetails.java managed bean. Previously we loaded certain bike in this way:
package com.jsfsample.managedbeans;
// imports
@ManagedBean(name="bikeDetails")
@RequestScoped
public class BikeDetails {

 private Integer bikeId;
 private Bike bike; 
 
 public void loadBike(){
  bike = BikeDataProvider.getInstance().getBikeById(bikeId);
 }
        ...
}
Now BikeDataProvider.java is not a singleton - it is a Spring service. BikeDetails.java managed bean is changed:
package com.jsfsample.managedbeans;
// imports
@ManagedBean(name="bikeDetails")
@RequestScoped
public class BikeDetails {

 private Integer bikeId;
 private Bike bike; 
 
 @ManagedProperty("#{bikeDataProvider}")
 private BikeDataProvider bikeDataProvider; // injected Spring service

 public void loadBike(){
  bike = bikeDataProvider.getBikeById(bikeId);
 }
        ...
}
We used the name of registered service ("bikeDataProvider") to inject it into JSF managed bean (please note that we used here an interface as an instance variable, Spring injects its concrete implementation). This injection is possible thanks to modifications from step 4.


That's all. Other JSF managed beans responsible for displaying bikes' lists or adding a bike use mentioned Spring service in the same way.

-------------------------------------------
Download source files:
The complete working example of mentioned application which will contain all described issues, will be available in the last (second) article of this serie.