A Re-usable Sample asset for a “Must Do at Login”
function in WebSphere Portal
Don Jones
WebSphere Portal Lab Services “SEAL” Team
23 July 2007
Abstract
A frequent customer question we get is “How do I make sure that the user ‘does
something’ at Portal login before being allowed to access Portal”? Examples of “does
something” that I’ve heard can be
Register that they’ve read and agreed to Terms and Conditions of usage
Set a value for a required user profile attribute
Change a password that has recently been reset
Sees a warning that their password is about to expire
….
I’ve written a sample servlet filter and portlet that work together to implement such a “do
something at login before continuing” function, and I’m making it available to the SEAL
team as a re-usable asset.
Previous customer approach – LoginUserAuth override
Many customers ask about whether Portal login can be extended to provide such a
function. While in principle we do allow customers to extend the LoginUser command,
and there is a white paper on that subject available in the Portal Zone, in general
extending the login to do this is insufficient. This is because in order to enforce the
“…and not allow the user to continue UNLESS / UNTIL the user achieves the necessary
state” that is the follow-on requirement, it is actually necessary to extend the
SessionValidator command. This is because if Login is the only hook point, then the user
could bypass the operations to “do something” by manually re-entering the /myportal
URL – because by then they’re logged in and Portal would not execute the Login
command extension for that user again.
New sample approach
Two things are necessary to implement this functionality:
1. An intercept/enforcement point that is executed on EVERY request to Portal (at
least to /myportal), to check whether the required state has been met
2. Some code to conduct any necessary user interactions to achieve the desired state
As the necessary “intercept/enforcement point”, my approach substitutes a servlet filter (a
public J2EE-architected construct) for the SessionValidator (a currently non-public,
poorly documented Portal API).
The code that conducts any user dialogs to ‘do something’ is implemented as a portlet.
Servlet Filter description
A servlet filter can examine and update the request before the actual servlet gets it, and
can also examine and update the response from the servlet before it is sent back to the
browser client. A servlet filter is declared in the application’s web.xml file and is
mapped to URL patterns, allowing control over which URLs the filter will apply to and
which it will not.
In the “Must Do at Login” sample, the filter implements the following logic:
if ( session has "already done" flag)
{
do nothing (pass request through, ignore response)
} else if ( request is NOT to the "Do-Something VP" ) {
save the current request URL in session
redirect to the "Do-Something VP"
} else { // request is to the "Do-Something VP"
do nothing on request
look at response
if ( response contains the "all done" signal from the VP )
{
set the "already done" flag in the session
retrieve the original URL from the session
redirect to the original URL
} else {
do nothing on the response
}
}
The above logic shows my approach to the servlet filter design, and some other design
assumptions regarding this sample implementation:
I use redirects to get the user from the servlet filter to the portlet, and then from
the servlet filter to the originally-requested URL.
The portlet is actually placed on a page within a specific Virtual Portal. This is
important for 2 reasons:
1. It makes it easy to redirect from the servlet filter to the portlet, just by using
the VP name.
2. Because the VP name will always show up in any URL to that Virtual Portal,
it gives me a safe way to know that a request is targeted at the VP that is
actually trying to “get the user into the right state”. This is important because
it allows for multiple-step dialogs with portlet actions in between each step
The servlet filter doesn’t actually go check for any state in the user registry. I
have centralized all user registry access only in the portlet, rather than have both
the portlet and the servlet filter looking at the user registry. The servlet filter
depends on the portlet to signal it when the user has achieved the desired state,
and the servlet filter then records this signal in the session. This means that there
will ALWAYS be at least one redirect from the filter to the Virtual Portal,
although that Virtual Portal may immediately signal back that the user is in the
desired state.
The servlet filter only looks at 3 things:
1. The session, for a flag that indicates whether the user has reached the desired
state or not (this is the “already done” flag referenced in the logic above
2. The request URL, to determine whether a request is to the “Do Something”
Virtual Portal or not. Requests to the “Do Something” VP are passed through,
while requests to any other Portal URL may be intercepted (depending on the
state of the session flag).
3. The response from Portal on any request to the “Do Something” URL. The
servlet filter is looking for the signal from the portlet that the user has reached
the desired state.
The following flow diagrams show how this works.
Requests to /portal are ignored
In order to know whether a user has reached a certain state, we need to know who the
user is. This means that only the protected Portal URLs (/myportal) are relevant.
Browser
Filter
DoSomething
VP
Other Portal
URL
/portal
Figure 1 - Initial requests to /portal
In Figure 1, the browser begins by making requests to /wps/portal. In the web.xml for
Portal, the “Must Do At Login” filter is mapped only to the /myportal URL. This means
that the filter is not even invoked by WAS for any requests that don’t target /myportal.
The user could request the /portal page and get the login portlet and log in, in which case
they are then redirected by Portal to the /myportal page, and the filter would then be
invoked.
If the user makes an initial request to /myportal without first logging on, then WAS
Security will work as normal and will intercept the request and redirect the user to the
form login page that Portal registers with WAS through the web.xml security constraint.
In Portal’s case, this is actually pointing at a “/redirect” URL that is implemented as
another servlet filter (one shipped as part of the out-of-the-box WP code) which in turn
redirects to the appropriate /portal login page. The “Must Do At Login” filter is never
invoked in this case because WAS security intercepts the unauthenticated /myportal
request before the container begins invoking filters and servlets.
First request to /myportal is intercepted
Eventually the user logs on and the first request to /myportal in a session is executed by
the web container. In this case the filter is invoked. See Figure 2 below.
Browser
Filter
DoSomething
VP
Other Portal
URL
/myportal
redirect to DoSomething VP
get /myportal/DoSomething VP
Initial response (state not achieved yet)
pass back
another get /myportal/DoSomething VP (action?)
trigger response (state achieved)
Discard response, redirect to original URL
Figure 2 - User accesses /myportal and is intercepted
Whenever the user makes their first request to /myportal after login, the filter will look
for a flag in the session to indicate that “all is well”. This flag is set only by the filter in a
different code path which has not yet been executed, and so the flag will not be there.
Because the flag is not present, the filter will redirect to the “/myportal/DoSomethingVP”
after saving the originally requested URL in the session.
When the browser fetches the /myportal/DoSomethingVP URL, the filter simply passes
the request through (because the filter is coded to allow any requests to the
DoSomethingVP through). The DoSomethingVP contains the portlet that checks the user
state. Assume that the user has not yet achieved the required state. The VP and portlet
simply render whatever dialog is necessary to bring the user to the required state (this is
what is labeled “Initial response” in the flow diagram above). The filter is coded such
that any response coming from the DoSomethingVP is checked for a “trigger” message
that indicates the VP is happy with the state of the user. If no such trigger is found, then
the response from the VP is simply passed back from the filter with no change.
The user cannot attempt to bypass this process by manually entering other Portal URLs,
because the servlet filter will not have gotten a response from the DoSomethingVP
indicating that such URLs should be allowed – so they will continue to be intercepted and
the user redirected to the DoSomethingVP.
The user may make several more DoSomethingVP requests. Eventually, perhaps an
action URL is performed within a DoSomethingVP portlet that will cause the desired
state to be achieved. The filter simply passes this all such requests through. At some
point one of those requests causes the desired state to be achieved. The response from
the DoSomethingVP to that request should have the trigger message or signal from the
VP to the filter that this user is “done”. The filter, which has been examining all
responses from the DoSomethingVP, puts the “all is well” flag into its session, discards
this last DoSomethingVP response, and instead issues a redirect to the original URL that
started all this.
All subsequent requests to any URL in this session will see the “all is well” flag in the
session and the filter will simply pass them through.
User may already be in desired state
In the step above where the user reached the desired state, it is assumed that the
DoSomethingVP would have recorded that fact, perhaps setting a persistent flag in the
user registry through PUMA and WMM, or some other persistent state stored
somewhere.
In that case, the next time the user logs in, the following flow would occur:
Browser
Filter
DoSomething
VP
Other Portal
URL
/myportal
redirect to DoSomething VP
get /myportal/DoSomething VP
trigger response (state achieved)
Discard response, redirect to original URL
Figure 3 - Flow when user is already in desired state
In this case, the initial request to /myportal is still intercepted by the filter, the original
request URL is saved in the session, and the browser is redirected to the
DoSomethingVP. The DoSomethingVP, however, checks whether the user is already in
the desired state, sees that she is, and immediately issues a response with the trigger text
signal. The filter then sets its own session flag, discards that response and issues an
immediate redirect to the originally requested URL.
Why do these redirects in this case?
This design is a tradeoff between the cost of doing these two redirects, one time at the
beginning of each new user session, against the cost of having to have the code to access
the user registry (or wherever the persistent user state is stored) from both the servlet
filter and in the DoSomethingVP portlets. Here the servlet filter is relatively “dumb” – it
delegates all the complexity of determining whether the user is in the right state to the
DoSomethingVP and the portlet(s) within it. This means that if a customer first decides
that their users must sign one Terms & Conditions form, and then later decides (after all
users have signed it) that a second condition must also be met, only the DoSomethingVP
portlets need to be updated to check a second condition – not both the portlets and the
filter. Not having to change the filter is good because the portlet(s) can be redeployed
while Portal is “live”, while changing filter code requires restarting the JVM.
This was my design choice, and it can certainly be changed for individual customers as
they see fit.
Message passing from Virtual Portal to servlet filter
When the DoSomethingVP decides that the user has reached the desired state, whether
that is immediately (by reading the persistent user registry flag) or after a dialog, the
DoSomethingVP must notify the servlet filter of that fact so that the servlet filter can set
its session flag and stop intercepting subsequent requests in that session. In other words,
there must be a message or event passed from the Portal back to the filter. This is
complicated by the fact that portlets tend not to have direct access to the underlying
HTTP response that Portal is building, so it was not possible to set a header in the
response that the filter could look for. Neither do portlets have access to the underlying
Portal web app HTTP session, to set the flag directly.
Given that a response was already being built and passed back, it seemed wasteful to use
some other “out of band” messaging mechanism between the Portal and the filter. In the
end, my design choice was to have the portlet insert a specific “trigger string”only in the
response after it decides the user has achieved the necessary state, and have the filter do a
string search in the response text for that string. The string should be strange enough that
it would be unlikely to be inserted inadvertently by portlets or theme code. This string is
a public static final constant in the filter code, which is then used by my sample portlet.
Now, this search over the response text is *only* done on responses to requests targeting
the “DoSomethingVP”, not on any other request to “normal” Portal URLs or other
Virtual Portals. Even with that optimization, I admit that string searches seem like a
costly way to accomplish this – and if the DoSomethingVP responses are very large, or
the set of dialogs necessary to achieve the desired state is lengthy, then the total cost of
the string search being done repeatedly adds up. I’d love to hear better suggestions.
The sample portlet
The portlet is coded to look in the user profile for an attribute named “employeeType”.
This attribute exists as part of the default WMM schema of a bootstrap Portal install, as
well as the inetOrgPerson default LDAP schema. If the value of that attribute is the
string “good” (case ignored) then the portlet takes that as the signal that the user has
already achieved the desired state and renders only the trigger response. If the value is
any other string or is null, then the portlet renders a view that includes a button that points
at an action URL to change the state.
Using the sample
The sample code is available in a RAD7 PIF called “MustDoAtLoginSamplePIF.zip”.
The following steps will allow you try out the sample:
1. The servlet filter is in a jar file called “mdal.jar” and should be placed in the
<WAS_ROOT>/lib/ext directory.
2. The portlet is in a WAR file called “MDAL Sample Portlet.war” and should be
installed into WebSphere Portal (I used the Web Module administration portlet to
install it).
3. The access controls for the result portlet should be set so that “All Authenticated
Users” are in the “User@” role on that portlet.
4. Create a Virtual Portal with a URL context of “doSomethingVP” (case is
important here, I think). This name is currently hard-coded in the filter. This
Virtual Portal should share the same user registry realm as the main (default)
Portal because presumably all users will need to access it. Place the sample
portlet on the main page of the VP. Optionally, you can remove any other portlets
on the main page. In a real customer deployment, it is likely that you should alter
the access controls on this page so that only “User@” role is granted, and remove
all “Privileged User@” role mappings.
5. If you want to see what the portlet does without the filter in the way, simply
navigate to that VP before activating the filter. You will be able to see the portlet
render the “trigger text” when it thinks you’ve reached the necessary state.
6. Optionally, add the “employeeType” user attribute to the “Edit My Profile”
portlet by logging in as wpsadmin, navigating to “Edit My Profile”, and using the
portlet menu to configure the portlet. You can then change the state of this
attribute to play around with the portlet/filter sample. Note: In a real customer
deployment, you would NOT want to let users directly access whatever attribute
stored this setting!
7. I have included the web.xml that I altered to include this new filter declaration
and URL mapping, in a file called “web.xml.altered.MDAL”. To activate the
servlet filter, you should make equivalent changes to the web.xml that is on your
system at
<PROFILES_ROOT>\wp_profile\config\cells\jr601C\applications\wps.ear\deployments\
wps\wps.war\WEB-INF
NOTE: Altering web.xml in this way will cause the filter to be loaded, but will
NOT be permanent. Whenever any service is applied to Portal, causing the Portal
EAR/WAR to be updated and redeployed, this modification will be lost. TODO:
Document the procedure to make such a modification permanent.
Work yet to be done
Make the VP name and the context root and Portal URLs configurable in the filter
(via the filter context passed to the init(FilterContext context) method).
Add a config mode to the portlet to configure at least the attribute name to be
checked and the value.
Handle single-valued attributes by configuration (the “employeeType” used in the
sample happens to be multi-valued, and the sample portlet is coded only for that
case).
Possible real-world extensions
Force password change after reset: Have a flag in the user registry that indicates
the password must be changed. Implement a portlet to change the password,
including checks on password strength and history if needed, and clear the flag.
Notify that a password is about to expire: have a timestamp indicating when the
last password change occurred, or when the next one is due. Implement a portlet
that calculates how long until the next change is due, and within a configurable
threshold to that time, put up a dialog that says “your password is about to expire”
with a link to a password change page (which must be something the filter is built
to allow access to). Since this is advisory only, the portlet should also have a
button that says “Not right now” that would also render the trigger text to allow
the user through.
Handle multiple different aspects of “desired state”. If the customer wants their
users to do N things before continuing, should this be N portlets, each on a
different VP page? If the servlet filter is “dumb”, how does the DoSomethingVP
know which states might be okay and which not yet achieved? Ideally, the
DoSomethingVP would handle that, but how? Have the initial portlet be a
launchpad of links to other portlets/pages to handle individual subtasks?
© Copyright 2026 Paperzz