Table of Contents
![]() |
Many IT organizations look to achieve a competitive advantage for the enterprise by improving business productivity and reducing costs. Today's top enterprises are realizing this goal by deploying enterprise portals within their IT infrastructure. Enterprise portals simplify access to information by providing a single source of interaction with corporate information. Although today?s packaged portal frameworks help enterprises launch portals more quickly, only JBoss Portal can deliver the benefits of a zero-cost open source license combined with a flexible and scalable underlying platform.
JBoss Portal provides an open source and standards-based environment for hosting and serving a portal's Web interface, publishing and managing its content, and customizing its experience. It is entirely standards-based and supports the JSR-168 portlet specification, which allows you to easily plug-in standards-compliant portlets to meet your specific portal needs. JBoss Portal is available through the business-friendly LGPL open source license and is supported by JBoss Inc. Professional Support and Consulting . JBoss support services are available to assist you in designing, developing, deploying, and ultimately managing your portal environment. JBoss Portal is currently developed by JBoss, Inc. developers, Novell developers, and community contributors.
The JBoss Portal framework and architecture includes the portal container and supports a wide range of features including standard portlets, single sign-on, clustering and internationalization. Portal themes and layouts are configurable. Fine-grained security administration down to portlet permissions rounds out the security model. JBoss Portal includes a rich content management system and message board support.
JBoss Portal Resources:
The JBoss Portal team encourages you to use this guide to install and configure JBoss Portal. If you encounter any configuration issues or simply want to take part in our community, we would love to hear from you in our forums.
The following list details features found in this document's related release. For a technical view of our features, view the Project Roadmap and Task List .
Technology and Architecture
Supported Standards
Portal and Portal Container
Themes and Layouts
User and Group Functionality
Permissions Management
Content Management System
Message Boards
We would like to thank all the developers that participate in the JBoss Portal project effort.
Specifically,
Contributions of any kind are always welcome, you can contribute by providing ideas, filling bug reports, producing some code, designing a theme, writing some documentation, etc... To report a bug please use our Jira system .
This chapter addresses migration issues from version 2.0 to 2.2 of JBoss Portal.
From version 2.0 to 2.2, the JBoss Portal deployment descriptors have changed when defining pages, portlets, and portal instances.
To describe the changes made to the deployment descriptors, we have made available an example that you can download here: HelloWorld Portlet . After this helloworldportlet.ear is deployed, you should be able to access the new portal page by pointing your browser to http://localhost:8080/portal/portal/default/HelloWorld .
All portal, page, and portlet instance deployment is now handled by one file: *-object.xml. You no longer need the *-portal.xml, *-pages.xml, and *-instances.xml found in JBoss Portal 2.0. For our example we make available helloworld-object.xml located under helloworldportlet.war/WEB-INF/ , and it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<if-exists>overwrite</if-exists>
<parent-ref>default</parent-ref>
<properties/>
<page>
<page-name>Hello World</page-name>
<properties/>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<instance-ref>HelloWorldPortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</deployment>
<deployment>
<if-exists>overwrite</if-exists>
<instance>
<instance-name>HelloWorldPortletInstance</instance-name>
<component-ref>helloworld.HelloWorldPortlet</component-ref>
</instance>
</deployment>
</deployments>
A deployment file can be composed of a set of <deployments>. In our example file, above, we are defining a page, placing the HelloWorldPortlet as a window on that page, and creating an instance of that portlet. You can then use the Management Portlet (bundled with JBoss Portal) to modify the instances of this portlet, reposition it, and so on...
From version 2.0 to 2.2, the JBoss Portal Content Management System changed from using Apache Slide API to the Java Content Repository (JCR), JSR-170 using the Apache Jackrabbit implementation.
Since the underlying layer of the CMS has changed, it will be necessary for users migrating from 2.0 to move their content, so the following steps describe how to perform this operation.
JBoss Portal v2.0 had native WebDAV support, allowing a user to connect to the content repository via the Operating System, given the proper credentials. You will use this method to extract the content, zip it in an archive, and upload it to the new CMS.
![]() |
![]() |
Database schema differs slightly between portal 2.0.0 and 2.0.1 versions. Some new talbes were added for new functionality. There were few columns removed or type changed also.
From 2.0.1 RC2 version portal performs schema update try during startup/deployment. Hibernate SchemaUpdate hbm2ddl tool is able to add new tables or new columns. What it doesn't do is removing unnessesary columns or column sql-type changes.
Besides of that, it is always good to back up your data as this behaviour might depends on different RDBMS versions.
In portal 2.0.1 there are some changes in db schema related to Forums Portlet
For eg. columns such as:
are now not used. These are retrieved using Hibernate collections storing capabilities.
Column:
had wrong SQL type. It was 'varchar(255)' in 2.0.0 and it is 'text' in 2.0.1.
After upgrading portal to 2.0.1, schema should be updated automaticly and all new nessesary tables/columns created. If this process fail the schema will be dropped/created. Remember to backup your data before doing migration!
After successfull update beware of the fact that you will have:
To deal with second issue we must change jbp_forums_posts-->jbp_text column type. It's very simple to do in MySQL RDBMS:
ALTER TABLE jbp_forums_posts CHANGE jbp_text jbp_text text
In Postgres it will be:
ALTER TABLE portal.jbp_forums_posts ALTER jbp_text TYPE text;
This will change column type.
Check in your RDBMS docs if such ALTER TABLE SQL statement works. If not you should probably recreate jbp_forums_posts table with proper SELECT/INSERT statement.
The JSR 168 specification aims at defining porlets that can be used by any JSR168 portlet container also called portals. There are different portals out there with commercial and non-commercial licences. In this chapter we will briefly describe such portlets but for more details you should read the specifications available on the web.
As of today, JBoss portal is fully JSR168 1.0 compliant, that means that any JSR168 portlet will behave as it should inside the portal.
What is really important to know about such portlets is that when a page is displayed it is divided into two distincts parts, an action part on one portlet followed by rendering parts for every porlets displayed on a page. A portal just aggregates all the chunks of HTML rendered by the different portlets of a page.
Before we even talk about portlets, let's talk about the container called portal.
A portal is basically a web application in which modules can be easily added or removed. We call those modules 'portlets'. A module can be as complex as a forum, a news management system or as simple as a text or text with images with no possible interaction.
On a single web page different portlets can appear at the same time.
A portal can be seen as pages with different areas and inside areas, different windows and each window having one portlet.
![]() |
To define your portals and page, you will need to create an XML files in order to declare your portlet, portlet instances, windows, pages and then your portals. All portal, page, and portlet instance deployment are handled by one file: *-object.xml.
It may be necessary at times for you to deploy your portlets and not have them assigned to any specific page, so an administrator can then use the management UI to place them where he wishes. This example walks the reader through deploying a portlet instance, but not assigning it to any specific page.
The helloworld-object.xml for a simple HelloWorldPortlet is described below:
<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<if-exists>overwrite</if-exists>
<instance>
<instance-name>HelloWorldPortletInstance</instance-name>
<component-ref>helloworld.HelloWorldPortlet</component-ref>
</instance>
</deployment>
</deployments>
A deployment file can be composed of a set of <deployments>. In our example, above, we are defining the HelloWorldPortletInstance, and referencing the HelloworldPortlet web application name and the definition in the portlet.xml. You can then use the Management Portlet (bundled with JBoss Portal) to modify the instances of this portlet, reposition it, and so on...
Once the portlet has been deployed (you can hot deploy it on a live instance of JBoss Portal, as well), you should see it in the Management Portlet under available portlet instances.
To illustrate our example, we have made available a portlet that you can download here: HelloWorld Portlet .
For our example we make available helloworld-object.xml located under helloworldportlet.war/WEB-INF/ , and it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<if-exists>overwrite</if-exists>
<parent-ref>default</parent-ref>
<properties/>
<page>
<page-name>Hello World</page-name>
<properties/>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<instance-ref>HelloWorldPortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</deployment>
<deployment>
<if-exists>overwrite</if-exists>
<instance>
<instance-name>HelloWorldPortletInstance</instance-name>
<component-ref>helloworld.HelloWorldPortlet</component-ref>
</instance>
</deployment>
</deployments>
A deployment file can be composed of a set of <deployments>. In our example file, above, we are defining a page, placing the HelloWorldPortlet as a window on that page, and creating an instance of that portlet. You can then use the Management Portlet (bundled with JBoss Portal) to modify the instances of this portlet, reposition it, and so on...
To illustrate our example, we have made available a portlet that you can download here: HelloPortal .
For our example we make available helloworld-object.xml located under helloworldportlet.war/WEB-INF/ , and it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<parent-ref/>
<if-exists>overwrite</if-exists>
<portal>
<portal-name>HelloPortal</portal-name>
<properties>
<!-- Set the layout for the default portal -->
<!-- see also portal-layouts.xml -->
<property>
<name>layout.id</name>
<value>generic</value>
</property>
<!-- Set the theme for the default portal -->
<!-- see also portal-themes.xml -->
<property>
<name>theme.id</name>
<value>Nphalanx</value>
</property>
<!-- set the default render set name (used by the render tag in layouts) -->
<!-- see also portal-renderSet.xml -->
<property>
<name>theme.renderSetId</name>
<value>divRenderer</value>
</property>
<!-- set the default strategy name (used by the strategy interceptor) -->
<!-- see also portal-strategies.xml -->
<property>
<name>layout.strategyId</name>
<value>maximizedRegion</value>
</property>
</properties>
<supported-modes>
<mode>view</mode>
<mode>edit</mode>
<mode>help</mode>
</supported-modes>
<supported-window-states>
<window-state>normal</window-state>
<window-state>minimized</window-state>
<window-state>maximized</window-state>
</supported-window-states>
<page>
<page-name>default</page-name>
<properties/>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<instance-ref>HelloWorldPortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</portal>
</deployment>
<deployment>
<if-exists>overwrite</if-exists>
<parent-ref>HelloPortal</parent-ref>
<page>
<page-name>foobar</page-name>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<instance-ref>HelloWorldPortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</deployment>
<deployment>
<if-exists>overwrite</if-exists>
<instance>
<instance-name>HelloWorldPortletInstance</instance-name>
<component-ref>helloworld.HelloWorldPortlet</component-ref>
</instance>
</deployment>
</deployments>
This example, when deployed, will register a new portal instance named HelloPortal with two pages in it. The portal instance can be accessed by navigating to: http://localhost:8080/portal/portal/HelloPortal for the default page, and http://localhost:8080/portal/portal/HelloPortal/foobar , for the second page created.
The portlet specification allows a portlet instance to override the preferences that were set in the portlet.xml. Using our HelloWorld example, we can demostrate how this is done in JBoss Portal.
In our sample helloworld-object.xml for a simple HelloWorldPortlet we will add preference attributes as such:
<?xml version="1.0" encoding="UTF-8"?>
<deployments>
<deployment>
<if-exists>overwrite</if-exists>
<instance>
<instance-name>HelloWorldPortletInstance</instance-name>
<component-ref>helloworld.HelloWorldPortlet</component-ref>
<preferences>
<preference>
<name>foo</name>
<value>bar</value>
<read-only>false</read-only>
</preference>
</preferences>
</instance>
</deployment>
</deployments>
In the example above, we are overriding the portlet.xml preference named foo and assigning it a value, bar . From within our portlet now, we will access the preferences as the Portlet API allows:
String somePref = request.getPreferences().getValue("foo", "somedefaultvalue");
Likewise, you can specify in the *-object.xml descriptor, an array of preferences, as the specification allows:
<preference>
<name>foo</name>
<value>hi</value>
<value>hello</value>
<value>yo!</value>
<read-only>true</read-only>
</preference>
...
Most of the time portals use very complicated urls, however it is possible to setup entry points in the portal that follow simple patterns.
Each portal container can contain multiple portals and within a given portal, windows are organized in pages, a page simply being a collection of windows associated to a name.
Before reading this chapter you must know how to define a page and a portal, you can refer to the chapter about XML descriptors to have a better understanding of those notions.
Each portal container can contains multiple portals, also there is one special portal which is the default portal, i.e the one used when no portal is specified in particular.
It is possible to have multiple pages per portal. As for portal there is a default page for a given portal. Once the portal has been selected, then a page must be used and all the windows present in that page will be rendered. The page selection mechanism is the following.
The CMSPortlet delivers content transparently, without modifying the url displayed. However, if you wish to deliver binary content (gif, jpeg, pdf, zip, etc...), it is desirable to display this content outside of the confines of the portal.
New in version 2.2, the portal features role based access control for all portal resources. The definition of security constraints is strait forward and simple. Each portal resource can define zero, one, or more security constraints, each binding a role to the allowed actions for the role and resource. For more details on how to secure portal resources take a look at security section in the user guide.
Portal security is governed by a set of portal policy configurations. Policy configurations can be created for different permission types, and accessed via the policy configuration service. The policy configuration maintains a set of security constraints, keyed by permission type and uri of the resource.
// create a new constraint
SecurityConstraint constraint = new SecurityConstraint("view,read","Admin");
// get the allowed actions as a set of strings
Set allowedActions = constraint.getActions();
// get the role this constraint is assigned to
String allowedRole = constraint.getRole();
Security constraints are the state holder of what role is allowed to execute what actions on a given resource. They are managed via a policy configuration. One policy configuration can be defined for each permission type.
Permissions are currently separated into 3 valid types:
The policy configuration maintains the constraint information for one permission type.
PortalPolicyConfig config = null;
//.... get the config from the config service (see below)
String uri = portalResourceHandle;
Set constraints = config.getConstraints(uri);
The policy configuration service is the root access point for configuration information. All active policy configurations are registered with this service, and can be accessed from here via their permission type.
import org.jboss.portal.security.config.PortalPolicyConfigService;
import org.jboss.portal.security.config.PortalPolicyConfig;
import org.jboss.portal.core.security.PermissionTypes;
PortalPolicyConfigService configService = null;
// configService = ... lookup the configService from the mbean server
// get the policy config for all portlet instances
PortalPolicyConfig instanceConfig = configService.getConfig(PermissionTypes.INSTANCE);
PortalPolicyConfig portalObjectConfig = configService.getConfig(PermissionTypes.PORTAL_OBJECT);
The policy configuration listener registers with the policy configuration, and listens to added, removed, and modified events. Each change of the security constraints maintained in a policy configuration is propagated to this listener. The listener builds the bridge to any security enforcement infrastructure.
The default implementation of the enforcement infrastructure is based in the Java Authorization Contract for Containers (JACC). It is implemented as a policy configuration listener that reacts to configuration change events, and populates the JACC policy with permissions that are created based on the security constraints propagated by the change events.
The defined security constraints are enforced via portal permissions. The default security implementation that comes with the portal contains a policy configuration listener that converts the constraint information into portal permissions, and populates a JACC (Java Authorization Contract for Containers) based security policy with them.
The configured constraints are enforced via an interceptor in the server invocation stack. For each request to the portal it creates a new portal permission to check access rights. The created permission contains the requested resource and action. The permission is passed to the portal policy, together with the portal subject to check if the permission is implied in the policy. Access will be granted if one of the security constraints in the policy configurations implies the provided check permission.
A factory is provided to create portal permissions. The PortalPermissionFactory is an interface that is implemented as an mbean, and can be injected wherever needed.
import org.jboss.portal.security.PortalPermission;
import org.jboss.portal.security.PortalPermissionFactory;
import org.jboss.portal.core.security.PermissionTypes;
PortalPermissionFactory portalPermissionFactory = ...;
PortalPermission componentPerm = portalPermissionFactory.createPermission(PermissionTypes.COMPONENT, uri, "view");
The portal policy is the interface that is being used to check if access to a requested resource is granted. It is made available as a thread local property throughout the lifetime of a portal request. The implementation of the policy is injected via a server invocation aspect (PolicyAssociationInterceptor). This interceptor gets the policy via the implementation of the PortalPolicyService. Here is the code to get to the portal policy:
import org.jboss.portal.security.PolicyAssociation;
import org.jboss.portal.security.PortalPolicy;
PortalPolicy policy = PolicyAssociation.getPolicy();
The portal subject represents the current user. Similar to the portal policy, it is made available for the lifetime of the portal request as a thread local property, which is injected by a server invocation aspect. Here is the code to get to the portal policy:
import org.jboss.portal.security.SubjectAssociation;
import org.jboss.portal.security.PortalSubject;
PortalSubject subject = SubjectAssociation.getSubject();
The default implementation of the security APIs is based on the Java Authorization Contract for Containers (JACC).
JACC is part of the J2EE specification, and defines a way for the servlet and ejb containers to secure web resources and ejbs with a role based model.
The policy configuration factory is an abstract singleton that serves as the access point for policy configurations. It features a static accessor to get the factory implementation.
public static PolicyConfigurationFactory getPolicyConfigurationFactory()
throws ClassNotFoundException, PolicyContextException
{
....
}
The policy configuration factory to load can be specified in a VM system property (-D) "javax.security.jacc.PolicyConfigurationFactory.provider". The default implementation that will be loaded if nothing else is defined, is org.jboss.security.jacc.JBossPolicyConfigurationFactory.
The policy configuration interface is the access point for all configured permissions of one context id. It allows to manipulate the content of the security policy (see below) which is the ultimate policy decission point. In the standard J2EE model, a context id is equivalent to the deployed context: the war or ejb archive. In the case of JBoss portal, this model was extended to allow a more flexible definition of the context id. The default implementation of the portal's JBossSecurityProvider (see below) creates a separate context id for each portal resource. This allows the portal to reload the content of a specific portal resources without having to refresh any of the other resource's security attributes.
The jacc policy is the ultimate policy decission point. It makes the decission wether a permission is implied or not. To make this decission it can do whatever is needed. The default implementation (org.jboss.security.jacc.DelegatingPolicy) delegates the decission to the policy context, which in turn delegates it to the java.security.Permissions that make up all configured permissions for a given role in the requested policy context.
The portal security provider interface wrapps the functionality in the jacc PolicyConfigurationFactory. It allows access to all available policy configurations. It also offers a method the check wether a particular policy context is in service or not. The jacc policy singleton is also available via this interface.
// check if the provided policy context id is available
boolean inService(String policyContextID) throws PolicyContextException;
// get the policy configuration for the provided policy context id
PolicyConfiguration getPolicyConfiguration(String contextID, boolean remove) throws PolicyContextException;
// get the jacc policy singleton
Policy getPolicy();
The jboss security provider extends the portal security provider, and adds access to the server configuration. This additional access allows a provider implementation to consider server configuration properties when making a decission about any of the policy context calls.
// get the portal server configuration
ServerConfig getServerConfig();
The portal policy service is the root service from where one can get access to the portal policy. The default implementation of this service interface (org.jboss.portal.security.impl.jacc.PortalPolicyServiceImpl) is an mbean. It uses the implementation of the JBossSecurityProvider interface to get to the jacc policy singleton. The security provider interface is a wrapper of the jacc PolicyConfigurationFactory. It's implementation delegates all calls to the standard jacc PolicyConfigurationFactory.
The PortalPolicyService exposes only one method:
PortalPolicy getPolicy();
The portal policy has only one method:
boolean implies(PortalSubject subject, PortalPermission permission);
The default implementation of the portal policy, an inner class of the policy service implementation, (org.jboss.portal.security.impl.jacc.PortalPolicyServiceImpl$PortalPolicyImpl), uses the security provider to gain access to the portal policy implementation. It uses the JaccHelper class in the same package to determine the java.security.ProtectionDomain and the policy context id before calling the jacc policy to do the actual permission check.
The remaining piece in the puzzle is the identity. How does the portal determine what user and ultimately what roles to check the access for?
As described above, the portal injects the org.jboss.portal.security.PortalSubject as a thread local property that is available throughout the portal request. The default implementation of this portal subject (org.jboss.portal.security.impl.jacc.JaccPortalSubject) wraps the jacc way of getting to the authenticated java.security.Subject, and reading the role memberships off of it. In other words: the mechanism of getting the subject and the subjects roles is identical to the way the application server id handling this security aspect.
As you can probably see above, there are many ways to plug into this infrastructure and adapt it to your needs. You will encounter the least amount of work if you plugin at the JACC layer. All you need to do is provide your own implementation of the JACC policy. All the rest of the infrastructure can stay as is. If you don't want to stay with JACC as your security provider, it will require you to do some more work, depending on how far you want to get away from JACC. To implement a security layer without any JACC artifacts, you'll need to provide the policy configuration lister, the policy enforcement interceptor and the policy and subject interceptors. Let's look at this in more detail.
As already mentioned above, the easiest way to get your own behavior for the portal authorization, you can provide your own implementation of the JACC policy. To do so, you'll need to create a class that extends java.security.Policy, and overwrites the implies method. Be aware that the portal goes beyond the JACC specification in that it allows new permission classes, other then the 5 predefined classes from the specification. All permissions used by the portal extend the abstract org.jboss.portal.security.PortalPermission class, which in turn extends java.security.Permission. The currently (as of 2.2) implemented permission classes are ComponentPermission, InstancePermission, and PortalObjectPermission. Your policy implementation can distinguish those permissions, and handle them differently if it so desires.
For an example on how to implement your own, take a look at the portal's default policy implementation. The class is org.jboss.portal.security.impl.jacc.PortalJaccPolicy. This policy is basically a copy of the application servers DelegatingPolicy class. The idea behind it is that the portal policy is stacked ontop of the J2SE policy, configured in the VM. The portal policy will handle authorization checks for all the allowed JACC permissions (for ejb and servlet/jsp calls), In addition to the basic J2SE permission types. It allows to configure external permissions that will be treated just like the basic JACC permissions. If the incoming permission to check is an instance of any of the five JACC permission classes, or one of the configured external permission classes, the policy will handle the implies check, otherwise it will delegate to the J2SE policy that was in place in the VM, before the portal policy was created. Remember that the java security model allows only one policy to be active in the VM at any given time. By stacking the policies there is a way to have several policies active with only one policy configured at the VM level.
It is up to your implementation if you want to copy this behavior of configurable external permissions and stacked policies or not. You could implement a flat policy that treats all permissions the same, but be aware that since your policy will take the place of the only policy in the system, that all policy decissions will be coming into your policy. So all security checks by the J2SE SecurityManager will have to be handled by your policy as well.
One strange anomalie that is currently built into the portal is the fact that your policy needs to adhere to a naming convention. There needs to be a method that is used by the policy service to pick up the policy instance. Your policy needs to provide a method with the following signature: (Note: the method signature is not enforced by any interface or abstract class, since the origin of this requirement is a workaround for an underlying problem with the policy configuration and redeployments of the portal sar):
public Policy getPolicyProxy()
You can return 'this' , or any decorator class of your policy that would allow you to restrict the externally available functionality of the policy.
The policy implementation must be an mbean. It is injected into the policy service mbean to make it available to other interested parties. Take a look at the jboss-service.xml in the jboss-portal.sar (in the meta-inf folder). The mbean definition for the "portal:service=SecurityProvider" injects the "jboss.security:service=JaccPolicyProvider" via the PolicyName attribute. In other words: the service that is configured as "jboss.security:service=JaccPolicyProvider" needs to expose a method as described above, that returns an implementation of the java.security.Policy interface (public Policy getPolicyProxy(){...}). This method will be called by the SecurityProvider service at startup to read the configured policy from the mbean server. Here is the section defining the jacc policy from the jboss-service.xml:
<mbean
code="org.jboss.portal.security.impl.jacc.PortalJaccPolicy"
name="jboss.security:service=JaccPolicyProvider"
xmbean-dd="org/jboss/portal/security/impl/jacc/PortalJaccPolicy.xml">
<attribute name="ExternalPermissionTypes">
org.jboss.portal.core.security.PortalObjectPermission,
org.jboss.portal.core.security.InstancePermission,
org.jboss.portal.core.security.ComponentPermission
</attribute>
</mbean>
And here is the section defining the jacc security provider service, and injecting the policy via the policy proxy attribute:
<mbean
code="org.jboss.portal.security.impl.jacc.JBossSecurityProviderImpl"
name="portal:service=SecurityProvider"
xmbean-dd="">
<xmbean>
...more descriptor info here...
</xmbean>
<attribute name="PolicyName">jboss.security:service=JaccPolicyProvider</attribute>
<attribute name="PolicyAttributeName">PolicyProxy</attribute>
</mbean>
Note: If there is no policy mbean active for the defined PolicyName and PolicyAttributeName in the SecurityProvider mbean, the policy currently set in the VM will be used instead. The policy will be determined via:
import java.security.Policy;
Policy policy = Policy.getPolicy();
If your policy extends PortalJaccPolicy a new instance will be created everytime the portal starts. This instance will not be set as the VM wide policy, leaving the original policy in place. In other words: Policy.getPolicy() will not return your policy. To get to your policy, you'll have to lookup the portal security provider, and get it from there.
JBossSecurityProvider provider = ....;
Policy policy = provider.getPolicy();
You could of course go even further and replace the implementation of the security provider itself. That way, you can decide how to get to the policy in whatever way.
Note that the current implementation is more complex than it should be. This is due to problems in the application server's JACC policy implementation. Once those problems are fixed, the portal's implementation will be simplified. Effectively: the portal should be able to just get the current policy in the VM, (Policy p = Policy.getPolicy();) and use it. The policy would still have to be configured with the external permissions (PortalPermission classes) to treat them like JACC permissions, and not delegate the permission check to the underlying J2SE policy.
As already mentioned before, implementing an authorization solution for the portal without the use of JACC all together is a bit harder. The default implementation relies havily on many of the JACC concepts. You will have to replace all of them, but it is possible.
To start, you'll need to change the way the security constraint information is converted into permissions. Or perhaps you wouldn't even want to convert them, and use the PortalPolicyConfigService and the PortalPolicyConfig as your one and only store of permission information. If you decide to create your own system of storing and enforcing permissions, you'll have to implement the org.jboss.portal.security.config.ConfigListener interface, and register it with the PortalPolicyConfig(s) you are interested in. Look at the org.jboss.portal.security.impl.JBossPortalPolicyConfigStoreImpl as an example of how this can be done. This is an mbean that injects the ConfigListener via an attribute (depends optional-attribute-name="ConfigListener"). If you take a look at the jboss-service.xml you'll see that this mbean is used three times, and each time a config listener is injected. The three mbeans represent three different policy configurations, and the same service (portal:policy=JaccPortalPolicyConfigurator) registers with all three of them as a ConfigListener. You would have to replace the implementation of the policy configurator (portal:policy=JaccPortalPolicyConfigurator) and configure the three instances of JBossPortalPolicyConfigStoreImpl to register your config listener instead. Your config listener can do whatever you desire. Just keep in mind that the result needs to be accessible for the policy enforcement.
Policy enforcement is initiated via the PolicyEnforcementInterceptor in the server invocation stack. This interceptor uses the results of two other interceptors:
These two interceptors inject the PortalSubject and the PortalPolicy as thread local properties. The policy enforcement interceptor creates a permission based on the requested resource and action, and checks the portal policy to see if the permission implies for the determined portal subject.
You would probably keep the concept of the subject around since this is what the JAAS login module populates with the authentication information from the login process. The portal policy is what is more interesting. Your ConfigListener will populate some store with the constraint information, and that store needs to be made available to the policy enforcement side. The way to do this is via the portal policy from the PolicyAssociationInterceptor. To inject your own implementation of the PortalPolicy interface, you can provide your own version of the PortalPolicyService interface. The default implementation is an mbean that is injected into the PolicyAssociationInterceptor. Write your own version of the PortalPolicyService and configure it in the jboss-service.xml, replacing the default PortalPolicyServiceImpl. Of course you could go even further and replace the PolicyAssociationInterceptor itself no make it independent from the PortalPolicyService. The important thing is that your implementation of the PortalPolicy needs to utilize what your ConfigListener stored before.
For completeness sake, let's take a look at the SubjectAssociationInterceptor as well. It is responsible for injecting the PortalSubject. The PortalSubleject is a flagging interface (has no methods), and the default implementation (JaccPortalSubject) is simply newed up every time the SubjectAssociationInterceptor is invoked. The PortalSubject is later on used by the PortalPolicy to check if a given PortalPermission implies for the given PortalSubject.
The first version of the Portlet Specification (JSR 168), regretfully, did not cover interaction between portlets on a page. The side-effect of diverting the issue to the subsequent release of the specification, has forced portal vendors to each craft their own proprietary API to achieve interportlet communication. This chapter covers the JBoss Portal Interportlet Communication API, and its ability to allow a developer to create links to other portal pages and affect behaviour in other portlets.
IPC requires that a listener be available to intercept requests and respond appropriately. To enable the listener, it has to be declared as an mbean in your service descriptor, as in our example under helloworldipcportlet.sar/META-INF/jboss-service.xml :
<server>
<mbean code="org.jboss.portal.core.event.PortalEventListenerServiceImpl"
name="portal:service=ListenerService,type=ipc_listener"
xmbean-dd=""
xmbean-code="org.jboss.portal.common.system.JBossServiceModelMBean">
<depends optional-attribute-name="Registry" proxy-type="attribute">portal:service=ListenerRegistry</depends>
<xmbean/>
<attribute name="RegistryId">ipc_listener</attribute>
<attribute name="ListenerClassName">org.jboss.portlet.hello.HelloWorldPortletB$Listener</attribute>
</mbean>
</server>
It is important to note here, that you will most likely not have to change any of these values, except for the following:
Enabling IPC, also requires that the listener be declared in the *-object.xml, so the Portal recognizes it. The declaration happens at the page level, as in our example:
<deployments>
<deployment>
<parent-ref>default</parent-ref>
<if-exists>overwrite</if-exists>
<page>
<page-name>IPC</page-name>
<listener>ipc_listener</listener>
<properties/>
...
Now that the listener is configured in the service descriptor and the portal can recognize it, we must create the appropriate listener class within our portlet.
In our example, Portlet A will be modifying the behaviour of Portlet B. So then we will declare the listener in Portlet B, the recipient portlet.
public static class Listener implements PortalNodeEventListener
{
public PortalNodeEvent onEvent(PortalNodeEventBubbler bubbler, PortalNodeEvent event)
{
PortalNode node = event.getNode();
// Get node name
String nodeName = node.getName();
// See if we need to create a new event or not
WindowActionEvent newEvent = null;
if(nodeName.equals("HelloWorldPortletAWindow") && event instanceof WindowActionEvent)
{
// Find window B
WindowActionEvent wae = (WindowActionEvent) event;
PortalNode windowB = node.resolve("../HelloWorldPortletBWindow");
if(windowB != null)
{
// We can redirect and modify the view/mode as well!
newEvent = new WindowActionEvent(windowB);
newEvent.setMode(wae.getMode());
//newEvent.setWindowState(WindowState.MAXIMIZED);
newEvent.setParameters(wae.getParameters());
}
}
if(newEvent != null)
{
// If we have a new event redirect to it
return newEvent;
}
else
{
// Otherwise bubble up
return bubbler.dispatch(event);
}
}
}
It is important to note here some of the important items in this listener class. Logic used to determine if the requesting node was Portlet A.:
nodeName.equals("HelloWorldPortletAWindow")
Get the current window object so we can dispatch the event to it:
PortalNode windowB = node.resolve("../HelloWorldPortletBWindow");
Set the original parameter from Portlet A, so Portlet B can access them in its processAction():
newEvent.setParameters(wae.getParameters());
Modify Portlet B windowmode and/or windowstate (ie, Maximize and place in Edit Mode):
newEvent.setMode(wae.getMode()); // wae.setMode(Mode.EDIT);
newEvent.setWindowState(wae.getWindowState()); // WindowState.MAXIMIZED
Creating a link from Portlet A to Portlet B occurs in the same way you would normally create a PortletURL:
html.append("<form action=\"" + resp.createActionURL() + "\" method=\"post\">");
html.append("<input type=\"text\" name=\"sometext\"><br/>");
html.append("<select name=\"color\">");
html.append("<option>blue</option>");
html.append("<option>red</option>");
html.append("<option>black</option>");
html.append("</select>");
html.append("<input type=\"submit\"/>");
html.append("</form>");
As you can see from the code above, we are creating a simple HTML form with an ActionURL from within Portlet A. It will target itself, but be intercepted by the listener, created in Portlet B. This form passes some text and a color value from input fields.
Now, in Portlet B, our listener innerclass will trigger the processAction() in Portlet B, reading in the parameters from the Portlet A form:
public void processAction(JBossActionRequest request, JBossActionResponse response) throws PortletException, PortletSecurityException, IOException
{
String color = request.getParameter("color");
String text = request.getParameter("sometext");
if(color != null && text != null)
{
response.setRenderParameter("color", color);
response.setRenderParameter("sometext", text);
}
}
Setting the render parameters, it will now pass them on to the Portlet B, doView();
As seen in the included NavigationPortlet (tabs found at the top of the default layout), we are able to create links to Portal Pages. Included in the download sample , you can see the basics of creating a link to a Portal Page. I have added comments in-line to explain the code sample below:
// Get the ParentNode. Since we are inside a Window, the Parent is the Page
PortalNode thisNode = req.getPortalNode().getParent();
// Get the Node in the Portal hierarchy tree known as "../default"
PortalNode linkToNode = thisNode.resolve("../default");
// Create a RenderURL to the "../default" Page Node
PortalNodeURL pageURL = resp.createRenderURL(linkToNode);
// Output the Node's name and URL for users
html.append("Page: " + linkToNode.getName() + " -> ");
html.append("<a href=\"" + pageURL.toString() + "\">" + linkToNode.getName() + "</a>");
Portals usually render the markup fragments of several portlets, and aggregate these fragments into one page that ultimately gets sent back as response. Each portlet on that page will be decorated by the portal to limit the real estate the portlet has on the page, but also to allow the portal to inject extra functionality on a per portlet basis. Classic examples of this injection are the maximize, minimize and mode change links that will appear in the portlet window , together with the title.
Layouts and themes allow to manipulate the look and feel of the portal. Layouts are responsible to render markup that will wrap the markup fragments produced by the individual portlets. Themes, on the other hand, are responsible to style and enhance this markup.
In JBoss Portal, layouts are implemented as a JSP or a Servlet. Themes are implemeted using CSS Style sheets, java script and images. The binding elemement between layouts and themes are the class and id attributes of the rendered markup.
JBoss Portal has the concept of regions on a page. When a page is defined, and portlet windows are assigned to the page, the region, and order inside the region, has to be specified as well. For portal layouts this has significant meaning. It defines the top most markup container that can wrap portlet content (other then the static markup in the JSP itself). In other words: from a layout perspective all portlets of a page are assigned to one or more regions. Each region can contain one or more portlets. To render the page content to return from a portal request, the portal has to render the layout JSP, and for each region, all the portlets in the region.
Since the markup around each region, and around each portlet inside that region, is effectively the same for all the pages of a portal, it makes sense to encapsulate it in its own entity.
To implement this encapsulation there are several ways:
In JBoss Portal you can currently see two out of these approaches, namley the first and the last. Examples for the first can be found in the portal-core.war, implemented by the nodesk and phalanx layouts. Examples for the third approach can be found in the same war, implemented by the industrial and Nphalanx layout. What encapsulates the markup generation for each region, window, and portlet decoration in this last approach is what's called the RenderSet.
The RenderSet consist of four interfaces that correspond with the four markup containers that wrap the markup fragments of one of more portlets:
While we want to leave it open to you to decide which way to implement your layouts and themes, we strongly believe that the last approach is superior, and allows for far more flexibility, and clearer separation of duties between portal developers and web designers.
Portal layouts also have the concept of a layout strategy. The layout strategy is a pluggable API, and lets the layout developer have a last say about the content to be rendered. The strategy is called right after the portal has determined what needs to be rendered as part of the current request. So the strategy is invoked right between the point where the portal knows what needs to be done, and before the actual work is initiated. The strategy gets all the details about what is going to happen, and it can take measures to influence those details.
Some simple examples of those measures are:
The last topic to introduce in this overview is the one of portal themes. A theme is a collection of web design artifacts. It defines a set of css, java script and image files that together decide about the look and feel of the portal page. The theme can take a wide spectrum of control over the look and feel. It can limit itself to decide fonts and colors, or it can take over a lot more and decide the placement (location) of portlets and much more.
Layouts are used by the portal to produce the actual markup of a portal response. After all the portlets on a page have been rendered and have produced their markup fragments, the layout is responsible for aggregating all these pieces, mix them with some ingredients from the portal itself, and at the end write the response back to the requesting client.
Layouts can be either a JSP or a Servlet. The portal determines the layout to use via the configured properties of the portal, or the requested page. Both, portal and pages, can define the layout to use in order to render their content. In case both define a layout, the layout defined for the page will overwrite the one defined for the portal.
A Layout is defined in the layout descriptor named portal-layouts.xml. This descriptor must be part of the portal application, and is picked up by the layout deployer. If the layout deployer detects such a descriptor in a web application, it will parse the content and register the layouts with the layout service of the portal. Here is an example of such a descriptor file:
<layouts>
<layout>
<name>phalanx</name>
<uri>/phalanx/index.jsp</uri>
</layout>
<layout>
<name>industrial</name>
<uri>/industrial/index.jsp</uri>
<uri state="maximized">/industrial/maximized.jsp</uri>
</layout>
</layouts>
Portals and pages can be configured to use a particular layout. The connection to the desired layout is made in the portal descriptor (YourNameHere-object.xml). Here is an example of such a portal descriptor:
<portal>
<portal-name>default</portal-name>
<properties>
<!-- Set the layout for the default portal -->
<!-- see also portal-layouts.xml -->
<property>
<name>layout.id</name>
<value>phalanx</value>
</property>
</properties>
<pages>
<page>
<page-name>theme test</page-name>
<properties>
<!-- set a difference layout for this page -->
<property>
<name>layout.id</name>
<value>industrial</value>
</property>
</properties>
</page>
</pages>
</portal>The name specified for the layout to use has to match one of the names defined in the portal-layouts.xml descriptor of one of the deployed applications.
As you can see, the portal or page property points to the layout to use via the name of the layout. The name has been given to the layout in the layout descriptor. It is in that layout descriptor where the name gets linked to the physical resource (the JSP or Servlet) that will actually render the layout.
To access a layout from code, you need to get a reference to the LayoutService interface. The layout service is an mbean that allows access to the PortalLayout interface for each layout that was defined in a portal layout descriptor. As a layout developer you should never have to deal with the layout service directly. Your layout hooks are the portal and page properties to configure the layout, and the layout strategy, where you can change the layout to use for the current request, before the actual render process begins.
Both descriptors, the portal and the theme descriptor, are located in the WEB-INF/ folder of the deployed portal application. Note that this is not limited to the portal-core.war, but can be added to any WAR that you deploy to the same server. The Portal runtime will detect the deployed application and introspect the WEB-INF folder for known descriptors like the two metioned here. If present, the appropriate meta data is formed and added to the portal runtime. From that time on the resources in that application are available to be used by the portal. This is an elegant way to dynamically add new layouts or themes to the portal without having to bring down , or even rebuild the core portal itself.
As you might have noticed already, a layout definition consists of a name and one or more uri elements. We have already seen the function of the name element. Now let's take a closer look at the uri element. In the example above, the phalanx layout defined one uri element only, the industrial layout defines two. What you can see in the industrial layout is the option of defining different uri's for different states. In this example , we configured the layout to use a different JSP if the layout state is maximized. If no such separation is made in the layout descriptor, then the portal will always use the same JSP for this layout. Note that the 'state' attribute value works together with the state that was set by the layout strategy. Please refere to the section about the layout strategy for more details.
The portal comes with a set of JSP tags that allow the layout developer faster development.
There are currently two taglibs, containing tags for different approaches to layouts:
The theme-basic-lib.tld contains a list of tags that allow a JSP writer to access the state of the rendered page content. It is built on the assumption that regions, portlet windows and portlet decoration is managed inside the JSP.
The portal-layout.tld contains tags that work under the assumption that the RenderSet will take care of how regions, portlet windows and the portlet decoration will be rendered. The advantage of this approach is that the resulting JSP is much simpler and easier to read and maintain.
Here is an example layout JSP that uses tags from the latter:
<%@ taglib uri="/WEB-INF/theme/portal-layout.tld" prefix="p" %>
<!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">
<head>
<title>JBoss Portal: 2.2 early (Industrial)</title>
<meta http-equiv="Content-Type" content="text/html;" />
<p:theme themeName='phalanx' />
<p:headerContent />
</head>
<body id="body">
<div id="portal-container">
<div id="sizer">
<div id="expander">
<div id="logoName"></div>
<table border="0" cellpadding="0" cellspacing="0" id="header-container">
<tr>
<td align="center" valign="top" id="header"><div id="spacer"></div></td>
</tr>
</table>
<div id="content-container">
<p:region regionName='This-Is-The-Page-Region-To-Query-The-Page'
regionID='This-Is-The-Tag-ID-Attribute-To-Match-The-CSS-Selector'/>
<p:region regionName='left' regionID='regionA'/>
<p:region regionName='center' regionID='regionB'/>
<hr class="cleaner" />
<div id="footer-container" class="portal-copyright">Powered by
<a class="portal-copyright" href="http://www.jboss.com/products/jbossportal">JBoss Portal</a><br/>
Theme by <a class="portal-copyright" href="http://www.novell.com">Novell</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
The theme tag looks for the determined theme of the current request (see Portal Themes for more details). If no theme was determined, this tag allows an optional attribute 'themeName' that can be used to specifiy a default theme to use as a last resort. Based on the determined theme name, the ThemeService is called to lookup the theme with this name and to get the resources associated with this theme. The resulting style and link elements are injected, making sure that war context URLS are resolved appropriately.
This tags allows portlets to inject content into the header. More details about this function are mentioned in the 'other Theme Functions' section of this document.
The region tag renders all the portlets in the specified region of the current page, using the determined RenderSet to produce the markup that surrounds the individual portlet markup fragments. The regionName attribute functions as a query param into the current page. It determines from what page region the portlets will be rendered in this tag. The regionID attribute is what the RenderSet can use to generate a css selector for this particular region. In case of the divRenderer, a DIV tag with an id attribute corresponding to the provided value will be rendered for this region. This id in turn can be picked up by the CSS to style the region.