While working on a new personal project, I decided to pick up and dig into Spring 3 MVC and Spring Security.  I've touched both of these technologies here and there in a number of other projects, but this new opportunity has really opened the door for a deep dive into Spring.  I know the Ruby fanatics out there would say I'm crazy, but once I got all of the awful XML configuration mess out of the way, I'm really enjoying Spring's stability and reliability.  I know Ruby and Rails is hip and what not, but Spring 3 has really made an impression on me.  It's hard to beat such a mature enterprise framework.

I setup a few Spring 3 controllers, and integrated Spring Security into my web-app.  All went great and so I added a simple form-based login to my Spring Security XML configuration.


Problem: Overriding UsernamePasswordAuthenticationFilter

When setting up a form-based login via a default Spring Security <http:security> configuration, Spring auto generates and configures a UsernamePasswordAuthenticationFilter bean.  This filter, by default, responds to the URL /j_spring_security_check when processing a login POST from your web-form.  First, I want to override Spring Security's default login process URL to /login instead of /j_spring_security_check.  Second, I've configured a Spring 3 controller to display my login web-form when a user visits /login.

That said, here's the underlying problem with Spring Security's default UsernamePasswordAuthenticationFilter: I want it to accept and process POST's to /login, but a GET or any HTTP method to /login should be forwarded to the next filter in the chain.  Not surprisingly, you cannot do this with Spring Security's default UsernamePasswordAuthenticationFilter because it does not @Override the doFilter() method of AbstractAuthenticationProcessingFilter.  In short, there's no way to get and check the incoming HTTP request method and re-route it using the default UsernamePasswordAuthenticationFilter.


Solution: Write your own Spring Security Authentication Filter

If you want a Spring controller to process GET requests to /login, but Spring Security to intercept and process a POST to /login, then you'll need to write your own Spring Security authentication filter.  Here's the idea:

public class MyFilter extends AbstractAuthenticationProcessingFilter {

private static final String DEFAULT_FILTER_PROCESSES_URL = "/login";
private static final String POST = "POST";

public MyFilter () {
super(DEFAULT_FILTER_PROCESSES_URL);
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException,
IOException, ServletException {
// You'll need to fill in the gaps here. See the source of
// UsernamePasswordAuthenticationFilter for a working implementation
// you can leverage.
}

@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if(request.getMethod().equals(POST)) {
// If the incoming request is a POST, then we send it up
// to the AbstractAuthenticationProcessingFilter.
super.doFilter(request, response, chain);
} else {
// If it's a GET, we ignore this request and send it
// to the next filter in the chain. In this case, that
// pretty much means the request will hit the /login
// controller which will process the request to show the
// login page.
chain.doFilter(request, response);
}
}

}

Note the good stuff inside of doFilter().  If the incoming request method is a POST, then we send it up to our AbstractAuthenticationProcessingFilter to actually process the login.  If it's a GET, or any other HTTP request method for that matter, we simply send it to the next filter in the chain.

Finally, remember that you'll need to define your own FORM_LOGIN_FILTER inside of your <security:http> Spring Security XML configuration to override the default /j_spring_security_check URL:

<security:http auto-config="false" use-expressions="true"
entry-point-ref="LoginUrlAuthenticationEntryPoint">
<security:custom-filter position="FORM_LOGIN_FILTER" ref="MyFilter" />
</security:http>

<bean id="LoginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login" />
</bean>

Enjoy!
A blog reader recently contacted me via email and asked, "hey, how does your koli.ch tiny URL thing work?"  Well, I would be happy to explain.  As previously discussed here, and here, I'm not using Apache's mod_rewrite RewriteMap engine.  No, koli.ch tiny URL's are using an interesting combination of Apache's mod_rewrite RewriteRule directive and Onyx, which is basically PHP talking to a MySQL database.

