[PicketLink] PicketLink with Ajax example

I created PicketLink with Ajax example.

This example uses PrimeFaces.

And this example prevents from no Ajax response when session was timeout.
This codes put GitHub.
https://github.com/subsonicsystems/picketlink-ajax-example

Execution environment
PicketLink 2.7.0.Final
PrimeFaces 5.2
WildFly 8.2.0.Final

A war file is as follows.
picketlink-ajax-example.war
picketlink-ajax-example-war

/WEB-INF/beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
        bean-discovery-mode="all">
</beans>

CDI version is 1.1.

A beans.xml is empty XML. When you wrote that bean-discovery-mode is annotated authentication cannot perform.

/WEB-INF/faces-config.xml

<?xml version="1.0"?>
<faces-config version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
    <application>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>ja</supported-locale>
        </locale-config>
        <resource-bundle>
            <base-name>resources.message</base-name>
            <var>msg</var>
        </resource-bundle>
    </application>
</faces-config>

JSF version is 2.2.

The <locale-config> is used in order to localize in JSF. Here, English and Japanese is set and English is default.

The <resource-bundle> is resource file setting. Because <base-name> is set resources.message, /WEB-INF/classes/resources/message_xx.properties is referenced. The xx is en and ja because it is set in <locale-config>. And the extension is .properties.

The <var> is used in order to define variable using EL expression. Here, it is msg. And for example a resource is called #{msg[‘index.title’]} in a xhtml file.

/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <context-param>
        <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>primefaces.THEME</param-name>
        <param-value>bootstrap</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

The servlet version is 3.1.

The first <context-param>, javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE is timezone that gets time in JSF. If it is true, it returns system timezone. Otherwise it returns UTC.

The second <context-param>, primefaces.THEME is PrimeFaces theme. The bootstrap is one of PrimeFaces themes.

SecurityInitializer.java

@Singleton
@Startup
public class SecurityInitializer {

	/**
	 * The PartitionManager.
	 */
	@Inject
	private PartitionManager partitionManager;

	/**
	 * Creates User.
	 */
	@PostConstruct
	public void create() {
		IdentityManager identityManager = this.partitionManager
				.createIdentityManager();

		User user = new User("jane");

		user.setEmail("jane@doe.com");
		user.setFirstName("Jane");
		user.setLastName("Doe");

		identityManager.add(user);
		identityManager.updateCredential(user, new Password("abcd1234"));
	}
	
}

This class is used in order to register a user when the application starts up. Because this class has @Startup this class will be called when the application starts up.

Here, the user information is hard coded, however actual use, you will use database.

HttpSecurityConfiguration.java

public class HttpSecurityConfiguration {

	/**
	 * Configures Http Security.
	 * 
	 * @param event the SecurityConfigurationEvent.
	 */
	public void onInit(@Observes SecurityConfigurationEvent event) {
		SecurityConfigurationBuilder builder = event.getBuilder();

		builder.http()
			.forPath("/protected/*")
				.authenticateWith()
					.scheme(FormWithAjaxAuthenticationScheme.class);
	}

}

This class sets about authentication. The argument of onInit method is @Observes SecurityConfigurationEvent. When the container deploys this application, a SecurityConfigurationEvent will be fired and this method will be executed.

Here, the /protected directory and its low tree is set to protect.

The scheme method is used in order to set custom authentication scheme. Here, a FormWithAjaxAuthenticationScheme class is set.

In the PicketLink standard scheme, when session was timeout, it will not return Ajax response. The FormWithAjaxAuthenticationScheme will return Ajax XML response.

FormWithAjaxAuthenticationScheme.java
The following code is partial code.

public class FormWithAjaxAuthenticationScheme implements
		HttpAuthenticationScheme<CustomAuthenticationConfiguration> {

In case you create custom scheme, you must implement HttpAuthenticationScheme<CustomAuthenticationConfiguration>.

/**
 * The timeout page URL.
 */
private static final String TIMEOUT_PAGE_URL = "/timeout.xhtml";

/*
 * (non-Javadoc)
 * 
 * @see
 * org.picketlink.http.authentication.HttpAuthenticationScheme#challengeClient
 * (javax.servlet.http.HttpServletRequest,
 * javax.servlet.http.HttpServletResponse)
 */
@Override
public void challengeClient(HttpServletRequest request,
		HttpServletResponse response) {

	if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
		sendXmlResponse(TIMEOUT_PAGE_URL, request, response);
		return;
	}

	forwardToPage(TIMEOUT_PAGE_URL, request, response);
}

/**
 * Sends XML response.
 * 
 * @param page the redirect page.
 * @param request the HttpServletRequest.
 * @param response the HttpServletResponse.
 */
