Use ProxyPassReverseCookieDomain with to maintain Tomcat sessions through mod_proxy_ajp

Posted on October 27th, 2007 in General,Linux System Administration by Brandon

I had a customer today who had problems using Tomcat sessions after configuring his application to run through mod_proxy_ajp. Everything worked correctly when hitting the application correctly on port 8080, but any attempts to hit the site through Apache and mod_proxy_ajp would result in the sessions not being saved, and a new session being created on every request.

The problem is that Tomcat is sending a Set-Cookie header with the Path that it knows about – which is different than what the browser is requesting.

The application is at http://www.mydomain.com/, and mod_proxy_ajp is redirecting that to http://localhost:8009/myapp/.

Here is the HTTP Response Headers that Tomcat is sending

HTTP/1.1 200 OK
Date: Sun, 28 Oct 2007 01:39:44 GMT
Set-Cookie: JSESSIONID=TOMCAT_SESSION_ID_HERE; Path=/myapp
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 11234
Connection: close

You can see in the Set-Cookie header that it is setting a cookie path of /myapp. The browser receives this and will only send that cookie back on requests sent for requests beginning with /myapp. Fortunately Apache 2.2 includes the ProxyPassReverseCookiePath directive to rewrite the Set-Cookie headers on these requests. You can configure a virtual host like this:

<VirtualHost *:80>
    ServerName www.realdomain.com
    ProxyRequests Off
    ProxyPass / ajp://127.0.0.1:8009/myapp/
    ProxyPassReverse / ajp://127.0.0.1:8009/myapp/
    ProxyPassReverseCookiePath /myapp /
</VirtualHost>

And now the HTTP Response headers look like this:

HTTP/1.1 200 OK
Date: Sun, 28 Oct 2007 01:39:44 GMT
Set-Cookie: JSESSIONID=TOMCAT_SESSION_ID_HERE; Path=/
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 11234
Connection: close

The browser now sees that the cookie is for / and will send the JSESSIONID cookie for all requests to this server.

Block comment spam with bcSpamBlock

Posted on October 10th, 2007 in General,Linux System Administration,Programming by Brandon

A while ago I installed Paul Butler’s JSSpamBlock on my WordPress blog here. His original idea is simple and brilliant: Spambots don’t (yet) execute Javascript. In fact, they usually post directly to the form without even displaying the form first. By having a hidden input field that is populated by javascript, you can verify that users are hitting the page without the user even noticing. For users with JavaScript disabled (are there any of you out there), they simply have to copy/paste a small string into a textbox for verification.

Since implementing a slightly modified version of it on this blog, I have gotten zero spam posts. Now, I wanted some way to implement the same logic on some of my own custom PHP sites to prevent spam on them as well.

While working on a way to re-implement Paul’s WordPress plugin in my own sites, I came up with something pretty clever. Instead of saving a row to a database every time that the form is displayed, you can use a little cryptography to make the client pass all of the data needed to validate the request back to you on its own. The idea is sortof merger between the JSSpamBlock plugin and TCP Syncookies, which use a similar method of having the client store the data for you.

Essentially, how it works, is that the function generates a Random ID. It then encrypts the current timestamp and the random ID using PHP’s crypt() function with some cryptographic salt that is unique to each server. All three of those values (the random ID, the timestamp, and the encrypted value) are then passed to the browser. The timestamp and the encrypted value are stored in hidden <input> fields, while the random ID displayed for the user to verification. If the user has JavaScript enabled, a few lines of JavaScript copy the random ID into another textbox, and then hide that prompt, so that it is never seen by the user. If the user doesn’t have JavaScript enabled, the would have to copy/paste that random ID into the textbox themselves, similar to a captcha.

When the form is submitted, it checks to make sure that the timestamp is not too old, and then re-encrypts the passed in timestamp and random ID using the same salt value to make sure it matches the crypted value passed in from the form. If everything matches, the comment is approved, otherwise an error is displayed to the user.

I wrote this up into a simple include file that can be used for any PHP application. I also implemented a quick WordPress plugin that uses the generic version. More information about it can be found on my new bcSpamBlock home page

Get your Dell Service Tag number via the Linux command-line

Posted on October 2nd, 2007 in General by Brandon

When your server is located in a data center far away, it makes it difficult to walk over to the box and read the service tag off of it. Fortunately, the Service Tag is stored somewhere in the system BIOS, and is accessible with the ‘dmidecode’ utility.

[root@host ~]# dmidecode|grep "Serial Number"
                Serial Number: 80NZV71

You’ll probably see several other serial numbers in there as well for things like your hard drives or other devices. The Dell shouldn’t be too difficult to pick out. I think they are always 7 digits and have letters in middle. There is lots of other interesting things in the ‘dmidecode’ output too, like the speed and type of each RAM module installed, and a description of all of the onboard devices (ie: video and network cards)

With Windows

Thanks to @kleinbaas who commented below how to do the same thing on a Windows machine:

  C:\Documents and Settings\brandon>wmic bios get serialnumber
  SerialNumber
  GX245D1

Fix for CentOS “Can’t do setuid (cannot exec sperl)”

Posted on October 1st, 2007 in General,Linux System Administration,Programming by Brandon

If you are running a Perl script with the setuid bit, it actually runs a slightly modified version of Perl so that it is a bit more cautious. On a CentOS box, you need to install the ‘perl-suidperl’ package to get the necessary files installed. Otherwise you get an error like this:

[root@host bin]# ls -al myscript.pl
-rws--S--- 1 mail mail 1218 Oct  1 13:09 myscript.pl

[root@host bin]# ./myscript.pl
Can't do setuid (cannot exec sperl)