Author:Scott_Stark@displayscape.com>
<This HowTo describes the steps for integrating a third party web container into the JBoss application server framework. A web container is a J2EE server component that enables access to servlets and JSP pages. Example servlet containers include Tomcat and Jetty. Integrating a servlet container into JBoss consists of mapping web-app.xml JNDI information into the JBoss JNDI namespace using an optional jboss-web.xml descriptor as well as delegating authentication and authorization to the JBoss security layer. These tasks are simplified by the org.jboss.web.AbstractWebContainer class. The remainder of this HowTo describes howto integrate a web container using the AbstractWebContainer class.
The org.jboss.web.AbstractWebContainer class is an implementation of a template pattern for web container integration into JBoss. This class should be subclassed by web container providers wishing to integrate their container into a JBoss server. AbstractWebContainer provides support for parsing the standard J2EE web-app.xml web application deployment descriptor JNDI and security elements as well as support for parsing the JBoss specific jboss-web.xml descriptor. The AbstractWebContainer is an abstract class that implements the AbstractWebContainerMBean JMX mbean interface used by the JBoss deployer when war files need to be deployed. Figure 11.1 presents some of the key AbstractWebContainer methods.
Figure 11.1. Key AbstractWebContainer Class Methods
package org.jboss.web; ... public abstract class AbstractWebContainer extends ServiceMBeanSupport implements AbstractWebContainerMBean { public synchronized void deploy(String ctxPath, String warUrl) throws DeploymentException { WebApplication warInfo = performDeploy(ctxPath, warUrl); ClassLoader loader = warInfo.getClassLoader(); Element webApp = warInfo.getWebApp(); Element jbossWeb = warInfo.getJbossWeb(); parseWebAppDescriptors(loader, webApp, jbossWeb); deploymentMap.put(warUrl, warInfo); } protected abstract WebApplication performDeploy(String ctxPath, String warUrl) throws Exception; public synchronized void undeploy(String warUrl) throws DeploymentException { performUndeploy(warUrl); // Remove the web application ENC... deploymentMap.remove(warUrl); } protected abstract void performUndeploy(String warUrl) throws Exception; public boolean isDeployed(String warUrl) { return deploymentMap.containsKey(warUrl); } public WebApplication getDeployedApp(String warUrl) { WebApplication appInfo = (WebApplication) deploymentMap.get(warUrl); return appInfo; } private void parseWebAppDescriptors(ClassLoader loader, Element webApp, Element jbossWeb) throws Exception { WebMetaData metaData = new WebMetaData(); metaData.importXml(webApp); if( jbossWeb != null ) metaData.importXml(jbossWeb); ... addEnvEntries(envEntries, envCtx); Iterator resourceRefs = metaData.getResourceReferences(); linkResourceRefs(resourceRefs, envCtx); Iterator ejbRefs = metaData.getEjbReferences(); linkEjbRefs(ejbRefs, envCtx); String securityDomain = metaData.getSecurityDomain(); linkSecurityDomain(securityDomain, envCtx); } protected void addEnvEntries(Iterator envEntries, Context envCtx) throws ClassNotFoundException, NamingException { ... } protected void linkResourceRefs(Iterator resourceRefs, Context envCtx) throws NamingException { ... } protected void linkEjbRefs(Iterator ejbRefs, Context envCtx) throws NamingException { ... } protected void linkSecurityDomain(String securityDomain, Context envCtx) throws NamingException { ... } }
public class WebApplication { /** Class loader of this application */ ClassLoader classLoader = null; /** name of this application */ String name = ""; /** URL where this application was deployed from */ URL url; /** The root element of thw web-app.xml descriptor. */ Element webApp; /** The root element of thw jboss-web.xml descriptor. */ Element jbossWeb; /** Arbitary data object for storing application specific data */ Object data; ... // WebApplication property getters/setters... }
To integrate your web container into JBoss create a subclass of AbstractWebContainer and implement the required performDeploy(String, String) and performUndeploy(String) methods. See the performDeploy and performUndeploy method notes in the preceeding section for details of the method implementations.
Ideally both web application and ejb authentication and authorization is handled by the same security code. To enable this for your web container you must hook into the JBoss security layer. This typically requires a request interceptor that maps from the web container security callouts to the JBoss security api calls. Integration with the JBossSX security framework is based on the establishment of a java:comp/env/security context as described in the linkSecurityDomain(String, Context) method comments in the overview section. The security context provides access to the JBossSX security mgr interface implementations for use by subclass request interceptors. A outline of the steps for authenticating a user is:
Example 11.1. Authentication Steps
// Get the username and password from the request context... String username = f(request); String password = f(request); // Get the JBoss security manager from the ENC context InitialContext iniCtx = new InitialContext(); EJBSecurityManager securityMgr = (EJBSecurityManager) iniCtx.lookup("java:comp/env/security/securityMgr"); SimplePrincipal principal = new SimplePrincipal(username); if( securityMgr.isValid(principal, password) ) { // Indicate the user is allowed access to the web content... // Propagate the user info to JBoss for any calls into made by the servlet SecurityAssociation.setPrincipal(principal); SecurityAssociation.setCredential(password.toCharArray()); } else { // Deny access... }
Example 11.2. Authorization Steps
// Get the username and required roles from the request context... String username = f(request); String[] roles = f(request); // Get the JBoss security manager from the ENC context InitialContext iniCtx = new InitialContext(); RealmMapping securityMgr = (RealmMapping) iniCtx.lookup("java:comp/env/security/realmMapping"); SimplePrincipal principal = new SimplePrincipal(username); Set requiredRoles = new HashSet(Arrays.asList(roles)); if( securityMgr.doesUserHaveRole(principal, requiredRoles) ) { // Indicate the user has the required roles for the web content... } else { // Deny access... }