So, let's follow http://koli.ch/x3dh through the redirection process.  The "3dh" you see on the end of each URL is a base-36 encoded number, that maps to a unique bookmark resource stored inside of Onyx.

Step 1 - koli.ch to mark.koli.ch

First, you may have noticed that http://koli.ch always redirects to http://mark.koli.ch by default.  This is accomplished using Apache's mod_rewrite in my virtual host configuration ...

RewriteCond %{HTTP_HOST} !^mark\.koli\.ch [NC]
RewriteRule ^/(.*)$ http://mark.koli.ch/$1 [R=301,L]

You'll notice that the Perl compatible regular expression in the RewriteRule directive captures the URL-path content after the first slash, allowing me to gracefully forward URL's like http://koli.ch/about-mark.html to http://mark.koli.ch/about-mark.html.  Consequently, tiny URL's like http://koli.ch/x3dh are forwarded to http://mark.koli.ch/x3dh.  And, this redirect is a 301 Moved Permanently instead of a default 302 Found redirect.


Step 2 - mark.koli.ch to onyx.koli.ch

Next, in the same virtual host configuration, I use mod_rewrite's RewriteRule directive to match URL-paths that represent a tiny URL.  As far as Onyx is concerned, all of my tiny URL's all start with "x" and contain at least one, but no more than ten, word characters following the "x" ...

RewriteCond %{REQUEST_URI} !\.(htm?l)$ [NC]
RewriteRule ^/x(\w{1,10})$ https://onyx.koli.ch/x$1 [L]

Notice the regular expression group, I'm only capturing the word-characters following the "x" in the request URI, then appending them onto https://onyx.koli.ch/x before handing it off to Onyx.  Note that I have not specified the redirect response code in the RewriteRule options.  In this case, Apache will 302 Found redirect to Onyx, which tells search engines and other bots that this redirect is much less permanent than a 301 Moved Permanently.


Step 3 - onyx.koli.ch to ?

Once the browser hits https://onyx.koli.ch/x, I use RewriteRule one last time to call a redirection controller I wrote in PHP which actually takes the tiny URL, sanitizes the request URI then looks it up in a MySQL database to retrieve the final URL to redirect to.  This is part of Onyx.  Here's the pseudo code ...

<?php

$uri = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : null;
if(empty($uri)) {
throw new InternalErrorException();
}

// Strip the leading / from the front of the URI
$uri = preg_replace("/^\//","",$uri);
@list(, $resource) = preg_split("/[\/\?]/", $uri, -1, PREG_SPLIT_NO_EMPTY);
if(!empty($resource)) {
$resource = preg_replace("/\D/","",$resource);
} else {
throw new BadRequestException();
}

// ... do some MySQL things here, look up the $resource in the DB.
$url = ... some URL from the database

// Redirect the user to their destination, via an HTTP 302 Found
header(HTTP_302_FOUND);

// Unset the Pragma HTTP response header; to avoid
// redirection issues on IE.
header(PRAGMA.": ");
header(CACHE_CONTROL.": no-store, no-cache");

header(LOCATION_HEADER.': '.$url);

?>

That's it.  Cheers.
I just discovered that dealing with MySQL triggers, in many instances, is quite painful.  For example, here's a trigger that deletes a bunch of rows in a table on every INSERT:

delimiter |
CREATE TRIGGER delete_expired_tweets AFTER INSERT ON tweets
FOR EACH ROW BEGIN
DELETE FROM tweets WHERE DATEDIFF(NOW(), created_at) > 365;
END;
|

delimiter ;

Ok, let's load this trigger into MySQL:

#/> mysql -h myhost -u normaluser -p mydatabase
Enter password: **********
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.0.41-community-nt MySQL Community Edition (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> source trigger.sql
ERROR 1227 (42000): Access denied; you need the SUPER privilege
for this operation

Access denied?  I dug into it, and confirmed that you can only add triggers if your user account has the SUPER privilege enabled.  You're probably thinking, "No kidding Sherlock, that's what the error message says."  Yes, I know that's what the error message says.  But here's the problem.  Normal database users created using "GRANT ALL PRIVILEGES ON database.* TO..." will not have the SUPER privilege assigned to them by default.  As described here, the SUPER privilege in MySQL let's the account do some things that normal database users, in most environments, should not be able to do (like kill database threads, modify global system variables, etc.).  As a result, it's a very bad idea to grant the SUPER privilege to normal database users, even if they just need the SUPER privilege to load a trigger.  You know better than that!

Even worse, suppose you GRANT SUPER PRIVILEGES to a single user, on a single database.  Well, that still won't be enough to load a trigger.  Unfortunately, loading triggers requires SUPER PRIVILEGES at the global level (e.g., GRANT SUPER PRIVILEGES ON *.*).  Again, it's a very bad ideal to grant normal database users the SUPER privilege.

So how exactly am I supposed to load this trigger?  Well as far as I can tell, assuming I refuse to give myself SUPER PRIVILEGES for the reasons I just explained, I have two options:

  1. Don't use triggers, and find another way to cleanup rows in my table.
  2. Log into the database as root/admin and load the trigger on behalf of the normal user.  If I wasn't the owner of this database server, this would probably involve asking my database administrator to load the trigger for me.

This is just one of many common annoyances with MySQL.  Sucks, I know.
You may have heard that Twitter plans to stop supporting HTTP Basic Authentication on June 30, 2010.  This means that starting on June 30th, to use Twitter's API, your application must support OAuth.  OAuth is a nice step up from basic authentication but it makes developing web or desktop applications that communicate with Twitter, slightly more painful.  Well, painful isn't the right word, but you definitely have to jump through more hoops to get things to work.  Gone are the days of simply sending a username and password to the API.

In response to this change, Twitter API proxy services like SuperTweet have popped up.  Turns out, if you know what you're doing with OAuth, SuperTweet and other API proxy services are entirely unnecessary, not to mention unsafe.  You're better off upgrading your applications to use OAuth the right way, instead of making them rely on potentially insecure third-party proxy services.  And again, it's not difficult, just a bit annoying.

Scenario

You're a developer, and you need to write some code that pulls in Tweets from one or more users.  Maybe you also need to pull down a list of followers for each of these users.  Not surprisingly, it's entirely unreasonable to ask each of them to authenticate your application using OAuth.  You just want to write code that pulls down their public timeline, followers, etc. avoiding the whole OAuth dance with each user, every time.

Solution

Register a new application on Twitter.  Then, dig into your application control panel and find your new "single access token" and "single access token secret" for the application you just registered.

As described here, "Twitter offers the ability for you to retrieve a single access token (complete with oauth_token_secret) from application detail pages found in your application control panel.  This is ideal for applications migrating to OAuth with single-user use cases ... By using a single access token, you don't need to implement the entire OAuth token acquisition dance. Instead, you can pick up from the point where you are working with an access token to make signed requests for Twitter resources."

This token and token secret is as close as you'll get to a username/password equivalent in OAuth.  In other words, once you have this one-time token and token secret for your application, you can issue signed OAuth requests against the Twitter API just like you would with a basic username and password.  If you want to think about it this way, the token is like your username and the token secret is like your password.  Don't share them.  Once you have these credentials, you can pull in Tweets for any public user, get their followers, read the public timeline, etc.

Here are several examples in a number of popular languages showing how you can use this one-time token and token secret in your project.

Yay for OAuth.
Date objects in Java, and probably most other robust languages, simply represent a snapshot of a point in time.  In other words, java.util.Date knows nothing about the time zone you're referring to when instantiating or manipulating a Date object.  Fact is, java.util.Date does not have to care about your time zone, because internally a Date is really nothing more than a count of the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.

If it helps, think about it this way: X milliseconds since the epoch is X milliseconds since the epoch in the US-Pacific time zone, X milliseconds since the epoch in GMT-0 (London), X milliseconds since the epoch in India, etc.  In short, when it's 1273947282085 milliseconds since the epoch, it's 1273947282085 milliseconds since the epoch everywhere in the world at the same time regardless of what time zone you're sitting in.  And since Java's util.Date is simply a snapshot of the number of milliseconds at a specific point in time, you can see why Date doesn't care about your time zone.  It's irrelevant.

But Mark, how do I convert a java.util.Date into a different time zone?  You can't, and that question makes no sense.  That's like asking me to "take a picture of the sound."  Here's some B.S. code that you should not use, but I've put it here for illustrative purposes:

// Do NOT use this, it does nothing and makes no sense.
public static final Date convertIntoTimeZone(Date date, TimeZone tz) {
final Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.setTimeZone(tz);
return cal.getTime();
}

You can't convert a Date into a different time zone, but you can use Java's handy DateFormat class to format a Date into the time zone of your choice.  To put it differently, let Date do its thing.  Then, when you're ready to display or print out a String representation of Date, that's when you tell DateFormat what time zone you want it in.  So, here's some code that makes sense, and actually works:

final Date currentTime = new Date();

final SimpleDateFormat sdf =
new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");

// Give it to me in US-Pacific time.
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println("LA time: " + sdf.format(currentTime));

// Give it to me in GMT-0 time.
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("GMT time: " + sdf.format(currentTime));

// Or maybe Zagreb local time.
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Zagreb"));
System.out.println("Zagreb time: " + sdf.format(currentTime));

// Even 10 hours and 10 minutes ahead of GMT
sdf.setTimeZone(TimeZone.getTimeZone("GMT+0010"));
System.out.println("10/10 ahead time: " + sdf.format(currentTime));

Yay for Dates and time zones!  Enjoy.
Dealing with HTTP's Digest authentication mechanism isn't too bad once you have the basic building blocks in place.  Luckily HttpClient 4 can automatically solve many types of authentication challenges for you, if used correctly.  Using HttpClient 4, I built an app that authenticates against a SOAP based web-service requiring WWW-Authenticate Digest authentication.  In a nutshell, the fundamental principal behind HTTP Digest authentication is simple:

  • The client asks for a page that requires authentication.
  • The server responds with an HTTP 401 response code, providing the authentication realm and a randomly-generated, single-use value called a "nonce".  The authentication "challenge" itself is encapsulated inside of the WWW-Authenticate HTTP response header.
  • The client "solves" the authentication challenge and a solution is sent back to the web-server via the HTTP Authorization header on a subsequent request.  The solution usually contains some type of MD5 hashed mess of your username, password, and "nonce".
  • Assuming the solution is acceptable the server responds with a successful type response, usually an HTTP 200 OK.

Here's a sample with a bit of pseudo code mixed in (so, you get the idea):

// A org.apache.http.impl.auth.DigestScheme instance is
// what will process the challenge from the web-server
final DigestScheme md5Auth = new DigestScheme();

// This should return an HTTP 401 Unauthorized with
// a challenge to solve.
final HttpResponse authResponse =
doPost(url, postBody, contentType);

// Validate that we got an HTTP 401 back
if(authResponse.getStatusLine().getStatusCode() ==
HttpStatus.SC_UNAUTHORIZED) {
if(authResponse.containsHeader("WWW-Authenticate")) {
// Get the challenge.
final Header challenge =
authResponse.getHeaders("WWW-Authenticate")[0];
// Solve it.
md5Auth.processChallenge(challenge);
// Generate a solution Authentication header using your
// username and password.
final Header solution = md5Auth.authenticate(
new UsernamePasswordCredentials(username, password),
new BasicHttpRequest(HttpPost.METHOD_NAME,
new URL(url).getPath()));
// Do another POST, but this time include the solution
// Authentication header as generated by HttpClient.
final HttpResponse goodResponse =
doPost(url, postBody, contentType, solution);
// ... do something useful with goodResponse, which assuming
// your credentials were valid, should contain the data you
// requested.
} else {
throw new Error("Web-service responded with Http 401, " +
"but didn't send us a usable WWW-Authenticate header.");
}
} else {
throw new Error("Didn't get an Http 401 " +
"like we were expecting.");
}

Enjoy.
I recently discovered that Pingdom, in many instances, does not correctly report page-load time.  As it turns out, when you ask Pingdom to tell you how fast your site loads it will incorrectly download all images and other resources referenced in your CSS, regardless of whether they are actually used on your site or not.  Of course this isn't ideal, because Pingdom will claim the page you're testing takes longer to load than it really does!  By comparison, smart web-browsers do not blindly download every image referenced in the CSS, on every page.  Instead, they download the resources as needed.

For folks who really care about site optimization and performance, this is a big deal.  Especially if you're hired to help a client optimize the page-load time of their web-site, but services like Pingdom lie and report junk.

Here's an example; imagine this is your homepage:

<html>
<head>
<title>My Homepage</title>
<style type="text/css">
#header {
background: black url(/header.png) no-repeat top left;
}
#homepage {
background: white url(/homepage.png) no-repeat top left;
}
#aboutus {
background: white url(/about-us.png) no-repeat top left;
}
#contact {
background: white url(/contact.png) no-repeat top left;
}
#footer {
background: black url(/footer.png) no-repeat top left;
}
</style>
</head>
<body>
<div id="header">header</div>
<div id="homepage">content</div>
<div id="footer">footer</div>
</body>
</html>