private void sendXmlResponse(String page, HttpServletRequest request,
		HttpServletResponse response) {
	response.setContentType("text/xml");
	response.setCharacterEncoding("UTF-8");

	try {
		response.getWriter()
				.printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"%s\"></redirect></partial-response>",
						request.getContextPath() + page).flush();
	} catch (IOException e) {
		e.printStackTrace();
	}

}

/**
 * Forwards to page.
 * 
 * @param page the redirect page.
 * @param request the HttpServletRequest.
 * @param response the HttpServletResponse.
 */
private void forwardToPage(String page, HttpServletRequest request,
		HttpServletResponse response) {

	try {
		response.sendRedirect(request.getContextPath() + page);
	} catch (IOException e) {
		e.printStackTrace();
	}

}

The challengeClient method will be executed when a unauthenticated user and a session timeout user accessed protected URL.

Because the PicketLink standard scheme does not response Ajax XML, in the browser side, the Ajax process cannot continue and the user will think that nothing is to happen when the user clicked a button.

When the browser requests Ajax, this code responses Ajax XML. Otherwise it responses URL to redirect.

/index.xhtml

<!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:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:p="http://primefaces.org/ui">
    <f:view transient="true">
        <h:head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
            <title><h:outputText value="#{msg['index.title']}"/></title>
            <h:outputStylesheet library="css" name="default.css"/>
        </h:head>
        <h:body>
            <p:link outcome="/login" value="#{msg['index.loginPage']}"/>
        </h:body>
    </f:view>
</html>

picketlink-ajax-example-index-en
This is a first page. At <html>, because xmlns:p=”http://primefaces.org/ui” exists, the code can treat PrimeFaces.

The <f:view transient=”true”> makes JSF stateless mode. In case of no stateless mode, if a user handled after session timeout, the ViewExpiredException will be fired. The stateless mode prevents from this.

At line 9, #{msg[‘index.title’]} calls index.title in a message resource file. A message resource file is a message_en.properties or a message_ja.properties. It depends on browser language setting.

At line 13, the <p:link> is PrimeFaces tag. It makes link of /login.xhtml. The outcome attribute omits .xhtml extension.

/login.xhtml

<!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:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:p="http://primefaces.org/ui">
    <f:view transient="true">
        <h:head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
            <title><h:outputText value="#{msg['login.title']}"/></title>
            <h:outputStylesheet library="css" name="default.css"/>
        </h:head>
        <h:body>
            <h:outputText value="#{msg['login.title']}"/>
            <div style="height: 10px;"></div>
            <h:form>
                <p:messages id="msg"/>
                <p:panelGrid columns="2" styleClass="ui-noborder">
                    <h:outputText value="#{msg['login.username']}"/>
                    <p:inputText value="#{loginCredentials.userId}"/>
                    <h:outputText value="#{msg['login.password']}"/>
                    <p:password value="#{loginCredentials.password}"/>
                </p:panelGrid>
                <div style="height: 10px;"></div>
                <p:commandButton value="#{msg['login.login']}" action="#{loginView.login()}" update="msg"/>
            </h:form>
            <p>
                <h:outputText value="#{msg['login.tip']}"/>
            </p>
        </h:body>
    </f:view>
</html>

picketlink-ajax-example-login-en
This file is login page.

In <p:inputText value=”#{loginCredentials.userId}”/> and <p:password value=”#{loginCredentials.password}”/>, loginCredentials is defined by PicketLink.

In <p:commandButton value=”#{msg[‘login.login’]}” action=”#{loginView.login()}” update=”msg”/>, loginView.login() executes login method in LoginView.java.

If a user failed login, <p:messages id=”msg”/> will be updated and a login failed message will be displayed because in p:commandButton, update attribute is msg.
picketlink-ajax-example-login-failed-en
If the user logged in succellfully, the user will be redirected /protected/home.xhtml.

LoginView.java

@Named
@RequestScoped
public class LoginView {

	/**
	 * The Identity.
	 */
	@Inject
	private Identity identity;

	/**
	 * Processes login.
	 * 
	 * @return the outcome.
	 */
	public String login() {

		if (identity.isLoggedIn()) {
			return "/protected/home?faces-redirect=true";
		}

		AuthenticationResult result = identity.login();

		if (AuthenticationResult.FAILED.equals(result)) {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			UIViewRoot uiViewRoot = facesContext.getViewRoot();
			ResourceBundle resourceBundle = ResourceBundle.getBundle(
					"resources.message", uiViewRoot.getLocale());
			String loginFailed = resourceBundle.getString("login.failed");
			facesContext.addMessage(null, new FacesMessage(loginFailed));
			return "";
		}

		return "/protected/home?faces-redirect=true";
	}

}

This class can be referenced by EL expression because @Named exists. When you use EL expression, the first capital letter of the class must be small letter. Therefore, in EL expression, the LoginView.java is loginView.

