then change the expression class of the image element on the layout to java.awt.Image as well. You’ll also have to add javax.imageio.ImageIO to the imports of the report.
This technique can be useful when you need to grab the image data dynamically (not from actual files on the filesystem), you can’t get each image from a URL (perhaps due to security constraints), and don’t want to use a custom Java datasource.
If you find the need to outsource some or all of your server environment during your bid to take over the world, remember that there’s a huge difference between a hosting provider that merely gives you access to hardware, be it physical or virtual, and one who truly manages those servers with you. Here’s a few traits to consider that can prove invaluable not only in day to day operations but when it comes time to upgrade, expand, or add to your deployment:
No single provider can excel in every area for which you might need a server. An asterisk VoIP deployment has very different requirements from a LAMP app for example. On the other hand, most apps one might deploy these days require knowledge of quite a few technologies, and most providers will probably tell you they can do whatever you need, so it’s important that you vet the provider’s competency in the areas that will benefit you the most.
Of course the level of competence in any area can vary from complete jackassery, to being able to solve a problem after exhaustive research, to being real innovators in a space, on the forefront of the subject, even disseminating their knowledge through blogging or other means.
Phone support is often overrated and inefficient, especially when it concerns servers. A phone call to support is almost always going to spawn a support ticket at some point, requiring follow-ups, attachments, etc. so it just makes sense to initiate it there.
A good trouble ticket system will allow you to email support with your issue, identifying your account with your email address, and will maintain any CCs you included on the original request.
When an issue reaches a support tech on the providers end who might not be the best qualified to handle it, the transition from that tech to another is a crucial step in the problem solving process. The customer shouldn’t be responsible for bringing each new tech assigned to the ticket up to speed.
Great support departments handle that transition so well that you have to double check the ticket to see who you’re replying to.
Specialization Rather Than Escalation
Most of us have had trouble tickets rise through tiers of support where the first is really just gathering information or digging through their knowledgebase for a previous answer, the second has some problem solving skills, and the third or higher are some form of ‘engineering’.
It’s fun to screw with first tier techs and tell them whatever they need to hear to escalate the ticket, but more fun when you get the sense that all of your provider’s support staff are ‘engineers’, and if a ticket does get handed off to another tech it’s most likely due only to a shift change or because the second tech really knows the crap out of the subject and the support team thinks that person would be the best to tackle it.
Whether the issue is handled via email, ticket system, instant message, or other medium, response time is key.
Most deployment servers are mission critical (for at least someone’s mission) and downtime of more than a few hours can cause rapid hair loss.
Even if an issue isn’t resolved immediately, some indicator that the provider is looking into the issue gives great piece of mind.
It’s no secret that you and your support staff love dealing with angry users, but it’s often beneficial to have trouble brought to your attention before your users notice. Maintaining resource monitoring and alert systems is a job in itself and a good provider will let you know not just when your server or app has been down for a while but when it’s getting close to consuming its allocated resources, is under some sort of malicious attack, or otherwise exhibiting odd behavior.
When done right the level of monitoring is so good that you feel like a jerk when you forget to tell the provider you’re going to work on your own application and will be taking it down.
They Take Action
Being notified that something isn’t working is one thing, but having a provider that takes obvious first steps to solve the problem, like restarting a service, can save all sorts of time, and may circumvent the need for you getting involved at all.
There are times when phone support does come in handy.
No one likes to be woken up in the middle of the night because an app has crashed and can’t be brought back up, but if the provider’s team has done everything they can without interaction from you and you’ve selfishly closed your eyes for a few hours without a mechanism to poke you for each new email received, a phone call may be the only recourse, and it’s certainly better than waking up to find that a critical service that has been down for hours.
It’s only when you really trust your provider that you can realize the true value of their services.
When you trust them to install and setup a third party application rather than tackling it yourself you save the inevitable hours searching through documentation and forums to resolve some stupid issue unique to your deployment environment.
When you trust their recommendation on which app to use to fulfill some need you can save hours of additional research time.
When you trust that their network, power, and most importantly people infrastructure can handle your app when it becomes the mega success you’ve dreamt it will be, you’re free to dream of the next.
If trust could be quantified and put on a feature list we’d certainly have an easier job of comparing these folks, but as we all know, this one can only be earned over time.
An Unsolicited Shout Out
I can say from experience that Contegix excels in all of these areas. I’m in no way affiliated with them, just a satisfied customer.
At RightsPro, we’ve chosen to go with jQuery UI as an interface framework and while the progress bars look great out of the box we wanted to add the effect of the progress growing to its value when the user visits the page to draw attention to it.
jQuery’s documentation for the UI components, including the progress bar, is straight forward.
Deciding where to handle authorization in a setup where Alfresco’s authentication is handled by CAS which itself authenticates against LDAP may not be as easy as it sounds. This post goes through some of the possibilities and one solution.
LDAP Authentication with an Expiration Date Attribute
On Alfresco version 2.x we extended the LDAPAuthenticationComponentImpl class to be able to evaluate an LDAP filter string, configurable via spring, which was used primarily for the purpose of determining whether the user’s access to Alfresco had expired, with the expiration date being stored as an LDAP attribute. So our ldap-authenication.properties file would contain something like:
Once the expiration date was reached the user was denied access to the application.
Moving to Single Sign On
We’re now migrating to Alfresco 3.x and also have the need to move to a single sign on solution. Jasig’s Central Authentication Service (CAS) was chosen as the implementation, requiring some changes to our expiration strategy.
In our previous configuration, authentication (is this user who they say they are) and authorization (is this user allowed to do x) were intertwined in our single custom LDAPAuthenticationComponentImpl class. Any other applications authenticating against the same LDAP server could implement their own authentication/authorization methods.
CAS however is only concerned with authentication, not authorization, and applications utilizing it need to be able to decouple those functions, which is a better architecture in most cases anyway.
Our task then is to determine where in the authentication/authorization strategy we should handle this expiration authorization.
Choosing Where to Handle Authorization
Customize the CAS Server?
Modifying the CAS LDAP authentication handler wouldn’t be an appropriate place for our expiration authorization since all CAS services share the same authentication handler and other applications that have no notion of the Alfresco service or its expiration could be denied authentication.
We could try implementing a CAS authorizing serviceRegistryDao which would in theory allow the CAS server to determine if the user were authorized to use the service requested beyond just the Enabled and SSO Participant settings. An authorization component could be defined that would make the authorization decision based on the service being requested and the user requesting it. Each service could choose its authorization component as an option during setup in the CAS Service Management application.
CAS really wants the client/application to handle authorization though, so customizing the server doesn’t look like a recommended approach.
We could setup Alfresco’s authentication chain to talk to CAS, but in version 3.2 Alfresco has changed its authentication configuration to use the notion of Authentication Subsystems (which seems nicely implemented) and most documentation indicates that integration with something like CAS is best achieved by using mod_cas or mod_auth_cas in Apache web server, and since we’re already using Apache in front of Tomcat with mod_proxy_ajp that approach seems like a good fit.
Wait, Can a Hacker Just Spoof HTTP Headers?
It looks like AJP between Tomcat and the web server is responsible for parsing these protocol specific (non-HTTP) headers to find the remote user value and set that in Tomcat’s HttpServletRequest, so a hacker can’t just modify the headers in their browser and have that be translated into an authenticated user.
However, it is extremely important that your Tomcat connector be behind a firewall and only accept connections from known web servers. Otherwise a hacker could set up their own web server with a bogus authentication mechanism which would add an authenticated user header in the AJP message, which in turn would translate to that user being signed in to a protected application.
mod_cas or mod_auth_cas?
With proper security in place we should be OK to use an Apache CAS module for authentication, but which one?
hasn’t been maintained in quite a while
has missing links all over the site
the documentation incorrectly states that “CAS stands for Common Authorization Service”
Option 1: Extend Alfresco’s Request Authn to Grab CAS Attribute
The CAS server can return attributes to the client and if mod_auth_cas passes those attributes through mod_proxy_ajp to Tomcat and Alfresco then we may be able to modify the component which checks that header for the authenticated username, HTTPRequestAuthenticationFilter, to also look for the expiration date attribute and authorize or deny the user.
After modifying Tomcat’s example snoop application to show all headers and attributes:
it doesn’t look like the additional attributes defined to be available to the CAS service are passed through mod_auth_cas and mod_proxy_ajp to the secured application. We might be able to pass the data through SAML attributes but it seems that would require POST requests.
Option 2: Extend Alfresco’s Request Authn to query LDAP directly
If we can’t get the expiration date attribute from the request headers we still may be able to modify the request authentication filter to make a trip directly to the LDAP server to query for the attribute and confirm or deny authorization, but maybe we can do everything at the web server.
Option 3: Handle Authorization at Apache
The ‘auth’ in mod_auth_cas appears to only include authentication but there may be hope in allowing mod_auth_cas to handle just the authentication part then using mod_authnz_ldap or the third-party mod_authz_ldap module to handle the authorization side.
mod_authnz_ldap’s Require ldap-filter looks promising, but we would need to insert a dynamic date (today’s) for comparison to the user’s expiration date. LDAP syntax doesn’t seem to have any keyword for the current date to be handled on the server side and it doesn’t look like mod_authnz_ldap has any special tags for injecting it in the filter string so the source code would have to be modified.
Unfortunately, upon further investigation mod_authz_ldap does not support secure SSL/TLS communication with the LDAP server and hasn’t been maintained in a quite a while, so that won’t work.
Dare I try modifying the mod_authnz_ldap source to allow for a dynamic replace of a date tag? Sure, why not?
The last time I wrote C code it was probably on a machine running Mac OS 7.6, but after several hours and as many espressos I’ve taken the relevant code from mod_authz_ldap’s source, tweaked it a bit, and found the appropriate place to inject it in mod_authnz_ldap’s authn_ldap_build_filter.
You can compile and install a single module on the server with:
apxs -i -a -c mod_authnz_ldap.c
then add the appropriate config to your location directive. So we have CAS performing authentication and a modified mod_authnz_ldap performing authorization on our Tomcat examples app:
As a fairly simple and common use case I choose a target of a line chart that showed the number of users of a few services over time and defined some basic requirements:
The data must be fetched from a separate URL, not defined on the presentation page (this URL will be a web service in production)
Three series must be displayed at once
The data points should have tooltips
‘Out-of-the-box’ components should be used when possible
A non-flash solution is preferred
Some of the points I found interesting from each framework follow. Note that the charts here are only screenshots as I didn’t find any immediately obvious way to get the real charts working on wordpress.com.
At this time it doesn’t seem that jQuery or jQuery UI has any built-in charting abilities but there are a ton of community plugins available.
Flot looked the most promising (Sparklines also looks very good for tiny charts).
Flot seems to prefer its data in JSON format organized by series and we want to simulate a web service so we’ll create a file data/users-series-format.json containing something like:
The YUI Charts Control (labeled as experimental at the time of this writing) creates nice looking charts, but they are flash-based.
There is plenty of documentation on YUI’s charts so I won’t go into too much detail but the concepts are similar to above.
YUI’s DataSource component can handle several data formats, for consistency’s sake I went with JSON so my file data/users-raw-format.json (named so since it most closely resembles the raw data used to build it) contains:
I did have trouble getting this data to load properly via URL when the HTML file containing the DataSource code was loaded in the browser via file:// rather than http:// even after adding the file location to the Flash global security settings.
Include the scripts (YUI’s dependency configurator comes in handy here), add a place holder div for the chart, get the data, and build the chart.
Don’t forget to set YAHOO.widget.Chart.SWFURL to a location containing the swf.
We were originally using Apple OS X Server as our LDAP store for our Alfresco instance.
Apple’s OS X Server uses OpenLDAP but adds custom schema for many things including users and groups. As a result we ended up using the description LDAP attribute for Alfresco’s ldap.synchronisation.groupIdAttributeName.
We’ve since migrated to a generic OpenLDAP server (with a bit of our own custom schema) so we’re now able to use the more common and unchanging cn attribute for the group id.
When we change ldap.synchronisation.groupIdAttributeName in ldap-synchronisation.properties Alfresco imports the new groups properly but group permissions on spaces will retain the old group name so we need to change those to use the new cn attribute.
What we did was to create a temporary table in the Alfresco database, import the mapping of the cn attribute to the description attribute, then run a query to replace the old authorities with the new.
We used phpLDAPAdmin to export our groups subtree as CSV with only the cn and description attributes, then imported that file into the t_ldap_groups table just created.
Replace the Old Authorities
I’m by no means an SQL expert but the query below does the following:
Strips GROUP_ from the current stored group long name
Searches the temporary LDAP table for that group long name and corresponding group short name
Updates the alf_authority.authority field with GROUP_group short name
SET authority = CONCAT('GROUP_',
(SELECT cn FROM t_ldap_groups WHERE description = SUBSTRING(alf_authority.authority, 7) LIMIT 1))
WHERE authority LIKE 'GROUP_%' AND
(SELECT cn FROM t_ldap_groups WHERE description = SUBSTRING(alf_authority.authority, 7) LIMIT 1) IS NOT NULL;
In Alfresco 2.x the authority is stored directly in the alf_access_control_entry table as well so the update statement would be a bit more complicated.
Drop the Temp Table
DROP TABLE t_ldap_groups;
So far we haven’t had any adverse effects on our development server doing things this way but if anyone has a better method or potential issues with this one let us know.
It seems the time has come that I start making my thoughts known to whoever might be listening out there via the sometimes informative, sometimes controversial, often ridiculous medium of blogging.
After investigating several services and open source blogging web apps I’ve chosen to give WordPress.com a try as you can no doubt see if you’re reading this post.
I was leaning towards a hosted service from the start as I have grown very weary of maintaining servers and apps in my ‘old age’. Google’s Blogger (formerly Blogspot) and WordPress.com emerged as the two best candidates for a ready-to-use, free, hosted blog platform that suited my needs.
I came across some nice comparisons with many user comments including this Pulsed post and Squidoo lens.
In the end I went with WordPress for a couple of reasons:
I don’t plan to ever have ads.
It seems to be widely used.
Most WordPress blogs I saw seemed to be cleaner than Blogger’s (whether that’s purely a function of the themes or the type of creators each attracts I’m not sure)
It shouldn’t be too tough to switch if I can’t stand it, but so far I do like the service/app.
I’d imagine the content here will consist primarily of brain dumps about enterprise java, open source integration, general technology thoughts, and the occasional rant. I’ll apologize in advanced for the terrible vocabulary and grammar.