Ok, so you've got a header and a footer that will appear on every page.  In addition, you've got a few other CSS selectors for the homepage, for your "about us" page, and for your "contact us" page.  In a real web-browser, when you visit this page the browser will load the following images as referenced in your CSS:

  • header.png
  • homepage.png
  • footer.png
However, when you test this same page using Pingdom, Pingdom will claim your site is loading the following resources:

  • header.png
  • homepage.png
  • about-us.png
  • contact.png
  • footer.png
Wait a second, that's not accurate at all!  On this hypothetical homepage, I'm definitely not using #aboutus or #contact anywhere, so why should the resources associated with these selectors be factored into my page load time?  In reality, they shouldn't be because that's not how real web-browsers work.

To further validate my findings, I used the Rackspace Cloud and allocated a new machine with a running web-server.  I loaded this hypothetical homepage HTML onto it, and asked Pingdom to tell me how fast it loads:

pingdom-lies-snap1.jpg

Wrong!  I'm not using aboutus.png or contactus.png anywhere on the homepage, so why should Pingdom factor the load time of those images into my test results?  In contrast, using Firefox and HttpFox, I verified that real web-browsers only load the resources they need to properly render the page:

pingdom-lies-browser-is-better.jpg

Here you can see the correct resources are loaded in Firefox: header.png, homepage.png, and footer.png.

Bottom line, you really shouldn't use Pingdom and other external performance analysis tools as "bibles" for improving your page-load time.  Clearly they're only tools to help you identify obvious problems, and are definitely not a complete solution.  For more accurate results, I would suggest using tools like YSlow and Google's Page Speed.

Cheers.
countdownlatch-demo-screenshot.pngWhile working on some nifty multi-threaded Java recently, a colleague pointed me to a few really useful Java classes: CountDownLatch and CyclicBarrier.  My code was quite typical, a parent worker thread spawns a bunch of children to do real work, and needs to wait for the children to finish before continuing.  The catch though, is that the child worker threads may or may not finish successfully, and in all likelihood will finish at different times.  Even so, the parent thread must wait until all of its children have finished because the parent can only make forward progress once the children are complete.  I whipped up a little demo (screen shot left) that spawns five worker threads which update a JProgressBar at a random interval.  The demo finishes once each progress bar hits 100%.