The @RequestScoped is CDI annotation(javax.enterprise.context.RequestScoped).

The Identity object is defined by PicketLink. It has user information. And it is injected by @Inject.

The login method is called by #{loginView.login()} in /login.xhtml.

At line 18, identity.isLoggedIn() validates whether a user already loggen in or not. If the user logged in, the user will be redirected /protected/home.xhtml. In line 19, .xhtml extension is omitted. If ?faces-redirect=true exists, the user is redirected, otherwise the browser URL does not change and content is rewritten by JavaScript.

At line 22, identity.login() executes authentication.

If the authentication failed, login failed massage will be displayed in /login.xhtml.

At line 28, the uiViewRoot.getLocale() gets locale information. If locale was en, a resourceBundle is /WEB-INF/classes/resources/message_en.properties. If locale was ja, the resourceBundle is /WEB-INF/classes/resources/message_ja.properties.

At line 29, login.failed is defined by the resourceBundle.

At line 30, login failed massage is set at FacesMessage. This massage is displayed <p:messages id=”msg”/> in /login.xhtml.

At line 31, return “” means that the URL does not change and the page is partially rewritten by Ajax.

If the user logged in successfully, the user will be redirected /protected/home.xhtml.

/protected/home.xhtml

<!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:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:p="http://primefaces.org/ui">
    <f:view transient="true">
        <h:head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
            <title><h:outputText value="#{msg['home.title']}"/></title>
            <h:outputStylesheet library="css" name="default.css"/>
        </h:head>
        <h:body>
            <p>
                <h:outputText value="#{msg['home.title']}"/>
            </p>
            <div style="height: 10px;"></div>
            <h:form>
                <h:outputText value="#{msg['home.currentDateTime']}"/><br/>
                <h:outputText id="currentDateTime" value="#{homeView.currentDateTime}">
                    <f:convertDateTime pattern="yyyy-MM-dd HH:mm:ss"/>
                </h:outputText>
                <div style="height: 10px;"></div>
                <p:commandButton value="#{msg['home.updateDateTime']}"
                        actionListener="#{homeView.updateDateTime()}" update="currentDateTime"/>
            </h:form>
                <div style="height: 30px;"></div>
            <h:form>
                <p:commandButton value="#{msg['home.logout']}" action="#{homeView.logout()}"/>
            </h:form>
        </h:body>
    </f:view>
</html>

picketlink-ajax-example-home-en
This is home page after logged in.

In this page, it displays current date and time. If the user clicked [Update date and time] button, updated date and time is displayed.

At line 23, a p:commandButton tag creates [Update date and time] button.

At line 24, homeView.updateDateTime() calls updateDateTime method in HomeView.java. This method updates currentDateTime field latest date and time.
And this tag contains update=”currentDateTime”. This means that tag has currentDateTime ID is updated. Therefore, in line 19, h:outputText tag is updated. And this tag contains value=”#{homeView.currentDateTime}”, it calls getCurrentDateTime method in HomeView.java. It returns value of currentDateTime field that be updated by updateDateTime method. This process is executed by Ajax.

At line 28, the p:commandButton tag creates [Logout] buton. When the user clicked [Logout] button, logout method in HomeView.java will be executed.

HomeView.java

@Named
@RequestScoped
public class HomeView {

	/**
	 * The Identity.
	 */
	@Inject
	private Identity identity;

	/**
	 * The current Date and time.
	 */
	private Date currentDateTime = new Date();

	/**
	 * Updates date and time.
	 */
	public void updateDateTime() {
		currentDateTime = new Date();
	}

	/**
	 * Processes logout.
	 * 
	 * @return the outcome.
	 */
	public String logout() {
		identity.logout();
		return "/loggedOut?faces-redirect=true";
	}

	/**
	 * Gets current date and time.
	 *
	 * @return the current date and time.
	 */
	public Date getCurrentDateTime() {
		return currentDateTime;
	}

	/**
	 * Sets current date and time.
	 *
	 * @param currentDateTime the current date and time.
	 */
	public void setCurrentDateTime(Date currentDateTime) {
		this.currentDateTime = currentDateTime;
	}

}

This is a backing bean called by /protected/home.xhtml.

The Identity object defined by PicketLink is injected by @Inject.

The updateDateTime method updates current date and time latest.

The logout method executes identity.logout(). And it redirects /loggedOut.xhtml.

/loggedOut.xhtml
This code omits.
picketlink-ajax-example-logged-out-en
This page displays logged out status.

/timeout.xhtml
This code omits.
picketlink-ajax-example-timeout-en
When a unauthenticated user and a session timeout user accessed protected directory(in this case, /protected directory and its low tree), this page will be displayed.